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