Como armazenar fluxo infinito para arquivo?

2
  • Vamos ter um fluxo de dados binários (como /dev/random , /dev/zero , etc.).
  • Vamos ter um arquivo cujo tamanho pode ser N no máximo.
  • Vamos o N é na ordem de gigabytes.

Existe qualquer método elegante / tecnologia-a-usar / hack no linux, para conseguir tal arquivo escrito continuamente tem no máximo N bytes de comprimento e sempre contém apenas o último dados escritos (sequencialmente)? Isso significa que não há grandes movimentos (arquivo para arquivo, memória para arquivo) apenas pequenos ajustes com os últimos / primeiros blocos de dados.

O truque que estou procurando é o arquivo começar a avançar e efetivamente esquecer qualquer conteúdo muito antigo (o que aumentaria o tamanho do arquivo em N) - rotação de conteúdo.

O princípio desejado pode ser expresso como:

inp = fopen(stream, "r");
out = fopen(file, "wN"); // "Special open" with maximal size of N

while (is_reading)
{        
    if (rd = fread(buff, block_size, 1, inp))
    {
        fwrite(buff, rd, 1, out); // Old content forgotten
        fflush(out);              // Allow others to instantly see the current content
    }
}

fclose(inp);
fclose(out);
    
por sharpener 01.06.2016 / 17:11

1 resposta

2

No Linux, você pode usar fallocate() para desalocar os dados no início do arquivo.

Deallocating file space

Specifying the FALLOC_FL_PUNCH_HOLE flag (available since Linux 2.6.38) in mode deallocates space (i.e., creates a hole) in the byte range starting at offset and continuing for len bytes. Within the specified range, partial filesystem blocks are zeroed, and whole filesystem blocks are removed from the file. After a successful call, subsequent reads from this range will return zeroes.

...

Isso não alterará o tamanho do arquivo informado por ls ou stat ou similar, mas reduzirá o uso real do disco como arquivo será esparso . Tentar ler os "buracos" no arquivo ainda terá sucesso e retornará 0 -filled bytes para o processo de leitura.

Algo parecido com isto:

size_t maxSize = 512UL * 1024UL * 1024UL;
char buffer[ 8 * 1024 ];
struct stat sb;
int in = open( inputFile, O_RDONLY );
int out = open( outputFile, O_WRONLY | O_CREAT | O_APPEND, 0644 );
fstat( out, &sb );
size_t fileSize = sb.st_size;

for ( ;; )
{
    ssize_t bytesRead = read( in, buffer, sizeof( buffer ) );
    if ( bytesRead < 0 )
    {
        break;
    }

    ssize_t bytesWritten = write( out, buffer, bytesRead );
    if ( bytesWritten < 0 )
    {
        break;
    }

    fileSize += bytesWritten;

    if ( fileSize > maxSize )
    {
        fsync( out );
        off_t endOfHole = fileSize - maxSize;
        fallocate( out, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
            0UL, endOfHole );
    }
}

Isso é suportado apenas no XFS, BTRFS, EXT4 e tmpfs.

Ele também precisa de muito mais verificação de erros e pode até não ser compilado como está. Também é muito ineficiente, uma vez que o tamanho máximo é atingido, ele chamará fallocate() para cada read() / write() cycle, e ele perfurará o "buraco" do início do arquivo toda vez.

Também não faz sentido usar o fread() / fwrite() em buffer para esse padrão de IO. Apenas read() / write() pedaços grandes o suficiente.

    
por 01.06.2016 / 17:54