16 uint64_t blerg_get_record_count(struct blerg *blerg) {
18 flock(blerg->meta_fd, LOCK_SH);
19 count = blerg->meta->sequence;
20 flock(blerg->meta_fd, LOCK_UN);
24 /* Returns last usable record */
25 uint64_t blerg_increment_record_count(struct blerg *blerg) {
27 flock(blerg->meta_fd, LOCK_EX);
28 count = blerg->meta->sequence++;
29 flock(blerg->meta_fd, LOCK_UN);
33 void blerg_segment_close(struct blerg *blerg) {
34 if (blerg->data != NULL)
35 munmap((void *)blerg->data, blerg->data_size);
36 if (blerg->data_fd != -1)
37 close(blerg->data_fd);
38 if (blerg->index != NULL)
39 munmap((void *)blerg->index, RECORDS_PER_SEGMENT * sizeof(struct record));
40 if (blerg->index_fd != -1)
41 close(blerg->index_fd);
44 int blerg_segment_switch(struct blerg *blerg, int new_segment) {
46 uint64_t max_sequence = blerg_get_record_count(blerg);
49 if (new_segment > max_sequence / RECORDS_PER_SEGMENT) {
50 fprintf(stderr, "Cannot switch to sequence beyond last record\n");
54 blerg_segment_close(blerg);
56 /* Load and map the index */
57 snprintf(filename, 512, "%s/index%d", blerg->base_path, new_segment);
58 blerg->index_fd = open(filename, O_RDWR | O_CREAT, 0600);
59 if (blerg->index_fd == -1) {
60 perror("Could not open index");
61 goto open_failed_index_open;
63 flock(blerg->index_fd, LOCK_EX);
64 fstat(blerg->index_fd, &st);
65 if (st.st_size == 0) {
68 memset((void *)&r, 0, sizeof(struct record));
69 for (i = 0; i < RECORDS_PER_SEGMENT; i++) {
70 write(blerg->index_fd, &r, sizeof(struct record));
73 flock(blerg->index_fd, LOCK_UN);
75 blerg->index = (struct record *) mmap(NULL, RECORDS_PER_SEGMENT * sizeof(struct record), PROT_READ | PROT_WRITE, MAP_SHARED, blerg->index_fd, 0);
76 if (blerg->index == MAP_FAILED) {
77 perror("Could not mmap index");
78 goto open_failed_index_mmap;
82 sprintf(filename, "%s/data%d", blerg->base_path, new_segment);
83 blerg->data_fd = open(filename, O_RDWR | O_APPEND | O_CREAT, 0600);
84 fstat(blerg->data_fd, &st);
85 blerg->data_size = st.st_size;
86 if (blerg->data_fd == -1) {
87 perror("Could not open data");
88 goto open_failed_data_open;
91 if (blerg->data_size > 0) {
92 blerg->data = (char *) mmap(NULL, blerg->data_size, PROT_READ, MAP_SHARED, blerg->data_fd, 0);
93 if (blerg->data == MAP_FAILED) {
94 perror("Could not mmap data");
95 goto open_failed_data_mmap;
101 open_failed_data_mmap:
102 close(blerg->data_fd);
103 open_failed_data_open:
104 munmap((void *)blerg->index, sizeof(RECORDS_PER_SEGMENT * sizeof(struct record)));
105 open_failed_index_mmap:
106 close(blerg->index_fd);
107 open_failed_index_open:
111 int blerg_exists(const char *name) {
112 int namelen = strlen(name);
115 if (!valid_name(name)) {
116 fprintf(stderr, "Invalid name\n");
120 snprintf(filename, 512, "%s/%s", DATA_PATH, name);
121 if (access(filename, F_OK) == -1)
127 struct blerg *blerg_open(const char *name) {
128 int namelen = strlen(name);
133 if (!valid_name(name)) {
134 fprintf(stderr, "Invalid name\n");
137 struct blerg *blerg = malloc(sizeof(struct blerg));
139 perror("Cannot allocate memory for blerg");
140 goto open_failed_blerg_malloc;
142 blerg->name = malloc(namelen + 1);
143 memcpy(blerg->name, name, namelen + 1);
144 blerg->meta_fd = blerg->index_fd = blerg->data_fd = -1;
149 /* Make the directory if it doesn't exist */
150 blerg->base_path = malloc(512);
151 snprintf(blerg->base_path, 512, "%s/%s", DATA_PATH, name);
152 if (access(blerg->base_path, F_OK) == -1)
153 mkdir(blerg->base_path, 0755);
155 /* Open and map metadata */
156 snprintf(filename, 512, "%s/meta", blerg->base_path);
157 blerg->meta_fd = open(filename, O_RDWR | O_CREAT, 0600);
158 if (blerg->meta_fd == -1) {
159 perror("Could not open metadata");
160 goto open_failed_meta_open;
162 fstat(blerg->meta_fd, &st);
163 if (st.st_size == 0) {
164 char *buf = (char *) malloc(sizeof(struct meta));
165 memset(buf, 0, sizeof(struct meta));
166 write(blerg->meta_fd, buf, sizeof(struct meta));
169 blerg->meta = (struct meta *) mmap(NULL, sizeof(struct meta), PROT_READ | PROT_WRITE, MAP_SHARED, blerg->meta_fd, 0);
170 if (blerg->meta == MAP_FAILED) {
171 perror("Could not map metadata");
172 goto open_failed_meta_mmap;
175 /* Open and map index and data for the current segment */
176 blerg->current_segment = blerg_get_record_count(blerg) / RECORDS_PER_SEGMENT;
177 if (!blerg_segment_switch(blerg, blerg->current_segment)) {
178 fprintf(stderr, "Could not switch segment\n");
179 goto open_failed_segment_switch;
184 open_failed_segment_switch:
185 munmap((void *)blerg->meta, sizeof(struct meta));
186 open_failed_meta_mmap:
187 close(blerg->meta_fd);
188 open_failed_meta_open:
191 open_failed_blerg_malloc:
195 int blerg_close(struct blerg *blerg) {
196 blerg_segment_close(blerg);
197 munmap((void *)blerg->meta, sizeof(struct meta));
198 close(blerg->meta_fd);
199 free(blerg->base_path);
205 int blerg_store(struct blerg *blerg, const char *data, int len) {
206 if (len > MAX_RECORD_SIZE) {
207 fprintf(stderr, "len > 64K\n");
211 flock(blerg->index_fd, LOCK_EX);
212 flock(blerg->data_fd, LOCK_EX);
214 uint64_t record = blerg_increment_record_count(blerg);
216 fprintf(stderr, "Could not find free record\n");
219 int segment = record / RECORDS_PER_SEGMENT;
220 if (segment != blerg->current_segment)
221 blerg_segment_switch(blerg, segment);
222 int seg_rec = record % RECORDS_PER_SEGMENT;
224 /* Get the position for the new data */
225 FILE *datafile = fdopen(dup(blerg->data_fd), "a");
226 fseek(datafile, 0, SEEK_END);
227 int curpos = ftell(datafile);
232 int n = write(blerg->data_fd, data + bytes, len);
234 perror("Could not write data");
235 /* Truncate anything we may have written */
236 ftruncate(blerg->data_fd, curpos);
240 } while (bytes < len);
241 blerg->index[seg_rec].flags = 0x0001;
242 blerg->index[seg_rec].offset = curpos;
243 blerg->index[seg_rec].length = len;
244 blerg->index[seg_rec].timestamp = time(NULL);
246 tag_scan(blerg->name, data, len, record);
248 flock(blerg->data_fd, LOCK_UN);
249 flock(blerg->index_fd, LOCK_UN);
254 int blerg_fetch(struct blerg *blerg, int record, char **data, int *length) {
256 fprintf(stderr, "Invalid record\n");
260 int segment = record / RECORDS_PER_SEGMENT;
261 if (segment != blerg->current_segment)
262 blerg_segment_switch(blerg, segment);
263 int seg_rec = record % RECORDS_PER_SEGMENT;
265 if ((blerg->index[seg_rec].flags & 0x1) == 0) {
266 fprintf(stderr, "Invalid record\n");
270 int rec_offset = blerg->index[seg_rec].offset;
271 int rec_length = blerg->index[seg_rec].length;
272 if (rec_offset >= blerg->data_size) {
273 /* We're accessing an out-of-bounds record in our mmap.
274 Recheck size and remap. */
276 fstat(blerg->data_fd, &st);
277 blerg->data_size = st.st_size;
278 if (rec_offset > blerg->data_size) {
279 fprintf(stderr, "Record offset outside of data!?");
283 munmap(blerg->data, blerg->data_size);
284 blerg->data = (char *) mmap(NULL, blerg->data_size, PROT_READ, MAP_SHARED, blerg->data_fd, 0);
285 if (blerg->data == MAP_FAILED) {
286 perror("Could not remap data");
291 *data = malloc(rec_length);
293 perror("Could not allocate string in fetch");
297 memcpy(*data, blerg->data + rec_offset, rec_length);
299 *length = rec_length;
304 time_t blerg_get_timestamp(struct blerg *blerg, int record) {
306 fprintf(stderr, "Invalid record\n");
310 int segment = record / RECORDS_PER_SEGMENT;
311 if (segment != blerg->current_segment)
312 blerg_segment_switch(blerg, segment);
313 int seg_rec = record % RECORDS_PER_SEGMENT;
315 if ((blerg->index[seg_rec].flags & 0x1) == 0) {
316 fprintf(stderr, "Invalid record\n");
320 return blerg->index[seg_rec].timestamp;