14 #define AFW_IMPLEMENTATION_ID "lmdb"
41 afw_rc_t afw_lmdb_internal_close_database(
void *val)
45 mdb_dbi_close(dbi_p->env, dbi_p->dbi);
62 MDB_dbi afw_lmdb_internal_open_database(
78 dbi_p = apr_hash_get(adaptor->dbi_handles, database->s, database->len);
88 dbi_p = afw_lmdb_internal_dbi_handle(
89 adaptor->dbEnv, dbi, adaptor_p, xctx);
92 apr_hash_set(adaptor->dbi_handles, database->s,
93 database->len, dbi_p);
94 }
else if (rc == MDB_NOTFOUND) {
111 afw_rc_t afw_lmdb_internal_close_cursor(
void *cursor)
113 mdb_cursor_close((MDB_cursor*)cursor);
118 MDB_cursor * afw_lmdb_internal_open_cursor(
124 MDB_cursor *cursor = NULL;
125 MDB_txn *txn = session->currTxn;
127 rc = mdb_cursor_open(txn, dbi, &cursor);
128 if (rc == MDB_NOTFOUND) {
130 "Cursor not found.", xctx);
133 "Unable to open cursor.", xctx);
144 void afw_lmdb_internal_set_key(
147 const afw_uuid_t * uuid,
151 key->ptr =
afw_pool_malloc(p, object_type_id->len +
sizeof(afw_uuid_t), xctx);
152 if (object_type_id->len)
153 memcpy((
char*)(key->ptr), object_type_id->s, object_type_id->len);
154 memcpy((
char*)(key->ptr) + object_type_id->len, uuid,
sizeof(afw_uuid_t));
155 key->size = object_type_id->len +
sizeof(afw_uuid_t);
165 void afw_lmdb_internal_get_key(
170 if (key->size >
sizeof(afw_uuid_t)) {
172 object_type_id->len = key->size -
sizeof(afw_uuid_t);
173 memcpy(uuid, key->ptr + object_type_id->len,
sizeof(afw_uuid_t));
175 object_type_id->len = 0;
176 memcpy(uuid, key->ptr,
sizeof(afw_uuid_t));
191 afw_rc_t afw_lmdb_internal_create_entry(
201 key.mv_data = (
void*)raw_key->ptr;
202 key.mv_size = raw_key->size;
204 value.mv_data = (
void*)raw_value->ptr;
205 value.mv_size = raw_value->size;
207 rc = mdb_put(txn, dbi, &key, &value, MDB_NOOVERWRITE);
220 afw_rc_t afw_lmdb_internal_replace_entry(
230 key.mv_data = (
void*)raw_key->ptr;
231 key.mv_size = raw_key->size;
233 value.mv_data = (
void*)raw_value->ptr;
234 value.mv_size = raw_value->size;
236 rc = mdb_put(txn, dbi, &key, &value, 0);
249 afw_rc_t afw_lmdb_internal_delete_entry(
259 key.mv_data = (
void*)raw_key->ptr;
260 key.mv_size = raw_key->size;
263 value.mv_data = (
void*)raw_value->ptr;
264 value.mv_size = raw_value->size;
266 value.mv_data = NULL;
270 rc = mdb_del(txn, dbi, &key, &value);
283 afw_rc_t afw_lmdb_internal_get_entry(
293 key.mv_data = (
void*)raw_key->ptr;
294 key.mv_size = raw_key->size;
296 memset(&value, 0,
sizeof(MDB_val));
298 rc = mdb_get(txn, dbi, &key, &value);
300 raw_value->ptr = value.mv_data;
301 raw_value->size = value.mv_size;
319 void afw_lmdb_internal_create_entry_from_object(
328 const afw_uuid_t *uuid;
331 MDB_txn *txn =
self->currTxn;
336 "Invalid object_id format (UUID required).", xctx);
342 afw_lmdb_internal_set_key(&key,
343 object_type_id, uuid, xctx->p, xctx);
345 value.ptr = object_string->ptr;
346 value.size = object_string->size;
348 rc = afw_lmdb_internal_create_entry(
349 txn, dbi, &key, &value, xctx);
352 "Error writing object to database.", xctx);
368 void afw_lmdb_internal_replace_entry_from_object(
377 const afw_uuid_t *uuid;
379 MDB_txn *txn =
self->currTxn;
385 "Invalid object_id format (UUID required).", xctx);
391 afw_lmdb_internal_set_key(&key,
392 object_type_id, uuid, xctx->p, xctx);
394 value.ptr = object_string->ptr;
395 value.size = object_string->size;
397 rc = afw_lmdb_internal_replace_entry(
398 txn, dbi, &key, &value, xctx);
401 "Error writing object to database.", xctx);
411 const afw_object_t * afw_lmdb_internal_create_object_from_entry(
420 value = afw_lmdb_internal_create_value_from_entry(
self,
421 object_type_id, object_id, dbi, xctx);
433 const afw_value_t * afw_lmdb_internal_create_value_from_entry(
446 const afw_uuid_t *uuid;
447 MDB_txn *txn = self->currTxn;
451 afw_lmdb_internal_set_key(&key,
452 object_type_id, uuid, xctx->p, xctx);
453 if (afw_lmdb_internal_get_entry(
454 txn, dbi, &key, &value, xctx) != 0)
458 "Unable to locate entry in database.", xctx);
462 raw.size = value.size;
466 adaptor->ubjson, &raw, NULL, xctx->p, xctx);
471 object_type_id, object_id, xctx);
485 void afw_lmdb_internal_save_config(
499 memset(&uuid, 0,
sizeof(afw_uuid_t));
501 dbi = afw_lmdb_internal_open_database(
self,
502 txn, &afw_lmdb_s_Primary, MDB_CREATE, xctx->p, xctx);
513 key.mv_data = (
void *)&uuid;
514 key.mv_size =
sizeof(afw_uuid_t);
515 data.mv_data = (
void *)raw->ptr;
516 data.mv_size = raw->size;
518 rc = mdb_put(txn, dbi, &key, &data, 0);
521 "Unable to write internal configuration.", xctx);
551 memset(&uuid, 0,
sizeof(afw_uuid_t));
556 object_type_id = &afw_lmdb_s_internalConfig;
558 dbi = afw_lmdb_internal_open_database(
self, txn,
559 &afw_lmdb_s_Primary, MDB_CREATE, p, xctx);
561 key.mv_data = (
void *)&uuid;
562 key.mv_size =
sizeof(afw_uuid_t);
563 memset(&data, 0,
sizeof(MDB_val));
565 rc = mdb_get(txn, dbi, &key, &data);
566 if (rc == MDB_NOTFOUND) {
581 key.mv_data = (
void *)&uuid;
582 key.mv_size =
sizeof(afw_uuid_t);
583 data.mv_data = (
void *)raw_out->ptr;
584 data.mv_size = raw_out->size;
586 rc = mdb_put(txn, dbi, &key, &data, 0);
589 "Unable to write internal configuration.", xctx);
591 }
else if (rc == 0) {
593 raw.ptr = data.mv_data;
594 raw.size = data.mv_size;
597 self->ubjson, &raw, NULL, p, xctx);
605 "Unable to find internal configuration in the primary database.", xctx);
624 self->pub.inf = &impl_afw_adaptor_key_value_inf;
655 txn = AFW_LMDB_GET_TRANSACTION();
658 &separator,
namespace, NULL);
661 dbi = afw_lmdb_internal_open_database(session->adaptor,
662 txn, database, MDB_CREATE, xctx->p, xctx);
664 rc = afw_lmdb_internal_create_entry(
665 txn, dbi, key, value, xctx);
668 "Unable to write key/value to database.", xctx);
680 impl_afw_adaptor_key_value_delete (
701 txn = AFW_LMDB_GET_TRANSACTION();
704 &separator,
namespace, NULL);
706 dbi = afw_lmdb_internal_open_database(session->adaptor,
707 txn, database, 0, xctx->p, xctx);
709 rc = afw_lmdb_internal_delete_entry(
710 txn, dbi, key, value, xctx);
711 if (rc == MDB_NOTFOUND) {
714 "Unable to delete key/value.", xctx);
719 "Unable to delete key/value to database.", xctx);
731 impl_afw_adaptor_key_value_replace (
753 txn = AFW_LMDB_GET_TRANSACTION();
756 &separator,
namespace, NULL);
759 dbi = afw_lmdb_internal_open_database(session->adaptor,
760 txn, database, 0, xctx->p, xctx);
762 dbi = afw_lmdb_internal_open_database(session->adaptor,
763 txn, database, MDB_CREATE, xctx->p, xctx);
766 rc = afw_lmdb_internal_get_entry(
767 txn, dbi, key, &existing, xctx);
769 (value->size != existing.size) ||
770 (memcmp(value->ptr, existing.ptr, value->size) != 0))
773 "Existing key/value does not exist for replacement.", xctx);
777 rc = afw_lmdb_internal_replace_entry(
778 txn, dbi, key, value, xctx);
779 if (rc == MDB_NOTFOUND) {
781 "Entry not found.", xctx);
784 "Unable to write key/value to database.", xctx);
816 txn = AFW_LMDB_GET_TRANSACTION();
819 &separator,
namespace, NULL);
821 dbi = afw_lmdb_internal_open_database(session->adaptor,
822 txn, database, 0, xctx->p, xctx);
824 afw_lmdb_internal_get_entry(
825 txn, dbi, key, &existing, xctx);
846 void afw_lmdb_internal_cursor_reset(
853 memset(&self->data, 0,
sizeof(MDB_val));
854 if (self->key_string) {
856 self->key_string->s, self->key_string->len,
859 self->key.mv_data = (
void *)key_string->s;
860 self->key.mv_size = key_string->len;
862 self->key.mv_data = NULL;
863 self->key.mv_size = 0;
867 switch (self->operator) {
868 case afw_query_criteria_filter_op_id_ne:
869 rc = mdb_cursor_get(self->cursor, &self->key,
870 &self->data, MDB_FIRST);
873 case afw_query_criteria_filter_op_id_eq:
874 rc = mdb_cursor_get(self->cursor, &self->key,
875 &self->data, MDB_SET);
878 case afw_query_criteria_filter_op_id_ge:
879 rc = mdb_cursor_get(self->cursor, &self->key,
880 &self->data, MDB_SET_RANGE);
883 case afw_query_criteria_filter_op_id_le:
884 rc = mdb_cursor_get(self->cursor, &self->key,
885 &self->data, MDB_SET_RANGE);
888 if (memcmp(self->key.mv_data, self->key_string->s,
889 self->key_string->len) > 0) {
891 rc = mdb_cursor_get(self->cursor, &self->key,
892 &self->data, MDB_PREV);
898 case afw_query_criteria_filter_op_id_lt:
899 rc = mdb_cursor_get(self->cursor, &self->key,
900 &self->data, MDB_SET_RANGE);
904 rc = mdb_cursor_get(self->cursor, &self->key,
905 &self->data, MDB_PREV);
910 case afw_query_criteria_filter_op_id_gt:
911 rc = mdb_cursor_get(self->cursor, &self->key,
912 &self->data, MDB_SET_RANGE);
913 if (self->key_string) {
914 if (memcmp(self->key.mv_data, self->key_string->s,
915 self->key_string->len) == 0) {
917 rc = mdb_cursor_get(self->cursor, &self->key,
918 &self->data, MDB_NEXT_NODUP);
926 "Unable to create cursor for this operator", xctx);
942 MDB_txn *txn = session->currTxn;
945 self->pub.inf = &impl_afw_adaptor_impl_index_cursor_inf;
947 self->session = session;
948 self->object_type_id = object_type_id;
949 self->unique = unique;
950 self->operator =
operator;
952 dbi = afw_lmdb_internal_open_database(self->session->adaptor,
953 txn, database, 0, xctx->p, xctx);
955 self->cursor = afw_lmdb_internal_open_cursor(session, dbi, xctx);
956 if (self->cursor == NULL) {
958 "Error opening index cursor.", xctx);
963 value->s, value->len, xctx->p, xctx);
965 self->key_string = NULL;
967 afw_lmdb_internal_cursor_reset(
self, xctx);
970 self->dbPri = afw_lmdb_internal_open_database(self->session->adaptor,
971 txn, &afw_lmdb_s_Primary, 0, xctx->p, xctx);
981 impl_afw_adaptor_impl_index_cursor_release (
989 mdb_cursor_close(self->cursor);
996 int afw_lmdb_internal_cursor_next(
1005 switch (self->operator) {
1006 case afw_query_criteria_filter_op_id_ne:
1007 rc = mdb_cursor_get(self->cursor, &self->key,
1008 &self->data, MDB_NEXT);
1009 if (self->key_string) {
1010 if (memcmp(self->key.mv_data, self->key_string->s,
1011 self->key_string->len) == 0) {
1013 rc = mdb_cursor_get(self->cursor, &self->key,
1014 &self->data, MDB_NEXT_NODUP);
1019 case afw_query_criteria_filter_op_id_eq:
1025 rc = mdb_cursor_get(self->cursor, &self->key,
1026 &self->data, MDB_NEXT_DUP);
1029 case afw_query_criteria_filter_op_id_gt:
1032 case afw_query_criteria_filter_op_id_ge:
1034 rc = mdb_cursor_get(self->cursor, &self->key,
1035 &self->data, MDB_NEXT);
1038 case afw_query_criteria_filter_op_id_lt:
1041 case afw_query_criteria_filter_op_id_le:
1043 rc = mdb_cursor_get(self->cursor, &self->key,
1044 &self->data, MDB_PREV);
1058 impl_afw_adaptor_impl_index_cursor_get_next_object (
1080 if (self->data.mv_data == NULL)
1083 memset(&data, 0,
sizeof(MDB_val));
1084 key.mv_data = (
void *)self->data.mv_data;
1085 key.mv_size = self->data.mv_size;
1086 rawKey.ptr = key.mv_data;
1087 rawKey.size = key.mv_size;
1089 txn = self->session->currTxn;
1092 rc = mdb_get(txn, self->dbPri, &key, &data);
1093 if (rc == MDB_NOTFOUND) {
1095 rc = afw_lmdb_internal_cursor_next(instance, xctx);
1102 "Error in mdb_get()!", xctx);
1105 afw_lmdb_internal_get_key(&rawKey, &object_type, &uuid);
1108 from_raw.ptr = data.mv_data;
1109 from_raw.size = data.mv_size;
1112 adaptor->ubjson, &from_raw, NULL, pool, xctx);
1117 self->object_type_id, object_id, xctx);
1120 rc = afw_lmdb_internal_cursor_next(instance, xctx);
1123 self->data.mv_data = NULL;
1126 }
while (
object == NULL && rc == MDB_NOTFOUND);
1149 const afw_uuid_t *uuid;
1156 if (self->operator != afw_query_criteria_filter_op_id_eq) {
1158 "The contains_object method for LMDB cursors only implements eq", xctx);
1164 afw_lmdb_internal_set_key(&index,
1165 self->object_type_id, uuid, xctx->p, xctx);
1168 self->key_string->s, self->key_string->len, xctx->p, xctx);
1170 key.mv_data = (
void *)key_string->s;
1171 key.mv_size = key_string->len;
1172 data.mv_data = (
void *)index.ptr;
1173 data.mv_size = index.size;
1175 rc = mdb_cursor_get(self->cursor, &key, &data, MDB_GET_BOTH);
1184 if (memcmp(data.mv_data, index.ptr, index.size) == 0) {
1190 afw_lmdb_internal_cursor_reset(
self, xctx);
1215 rc = mdb_cursor_count(self->cursor, &count_this);
1216 rc = mdb_cursor_count(that->cursor, &count_that);
1219 if (count_this < count_that)
1229 impl_afw_adaptor_impl_index_cursor_get_count(
1240 if (self->operator != afw_query_criteria_filter_op_id_eq) {
1244 rc = mdb_cursor_count(self->cursor, count);
1246 return (rc == 0) ? true :
false;
1265 self->pub.inf = &impl_afw_adaptor_transaction_inf;
1274 apr_thread_rwlock_rdlock(session->adaptor->dbLock);
1276 rc = mdb_txn_begin(session->adaptor->dbEnv, NULL, 0, &self->txn);
1278 apr_thread_rwlock_unlock(session->adaptor->dbLock);
1281 "Unable to begin transaction.", xctx);
1284 session->transaction =
self;
1285 session->currTxn =
self->txn;
1297 impl_afw_adaptor_transaction_release (
1308 if (session->transaction) {
1309 mdb_txn_abort(self->txn);
1310 apr_thread_rwlock_unlock(session->adaptor->dbLock);
1314 session->transaction = NULL;
1323 impl_afw_adaptor_transaction_commit (
1334 rc = mdb_txn_commit(self->txn);
1336 apr_thread_rwlock_unlock(session->adaptor->dbLock);
1339 "Unable to commit transaction.", xctx);
1342 apr_thread_rwlock_unlock(session->adaptor->dbLock);
1346 session->transaction = NULL;
1354 afw_lmdb_internal_reader_check(
1363 rc = mdb_reader_check(self->dbEnv, deadReaders);
1375 int afw_lmdb_internal_reader_list_cb(
1384 message->s, message->len, context->pool, context->xctx);
1386 return (
int)strlen(msg);
1393 int afw_lmdb_internal_reader_list(
1409 rc = mdb_reader_list(self->dbEnv, afw_lmdb_internal_reader_list_cb, &ctx);
Adaptive Framework Core API.
Interface afw_interface implementation declares.
Interface afw_interface implementation declares.
Interface afw_interface implementation declares.
Adaptive Framework register generated (afw_lmdb) header.
Adaptive Framework LMDB Adaptor Internal Header.
afw_lmdb_transaction_t * afw_lmdb_transaction_create(afw_lmdb_adaptor_session_t *session, afw_xctx_t *xctx)
Internal create a LMDB adaptor transaction.
#define AFW_LMDB_END_TRANSACTION()
End an LMDB transaction.
#define AFW_LMDB_BEGIN_TRANSACTION(adaptor, session, flags, exclusive, xctx)
Begin an LMDB transaction.
afw_lmdb_key_value_t * afw_lmdb_key_value_create(afw_lmdb_adaptor_session_t *session, afw_xctx_t *xctx)
Internal create a LMDB adaptor key/value.
#define AFW_LMDB_COMMIT_TRANSACTION()
Commit a transaction.
Adaptive Framework UUID header.
const afw_adaptor_impl_index_cursor_t * impl_afw_adaptor_impl_index_cursor_inner_join(const afw_adaptor_impl_index_cursor_t *instance, const afw_adaptor_impl_index_cursor_t *cursor, afw_xctx_t *xctx)
afw_boolean_t impl_afw_adaptor_impl_index_cursor_contains_object(const afw_adaptor_impl_index_cursor_t *instance, const afw_object_t *object, afw_xctx_t *xctx)
const afw_memory_t * impl_afw_adaptor_key_value_get(const afw_adaptor_key_value_t *instance, const afw_utf8_t *namespace, const afw_memory_t *key, afw_xctx_t *xctx)
void impl_afw_adaptor_key_value_add(const afw_adaptor_key_value_t *instance, const afw_utf8_t *namespace, const afw_memory_t *key, const afw_memory_t *value, afw_xctx_t *xctx)
afw_value_as_object(const afw_value_t *value, afw_xctx_t *xctx)
Typesafe cast of data type object.
#define AFW_UTF8_FMT_ARG(A_STRING)
Convenience Macro for use with AFW_UTF8_FMT to specify arg.
#define AFW_UTF8_LITERAL(A_STRING)
String literal initializer.
#define AFW_UTF8_FMT
Format string specifier used for afw_utf8_t.
char afw_utf8_octet_t
8 bits of utf-8 codepoint.
#define AFW_POSSIBLY_UNUSED_VARIABLE
Macro to avoid unused variable warning.
#define afw_content_type_raw_to_value(instance, raw, source_location, p, xctx)
Call method raw_to_value of interface afw_content_type.
#define afw_content_type_object_to_raw(instance, object, options, p, xctx)
Convert object to the raw in specified pool.
#define AFW_THROW_ERROR_RV_Z(code, rv_source_id, rv, message_z, xctx)
Macro used to set error and rv in xctx and throw it.
#define AFW_THROW_ERROR_RV_FZ(code, rv_source_id, rv, xctx, format_z,...)
Macro used to set error and rv in xctx and throw it.
#define AFW_THROW_ERROR_Z(code, message_z, xctx)
Macro used to set error and 0 rv in xctx and throw it.
afw_object_options_essential
Object processing options - metaLimited.
#define afw_object_create_managed(p, xctx)
Create an empty entity object in its own pool.
afw_object_set_property(const afw_object_t *instance, const afw_utf8_t *property_name, const afw_value_t *value, afw_xctx_t *xctx)
Set the value of an object's property.
#define afw_pool_malloc(instance, size, xctx)
Call method malloc of interface afw_pool.
#define afw_pool_calloc_type(instance, type, xctx)
Macro to allocate cleared memory to hold type in pool.
afw_query_criteria_filter_op_id_t
const afw_utf8_t * afw_utf8_concat(const afw_pool_t *p, afw_xctx_t *xctx,...)
Concatenate strings with result in specifed pool.
#define afw_utf8_create_copy(s, len, p, xctx)
Make a utf-8 sting from chars in pool specified.
#define afw_utf8_from_utf8_z(s_z, p, xctx)
Make utf-8 string without copy in specified pool.
const afw_utf8_z_t * afw_utf8_to_utf8_z(const afw_utf8_t *string, const afw_pool_t *p, afw_xctx_t *xctx)
Convert utf8 to utf8_z in specified pool.
afw_uuid_from_utf8(const afw_utf8_t *s, const afw_pool_t *p, afw_xctx_t *xctx)
Convert standard format UUID utf-8 string to uuid.
afw_uuid_to_utf8(const afw_uuid_t *uuid, const afw_pool_t *p, afw_xctx_t *xctx)
Convert uuid to a standard format UUID utf-8 string.
afw_value_create_dateTime_now_utc(const afw_pool_t *p, afw_xctx_t *xctx)
Create a dateTime value with current time.
#define afw_xctx_calloc_type(type, xctx)
Macro to allocate cleared memory to hold type in xctx's pool.
Interface afw_adaptor_impl_index_cursor public struct.
Interface afw_adaptor_key_value public struct.
Interface afw_adaptor public struct.
Interface afw_adaptor_session public struct.
Interface afw_adaptor_transaction public struct.
Struct for memory pointer and size.
Interface afw_object public struct.
Interface afw_pool public struct.
NFC normalized UTF-8 string.
Interface afw_value public struct.
Interface afw_xctx public struct.