- Vamos ter qualquer fluxo de dados binários (como
/dev/random
,,/dev/zero
etc.). - 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 ls
ou stat
similar, mas reduzirá o uso real do disco, pois oo arquivo será esparso. Tentar ler os "buracos" no arquivo ainda terá sucesso e retornará 0
bytes 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()
.