lmdb_triplestore.pyx 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371
  1. import logging
  2. import sys
  3. import rdflib
  4. #from cython.parallel import prange
  5. from rdflib.graph import DATASET_DEFAULT_GRAPH_ID as RDFLIB_DEFAULT_GRAPH_URI
  6. from lakesuperior.store.base_lmdb_store import (
  7. KeyExistsError, KeyNotFoundError, LmdbError)
  8. from lakesuperior.util.toolbox import get_tree_size
  9. from libc.stdlib cimport malloc, free
  10. cimport lakesuperior.cy_include.collections as cc
  11. cimport lakesuperior.cy_include.cylmdb as lmdb
  12. from lakesuperior.model.base cimport (
  13. FIRST_KEY, KLEN, DBL_KLEN, TRP_KLEN, QUAD_KLEN,
  14. Key, DoubleKey, TripleKey, QuadKey,
  15. Buffer, buffer_dump
  16. )
  17. from lakesuperior.store.base_lmdb_store cimport (
  18. _check, BaseLmdbStore, data_v, dbi, key_v)
  19. from lakesuperior.model.rdf.graph cimport Graph
  20. from lakesuperior.model.rdf.term cimport (
  21. Term, deserialize_to_rdflib, serialize_from_rdflib)
  22. from lakesuperior.model.rdf.triple cimport BufferTriple
  23. from lakesuperior.model.structures.hash cimport (
  24. HLEN_128 as HLEN, Hash128, hash128)
  25. # Integer keys and values are stored in the system's native byte order.
  26. # Therefore they must be parsed left-to-right if the system is big-endian,
  27. # and right-to-left if little-endian, in order to maintain the correct
  28. # sorting order.
  29. BIG_ENDIAN = sys.byteorder == 'big'
  30. LSUP_REVERSEKEY = 0 if BIG_ENDIAN else lmdb.MDB_REVERSEKEY
  31. LSUP_REVERSEDUP = 0 if BIG_ENDIAN else lmdb.MDB_REVERSEDUP
  32. INT_KEY_MASK = lmdb.MDB_INTEGERKEY | LSUP_REVERSEKEY
  33. INT_DUP_KEY_MASK = (
  34. lmdb.MDB_DUPSORT | lmdb.MDB_DUPFIXED | lmdb.MDB_INTEGERKEY
  35. | LSUP_REVERSEKEY | LSUP_REVERSEDUP
  36. )
  37. INT_DUP_MASK = (
  38. lmdb.MDB_DUPSORT | lmdb.MDB_DUPFIXED | lmdb.MDB_INTEGERDUP
  39. | LSUP_REVERSEKEY | LSUP_REVERSEDUP
  40. )
  41. cdef:
  42. # Term key to serialized term
  43. DbLabel DB_T_ST = 't:st___',
  44. # Joined triple keys to context key
  45. DbLabel DB_SPO_C = 'spo:c__',
  46. # This has empty values and is used to keep track of empty contexts.
  47. DbLabel DB_C_ = 'c:_____',
  48. # Prefix to namespace
  49. DbLabel DB_PFX_NS = 'pfx:ns_',
  50. # Indices
  51. # Namespace to prefix
  52. DbLabel DB_NS_PFX = 'ns:pfx_',
  53. # Term hash to term key
  54. DbLabel DB_TH_T = 'th:t___',
  55. # 1-bound lookups
  56. DbLabel DB_S_PO = 's:po___',
  57. DbLabel DB_P_SO = 'p:so___',
  58. DbLabel DB_O_SP = 'o:sp___',
  59. # 2-bound lookups
  60. DbLabel DB_PO_S = 'po:s___',
  61. DbLabel DB_SO_P = 'so:p___',
  62. DbLabel DB_SP_O = 'sp:o___',
  63. # Context lookup
  64. DbLabel DB_C_SPO = 'c:spo__',
  65. lookup_rank = [0, 2, 1]
  66. """
  67. Order in which keys are looked up if two terms are bound.
  68. The indices with the smallest average number of values per key should be
  69. looked up first.
  70. 0 = s:po
  71. 1 = p:so
  72. 2 = o:sp
  73. """
  74. lookup_ordering = [
  75. [0, 1, 2], # spo
  76. [1, 0, 2], # pso
  77. [2, 0, 1], # osp
  78. ]
  79. lookup_ordering_2bound = [
  80. [1, 2, 0], # po:s
  81. [0, 2, 1], # so:p
  82. [0, 1, 2], # sp:o
  83. ]
  84. lookup_indices = [
  85. DB_S_PO,
  86. DB_P_SO,
  87. DB_O_SP,
  88. DB_PO_S,
  89. DB_SO_P,
  90. DB_SP_O,
  91. ]
  92. logger = logging.getLogger(__name__)
  93. cdef class LmdbTriplestore(BaseLmdbStore):
  94. """
  95. Low-level triplestore layer.
  96. This class extends the general-purpose :py:class:`BaseLmdbStore` and maps
  97. triples and contexts to key-value records in LMDB. It can be used in the
  98. application context (``env.app_globals.rdf_store``), or an independent
  99. instance can be spun up in an arbitrary disk location.
  100. This class provides the base for the RDFlib-compatible backend in the
  101. :py:class:`lakesuperior.store.ldp_rs.lmdb_store.LmdbStore`.
  102. """
  103. dbi_labels = [
  104. DB_T_ST,
  105. DB_SPO_C,
  106. DB_C_,
  107. DB_PFX_NS,
  108. DB_NS_PFX,
  109. DB_TH_T,
  110. DB_S_PO,
  111. DB_P_SO,
  112. DB_O_SP,
  113. DB_PO_S,
  114. DB_SO_P,
  115. DB_SP_O,
  116. DB_C_SPO,
  117. ]
  118. dbi_flags = {
  119. DB_C_: INT_KEY_MASK,
  120. DB_T_ST: INT_KEY_MASK,
  121. DB_S_PO: INT_DUP_KEY_MASK,
  122. DB_P_SO: INT_DUP_KEY_MASK,
  123. DB_O_SP: INT_DUP_KEY_MASK,
  124. DB_PO_S: INT_DUP_MASK,
  125. DB_SO_P: INT_DUP_MASK,
  126. DB_SP_O: INT_DUP_MASK,
  127. DB_C_SPO: INT_DUP_KEY_MASK,
  128. DB_SPO_C: INT_DUP_MASK,
  129. }
  130. logger.debug(f'DBI flags: {dbi_flags}')
  131. flags = 0
  132. options = {
  133. 'map_size': 1024 ** 4 # 1Tb.
  134. }
  135. # DB management methods.
  136. cpdef dict stats(self):
  137. """
  138. Gather statistics about the database."""
  139. st = self._stats()
  140. st['num_triples'] = st['db_stats'][DB_SPO_C]['ms_entries']
  141. st['store_size'] = get_tree_size(self.env_path)
  142. return st
  143. cpdef size_t _len(self, context=None) except -1:
  144. """
  145. Return the length of the dataset.
  146. The RDFLib interface defines `__len__` in a nonstandard way that
  147. causes a Cython compilation error, so this method is called by the
  148. `__len__` method of its Python counterpart.
  149. """
  150. cdef:
  151. size_t ct
  152. Key ck
  153. if context is not None:
  154. ck = self.to_key(context)
  155. key_v.mv_data = &ck
  156. key_v.mv_size = KLEN
  157. cur = self._cur_open(DB_C_SPO)
  158. try:
  159. _check(lmdb.mdb_cursor_get(
  160. cur, &key_v, NULL, lmdb.MDB_SET))
  161. _check(lmdb.mdb_cursor_count(cur, &ct))
  162. except KeyNotFoundError:
  163. return 0
  164. else:
  165. return ct
  166. finally:
  167. #pass
  168. self._cur_close(cur)
  169. else:
  170. return self.stats()['num_triples']
  171. ## PRIVATE METHODS ##
  172. # Triple and graph methods.
  173. cpdef void add(self, triple, context=None, quoted=False) except *:
  174. """
  175. Add a triple and start indexing.
  176. :param tuple(rdflib.Identifier) triple: Tuple of three identifiers.
  177. :param context: Context identifier. ``None`` inserts in the default
  178. graph.
  179. :type context: rdflib.Identifier or None
  180. :param bool quoted: Not used.
  181. """
  182. cdef:
  183. lmdb.MDB_cursor *icur
  184. lmdb.MDB_val spo_v, c_v, null_v, key_v, data_v
  185. unsigned char i
  186. Hash128 thash
  187. QuadKey spock
  188. Buffer pk_t
  189. c = self._normalize_context(context)
  190. if c is None:
  191. c = RDFLIB_DEFAULT_GRAPH_URI
  192. s, p, o = triple
  193. icur = self._cur_open(DB_TH_T)
  194. try:
  195. for i, term_obj in enumerate((s, p, o, c)):
  196. serialize_from_rdflib(term_obj, &pk_t)
  197. hash128(&pk_t, &thash)
  198. try:
  199. key_v.mv_data = thash
  200. key_v.mv_size = HLEN
  201. _check(lmdb.mdb_get(
  202. self.txn, self.get_dbi(DB_TH_T), &key_v, &data_v))
  203. spock[i] = (<Key*>data_v.mv_data)[0]
  204. except KeyNotFoundError:
  205. # If term_obj is not found, add it...
  206. logger.debug('Hash {} not found. Adding to DB.'.format(
  207. thash[: HLEN]))
  208. spock[i] = self._append(&pk_t, dblabel=DB_T_ST)
  209. # ...and index it.
  210. key_v.mv_data = thash
  211. key_v.mv_size = HLEN
  212. data_v.mv_data = spock + i
  213. data_v.mv_size = KLEN
  214. _check(
  215. lmdb.mdb_cursor_put(icur, &key_v, &data_v, 0),
  216. 'Error setting key {}.'.format(thash))
  217. finally:
  218. self._cur_close(icur)
  219. spo_v.mv_data = spock # address of sk in spock
  220. spo_v.mv_size = TRP_KLEN # Grab 3 keys
  221. c_v.mv_data = spock + 3 # address of ck in spock
  222. c_v.mv_size = KLEN
  223. null_v.mv_data = b''
  224. null_v.mv_size = 0
  225. try:
  226. _check(lmdb.mdb_put(
  227. self.txn, self.get_dbi(DB_C_), &c_v, &null_v,
  228. lmdb.MDB_NOOVERWRITE))
  229. except KeyExistsError:
  230. pass
  231. try:
  232. # Add triple:context association.
  233. _check(lmdb.mdb_put(
  234. self.txn, self.get_dbi(DB_SPO_C), &spo_v, &c_v,
  235. lmdb.MDB_NODUPDATA))
  236. except KeyExistsError:
  237. pass
  238. try:
  239. # Index context:triple association.
  240. _check(lmdb.mdb_put(
  241. self.txn, self.get_dbi(DB_C_SPO), &c_v, &spo_v,
  242. lmdb.MDB_NODUPDATA))
  243. except KeyExistsError:
  244. pass
  245. self._index_triple(IDX_OP_ADD, [spock[0], spock[1], spock[2]])
  246. cpdef void add_graph(self, c) except *:
  247. """
  248. Add a graph (context) to the database.
  249. This creates an empty graph by associating the graph URI with the
  250. pickled `None` value. This prevents from removing the graph when all
  251. triples are removed.
  252. :param rdflib.URIRef graph: URI of the named graph to add.
  253. """
  254. cdef:
  255. lmdb.MDB_txn *_txn
  256. Buffer _sc
  257. Key ck
  258. c = self._normalize_context(c)
  259. ck = self.to_key(c)
  260. if not self._key_exists(<unsigned char*>&ck, KLEN, DB_C_):
  261. # Insert context term if not existing.
  262. if self.is_txn_rw:
  263. #logger.debug('Working in existing RW transaction.')
  264. _txn = self.txn
  265. else:
  266. #logger.debug('Opening a temporary RW transaction.')
  267. _check(lmdb.mdb_txn_begin(self.dbenv, NULL, 0, &_txn))
  268. # Open new R/W transactions.
  269. try:
  270. # Add to list of contexts.
  271. key_v.mv_data = &ck
  272. key_v.mv_size = KLEN
  273. data_v.mv_data = &ck # Whatever, length is zero anyways
  274. data_v.mv_size = 0
  275. _check(lmdb.mdb_put(
  276. _txn, self.get_dbi(DB_C_), &key_v, &data_v, 0
  277. ))
  278. if not self.is_txn_rw:
  279. _check(lmdb.mdb_txn_commit(_txn))
  280. # Kick the main transaction to see the new terms.
  281. lmdb.mdb_txn_reset(self.txn)
  282. _check(lmdb.mdb_txn_renew(self.txn))
  283. except:
  284. if not self.is_txn_rw:
  285. lmdb.mdb_txn_abort(_txn)
  286. raise
  287. cpdef void _remove(self, tuple triple_pattern, context=None) except *:
  288. cdef:
  289. lmdb.MDB_val spok_v, ck_v
  290. TripleKey spok_cur
  291. Key ck
  292. if context is not None:
  293. try:
  294. ck = self.to_key(context)
  295. except KeyNotFoundError:
  296. # If context is specified but not found, return to avoid
  297. # deleting the wrong triples.
  298. return
  299. # Get the matching pattern.
  300. match_set = self.triple_keys(triple_pattern, context)
  301. dcur = self._cur_open(DB_SPO_C)
  302. icur = self._cur_open(DB_C_SPO)
  303. try:
  304. spok_v.mv_size = TRP_KLEN
  305. # If context was specified, remove only associations with that context.
  306. match_set.keys.seek()
  307. if context is not None:
  308. ck_v.mv_data = &ck
  309. ck_v.mv_size = KLEN
  310. while match_set.keys.get_next(&spok_cur):
  311. spok_v.mv_data = spok_cur
  312. # Delete spo:c entry.
  313. try:
  314. _check(lmdb.mdb_cursor_get(
  315. dcur, &spok_v, &ck_v, lmdb.MDB_GET_BOTH))
  316. except KeyNotFoundError:
  317. pass
  318. else:
  319. _check(lmdb.mdb_cursor_del(dcur, 0))
  320. # Restore ck after delete.
  321. ck_v.mv_data = &ck
  322. # Delete c:spo entry.
  323. try:
  324. _check(lmdb.mdb_cursor_get(
  325. icur, &ck_v, &spok_v, lmdb.MDB_GET_BOTH))
  326. except KeyNotFoundError:
  327. pass
  328. else:
  329. _check(lmdb.mdb_cursor_del(icur, 0))
  330. # Delete lookup indices, only if no other context
  331. # association is present.
  332. # spok_v has changed on mdb_cursor_del. Restore.
  333. spok_v.mv_data = spok_cur
  334. try:
  335. _check(lmdb.mdb_cursor_get(
  336. dcur, &spok_v, NULL, lmdb.MDB_SET))
  337. except KeyNotFoundError:
  338. self._index_triple(IDX_OP_REMOVE, spok_cur)
  339. # If no context is specified, remove all associations.
  340. else:
  341. logger.debug('Removing triples in all contexts.')
  342. # Loop over all SPO matching the triple pattern.
  343. while match_set.keys.get_next(&spok_cur):
  344. spok_v.mv_data = spok_cur
  345. # Loop over all context associations for this SPO.
  346. try:
  347. _check(lmdb.mdb_cursor_get(
  348. dcur, &spok_v, &ck_v, lmdb.MDB_SET_KEY))
  349. except KeyNotFoundError:
  350. # Move on to the next SPO.
  351. continue
  352. else:
  353. ck = (<Key*>ck_v.mv_data)[0]
  354. while True:
  355. # Delete c:spo association.
  356. try:
  357. _check(lmdb.mdb_cursor_get(
  358. icur, &ck_v, &spok_v, lmdb.MDB_GET_BOTH))
  359. except KeyNotFoundError:
  360. pass
  361. else:
  362. lmdb.mdb_cursor_del(icur, 0)
  363. # Restore the pointer to the deleted SPO.
  364. spok_v.mv_data = spok_cur
  365. # Move on to next associated context.
  366. try:
  367. _check(lmdb.mdb_cursor_get(
  368. dcur, &spok_v, &ck_v, lmdb.MDB_NEXT_DUP))
  369. except KeyNotFoundError:
  370. break
  371. # Then delete the spo:c association.
  372. try:
  373. _check(lmdb.mdb_cursor_get(
  374. dcur, &spok_v, &ck_v, lmdb.MDB_SET))
  375. except KeyNotFoundError:
  376. pass
  377. else:
  378. lmdb.mdb_cursor_del(dcur, lmdb.MDB_NODUPDATA)
  379. self._index_triple(IDX_OP_REMOVE, spok_cur)
  380. finally:
  381. self._cur_close(dcur)
  382. self._cur_close(icur)
  383. cdef void _index_triple(self, int op, TripleKey spok) except *:
  384. """
  385. Update index for a triple and context (add or remove).
  386. :param str op: one of ``IDX_OP_ADD`` or ``IDX_OP_REMOVE``.
  387. :param TripleKey spok: Triple key to index.
  388. """
  389. cdef:
  390. DoubleKey dbl_keys[3]
  391. size_t i = 0
  392. lmdb.MDB_val key_v, dbl_key_v
  393. dbl_keys = [
  394. [spok[1], spok[2]], # pok
  395. [spok[0], spok[2]], # sok
  396. [spok[0], spok[1]], # spk
  397. ]
  398. #logger.debug(f'''Indices:
  399. #spok: {[spok[0], spok[1], spok[2]]}
  400. #sk: {spok[0]}
  401. #pk: {spok[1]}
  402. #ok: {spok[2]}
  403. #pok: {dbl_keys[0]}
  404. #sok: {dbl_keys[1]}
  405. #spk: {dbl_keys[2]}
  406. #''')
  407. key_v.mv_size = KLEN
  408. dbl_key_v.mv_size = DBL_KLEN
  409. #logger.debug('Start indexing: {}.'.format(spok[: TRP_KLEN]))
  410. #if op == IDX_OP_REMOVE:
  411. # logger.debug(f'Remove {spok[0]} from indices.')
  412. #else:
  413. # logger.debug(f'Add {spok[0]} to indices.')
  414. while i < 3:
  415. cur1 = self._cur_open(lookup_indices[i]) # s:po, p:so, o:sp
  416. cur2 = self._cur_open(lookup_indices[i + 3])# po:s, so:p, sp:o
  417. try:
  418. key_v.mv_data = spok + i
  419. dbl_key_v.mv_data = dbl_keys[i]
  420. # Removal op indexing.
  421. if op == IDX_OP_REMOVE:
  422. try:
  423. _check(lmdb.mdb_cursor_get(
  424. cur1, &key_v, &dbl_key_v, lmdb.MDB_GET_BOTH))
  425. except KeyNotFoundError:
  426. pass
  427. else:
  428. _check(lmdb.mdb_cursor_del(cur1, 0))
  429. # Restore pointers after delete.
  430. key_v.mv_data = spok + i
  431. dbl_key_v.mv_data = dbl_keys[i]
  432. try:
  433. _check(lmdb.mdb_cursor_get(
  434. cur2, &dbl_key_v, &key_v, lmdb.MDB_GET_BOTH))
  435. except KeyNotFoundError:
  436. pass
  437. else:
  438. _check(lmdb.mdb_cursor_del(cur2, 0))
  439. # Addition op indexing.
  440. elif op == IDX_OP_ADD:
  441. try:
  442. _check(lmdb.mdb_cursor_put(
  443. cur1, &key_v, &dbl_key_v, lmdb.MDB_NODUPDATA))
  444. except KeyExistsError:
  445. pass
  446. try:
  447. _check(lmdb.mdb_cursor_put(
  448. cur2, &dbl_key_v, &key_v, lmdb.MDB_NODUPDATA))
  449. except KeyExistsError:
  450. pass
  451. else:
  452. raise ValueError(
  453. 'Index operation \'{}\' is not supported.'.format(op))
  454. i += 1
  455. finally:
  456. #pass
  457. self._cur_close(cur1)
  458. self._cur_close(cur2)
  459. cpdef void _remove_graph(self, object gr_uri) except *:
  460. """
  461. Delete a context.
  462. """
  463. cdef:
  464. Hash128 chash
  465. Key ck
  466. lmdb.MDB_val ck_v, chash_v
  467. Buffer pk_c
  468. # Gather information on the graph prior to deletion.
  469. try:
  470. ck = self.to_key(gr_uri)
  471. except KeyNotFoundError:
  472. return
  473. # Remove all triples and indices associated with the graph.
  474. self._remove((None, None, None), gr_uri)
  475. # Remove the graph if it is in triples.
  476. self._remove((gr_uri, None, None))
  477. self._remove((None, None, gr_uri))
  478. # Clean up all terms related to the graph.
  479. serialize_from_rdflib(gr_uri, &pk_c)
  480. hash128(&pk_c, &chash)
  481. ck_v.mv_size = KLEN
  482. chash_v.mv_size = HLEN
  483. try:
  484. ck_v.mv_data = &ck
  485. _check(lmdb.mdb_del(self.txn, self.get_dbi(DB_C_), &ck_v, NULL))
  486. ck_v.mv_data = &ck
  487. _check(lmdb.mdb_del(self.txn, self.get_dbi(DB_T_ST), &ck_v, NULL))
  488. chash_v.mv_data = chash
  489. _check(lmdb.mdb_del(self.txn, self.get_dbi(DB_TH_T), &chash_v, NULL))
  490. except KeyNotFoundError:
  491. pass
  492. # Lookup methods.
  493. def contexts(self, triple=None):
  494. """
  495. Get a list of all contexts.
  496. :rtype: set(URIRef)
  497. """
  498. cdef:
  499. size_t sz, i
  500. Key* match
  501. try:
  502. self.all_contexts(&match, &sz, triple)
  503. ret = set()
  504. for i in range(sz):
  505. ret.add(self.from_key(match[i]))
  506. finally:
  507. free(match)
  508. return ret
  509. def triples(self, triple_pattern, context=None):
  510. """
  511. Generator over matching triples.
  512. :param tuple triple_pattern: 3 RDFLib terms
  513. :param context: Context graph, if available.
  514. :type context: rdflib.Graph or None
  515. :rtype: Iterator
  516. :return: Generator over triples and contexts in which each result has
  517. the following format::
  518. (s, p, o), generator(contexts)
  519. Where the contexts generator lists all context that the triple appears
  520. in.
  521. """
  522. cdef:
  523. size_t i = 0
  524. TripleKey it_cur
  525. lmdb.MDB_val key_v, data_v
  526. # This sounds strange, RDFLib should be passing None at this point,
  527. # but anyway...
  528. context = self._normalize_context(context)
  529. logger.debug(
  530. 'Getting triples for: {}, {}'.format(triple_pattern, context))
  531. rset = self.triple_keys(triple_pattern, context)
  532. #logger.debug('Triple keys found: {}'.format(rset.data[:rset.size]))
  533. cur = self._cur_open(DB_SPO_C)
  534. try:
  535. key_v.mv_size = TRP_KLEN
  536. rset.keys.seek()
  537. while rset.keys.get_next(&it_cur):
  538. key_v.mv_data = it_cur
  539. # Get contexts associated with each triple.
  540. contexts = []
  541. # This shall never be MDB_NOTFOUND.
  542. _check(lmdb.mdb_cursor_get(cur, &key_v, &data_v, lmdb.MDB_SET))
  543. while True:
  544. c_uri = self.from_key((<Key*>data_v.mv_data)[0])
  545. contexts.append(
  546. Graph(self, uri=c_uri)
  547. )
  548. try:
  549. _check(lmdb.mdb_cursor_get(
  550. cur, &key_v, &data_v, lmdb.MDB_NEXT_DUP))
  551. except KeyNotFoundError:
  552. break
  553. yield (
  554. (
  555. self.from_key((<Key*>key_v.mv_data)[0]),
  556. self.from_key((<Key*>key_v.mv_data)[1]),
  557. self.from_key((<Key*>key_v.mv_data)[2]),
  558. ),
  559. tuple(contexts)
  560. )
  561. finally:
  562. self._cur_close(cur)
  563. cpdef Graph triple_keys(
  564. self, tuple triple_pattern, context=None, uri=None
  565. ):
  566. """
  567. Top-level lookup method.
  568. This method is used by `triples` which returns native Python tuples,
  569. as well as by other methods that need to iterate and filter triple
  570. keys without incurring in the overhead of converting them to triples.
  571. :param tuple triple_pattern: 3 RDFLib terms
  572. :param context: Context graph or URI, or None.
  573. :type context: rdflib.term.Identifier or None
  574. """
  575. cdef:
  576. size_t ct = 0, i = 0
  577. lmdb.MDB_cursor *icur
  578. lmdb.MDB_val key_v, data_v
  579. Key tk, ck
  580. TripleKey spok
  581. Graph flt_res, ret
  582. if context is not None:
  583. try:
  584. ck = self.to_key(context)
  585. except KeyNotFoundError:
  586. # Context not found.
  587. return Graph(self, uri=uri)
  588. icur = self._cur_open(DB_C_SPO)
  589. try:
  590. key_v.mv_data = &ck
  591. key_v.mv_size = KLEN
  592. # s p o c
  593. if all(triple_pattern):
  594. for i, term in enumerate(triple_pattern):
  595. try:
  596. tk = self.to_key(term)
  597. except KeyNotFoundError:
  598. # A term key was not found.
  599. return Graph(self, uri=uri)
  600. spok[i] = tk
  601. data_v.mv_data = spok
  602. data_v.mv_size = TRP_KLEN
  603. try:
  604. _check(lmdb.mdb_cursor_get(
  605. icur, &key_v, &data_v, lmdb.MDB_GET_BOTH))
  606. except KeyNotFoundError:
  607. # Triple not found.
  608. #logger.debug('spok / ck pair not found.')
  609. return Graph(self, uri=uri)
  610. ret = Graph(self, 1, uri=uri)
  611. ret.keys.add(&spok)
  612. return ret
  613. # ? ? ? c
  614. elif not any(triple_pattern):
  615. # Get all triples from the context
  616. try:
  617. _check(lmdb.mdb_cursor_get(
  618. icur, &key_v, &data_v, lmdb.MDB_SET))
  619. except KeyNotFoundError:
  620. # Triple not found.
  621. return Graph(self, uri=uri)
  622. _check(lmdb.mdb_cursor_count(icur, &ct))
  623. ret = Graph(self, ct, uri=uri)
  624. _check(lmdb.mdb_cursor_get(
  625. icur, &key_v, &data_v, lmdb.MDB_GET_MULTIPLE))
  626. while True:
  627. # Loop over page data.
  628. spok_page = <TripleKey*>data_v.mv_data
  629. for i in range(data_v.mv_size // TRP_KLEN):
  630. ret.keys.add(spok_page + i)
  631. try:
  632. # Get next page.
  633. _check(lmdb.mdb_cursor_get(
  634. icur, &key_v, &data_v, lmdb.MDB_NEXT_MULTIPLE))
  635. except KeyNotFoundError:
  636. return ret
  637. # Regular lookup. Filter _lookup() results by context.
  638. else:
  639. try:
  640. res = self._lookup(triple_pattern)
  641. except KeyNotFoundError:
  642. return Graph(self, uri=uri)
  643. key_v.mv_data = &ck
  644. key_v.mv_size = KLEN
  645. data_v.mv_size = TRP_KLEN
  646. flt_res = Graph(self, res.capacity, uri=uri)
  647. res.keys.seek()
  648. while res.keys.get_next(&spok):
  649. data_v.mv_data = spok
  650. try:
  651. # Verify that the triple is associated with the
  652. # context being searched.
  653. _check(lmdb.mdb_cursor_get(
  654. icur, &key_v, &data_v, lmdb.MDB_GET_BOTH))
  655. except KeyNotFoundError:
  656. continue
  657. else:
  658. flt_res.keys.add(&spok)
  659. return flt_res
  660. finally:
  661. self._cur_close(icur)
  662. # Unfiltered lookup. No context checked.
  663. else:
  664. try:
  665. res = self._lookup(triple_pattern)
  666. except KeyNotFoundError:
  667. return Graph(self, uri=uri)
  668. return res
  669. cdef Graph _lookup(self, tuple triple_pattern):
  670. """
  671. Look up triples in the indices based on a triple pattern.
  672. :rtype: Iterator
  673. :return: Matching triple keys.
  674. """
  675. cdef:
  676. size_t ct = 0
  677. lmdb.MDB_stat db_stat
  678. lmdb.MDB_val spok_v, ck_v
  679. TripleKey spok
  680. Key sk, pk, ok, tk1, tk2, tk3
  681. s, p, o = triple_pattern
  682. try:
  683. if s is not None:
  684. sk = self.to_key(s)
  685. if p is not None:
  686. pk = self.to_key(p)
  687. if o is not None:
  688. ok = self.to_key(o)
  689. except KeyNotFoundError:
  690. return Graph(self)
  691. if s is not None:
  692. tk1 = sk
  693. if p is not None:
  694. tk2 = pk
  695. # s p o
  696. if o is not None:
  697. tk3 = ok
  698. spok_v.mv_data = spok
  699. spok_v.mv_size = TRP_KLEN
  700. try:
  701. spok = [tk1, tk2, tk3]
  702. _check(lmdb.mdb_get(
  703. self.txn, self.get_dbi(DB_SPO_C), &spok_v, &ck_v))
  704. except KeyNotFoundError:
  705. return Graph(self)
  706. matches = Graph(self, 1)
  707. matches.keys.add(&spok)
  708. return matches
  709. # s p ?
  710. return self._lookup_2bound(0, 1, [tk1, tk2])
  711. if o is not None: # s ? o
  712. tk2 = ok
  713. return self._lookup_2bound(0, 2, [tk1, tk2])
  714. # s ? ?
  715. return self._lookup_1bound(0, tk1)
  716. if p is not None:
  717. tk1 = pk
  718. if o is not None: # ? p o
  719. tk2 = ok
  720. return self._lookup_2bound(1, 2, [tk1, tk2])
  721. # ? p ?
  722. return self._lookup_1bound(1, tk1)
  723. if o is not None: # ? ? o
  724. tk1 = ok
  725. return self._lookup_1bound(2, tk1)
  726. # ? ? ?
  727. # Get all triples in the database.
  728. dcur = self._cur_open(DB_SPO_C)
  729. try:
  730. _check(
  731. lmdb.mdb_stat(
  732. self.txn, lmdb.mdb_cursor_dbi(dcur), &db_stat
  733. ), 'Error gathering DB stats.'
  734. )
  735. ct = db_stat.ms_entries
  736. ret = Graph(self, ct)
  737. #logger.debug(f'Triples found: {ct}')
  738. if ct == 0:
  739. return Graph(self)
  740. _check(lmdb.mdb_cursor_get(
  741. dcur, &key_v, &data_v, lmdb.MDB_FIRST))
  742. while True:
  743. spok = <TripleKey>key_v.mv_data
  744. ret.keys.add(&spok)
  745. try:
  746. _check(lmdb.mdb_cursor_get(
  747. dcur, &key_v, &data_v, lmdb.MDB_NEXT_NODUP))
  748. except KeyNotFoundError:
  749. break
  750. return ret
  751. finally:
  752. self._cur_close(dcur)
  753. cdef Graph _lookup_1bound(self, unsigned char idx, Key luk):
  754. """
  755. Lookup triples for a pattern with one bound term.
  756. :param str idx_name: The index to look up as one of the keys of
  757. ``_lookup_ordering``.
  758. :param rdflib.URIRef term: Bound term to search for.
  759. :rtype: Iterator(bytes)
  760. :return: SPO keys matching the pattern.
  761. """
  762. cdef:
  763. unsigned int dbflags
  764. unsigned char term_order[3]
  765. size_t ct, i
  766. lmdb.MDB_cursor *icur
  767. lmdb.MDB_val key_v, data_v
  768. TripleKey spok
  769. #logger.debug(f'lookup 1bound: {idx}, {luk}')
  770. term_order = lookup_ordering[idx]
  771. icur = self._cur_open(lookup_indices[idx])
  772. logging.debug(f'DB label: {lookup_indices[idx]}')
  773. logging.debug('term order: {}'.format(term_order[: 3]))
  774. try:
  775. key_v.mv_data = &luk
  776. key_v.mv_size = KLEN
  777. _check(lmdb.mdb_cursor_get(icur, &key_v, &data_v, lmdb.MDB_SET))
  778. _check(lmdb.mdb_cursor_count(icur, &ct))
  779. # Allocate memory for results.
  780. ret = Graph(self, ct)
  781. _check(lmdb.mdb_cursor_get(icur, &key_v, &data_v, lmdb.MDB_SET))
  782. _check(lmdb.mdb_cursor_get(
  783. icur, &key_v, &data_v, lmdb.MDB_GET_MULTIPLE))
  784. while True:
  785. lu_dset = <DoubleKey*>data_v.mv_data
  786. for i in range(data_v.mv_size // DBL_KLEN):
  787. spok[term_order[0]] = luk
  788. spok[term_order[1]] = lu_dset[i][0]
  789. spok[term_order[2]] = lu_dset[i][1]
  790. ret.keys.add(&spok)
  791. try:
  792. # Get results by the page.
  793. _check(lmdb.mdb_cursor_get(
  794. icur, &key_v, &data_v, lmdb.MDB_NEXT_MULTIPLE))
  795. except KeyNotFoundError:
  796. return ret
  797. finally:
  798. self._cur_close(icur)
  799. cdef Graph _lookup_2bound(
  800. self, unsigned char idx1, unsigned char idx2, DoubleKey tks
  801. ):
  802. """
  803. Look up triples for a pattern with two bound terms.
  804. :param str idx1: The index to look up as one of the keys of
  805. ``lookup_ordering_2bound``.
  806. :param rdflib.URIRef term1: First bound term to search for.
  807. :rtype: Iterator(bytes)
  808. :return: SPO keys matching the pattern.
  809. """
  810. cdef:
  811. unsigned char luk1_offset, luk2_offset
  812. unsigned int dbflags
  813. unsigned char term_order[3] # Lookup ordering
  814. size_t ct, i = 0
  815. lmdb.MDB_cursor* icur
  816. Graph ret
  817. DoubleKey luk
  818. TripleKey spok
  819. for i in range(3):
  820. if (
  821. idx1 in lookup_ordering_2bound[i][: 2]
  822. and idx2 in lookup_ordering_2bound[i][: 2]):
  823. term_order = lookup_ordering_2bound[i]
  824. if term_order[0] == idx1:
  825. luk1_offset = 0
  826. luk2_offset = 1
  827. else:
  828. luk1_offset = 1
  829. luk2_offset = 0
  830. dblabel = lookup_indices[i + 3] # skip 1bound index labels
  831. break
  832. if i == 2:
  833. raise ValueError(
  834. 'Indices {} and {} not found in LU keys.'.format(
  835. idx1, idx2))
  836. # Compose term keys in lookup key.
  837. luk[luk1_offset] = tks[0]
  838. luk[luk2_offset] = tks[1]
  839. icur = self._cur_open(dblabel)
  840. try:
  841. key_v.mv_data = luk
  842. key_v.mv_size = DBL_KLEN
  843. # Count duplicates for key and allocate memory for result set.
  844. _check(lmdb.mdb_cursor_get(icur, &key_v, &data_v, lmdb.MDB_SET))
  845. _check(lmdb.mdb_cursor_count(icur, &ct))
  846. ret = Graph(self, ct)
  847. _check(lmdb.mdb_cursor_get(icur, &key_v, &data_v, lmdb.MDB_SET))
  848. _check(lmdb.mdb_cursor_get(
  849. icur, &key_v, &data_v, lmdb.MDB_GET_MULTIPLE))
  850. while True:
  851. lu_dset = <Key*>data_v.mv_data
  852. for i in range(data_v.mv_size // KLEN):
  853. spok[term_order[0]] = luk[0]
  854. spok[term_order[1]] = luk[1]
  855. spok[term_order[2]] = lu_dset[i]
  856. ret.keys.add(&spok)
  857. try:
  858. # Get results by the page.
  859. _check(lmdb.mdb_cursor_get(
  860. icur, &key_v, &data_v, lmdb.MDB_NEXT_MULTIPLE))
  861. except KeyNotFoundError:
  862. return ret
  863. finally:
  864. self._cur_close(icur)
  865. cdef void _all_term_keys(self, term_type, cc.HashSet** tkeys) except *:
  866. """
  867. Return all keys of a (``s:po``, ``p:so``, ``o:sp``) index.
  868. """
  869. cdef:
  870. size_t i = 0
  871. lmdb.MDB_stat stat
  872. cc.HashSetConf tkeys_conf
  873. idx_label = lookup_indices['spo'.index(term_type)]
  874. icur = self._cur_open(idx_label)
  875. try:
  876. _check(lmdb.mdb_stat(self.txn, lmdb.mdb_cursor_dbi(icur), &stat))
  877. cc.hashset_conf_init(&tkeys_conf)
  878. tkeys_conf.initial_capacity = 1024
  879. tkeys_conf.load_factor = .75
  880. tkeys_conf.key_length = KLEN
  881. tkeys_conf.key_compare = cc.CC_CMP_POINTER
  882. tkeys_conf.hash = cc.POINTER_HASH
  883. cc.hashset_new_conf(&tkeys_conf, tkeys)
  884. try:
  885. _check(lmdb.mdb_cursor_get(
  886. icur, &key_v, NULL, lmdb.MDB_FIRST))
  887. except KeyNotFoundError:
  888. return
  889. while True:
  890. cc.hashset_add(tkeys[0], key_v.mv_data)
  891. rc = lmdb.mdb_cursor_get(
  892. icur, &key_v, NULL, lmdb.MDB_NEXT_NODUP)
  893. try:
  894. _check(rc)
  895. except KeyNotFoundError:
  896. return
  897. i += 1
  898. finally:
  899. self._cur_close(icur)
  900. def all_terms(self, term_type):
  901. """
  902. Return all terms of a type (``s``, ``p``, or ``o``) in the store.
  903. """
  904. cdef:
  905. void* cur
  906. cc.HashSet* tkeys
  907. cc.HashSetIter it
  908. ret = set()
  909. try:
  910. self._all_term_keys(term_type, &tkeys)
  911. cc.hashset_iter_init(&it, tkeys)
  912. while cc.hashset_iter_next(&it, &cur) != cc.CC_ITER_END:
  913. ret.add(self.from_key((<Key*>cur)[0]))
  914. finally:
  915. if tkeys:
  916. free(tkeys)
  917. return ret
  918. cpdef tuple all_namespaces(self):
  919. """
  920. Return all registered namespaces.
  921. """
  922. cdef:
  923. size_t i = 0
  924. lmdb.MDB_stat stat
  925. ret = []
  926. dcur = self._cur_open(DB_PFX_NS)
  927. try:
  928. try:
  929. _check(lmdb.mdb_cursor_get(
  930. dcur, &key_v, &data_v, lmdb.MDB_FIRST))
  931. except KeyNotFoundError:
  932. return tuple()
  933. while True:
  934. ret.append((
  935. (<unsigned char *>key_v.mv_data)[: key_v.mv_size].decode(),
  936. (<unsigned char *>data_v.mv_data)[: data_v.mv_size].decode()))
  937. try:
  938. _check(lmdb.mdb_cursor_get(
  939. dcur, &key_v, &data_v, lmdb.MDB_NEXT))
  940. except KeyNotFoundError:
  941. return tuple(ret)
  942. i += 1
  943. finally:
  944. self._cur_close(dcur)
  945. cdef void all_contexts(
  946. self, Key** ctx, size_t* sz, triple=None
  947. ) except *:
  948. """
  949. Get a list of all contexts.
  950. """
  951. cdef:
  952. size_t ct
  953. lmdb.MDB_stat stat
  954. lmdb.MDB_val key_v, data_v
  955. TripleKey spok
  956. cur = (
  957. self._cur_open(DB_SPO_C) if triple and all(triple)
  958. else self._cur_open(DB_C_))
  959. try:
  960. if triple and all(triple):
  961. _check(lmdb.mdb_stat(
  962. self.txn, lmdb.mdb_cursor_dbi(cur), &stat))
  963. spok = [
  964. self.to_key(triple[0]),
  965. self.to_key(triple[1]),
  966. self.to_key(triple[2]),
  967. ]
  968. key_v.mv_data = spok
  969. key_v.mv_size = TRP_KLEN
  970. try:
  971. _check(lmdb.mdb_cursor_get(
  972. cur, &key_v, &data_v, lmdb.MDB_SET_KEY))
  973. except KeyNotFoundError:
  974. ctx[0] = NULL
  975. return
  976. ctx[0] = <Key*>malloc(stat.ms_entries * KLEN)
  977. sz[0] = 0
  978. while True:
  979. ctx[0][sz[0]] = (<Key*>data_v.mv_data)[0]
  980. sz[0] += 1
  981. try:
  982. _check(lmdb.mdb_cursor_get(
  983. cur, &key_v, &data_v, lmdb.MDB_NEXT_DUP))
  984. except KeyNotFoundError:
  985. break
  986. else:
  987. _check(lmdb.mdb_stat(
  988. self.txn, lmdb.mdb_cursor_dbi(cur), &stat))
  989. try:
  990. _check(lmdb.mdb_cursor_get(
  991. cur, &key_v, &data_v, lmdb.MDB_FIRST))
  992. except KeyNotFoundError:
  993. ctx[0] = NULL
  994. return
  995. ctx[0] = <Key*>malloc(stat.ms_entries * KLEN)
  996. sz[0] = 0
  997. while True:
  998. ctx[0][sz[0]] = (<Key*>key_v.mv_data)[0]
  999. sz[0] += 1
  1000. try:
  1001. _check(lmdb.mdb_cursor_get(
  1002. cur, &key_v, NULL, lmdb.MDB_NEXT))
  1003. except KeyNotFoundError:
  1004. break
  1005. finally:
  1006. self._cur_close(cur)
  1007. # Key conversion methods.
  1008. cdef inline void lookup_term(self, const Key tk, Buffer* data) except *:
  1009. """
  1010. look up a term by key.
  1011. :param Key key: The key to be looked up.
  1012. :param Buffer *data: Buffer structure containing the serialized term.
  1013. """
  1014. cdef:
  1015. lmdb.MDB_val key_v, data_v
  1016. key_v.mv_data = &tk
  1017. key_v.mv_size = KLEN
  1018. _check(
  1019. lmdb.mdb_get(
  1020. self.txn, self.get_dbi(DB_T_ST), &key_v, &data_v
  1021. ),
  1022. f'Error getting data for key \'{tk}\'.'
  1023. )
  1024. data.addr = data_v.mv_data
  1025. data.sz = data_v.mv_size
  1026. cdef object from_key(self, const Key tk):
  1027. """
  1028. Convert a single key into one term.
  1029. :param Key key: The key to be converted.
  1030. """
  1031. cdef Buffer pk_t
  1032. #logger.info(f'From key:{tk}')
  1033. self.lookup_term(tk, &pk_t)
  1034. #logger.info(f'from_key buffer: {buffer_dump(&pk_t)}')
  1035. # TODO Make Term a class and return that.
  1036. return deserialize_to_rdflib(&pk_t)
  1037. cdef Key to_key(self, term) except? 0:
  1038. """
  1039. Convert a term into a key and insert it in the term key store.
  1040. :param rdflib.Term term: An RDFLib term (URIRef, BNode, Literal).
  1041. :param Key key: Key that will be produced.
  1042. :rtype: void
  1043. """
  1044. cdef:
  1045. lmdb.MDB_txn *_txn
  1046. Hash128 thash
  1047. Buffer pk_t
  1048. Key tk
  1049. #logger.info(f'Serializing term: {term}')
  1050. serialize_from_rdflib(term, &pk_t)
  1051. hash128(&pk_t, &thash)
  1052. key_v.mv_data = thash
  1053. key_v.mv_size = HLEN
  1054. try:
  1055. #logger.debug(
  1056. # f'Check {buffer_dump(&pk_t)} with hash '
  1057. # f'{(<unsigned char*>thash)[:HLEN]} in store before adding.'
  1058. #)
  1059. _check(lmdb.mdb_get(
  1060. self.txn, self.get_dbi(DB_TH_T), &key_v, &data_v)
  1061. )
  1062. return (<Key*>data_v.mv_data)[0]
  1063. except KeyNotFoundError:
  1064. #logger.info(f'Adding term {term} to store.')
  1065. # If key is not in the store, add it.
  1066. if self.is_txn_rw:
  1067. # Use existing R/W transaction.
  1068. #logger.info('Working in existing RW transaction.')
  1069. _txn = self.txn
  1070. else:
  1071. # Open new R/W transaction.
  1072. #logger.info('Opening a temporary RW transaction.')
  1073. _check(lmdb.mdb_txn_begin(self.dbenv, NULL, 0, &_txn))
  1074. try:
  1075. # Main entry.
  1076. tk = self._append(&pk_t, DB_T_ST, txn=_txn)
  1077. # Index.
  1078. data_v.mv_data = &tk
  1079. data_v.mv_size = KLEN
  1080. _check(lmdb.mdb_put(
  1081. _txn, self.get_dbi(DB_TH_T), &key_v, &data_v, 0
  1082. ))
  1083. if not self.is_txn_rw:
  1084. _check(lmdb.mdb_txn_commit(_txn))
  1085. # Kick the main transaction to see the new terms.
  1086. lmdb.mdb_txn_reset(self.txn)
  1087. _check(lmdb.mdb_txn_renew(self.txn))
  1088. return tk
  1089. except:
  1090. if not self.is_txn_rw:
  1091. lmdb.mdb_txn_abort(_txn)
  1092. raise
  1093. cdef Key _append(
  1094. self, Buffer *value,
  1095. DbLabel dblabel=b'', lmdb.MDB_txn *txn=NULL,
  1096. unsigned int flags=0
  1097. ) except? 0:
  1098. """
  1099. Append one or more keys and values to the end of a database.
  1100. :param lmdb.Cursor cur: The write cursor to act on.
  1101. :param list(bytes) values: Value(s) to append.
  1102. :rtype: Key
  1103. :return: Key inserted.
  1104. """
  1105. cdef:
  1106. lmdb.MDB_cursor *cur
  1107. Key new_idx
  1108. lmdb.MDB_val key_v, data_v
  1109. if txn is NULL:
  1110. txn = self.txn
  1111. cur = self._cur_open(dblabel, txn=txn)
  1112. try:
  1113. _check(lmdb.mdb_cursor_get(cur, &key_v, NULL, lmdb.MDB_LAST))
  1114. except KeyNotFoundError:
  1115. new_idx = FIRST_KEY
  1116. else:
  1117. new_idx = (<Key*>key_v.mv_data)[0] + 1
  1118. finally:
  1119. self._cur_close(cur)
  1120. key_v.mv_data = &new_idx
  1121. logger.debug(f'New index: {new_idx}')
  1122. #logger.debug('Key data inserted: {}'.format((<unsigned char*>key_v.mv_data)[:KLEN]))
  1123. key_v.mv_size = KLEN
  1124. data_v.mv_data = value.addr
  1125. data_v.mv_size = value.sz
  1126. lmdb.mdb_put(
  1127. txn, self.get_dbi(dblabel), &key_v, &data_v,
  1128. flags | lmdb.MDB_APPEND)
  1129. return new_idx
  1130. def _normalize_context(self, context):
  1131. """
  1132. Normalize a context parameter to conform to the model expectations.
  1133. :param context: Context URI or graph.
  1134. :type context: URIRef or Graph or None
  1135. """
  1136. if isinstance(context, rdflib.Graph):
  1137. if context == self or isinstance(
  1138. context.identifier, rdflib.Variable
  1139. ):
  1140. context = None
  1141. else:
  1142. context = context.identifier
  1143. elif isinstance(context, str):
  1144. context = rdflib.URIRef(context)
  1145. return context