aboutsummaryrefslogtreecommitdiffstats
path: root/src/statfile.c
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@rambler-co.ru>2008-11-28 19:29:00 +0300
committerVsevolod Stakhov <vsevolod@rambler-co.ru>2008-11-28 19:29:00 +0300
commit06661f20cbb9d2f1d0f8a68fb7bc46dcd97c6276 (patch)
treed1054848d24437038adb3f75cbfc028c94e69548 /src/statfile.c
parentf1fdc9c6c1fa897f6eac5abc4cd193b55d31e7bc (diff)
downloadrspamd-06661f20cbb9d2f1d0f8a68fb7bc46dcd97c6276.tar.gz
rspamd-06661f20cbb9d2f1d0f8a68fb7bc46dcd97c6276.zip
* Write functions to operate blocks in stat files
* Write test case for statistics files API
Diffstat (limited to 'src/statfile.c')
-rw-r--r--src/statfile.c144
1 files changed, 141 insertions, 3 deletions
diff --git a/src/statfile.c b/src/statfile.c
index ba735bcbf..fc7ebfc7a 100644
--- a/src/statfile.c
+++ b/src/statfile.c
@@ -38,12 +38,12 @@ statfile_pool_check (stat_file_t *file)
return -1;
}
- if (file->len - sizeof (f->header) % sizeof (struct stat_file_block) != 0) {
+ if ((file->len - sizeof (f->header)) % sizeof (struct stat_file_block) != 0) {
msg_info ("statfile_pool_check: file %s does not contain integer count of stat blocks", file->filename);
return -1;
}
- file->blocks = file->len - sizeof (f->header) / sizeof (struct stat_file_block);
+ file->blocks = (file->len - sizeof (f->header)) / sizeof (struct stat_file_block);
return 0;
}
@@ -189,6 +189,7 @@ statfile_pool_create (statfile_pool_t *pool, char *filename, size_t blocks)
static struct stat_file_header header = {
{'r', 's', 'd'},
{1, 0},
+ {0, 0, 0},
0
};
static struct stat_file_block block = {0, 0, 0, 0};
@@ -199,7 +200,7 @@ statfile_pool_create (statfile_pool_t *pool, char *filename, size_t blocks)
return 0;
}
- if ((fd = open (filename, O_RDWR | O_TRUNC | O_CREAT)) == -1 ) {
+ if ((fd = open (filename, O_RDWR | O_TRUNC | O_CREAT, S_IWUSR | S_IRUSR)) == -1 ) {
msg_info ("statfile_pool_create: cannot create file %s, error %m, %d", filename, errno);
return -1;
}
@@ -239,3 +240,140 @@ statfile_pool_delete (statfile_pool_t *pool)
memory_pool_delete (pool->pool);
g_free (pool);
}
+
+void
+statfile_pool_lock_file (statfile_pool_t *pool, char *filename)
+{
+ stat_file_t *file;
+
+ if ((file = g_hash_table_lookup (pool->files, filename)) == NULL) {
+ msg_info ("statfile_pool_lock_file: file %s is not opened", filename);
+ return;
+ }
+
+ memory_pool_lock_mutex (file->lock);
+}
+
+void
+statfile_pool_unlock_file (statfile_pool_t *pool, char *filename)
+{
+ stat_file_t *file;
+
+ if ((file = g_hash_table_lookup (pool->files, filename)) == NULL) {
+ msg_info ("statfile_pool_unlock_file: file %s is not opened", filename);
+ return;
+ }
+
+ memory_pool_unlock_mutex (file->lock);
+}
+
+uint32_t
+statfile_pool_get_block (statfile_pool_t *pool, char *filename, uint32_t h1, uint32_t h2, time_t now)
+{
+ stat_file_t *file;
+ struct stat_file_block *block;
+ struct stat_file_header *header;
+ unsigned int i, blocknum;
+ u_char *c;
+
+ if ((file = g_hash_table_lookup (pool->files, filename)) == NULL) {
+ msg_info ("statfile_pool_get_block: file %s is not opened", filename);
+ return 0;
+ }
+
+ file->access_time = now;
+ if (!file->map) {
+ return 0;
+ }
+
+ blocknum = h1 % file->blocks;
+ header = (struct stat_file_header *)file->map;
+ c = (u_char *)file->map + sizeof (struct stat_file_header) + blocknum * sizeof (struct stat_file_block);
+ block = (struct stat_file_block *)c;
+
+ for (i = 0; i < CHAIN_LENGTH; i ++) {
+ if (i + blocknum > file->blocks) {
+ break;
+ }
+ msg_debug ("statfile_pool_get_block: test block with h1=%u, h2=%u, number %u in chain %u", block->hash1, block->hash2, i, blocknum);
+ if (block->hash1 == h1 && block->hash2 == h2) {
+ msg_debug ("statfile_pool_get_block: found block with h1=%u, h2=%u, number %u in chain %u", h1, h2, i, blocknum);
+ block->last_access = now - (time_t)header->create_time;
+ return block->value;
+ }
+ c += sizeof (struct stat_file_block);
+ block = (struct stat_file_block *)c;
+ }
+
+ msg_debug ("statfile_pool_get_block: block with h1=%u, h2=%u, not found in chain %u", h1, h2, blocknum);
+
+ return 0;
+}
+
+void
+statfile_pool_set_block (statfile_pool_t *pool, char *filename, uint32_t h1, uint32_t h2, time_t now, uint32_t value)
+{
+ stat_file_t *file;
+ struct stat_file_block *block, *to_expire = NULL;
+ struct stat_file_header *header;
+ unsigned int i, blocknum, oldest = 0;
+ u_char *c;
+
+ if ((file = g_hash_table_lookup (pool->files, filename)) == NULL) {
+ msg_info ("statfile_pool_set_block: file %s is not opened", filename);
+ return;
+ }
+
+ file->access_time = now;
+ if (!file->map) {
+ return;
+ }
+
+ blocknum = h1 % file->blocks;
+ header = (struct stat_file_header *)file->map;
+ c = (u_char *)file->map + sizeof (struct stat_file_header) + blocknum * sizeof (struct stat_file_block);
+ block = (struct stat_file_block *)c;
+
+ for (i = 0; i < CHAIN_LENGTH; i ++) {
+ if (i + blocknum > file->blocks) {
+ /* Need to expire some block in chain */
+ msg_debug ("statfile_pool_set_block: chain %u is full, starting expire", blocknum);
+ break;
+ }
+ /* Check whether we have a free block in chain */
+ if (block->hash1 == 0 && block->hash2 == 0) {
+ /* Write new block here */
+ msg_debug ("statfile_pool_set_block: found free block %u in chain %u, set h1=%u, h2=%u", i, blocknum, h1, h2);
+ block->hash1 = h1;
+ block->hash2 = h2;
+ block->value = value;
+ block->last_access = now - (time_t)header->create_time;
+ return;
+ }
+ if (block->last_access > oldest) {
+ to_expire = block;
+ }
+ c += sizeof (struct stat_file_block);
+ block = (struct stat_file_block *)c;
+ }
+
+ /* Try expire some block */
+ if (to_expire) {
+ block = to_expire;
+ }
+ else {
+ /* Expire first block in chain */
+ c = (u_char *)file->map + sizeof (struct stat_file_header) + blocknum * sizeof (struct stat_file_block);
+ block = (struct stat_file_block *)c;
+ }
+ block->last_access = now - (time_t)header->create_time;
+ block->hash1 = h1;
+ block->hash2 = h2;
+ block->value = value;
+}
+
+int
+statfile_pool_is_open (statfile_pool_t *pool, char *filename)
+{
+ return g_hash_table_lookup (pool->files, filename) != NULL;
+}