Auto-defrag cache file
This commit is contained in:
parent
a60f347648
commit
bc86bc91f7
@ -141,6 +141,12 @@ copy_between_files(int infd, int outfd, off_t in_pos, size_t len, uint8_t *buf,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline off_t
|
||||||
|
size_of_cache_file(DiskCache *self) {
|
||||||
|
return lseek(self->cache_file_fd, 0, SEEK_END);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t hash_key[MAX_KEY_SIZE];
|
uint8_t hash_key[MAX_KEY_SIZE];
|
||||||
unsigned short hash_keylen;
|
unsigned short hash_keylen;
|
||||||
@ -156,7 +162,7 @@ defrag(DiskCache *self) {
|
|||||||
const size_t bufsz = 1024 * 1024;
|
const size_t bufsz = 1024 * 1024;
|
||||||
bool lock_released = false, ok = false;
|
bool lock_released = false, ok = false;
|
||||||
|
|
||||||
off_t size_on_disk = lseek(self->cache_file_fd, 0, SEEK_CUR);
|
off_t size_on_disk = size_of_cache_file(self);
|
||||||
if (size_on_disk <= 0) goto cleanup;
|
if (size_on_disk <= 0) goto cleanup;
|
||||||
size_t num_entries = HASH_COUNT(self->entries);
|
size_t num_entries = HASH_COUNT(self->entries);
|
||||||
if (!num_entries) goto cleanup;
|
if (!num_entries) goto cleanup;
|
||||||
@ -221,22 +227,50 @@ cleanup:
|
|||||||
if (new_cache_file > -1) safe_close(new_cache_file, __FILE__, __LINE__);
|
if (new_cache_file > -1) safe_close(new_cache_file, __FILE__, __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmp_pos_in_cache_file(void *a_, void *b_) {
|
||||||
|
CacheEntry *a = a_, *b = b_;
|
||||||
|
return a->pos_in_cache_file - b->pos_in_cache_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
find_hole(DiskCache *self) {
|
||||||
|
off_t required_size = self->currently_writing.data_sz, prev = -1;
|
||||||
|
HASH_SORT(self->entries, cmp_pos_in_cache_file);
|
||||||
|
CacheEntry *s, *tmp;
|
||||||
|
HASH_ITER(hh, self->entries, s, tmp) {
|
||||||
|
if (s->pos_in_cache_file >= 0) {
|
||||||
|
if (prev >= 0 && s->pos_in_cache_file - prev > required_size) {
|
||||||
|
self->currently_writing.pos_in_cache_file = prev;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prev = s->pos_in_cache_file + s->data_sz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
find_cache_entry_to_write(DiskCache *self) {
|
find_cache_entry_to_write(DiskCache *self) {
|
||||||
CacheEntry *tmp, *s;
|
CacheEntry *tmp, *s;
|
||||||
off_t size_on_disk = lseek(self->cache_file_fd, 0, SEEK_END);
|
off_t size_on_disk = size_of_cache_file(self);
|
||||||
if (self->total_size && size_on_disk > 0 && (size_t)size_on_disk > self->total_size * 2) defrag(self);
|
if (self->total_size && size_on_disk > 0 && (size_t)size_on_disk > self->total_size * 2) defrag(self);
|
||||||
HASH_ITER(hh, self->entries, s, tmp) {
|
HASH_ITER(hh, self->entries, s, tmp) {
|
||||||
if (!s->written_to_disk) {
|
if (!s->written_to_disk) {
|
||||||
if (s->data) {
|
if (s->data) {
|
||||||
|
if (self->currently_writing.data) free(self->currently_writing.data);
|
||||||
self->currently_writing.data = s->data;
|
self->currently_writing.data = s->data;
|
||||||
s->data = NULL;
|
s->data = NULL;
|
||||||
self->currently_writing.data_sz = s->data_sz;
|
self->currently_writing.data_sz = s->data_sz;
|
||||||
|
self->currently_writing.pos_in_cache_file = -1;
|
||||||
xor_data(s->encryption_key, sizeof(s->encryption_key), self->currently_writing.data, s->data_sz);
|
xor_data(s->encryption_key, sizeof(s->encryption_key), self->currently_writing.data, s->data_sz);
|
||||||
self->currently_writing.hash_keylen = MIN(s->hash_keylen, MAX_KEY_SIZE);
|
self->currently_writing.hash_keylen = MIN(s->hash_keylen, MAX_KEY_SIZE);
|
||||||
memcpy(self->currently_writing.hash_key, s->hash_key, self->currently_writing.hash_keylen);
|
memcpy(self->currently_writing.hash_key, s->hash_key, self->currently_writing.hash_keylen);
|
||||||
|
find_hole(self);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
s->written_to_disk = true;
|
||||||
|
s->pos_in_cache_file = 0;
|
||||||
|
s->data_sz = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -246,13 +280,16 @@ static inline bool
|
|||||||
write_dirty_entry(DiskCache *self) {
|
write_dirty_entry(DiskCache *self) {
|
||||||
size_t left = self->currently_writing.data_sz;
|
size_t left = self->currently_writing.data_sz;
|
||||||
uint8_t *p = self->currently_writing.data;
|
uint8_t *p = self->currently_writing.data;
|
||||||
self->currently_writing.pos_in_cache_file = lseek(self->cache_file_fd, 0, SEEK_CUR);
|
|
||||||
if (self->currently_writing.pos_in_cache_file < 0) {
|
if (self->currently_writing.pos_in_cache_file < 0) {
|
||||||
perror("Failed to seek in disk cache file");
|
self->currently_writing.pos_in_cache_file = size_of_cache_file(self);
|
||||||
return false;
|
if (self->currently_writing.pos_in_cache_file < 0) {
|
||||||
|
perror("Failed to seek in disk cache file");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
off_t offset = self->currently_writing.pos_in_cache_file;
|
||||||
while (left > 0) {
|
while (left > 0) {
|
||||||
ssize_t n = write(self->cache_file_fd, p, left);
|
ssize_t n = pwrite(self->cache_file_fd, p, left, offset);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
if (errno == EINTR || errno == EAGAIN) continue;
|
if (errno == EINTR || errno == EAGAIN) continue;
|
||||||
perror("Failed to write to disk-cache file");
|
perror("Failed to write to disk-cache file");
|
||||||
@ -266,6 +303,7 @@ write_dirty_entry(DiskCache *self) {
|
|||||||
}
|
}
|
||||||
left -= n;
|
left -= n;
|
||||||
p += n;
|
p += n;
|
||||||
|
offset += n;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user