db_manage.c
Go to the documentation of this file.00001
00011 #define _GNU_SOURCE
00012
00013 #include <stdlib.h>
00014 #include <sys/fcntl.h>
00015 #include <sys/mman.h>
00016 #include <sys/types.h>
00017 #include <sys/stat.h>
00018 #include <unistd.h>
00019 #include <errno.h>
00020 #include <string.h>
00021 #include <stdio.h>
00022
00023 #include "odb.h"
00024 #include "op_string.h"
00025 #include "op_libiberty.h"
00026
00027
00028 static __inline odb_descr_t * odb_to_descr(odb_data_t * data)
00029 {
00030 return (odb_descr_t *)(((char*)data->base_memory) + data->sizeof_header);
00031 }
00032
00033
00034 static __inline odb_node_t * odb_to_node_base(odb_data_t * data)
00035 {
00036 return (odb_node_t *)(((char *)data->base_memory) + data->offset_node);
00037 }
00038
00039
00040 static __inline odb_index_t * odb_to_hash_base(odb_data_t * data)
00041 {
00042 return (odb_index_t *)(((char *)data->base_memory) +
00043 data->offset_node +
00044 (data->descr->size * sizeof(odb_node_t)));
00045 }
00046
00047
00051 static unsigned int tables_size(odb_data_t const * data, odb_node_nr_t node_nr)
00052 {
00053 size_t size;
00054
00055 size = node_nr * (sizeof(odb_index_t) * BUCKET_FACTOR);
00056 size += node_nr * sizeof(odb_node_t);
00057 size += data->offset_node;
00058
00059 return size;
00060 }
00061
00062
00063 int odb_grow_hashtable(odb_data_t * data)
00064 {
00065 unsigned int old_file_size;
00066 unsigned int new_file_size;
00067 unsigned int pos;
00068 void * new_map;
00069
00070 old_file_size = tables_size(data, data->descr->size);
00071 new_file_size = tables_size(data, data->descr->size * 2);
00072
00073 if (ftruncate(data->fd, new_file_size))
00074 return 1;
00075
00076 new_map = mremap(data->base_memory,
00077 old_file_size, new_file_size, MREMAP_MAYMOVE);
00078
00079 if (new_map == MAP_FAILED)
00080 return 1;
00081
00082 data->base_memory = new_map;
00083 data->descr = odb_to_descr(data);
00084 data->descr->size *= 2;
00085 data->node_base = odb_to_node_base(data);
00086 data->hash_base = odb_to_hash_base(data);
00087 data->hash_mask = (data->descr->size * BUCKET_FACTOR) - 1;
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 #if 0
00105 for (pos = 0 ; pos < data->descr->size*BUCKET_FACTOR ; ++pos)
00106 data->hash_base[pos] = 0;
00107 #endif
00108
00109 for (pos = 1; pos < data->descr->current_size; ++pos) {
00110 odb_node_t * node = &data->node_base[pos];
00111 size_t index = odb_do_hash(data, node->key);
00112 node->next = data->hash_base[index];
00113 data->hash_base[index] = pos;
00114 }
00115
00116 return 0;
00117 }
00118
00119
00120 void odb_init(odb_t * odb)
00121 {
00122 odb->data = NULL;
00123 }
00124
00125
00126
00127 #define DEFAULT_NODE_NR(offset_node) 128
00128 #define FILES_HASH_SIZE 512
00129
00130 static struct list_head files_hash[FILES_HASH_SIZE];
00131
00132
00133 static void init_hash()
00134 {
00135 size_t i;
00136 for (i = 0; i < FILES_HASH_SIZE; ++i)
00137 list_init(&files_hash[i]);
00138 }
00139
00140
00141 static odb_data_t *
00142 find_samples_data(size_t hash, char const * filename)
00143 {
00144 struct list_head * pos;
00145
00146
00147 if (files_hash[0].next == NULL) {
00148 init_hash();
00149 return NULL;
00150 }
00151
00152 list_for_each(pos, &files_hash[hash]) {
00153 odb_data_t * entry = list_entry(pos, odb_data_t, list);
00154 if (strcmp(entry->filename, filename) == 0)
00155 return entry;
00156 }
00157
00158 return NULL;
00159 }
00160
00161
00162 int odb_open(odb_t * odb, char const * filename, enum odb_rw rw,
00163 size_t sizeof_header)
00164 {
00165 struct stat stat_buf;
00166 odb_node_nr_t nr_node;
00167 odb_data_t * data;
00168 size_t hash;
00169 int err = 0;
00170
00171 int flags = (rw == ODB_RDWR) ? (O_CREAT | O_RDWR) : O_RDONLY;
00172 int mmflags = (rw == ODB_RDWR) ? (PROT_READ | PROT_WRITE) : PROT_READ;
00173
00174 hash = op_hash_string(filename) % FILES_HASH_SIZE;
00175 data = find_samples_data(hash, filename);
00176 if (data) {
00177 odb->data = data;
00178 data->ref_count++;
00179 return 0;
00180 }
00181
00182 data = xmalloc(sizeof(odb_data_t));
00183 memset(data, '\0', sizeof(odb_data_t));
00184 list_init(&data->list);
00185 data->offset_node = sizeof_header + sizeof(odb_descr_t);
00186 data->sizeof_header = sizeof_header;
00187 data->ref_count = 1;
00188 data->filename = xstrdup(filename);
00189
00190 data->fd = open(filename, flags, 0644);
00191 if (data->fd < 0) {
00192 err = errno;
00193 goto out;
00194 }
00195
00196 if (fstat(data->fd, &stat_buf)) {
00197 err = errno;
00198 goto fail;
00199 }
00200
00201 if (stat_buf.st_size == 0) {
00202 size_t file_size;
00203
00204 if (rw == ODB_RDONLY) {
00205 err = EIO;
00206 goto fail;
00207 }
00208
00209 nr_node = DEFAULT_NODE_NR(data->offset_node);
00210
00211 file_size = tables_size(data, nr_node);
00212 if (ftruncate(data->fd, file_size)) {
00213 err = errno;
00214 goto fail;
00215 }
00216 } else {
00217
00218 nr_node = (stat_buf.st_size - data->offset_node) /
00219 ((sizeof(odb_index_t) * BUCKET_FACTOR) + sizeof(odb_node_t));
00220 }
00221
00222 data->base_memory = mmap(0, tables_size(data, nr_node), mmflags,
00223 MAP_SHARED, data->fd, 0);
00224
00225 if (data->base_memory == MAP_FAILED) {
00226 err = errno;
00227 goto fail;
00228 }
00229
00230 data->descr = odb_to_descr(data);
00231
00232 if (stat_buf.st_size == 0) {
00233 data->descr->size = nr_node;
00234
00235 data->descr->current_size = 1;
00236 } else {
00237
00238 if (nr_node != data->descr->size) {
00239 err = EINVAL;
00240 goto fail_unmap;
00241 }
00242 }
00243
00244 data->hash_base = odb_to_hash_base(data);
00245 data->node_base = odb_to_node_base(data);
00246 data->hash_mask = (data->descr->size * BUCKET_FACTOR) - 1;
00247
00248 list_add(&data->list, &files_hash[hash]);
00249 odb->data = data;
00250 out:
00251 return err;
00252 fail_unmap:
00253 munmap(data->base_memory, tables_size(data, nr_node));
00254 fail:
00255 close(data->fd);
00256 free(data->filename);
00257 free(data);
00258 odb->data = NULL;
00259 goto out;
00260 }
00261
00262
00263 void odb_close(odb_t * odb)
00264 {
00265 odb_data_t * data = odb->data;
00266
00267 if (data) {
00268 data->ref_count--;
00269 if (data->ref_count == 0) {
00270 size_t size = tables_size(data, data->descr->size);
00271 list_del(&data->list);
00272 munmap(data->base_memory, size);
00273 if (data->fd >= 0)
00274 close(data->fd);
00275 free(data->filename);
00276 free(data);
00277 odb->data = NULL;
00278 }
00279 }
00280 }
00281
00282
00283 int odb_open_count(odb_t const * odb)
00284 {
00285 if (!odb->data)
00286 return 0;
00287 return odb->data->ref_count;
00288 }
00289
00290
00291 void * odb_get_data(odb_t * odb)
00292 {
00293 return odb->data->base_memory;
00294 }
00295
00296
00297 void odb_sync(odb_t const * odb)
00298 {
00299 odb_data_t * data = odb->data;
00300 size_t size;
00301
00302 if (!data)
00303 return;
00304
00305 size = tables_size(data, data->descr->size);
00306 msync(data->base_memory, size, MS_ASYNC);
00307 }