Fix some memory/fd leaks for tag searching and empty account listing
[blerg.git] / database.c
index ce03171..1e33811 100644 (file)
@@ -2,6 +2,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
+#include <time.h>
 #include <unistd.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -11,8 +12,6 @@
 #include "database.h"
 #include "config.h"
 
-#define RECORDS_PER_SEGMENT 65536
-
 uint64_t blerg_get_record_count(struct blerg *blerg) {
        uint64_t count;
        flock(blerg->meta_fd, LOCK_SH);
@@ -21,7 +20,7 @@ uint64_t blerg_get_record_count(struct blerg *blerg) {
        return count;
 }
 
-// Returns last usable record
+/* Returns last usable record */
 uint64_t blerg_increment_record_count(struct blerg *blerg) {
        uint64_t count;
        flock(blerg->meta_fd, LOCK_EX);
@@ -36,7 +35,7 @@ void blerg_segment_close(struct blerg *blerg) {
        if (blerg->data_fd != -1)
                close(blerg->data_fd);
        if (blerg->index != NULL)
-               munmap((void *)blerg->index, sizeof(RECORDS_PER_SEGMENT * sizeof(struct record)));
+               munmap((void *)blerg->index, RECORDS_PER_SEGMENT * sizeof(struct record));
        if (blerg->index_fd != -1)
                close(blerg->index_fd);
 }
@@ -53,7 +52,7 @@ int blerg_segment_switch(struct blerg *blerg, int new_segment) {
 
        blerg_segment_close(blerg);
 
-       // Load and map the index
+       /* Load and map the index */
        snprintf(filename, 512, "%s/index%d", blerg->base_path, new_segment);
        blerg->index_fd = open(filename, O_RDWR | O_CREAT, 0600);
        if (blerg->index_fd == -1) {
@@ -78,7 +77,7 @@ int blerg_segment_switch(struct blerg *blerg, int new_segment) {
                goto open_failed_index_mmap;
        }
 
-       // Load data file
+       /* Load data file */
        sprintf(filename, "%s/data%d", blerg->base_path, new_segment);
        blerg->data_fd = open(filename, O_RDWR | O_APPEND | O_CREAT, 0600);
        fstat(blerg->data_fd, &st);
@@ -101,13 +100,29 @@ int blerg_segment_switch(struct blerg *blerg, int new_segment) {
 open_failed_data_mmap:
        close(blerg->data_fd);
 open_failed_data_open:
-       munmap((void *)blerg->index, sizeof(65536 * sizeof(struct record)));
+       munmap((void *)blerg->index, sizeof(RECORDS_PER_SEGMENT * sizeof(struct record)));
 open_failed_index_mmap:
        close(blerg->index_fd);
 open_failed_index_open:
        return 0;
 }
 
+int blerg_exists(const char *name) {
+       int namelen = strlen(name);
+       char filename[512];
+
+       if (namelen > 32) {
+               perror("Name too long");
+               return 0;
+       }
+
+       snprintf(filename, 512, "%s/%s", DATA_PATH, name);
+       if (access(filename, F_OK) == -1)
+               return 0;
+       else
+               return 1;
+}
+
 struct blerg *blerg_open(const char *name) {
        int namelen = strlen(name);
        char filename[512];
@@ -123,18 +138,20 @@ struct blerg *blerg_open(const char *name) {
                perror("Cannot allocate memory for blerg");
                goto open_failed_blerg_malloc;
        }
+       blerg->name = malloc(namelen + 1);
+       memcpy(blerg->name, name, namelen + 1);
        blerg->meta_fd = blerg->index_fd = blerg->data_fd = -1;
        blerg->meta = NULL;
        blerg->index = NULL;
        blerg->data = NULL;
 
-       // Make the directory if it doesn't exist
+       /* Make the directory if it doesn't exist */
        blerg->base_path = malloc(512);
        snprintf(blerg->base_path, 512, "%s/%s", DATA_PATH, name);
        if (access(blerg->base_path, F_OK) == -1)
                mkdir(blerg->base_path, 0755);
 
-       // Open and map metadata
+       /* Open and map metadata */
        snprintf(filename, 512, "%s/meta", blerg->base_path);
        blerg->meta_fd = open(filename, O_RDWR | O_CREAT, 0600);
        if (blerg->meta_fd == -1) {
@@ -154,7 +171,7 @@ struct blerg *blerg_open(const char *name) {
                goto open_failed_meta_mmap;
        }
 
-       // Open and map index and data for the current segment
+       /* Open and map index and data for the current segment */
        blerg->current_segment = blerg_get_record_count(blerg) / RECORDS_PER_SEGMENT;
        if (!blerg_segment_switch(blerg, blerg->current_segment)) {
                fprintf(stderr, "Could not switch segment\n");
@@ -168,6 +185,7 @@ open_failed_segment_switch:
 open_failed_meta_mmap:
        close(blerg->meta_fd);
 open_failed_meta_open:
+       free(blerg->name);
        free(blerg);
 open_failed_blerg_malloc:
        return NULL;
@@ -178,12 +196,13 @@ int blerg_close(struct blerg *blerg) {
        munmap((void *)blerg->meta, sizeof(struct meta));
        close(blerg->meta_fd);
        free(blerg->base_path);
+       free(blerg->name);
        free(blerg);
        return 1;
 }
 
 int blerg_store(struct blerg *blerg, const char *data, int len) {
-       if (len > 65536) {
+       if (len > MAX_RECORD_SIZE) {
                printf("len > 64K\n");
                return -1;
        }
@@ -191,17 +210,17 @@ int blerg_store(struct blerg *blerg, const char *data, int len) {
        flock(blerg->index_fd, LOCK_EX);
        flock(blerg->data_fd, LOCK_EX);
 
-       uint64_t rec = blerg_increment_record_count(blerg);
-       if (rec == -1) {
+       uint64_t record = blerg_increment_record_count(blerg);
+       if (record == -1) {
                printf("Could not find free record\n");
                return -1;
        }
-       int segment = rec / RECORDS_PER_SEGMENT;
+       int segment = record / RECORDS_PER_SEGMENT;
        if (segment != blerg->current_segment)
                blerg_segment_switch(blerg, segment);
-       rec = rec % RECORDS_PER_SEGMENT;
+       int seg_rec = record % RECORDS_PER_SEGMENT;
 
-       // Get the position for the new data
+       /* Get the position for the new data */
        FILE *datafile = fdopen(dup(blerg->data_fd), "a");
        fseek(datafile, 0, SEEK_END);
        int curpos = ftell(datafile);
@@ -212,43 +231,46 @@ int blerg_store(struct blerg *blerg, const char *data, int len) {
                int n = write(blerg->data_fd, data + bytes, len);
                if (n == -1) {
                        perror("Could not write data");
-                       // Truncate anything we may have written
+                       /* Truncate anything we may have written */
                        ftruncate(blerg->data_fd, curpos);
                        return -1;
                }
                bytes += n;
        } while (bytes < len);
-       blerg->index[rec].flags = 0x0001;
-       blerg->index[rec].offset = curpos;
-       blerg->index[rec].length = len;
+       blerg->index[seg_rec].flags = 0x0001;
+       blerg->index[seg_rec].offset = curpos;
+       blerg->index[seg_rec].length = len;
+       blerg->index[seg_rec].timestamp = time(NULL);
+
+       tag_scan(blerg->name, data, len, record);
 
        flock(blerg->data_fd, LOCK_UN);
        flock(blerg->index_fd, LOCK_UN);
 
-       return segment * RECORDS_PER_SEGMENT + rec;
+       return record;
 }
 
-int blerg_fetch(struct blerg *blerg, int rec, char **data, int *length) {
-       if (rec < 0) {
+int blerg_fetch(struct blerg *blerg, int record, char **data, int *length) {
+       if (record < 0) {
                printf("Invalid record\n");
                return 0;
        }
 
-       int segment = rec / RECORDS_PER_SEGMENT;
+       int segment = record / RECORDS_PER_SEGMENT;
        if (segment != blerg->current_segment)
                blerg_segment_switch(blerg, segment);
-       rec = rec % RECORDS_PER_SEGMENT;
+       int seg_rec = record % RECORDS_PER_SEGMENT;
 
-       if ((blerg->index[rec].flags & 0x1) == 0) {
+       if ((blerg->index[seg_rec].flags & 0x1) == 0) {
                printf("Invalid record\n");
                return 0;
        }
 
-       int rec_offset = blerg->index[rec].offset;
-       int rec_length = blerg->index[rec].length;
+       int rec_offset = blerg->index[seg_rec].offset;
+       int rec_length = blerg->index[seg_rec].length;
        if (rec_offset >= blerg->data_size) {
-               // We're accessing an out-of-bounds record in our mmap.
-               // Recheck size and remap.
+               /* We're accessing an out-of-bounds record in our mmap.
+                  Recheck size and remap. */
                struct stat st;
                fstat(blerg->data_fd, &st);
                blerg->data_size = st.st_size;
@@ -277,3 +299,22 @@ int blerg_fetch(struct blerg *blerg, int rec, char **data, int *length) {
 
        return 1;
 }
+
+time_t blerg_get_timestamp(struct blerg *blerg, int record) {
+       if (record < 0) {
+               printf("Invalid record\n");
+               return 0;
+       }
+
+       int segment = record / RECORDS_PER_SEGMENT;
+       if (segment != blerg->current_segment)
+               blerg_segment_switch(blerg, segment);
+       int seg_rec = record % RECORDS_PER_SEGMENT;
+
+       if ((blerg->index[seg_rec].flags & 0x1) == 0) {
+               printf("Invalid record\n");
+               return 0;
+       }
+
+       return blerg->index[seg_rec].timestamp;
+}