00001
00002 #include <microfeed-provider/microfeeddatabase.h>
00003 #include <microfeed-common/microfeedmisc.h>
00004 #include <microfeed-common/microfeedthread.h>
00005 #include <microfeed-common/microfeedstore.h>
00006
00007 #include <errno.h>
00008 #include <string.h>
00009 #include <db.h>
00010
00011 struct _MicrofeedDatabaseEnvironment {
00012 unsigned int reference_count;
00013 MicrofeedMutex* mutex;
00014 char* name;
00015 DB_ENV* db_env;
00016 MicrofeedStore* databases;
00017 };
00018
00019 struct _MicrofeedDatabase {
00020 unsigned int reference_count;
00021 MicrofeedMutex* mutex;
00022 MicrofeedDatabaseEnvironment* database_environment;
00023 char* name;
00024 MicrofeedDatabaseCompareFunction compare_function;
00025 DB* db;
00026 MicrofeedDatabaseIndex* indices;
00027 MicrofeedDatabaseIterator* iterators;
00028 };
00029
00030 struct _MicrofeedDatabaseIndex {
00031 MicrofeedDatabaseIndex* next;
00032
00033 MicrofeedDatabase* database;
00034 char* name;
00035 DB* db;
00036 MicrofeedDatabaseIndexFunction index_function;
00037 };
00038
00039 struct _MicrofeedDatabaseIterator {
00040 MicrofeedDatabaseIterator* previous;
00041 MicrofeedDatabaseIterator* next;
00042
00043 MicrofeedDatabase* database;
00044 DBC* db_cursor;
00045 DBT key;
00046 DBT data;
00047 void (*next_function)(MicrofeedDatabaseIterator* iterator);
00048 DB* index_db;
00049 DBT index_key;
00050 int backwards : 1;
00051 };
00052
00053 static void lock_environment_for_writing(MicrofeedDatabaseEnvironment* database_environment);
00054 static void unlock_environment(MicrofeedDatabaseEnvironment* database_environment);
00055 static int key_compare_function(DB *db, const DBT *dbt1, const DBT *dbt2);
00056 static int index_callback(DB* secondary, const DBT* key, const DBT* data, DBT* result);
00057 static void remove_data(MicrofeedDatabase* database, DB* db, const void* key, const size_t key_size);
00058 static void remove_data_range(MicrofeedDatabase* database, DB* db, const void* start_key, const size_t start_key_size, const void* end_key, const size_t end_key_size);
00059 static void iterator_free(MicrofeedDatabaseIterator* iterator);
00060 static void database_iterator_next(MicrofeedDatabaseIterator* iterator);
00061 static void database_index_iterator_next(MicrofeedDatabaseIterator* iterator);
00062
00063 MicrofeedDatabaseEnvironment* microfeed_database_environment_new(const char* name, const char* directory) {
00064 MicrofeedDatabaseEnvironment* database_environment = NULL;
00065
00066 if (microfeed_util_create_directory_recursively(directory)) {
00067 database_environment = microfeed_memory_allocate(MicrofeedDatabaseEnvironment);
00068 microfeed_util_create_directory_recursively(directory);
00069 if (db_env_create(&database_environment->db_env, 0) || database_environment->db_env->open(database_environment->db_env, directory, DB_CREATE | DB_THREAD | DB_PRIVATE | DB_INIT_CDB | DB_INIT_MPOOL, 0)) {
00070 microfeed_memory_free(database_environment);
00071 database_environment = NULL;
00072 } else {
00073 database_environment->reference_count = 1;
00074 database_environment->mutex = microfeed_mutex_new();
00075 database_environment->name = strdup(name);
00076 database_environment->databases = microfeed_store_new_sorted((MicrofeedStoreCompareKeysFunction)strcmp,
00077 (MicrofeedStoreGetKeyFunction)microfeed_database_get_name);
00078 }
00079 }
00080
00081 return database_environment;
00082 }
00083
00084 void microfeed_database_environment_free(MicrofeedDatabaseEnvironment* database_environment) {
00085 free(database_environment->name);
00086 database_environment->db_env->close(database_environment->db_env, 0);
00087 database_environment->db_env = NULL;
00088 microfeed_memory_free(database_environment);
00089 }
00090
00091 MicrofeedDatabaseEnvironment* microfeed_database_environment_ref(MicrofeedDatabaseEnvironment* database_environment) {
00092 microfeed_mutex_lock(database_environment->mutex);
00093
00094 database_environment->reference_count++;
00095
00096 microfeed_mutex_unlock(database_environment->mutex);
00097
00098 return database_environment;
00099 }
00100
00101 void microfeed_database_environment_unref(MicrofeedDatabaseEnvironment* database_environment) {
00102 microfeed_mutex_lock(database_environment->mutex);
00103
00104 database_environment->reference_count--;
00105 if (database_environment->reference_count == 0) {
00106 microfeed_database_environment_free(database_environment);
00107 } else {
00108
00109 microfeed_mutex_unlock(database_environment->mutex);
00110 }
00111 }
00112
00113 MicrofeedDatabase* microfeed_database_environment_get_database(MicrofeedDatabaseEnvironment* database_environment, const char* name, MicrofeedDatabaseCompareFunction compare_function) {
00114 MicrofeedDatabase* database;
00115
00116 microfeed_mutex_lock(database_environment->mutex);
00117
00118 if ((database = microfeed_store_get(database_environment->databases, name, MicrofeedDatabase))) {
00119 microfeed_database_ref(database);
00120 } else {
00121 database = microfeed_memory_allocate(MicrofeedDatabase);
00122 if (db_create(&database->db, database_environment->db_env, 0) ||
00123 (compare_function && database->db->set_bt_compare(database->db, key_compare_function)) ||
00124 database->db->open(database->db, NULL, database_environment->name, name, DB_BTREE, DB_CREATE | DB_THREAD, 0)) {
00125 microfeed_memory_free(database);
00126 database = NULL;
00127 } else {
00128 database->reference_count = 1;
00129 database->mutex = microfeed_mutex_new();
00130 database->database_environment = database_environment;
00131 database_environment->reference_count++;
00132 database->name = strdup(name);
00133 database->compare_function = compare_function;
00134 database->indices = NULL;
00135 database->iterators = NULL;
00136 database->db->app_private = database;
00137
00138 microfeed_store_insert(database_environment->databases, database);
00139 }
00140 }
00141
00142 microfeed_mutex_unlock(database_environment->mutex);
00143
00144 return database;
00145 }
00146
00147 MicrofeedDatabaseIndex* microfeed_database_get_index(MicrofeedDatabase* database, const char* name, MicrofeedDatabaseIndexFunction index_function) {
00148 MicrofeedDatabaseIndex* database_index;
00149 char* full_name;
00150
00151 microfeed_mutex_lock(database->mutex);
00152
00153 for (database_index = database->indices; database_index; database_index = database_index->next) {
00154 if (!strcmp(database_index->name, name)) {
00155 break;
00156 }
00157 }
00158 if (!database_index) {
00159 database_index = microfeed_memory_allocate(MicrofeedDatabaseIndex);
00160 full_name = microfeed_util_string_concatenate(database->name, ":microfeed.index:", name, NULL);
00161 if (db_create(&database_index->db, database->database_environment->db_env, 0) ||
00162 database_index->db->open(database_index->db, NULL, database->database_environment->name, full_name, DB_BTREE, DB_CREATE | DB_THREAD, 0)) {
00163 microfeed_memory_free(database_index);
00164 database_index = NULL;
00165 } else if (database->db->associate(database->db, NULL, database_index->db, index_callback, DB_CREATE)) {
00166 database_index->db->close(database_index->db, 0);
00167 microfeed_memory_free(database_index);
00168 database_index = NULL;
00169 } else {
00170 database_index->database = database;
00171 database_index->name = strdup(name);
00172 database_index->index_function = index_function;
00173 database_index->db->app_private = database_index;
00174
00175 database_index->next = database->indices;
00176 database->indices = database_index;
00177 }
00178 free(full_name);
00179 }
00180
00181 microfeed_mutex_unlock(database->mutex);
00182
00183 return database_index;
00184 }
00185
00186 void microfeed_database_free(MicrofeedDatabase* database) {
00187 MicrofeedDatabaseIndex* database_index;
00188 MicrofeedDatabaseIndex* next_database_index;
00189
00190 for (database_index = database->indices; database_index; database_index = next_database_index) {
00191 next_database_index = database_index->next;
00192 database_index->db->close(database_index->db, 0);
00193 free(database_index->name);
00194 microfeed_memory_free(database_index);
00195 }
00196 database->db->close(database->db, 0);
00197 database->db = NULL;
00198
00199 microfeed_mutex_lock(database->database_environment->mutex);
00200
00201 microfeed_store_remove(database->database_environment->databases, database);
00202
00203 microfeed_mutex_unlock(database->database_environment->mutex);
00204
00205 microfeed_mutex_free(database->mutex);
00206 database->mutex = NULL;
00207 microfeed_database_environment_unref(database->database_environment);
00208 database->database_environment = NULL;
00209 free(database->name);
00210 database->name = NULL;
00211
00212 microfeed_memory_free(database);
00213 }
00214
00215 MicrofeedDatabase* microfeed_database_ref(MicrofeedDatabase* database) {
00216 microfeed_mutex_lock(database->mutex);
00217
00218 database->reference_count++;
00219
00220 microfeed_mutex_unlock(database->mutex);
00221
00222 return database;
00223 }
00224
00225 void microfeed_database_unref(MicrofeedDatabase* database) {
00226 microfeed_mutex_lock(database->mutex);
00227
00228 database->reference_count--;
00229 if (database->reference_count == 0) {
00230 microfeed_database_free(database);
00231 } else {
00232
00233 microfeed_mutex_unlock(database->mutex);
00234 }
00235 }
00236
00237 const char* microfeed_database_get_name(MicrofeedDatabase* database) {
00238
00239 return database->name;
00240 }
00241
00242 int microfeed_database_get_data(MicrofeedDatabase* database, const void* key, size_t key_size, void** data, size_t* data_size) {
00243 int retvalue = 0;
00244 DBT dbt_key;
00245 DBT dbt_data;
00246
00247 microfeed_mutex_lock(database->mutex);
00248
00249 memset(&dbt_key, 0, sizeof(DBT));
00250 memset(&dbt_data, 0, sizeof(DBT));
00251 dbt_key.data = (void*)key;
00252 dbt_key.size = key_size;
00253 dbt_data.flags = DB_DBT_MALLOC;
00254
00255 if (!database->db->get(database->db, NULL, &dbt_key, &dbt_data, 0)) {
00256 *data = dbt_data.data;
00257 *data_size = dbt_data.size;
00258 retvalue = 1;
00259 }
00260
00261 microfeed_mutex_unlock(database->mutex);
00262
00263 return retvalue;
00264 }
00265
00266 int microfeed_database_get_data_partial(MicrofeedDatabase* database, const void* key, size_t key_size, void* data, size_t* data_size, size_t offset) {
00267 int retvalue = 0;
00268 DBT dbt_key;
00269 DBT dbt_data;
00270
00271 microfeed_mutex_lock(database->mutex);
00272
00273 memset(&dbt_key, 0, sizeof(DBT));
00274 memset(&dbt_data, 0, sizeof(DBT));
00275 dbt_key.data = (void*)key;
00276 dbt_key.size = key_size;
00277 dbt_data.data = (void*)data;
00278 dbt_data.ulen = *data_size;
00279 dbt_data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL;
00280 dbt_data.dlen = *data_size;
00281 dbt_data.doff = offset;
00282
00283 if (!database->db->get(database->db, NULL, &dbt_key, &dbt_data, 0)) {
00284 *data_size = dbt_data.size;
00285 retvalue = 1;
00286 }
00287
00288 microfeed_mutex_unlock(database->mutex);
00289
00290 return retvalue;
00291 }
00292
00293
00294 MicrofeedDatabaseIterator* microfeed_database_iterate(MicrofeedDatabase* database, const void* start_key, const size_t start_key_size, int backwards) {
00295 MicrofeedDatabaseIterator* iterator;
00296
00297 microfeed_mutex_lock(database->mutex);
00298
00299 iterator = microfeed_memory_allocate(MicrofeedDatabaseIterator);
00300 iterator->database = database;
00301 iterator->next_function = database_iterator_next;
00302 iterator->backwards = backwards;
00303 iterator->index_db = NULL;
00304 memset(&iterator->key, 0, sizeof(DBT));
00305 memset(&iterator->data, 0, sizeof(DBT));
00306 iterator->key.flags = DB_DBT_REALLOC;
00307 iterator->data.flags = DB_DBT_REALLOC;
00308 iterator->data.data = malloc(1);
00309 iterator->data.size = 1;
00310
00311 if (start_key) {
00312 iterator->key.data = malloc(start_key_size);
00313 memcpy(iterator->key.data, start_key, start_key_size);
00314 iterator->key.size = start_key_size;
00315 }
00316 iterator->next_function(iterator);
00317
00318 if (database->iterators) {
00319 database->iterators->previous = iterator;
00320 iterator->next = database->iterators;
00321 } else {
00322 iterator->next = NULL;
00323 }
00324 iterator->previous = NULL;
00325 database->iterators = iterator;
00326
00327 microfeed_mutex_unlock(database->mutex);
00328
00329 return iterator;
00330 }
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348 void microfeed_database_replace_data(MicrofeedDatabase* database, const void* key, const size_t key_size, const void* data, const size_t data_size) {
00349 DBT dbt_key;
00350 DBT dbt_data;
00351 int error;
00352
00353 lock_environment_for_writing(database->database_environment);
00354
00355 memset(&dbt_key, 0, sizeof(DBT));
00356 memset(&dbt_data, 0, sizeof(DBT));
00357 dbt_key.data = (void*)key;
00358 dbt_key.size = key_size;
00359 dbt_data.data = (void*)data;
00360 dbt_data.size = data_size;
00361 if ((error = database->db->put(database->db, NULL, &dbt_key, &dbt_data, 0))) {
00362 fprintf(stderr, "DB->put failed: %s\n", db_strerror(error));
00363 }
00364
00365 database->db->sync(database->db, 0);
00366
00367 unlock_environment(database->database_environment);
00368 }
00369
00370 void microfeed_database_replace_data_partial(MicrofeedDatabase* database, const void* key, size_t key_size, const void* data, size_t data_size, size_t offset) {
00371 DBT dbt_key;
00372 DBT dbt_data;
00373 int error;
00374
00375 lock_environment_for_writing(database->database_environment);
00376
00377 memset(&dbt_key, 0, sizeof(DBT));
00378 memset(&dbt_data, 0, sizeof(DBT));
00379 dbt_key.data = (void*)key;
00380 dbt_key.size = key_size;
00381 dbt_data.data = (void*)data;
00382 dbt_data.size = data_size;
00383 dbt_data.flags = DB_DBT_PARTIAL;
00384 dbt_data.dlen = data_size;
00385 dbt_data.doff = offset;
00386 if ((error = database->db->put(database->db, NULL, &dbt_key, &dbt_data, 0))) {
00387 fprintf(stderr, "DB->put failed in replace_data_partial: %s\n", db_strerror(error));
00388 }
00389
00390 database->db->sync(database->db, 0);
00391
00392 unlock_environment(database->database_environment);
00393 }
00394
00395 void microfeed_database_remove_data(MicrofeedDatabase* database, const void* key, const size_t key_size) {
00396 remove_data(database, database->db, key, key_size);
00397 }
00398
00399 void microfeed_database_remove_data_range(MicrofeedDatabase* database, const void* start_key, const size_t start_key_size, const void* end_key, const size_t end_key_size) {
00400 remove_data_range(database, database->db, start_key, start_key_size, end_key, end_key_size);
00401 }
00402
00403 MicrofeedDatabase* microfeed_database_index_get_database(MicrofeedDatabaseIndex* database_index) {
00404
00405 return database_index->database;
00406 }
00407
00408 const char* microfeed_database_index_get_name(MicrofeedDatabaseIndex* database_index) {
00409
00410 return database_index->name;
00411 }
00412
00413 int microfeed_database_index_get_data(MicrofeedDatabaseIndex* database_index, const void* index_key, const size_t index_key_size, void** key, size_t* key_size, void** data, size_t* data_size) {
00414 int retvalue = 0;
00415 DBT dbt_index_key;
00416 DBT dbt_key;
00417 DBT dbt_data;
00418
00419 microfeed_mutex_lock(database_index->database->mutex);
00420
00421 memset(&dbt_index_key, 0, sizeof(DBT));
00422 memset(&dbt_key, 0, sizeof(DBT));
00423 memset(&dbt_data, 0, sizeof(DBT));
00424 dbt_index_key.data = (void*)index_key;
00425 dbt_index_key.size = index_key_size;
00426 dbt_key.flags = DB_DBT_MALLOC;
00427 dbt_data.flags = DB_DBT_MALLOC;
00428
00429 if (!database_index->db->pget(database_index->db, NULL, &dbt_index_key, &dbt_key, &dbt_data, 0)) {
00430 *key = (char*)dbt_key.data;
00431 *key_size = dbt_key.size;
00432 *data = dbt_data.data;
00433 *data_size = dbt_data.size;
00434 retvalue = 1;
00435 }
00436
00437 microfeed_mutex_unlock(database_index->database->mutex);
00438
00439 return retvalue;
00440
00441 }
00442
00443 MicrofeedDatabaseIterator* microfeed_database_index_iterate(MicrofeedDatabaseIndex* database_index, const void* start_key, const size_t start_key_size, int backwards) {
00444 MicrofeedDatabaseIterator* iterator;
00445
00446 microfeed_mutex_lock(database_index->database->mutex);
00447
00448 iterator = microfeed_memory_allocate(MicrofeedDatabaseIterator);
00449 iterator->database = database_index->database;
00450 iterator->next_function = database_index_iterator_next;
00451 iterator->backwards = backwards;
00452 iterator->index_db = database_index->db;
00453 memset(&iterator->key, 0, sizeof(DBT));
00454 memset(&iterator->data, 0, sizeof(DBT));
00455 memset(&iterator->index_key, 0, sizeof(DBT));
00456 iterator->key.flags = DB_DBT_REALLOC;
00457 iterator->data.flags = DB_DBT_REALLOC;
00458 iterator->index_key.flags = DB_DBT_REALLOC;
00459 iterator->data.data = malloc(1);
00460 iterator->data.size = 1;
00461
00462 if (start_key) {
00463 iterator->index_key.data = malloc(start_key_size);
00464 memcpy(iterator->index_key.data, start_key, start_key_size);
00465 iterator->index_key.size = start_key_size;
00466 }
00467 iterator->next_function(iterator);
00468
00469 if (database_index->database->iterators) {
00470 database_index->database->iterators->previous = iterator;
00471 iterator->next = database_index->database->iterators;
00472 } else {
00473 iterator->next = NULL;
00474 }
00475 iterator->previous = NULL;
00476 database_index->database->iterators = iterator;
00477
00478 microfeed_mutex_unlock(database_index->database->mutex);
00479
00480 return iterator;
00481 }
00482
00483 void microfeed_database_index_remove_data(MicrofeedDatabaseIndex* database_index, const void* key, const size_t key_size) {
00484 remove_data(database_index->database, database_index->db, key, key_size);
00485 }
00486
00487 void microfeed_database_index_remove_data_range(MicrofeedDatabaseIndex* database_index, const void* start_key, const size_t start_key_size, const void* end_key, const size_t end_key_size) {
00488 remove_data_range(database_index->database, database_index->db, start_key, start_key_size, end_key, end_key_size);
00489 }
00490
00491 void microfeed_database_iterator_free(MicrofeedDatabaseIterator* iterator) {
00492 microfeed_mutex_lock(iterator->database->mutex);
00493
00494 if (iterator->next) {
00495 iterator->next->previous = iterator->previous;
00496 }
00497 if (iterator->previous) {
00498 iterator->previous->next = iterator->next;
00499 } else if (iterator->database) {
00500 iterator->database->iterators = iterator->next;
00501 }
00502
00503 microfeed_mutex_unlock(iterator->database->mutex);
00504
00505 iterator_free(iterator);
00506 iterator->database = NULL;
00507 microfeed_memory_free(iterator);
00508 }
00509
00510 int microfeed_database_iterator_get(MicrofeedDatabaseIterator* iterator, const void** key, size_t* key_size, const void** data, size_t* data_size) {
00511 int success = 0;
00512
00513 microfeed_mutex_lock(iterator->database->mutex);
00514
00515 if (iterator->data.data) {
00516 *key = iterator->key.data;
00517 *key_size = iterator->key.size;
00518 *data = iterator->data.data;
00519 *data_size = iterator->data.size;
00520 success = 1;
00521 }
00522
00523 microfeed_mutex_unlock(iterator->database->mutex);
00524
00525 return success;
00526 }
00527
00528 void microfeed_database_iterator_next(MicrofeedDatabaseIterator* iterator) {
00529 microfeed_mutex_lock(iterator->database->mutex);
00530
00531 iterator->next_function(iterator);
00532
00533 microfeed_mutex_unlock(iterator->database->mutex);
00534 }
00535
00536 static void remove_data(MicrofeedDatabase* database, DB* db, const void* key, const size_t key_size) {
00537 DBT dbt_key;
00538
00539 lock_environment_for_writing(database->database_environment);
00540
00541 memset(&dbt_key, 0, sizeof(DBT));
00542 dbt_key.data = (void*)key;
00543 dbt_key.size = key_size;
00544
00545 db->del(db, NULL, &dbt_key, 0);
00546
00547 unlock_environment(database->database_environment);
00548 }
00549
00550 static void remove_data_range(MicrofeedDatabase* database, DB* db, const void* start_key, const size_t start_key_size, const void* end_key, const size_t end_key_size) {
00551 DBC* db_cursor;
00552 DBT dbt_key;
00553 DBT dbt_data;
00554
00555 lock_environment_for_writing(database->database_environment);
00556
00557 if (!db->cursor(db, NULL, &db_cursor, DB_WRITECURSOR)) {
00558 memset(&dbt_key, 0, sizeof(DBT));
00559 memset(&dbt_data, 0, sizeof(DBT));
00560 dbt_key.flags = DB_DBT_REALLOC;
00561 dbt_data.flags = DB_DBT_REALLOC;
00562 if (start_key) {
00563 dbt_key.data = malloc(start_key_size);
00564 memcpy(dbt_key.data, start_key, start_key_size);
00565 dbt_key.size = start_key_size;
00566 }
00567 if ((start_key && !db_cursor->c_get(db_cursor, &dbt_key, &dbt_data, DB_SET_RANGE)) || (!start_key && !db_cursor->c_get(db_cursor, &dbt_key, &dbt_data, DB_FIRST))) {
00568 do {
00569 db_cursor->c_del(db_cursor, 0);
00570 if (end_key && end_key_size == dbt_key.size && memcmp(end_key, dbt_key.data, end_key_size) <= 0) {
00571 break;
00572 }
00573 } while (!db_cursor->c_get(db_cursor, &dbt_key, &dbt_data, DB_NEXT));
00574 }
00575 db_cursor->c_close(db_cursor);
00576 }
00577
00578 unlock_environment(database->database_environment);
00579
00580 }
00581
00582 static void iterator_free(MicrofeedDatabaseIterator* iterator) {
00583 if (iterator->db_cursor) {
00584 iterator->db_cursor->c_close(iterator->db_cursor);
00585 iterator->db_cursor = NULL;
00586 }
00587 free(iterator->key.data);
00588 free(iterator->data.data);
00589 free(iterator->index_key.data);
00590 iterator->key.data = NULL;
00591 iterator->data.data = NULL;
00592 iterator->index_key.data = NULL;
00593 }
00594
00595 static void database_iterator_next(MicrofeedDatabaseIterator* iterator) {
00596 char* previous_key = NULL;
00597
00598 if (iterator->data.data) {
00599 if (!iterator->db_cursor) {
00600 if (iterator->key.data) {
00601 previous_key = malloc(iterator->key.size);
00602 memcpy(previous_key, iterator->key.data, iterator->key.size);
00603 if (iterator->database->db->cursor(iterator->database->db, NULL, &iterator->db_cursor, 0) ||
00604 iterator->db_cursor->c_get(iterator->db_cursor, &iterator->key, &iterator->data, DB_SET_RANGE) ||
00605 (!strcmp(iterator->key.data, previous_key) && iterator->db_cursor->c_get(iterator->db_cursor, &iterator->key, &iterator->data, (iterator->backwards ? DB_PREV : DB_NEXT)))) {
00606 iterator_free(iterator);
00607 }
00608 free(previous_key);
00609 } else {
00610 if (iterator->database->db->cursor(iterator->database->db, NULL, &iterator->db_cursor, 0) ||
00611 iterator->db_cursor->c_get(iterator->db_cursor, &iterator->key, &iterator->data, (iterator->key.data ? DB_SET_RANGE : (iterator->backwards ? DB_LAST : DB_FIRST)))) {
00612 iterator_free(iterator);
00613 }
00614 }
00615 } else {
00616 if (iterator->db_cursor->c_get(iterator->db_cursor, &iterator->key, &iterator->data, (iterator->backwards ? DB_PREV : DB_NEXT))) {
00617 iterator_free(iterator);
00618 }
00619 }
00620 }
00621 }
00622
00623 static void database_index_iterator_next(MicrofeedDatabaseIterator* iterator) {
00624 char* previous_key = NULL;
00625
00626 if (iterator->data.data) {
00627 if (!iterator->db_cursor) {
00628 if (iterator->index_key.data) {
00629 previous_key = malloc(iterator->index_key.size);
00630 memcpy(previous_key, iterator->index_key.data, iterator->index_key.size);
00631 if (iterator->index_db->cursor(iterator->index_db, NULL, &iterator->db_cursor, 0) ||
00632 iterator->db_cursor->c_pget(iterator->db_cursor, &iterator->index_key, &iterator->key, &iterator->data, DB_SET_RANGE) ||
00633 (!strcmp(iterator->index_key.data, previous_key) && iterator->db_cursor->c_pget(iterator->db_cursor, &iterator->index_key, &iterator->key, &iterator->data, (iterator->backwards ? DB_PREV : DB_NEXT)))) {
00634 iterator_free(iterator);
00635 }
00636 free(previous_key);
00637 } else {
00638 if (iterator->index_db->cursor(iterator->index_db, NULL, &iterator->db_cursor, 0) ||
00639 iterator->db_cursor->c_pget(iterator->db_cursor, &iterator->index_key, &iterator->key, &iterator->data, (iterator->index_key.data ? DB_SET_RANGE : (iterator->backwards ? DB_LAST : DB_FIRST)))) {
00640 iterator_free(iterator);
00641 }
00642 }
00643 } else {
00644 if (iterator->db_cursor->c_pget(iterator->db_cursor, &iterator->index_key, &iterator->key, &iterator->data, (iterator->backwards ? DB_PREV : DB_NEXT))) {
00645 iterator_free(iterator);
00646 }
00647 }
00648 }
00649 }
00650
00651 static void lock_environment_for_writing(MicrofeedDatabaseEnvironment* database_environment) {
00652 MicrofeedStoreIterator* store_iterator;
00653 MicrofeedDatabase* database;
00654 MicrofeedDatabaseIterator* database_iterator;
00655
00656 microfeed_mutex_lock(database_environment->mutex);
00657
00658 for (store_iterator = microfeed_store_iterate(database_environment->databases, NULL);
00659 (database = microfeed_store_iterator_get(store_iterator, MicrofeedDatabase));
00660 microfeed_store_iterator_next(store_iterator)) {
00661 microfeed_mutex_lock(database->mutex);
00662 for (database_iterator = database->iterators; database_iterator; database_iterator = database_iterator->next) {
00663 if (database_iterator->data.data && database_iterator->db_cursor) {
00664 database_iterator->db_cursor->c_close(database_iterator->db_cursor);
00665 database_iterator->db_cursor = NULL;
00666 }
00667 }
00668 }
00669 }
00670
00671 static void unlock_environment(MicrofeedDatabaseEnvironment* database_environment) {
00672 MicrofeedStoreIterator* store_iterator;
00673 MicrofeedDatabase* database;
00674
00675 for (store_iterator = microfeed_store_iterate(database_environment->databases, NULL);
00676 (database = microfeed_store_iterator_get(store_iterator, MicrofeedDatabase));
00677 microfeed_store_iterator_next(store_iterator)) {
00678 microfeed_mutex_unlock(database->mutex);
00679 }
00680
00681 microfeed_mutex_unlock(database_environment->mutex);
00682 }
00683
00684 static int index_callback(DB* db, const DBT* key, const DBT* data, DBT* result) {
00685 int retvalue = EINVAL;
00686 MicrofeedDatabaseIndex* database_index;
00687 void* index_key;
00688 size_t index_key_size;
00689
00690 if ((database_index = (MicrofeedDatabaseIndex*)db->app_private)) {
00691 database_index->index_function(key->data, key->size, data->data, data->size, &index_key, &index_key_size);
00692 result->data = index_key;
00693 result->size = index_key_size;
00694 retvalue = 0;
00695 }
00696
00697 return retvalue;
00698 }
00699
00700 static int key_compare_function(DB *db, const DBT *dbt1, const DBT *dbt2) {
00701 int retvalue = 0;
00702 MicrofeedDatabase* database;
00703
00704 if ((database = (MicrofeedDatabase*)db->app_private)) {
00705 retvalue = database->compare_function(dbt1->data, dbt1->size, dbt2->data, dbt2->size);
00706 }
00707
00708 return retvalue;
00709 }