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