Como armazenar fluxo infinito em arquivo?

Como armazenar fluxo infinito em arquivo?
  • Vamos ter qualquer fluxo de dados binários (como /dev/random,, /dev/zeroetc.).
  • Vamos ter um arquivo cujo tamanho pode ser N no máximo.
  • Vamos que o N esteja na ordem de gigabytes.

Existequalquer elegantemétodo/tecnologia para usar/hackear no Linux, para alcançar talarquivogravado continuamente tem no máximo N bytes e sempre contém apenas os últimos dados gravados (sequencialmente)? Isso significa que não há grandes movimentos (arquivo para arquivo, memória para arquivo), apenas pequenos ajustes nos últimos/primeiros blocos de dados.

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

O princípio desejado poderia 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);

Responder1

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

Desalocando espaço de arquivo

Especificar o sinalizador FALLOC_FL_PUNCH_HOLE (disponível desde Linux 2.6.38) no modo desaloca espaço (ou seja, cria um buraco) no intervalo de bytes começando no deslocamento e continuando por len bytes. Dentro do intervalo especificado, os blocos parciais do sistema de arquivos são zerados e os blocos inteiros do sistema de arquivos são removidos do arquivo. Após uma chamada bem-sucedida, as leituras subsequentes desse intervalo retornarão zeros.

...

Isso não alterará o tamanho do arquivo relatado por lsou statsimilar, mas reduzirá o uso real do disco, pois oo arquivo será esparso. Tentar ler os "buracos" no arquivo ainda terá sucesso e retornará 0bytes preenchidos para o processo de leitura.

Algo assim:

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 é compatível apenas com XFS, BTRFS, EXT4 e tmpfs.

Ele também precisa de muito mais verificação de erros e pode nem ser compilado como está. Também é muito ineficiente, pois quando o tamanho máximo for atingido, ele solicitará fallocate()cada ciclo read()/ write()e perfurará o "buraco" desde o início do arquivo todas as vezes.

Também não faz sentido usar buffered fread()/ fwrite()para esse padrão IO. read()Pedaços grandes o suficiente write().

informação relacionada