graph.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. #include "store_htable.h"
  2. #include "store_mdb.h"
  3. #include "graph.h"
  4. // Initial size of lookup graph. It will double each time capacity is reached.
  5. #define LOOKUP_GR_INIT_SIZE 64
  6. // Expand hash table memory by this factor to keep a good load factor.
  7. #define PREALLOC_FACTOR 1.4
  8. // Assume VERY coarsly that the number of unique terms will be in general
  9. // 1.7 times the number of triples. This is conservative to maintain load
  10. // factor low.
  11. #define IDX_SIZE_RATIO 1.7
  12. typedef enum KSetFlag {
  13. LSUP_KS_NONE = 0,
  14. LSUP_KS_CHECK_CAP = 1 << 0,
  15. LSUP_KS_CHECK_DUP = 1 << 1,
  16. } KSetFlag;
  17. typedef struct Graph {
  18. const LSUP_Env * env; // LSUP environment.
  19. LSUP_store_type store_type; // Back end type: in-memory or MDB.
  20. LSUP_Term *uri; // Graph "name" (URI)
  21. union { // Back end, defined by store_type.
  22. LSUP_HTStore * ht_store;
  23. LSUP_MDBStore * mdb_store;
  24. };
  25. LSUP_NSMap * nsm; // Namespace map.
  26. } Graph;
  27. typedef struct GraphIterator {
  28. const Graph * graph; // Parent graph.
  29. union { // Internal store iterator.
  30. LSUP_HTIterator * ht_iter;
  31. LSUP_MDBIterator * mdb_iter;
  32. };
  33. size_t ct; // Total matches.
  34. } GraphIterator;
  35. /**
  36. * Extern inline functions.
  37. */
  38. size_t LSUP_graph_size (const LSUP_Graph *gr);
  39. /* * * Post-lookup callback prototypes * * */
  40. int match_add_fn(
  41. LSUP_Graph *src, LSUP_Graph *dest, const LSUP_TripleKey *spok,
  42. void *ctx);
  43. int match_rm_fn(
  44. LSUP_Graph *src, LSUP_Graph *dest, const LSUP_TripleKey *spok,
  45. void *ctx);
  46. static LSUP_rc
  47. graph_iter_next_buffer (GraphIterator *it, LSUP_SerTriple *sspo);
  48. static inline bool is_null_trp (const LSUP_TripleKey *trp)
  49. {
  50. return (
  51. *trp[0] == NULL_KEY &&
  52. *trp[1] == NULL_KEY &&
  53. *trp[2] == NULL_KEY);
  54. }
  55. #define ENTRY(a, b) (be) == (LSUP_STORE_##a) ||
  56. static inline bool
  57. check_backend (LSUP_store_type be)
  58. { return (BACKEND_TBL false); }
  59. #undef ENTRY
  60. /* * * GRAPH * * */
  61. Graph *
  62. LSUP_graph_new_env (const LSUP_Env *env, const LSUP_store_type store_type)
  63. {
  64. if (UNLIKELY (!env)) {
  65. log_error ("No valid environment passed. Did you call LSUP_init()?");
  66. return NULL;
  67. }
  68. if (UNLIKELY (!check_backend (store_type))) return NULL;
  69. LSUP_Graph *gr;
  70. MALLOC_GUARD (gr, NULL);
  71. gr->uri = LSUP_uri_new (NULL);
  72. gr->store_type = store_type;
  73. gr->env = env;
  74. gr->nsm = env->nsm;
  75. if (gr->store_type == LSUP_STORE_MEM) {
  76. gr->ht_store = LSUP_htstore_new();
  77. if (UNLIKELY (!gr->ht_store)) return NULL;
  78. } else if (gr->store_type == LSUP_STORE_MDB) {
  79. gr->mdb_store = env->mdbstore;
  80. } else { // LSUP_STORE_MDB_TMP
  81. gr->mdb_store = env->mdbstore_ramdisk;
  82. }
  83. log_debug ("Graph created.");
  84. return gr;
  85. }
  86. /**
  87. * Copy triples from a source graph into a destination one.
  88. *
  89. * The destination graph is not initialized here, so the copy is cumulative.
  90. */
  91. static LSUP_rc
  92. graph_copy_contents (const LSUP_Graph *src, LSUP_Graph *dest)
  93. {
  94. LSUP_rc rc = LSUP_NOACTION;
  95. GraphIterator *it = LSUP_graph_lookup (src, NULL, NULL, NULL, NULL);
  96. LSUP_SerTriple sspo;
  97. LSUP_GraphIterator *add_it = LSUP_graph_add_init (dest);
  98. while (graph_iter_next_buffer (it, &sspo) != LSUP_END) {
  99. log_debug ("Inserting triple #%lu", LSUP_graph_iter_cur (it));
  100. LSUP_rc add_rc = LSUP_graph_add_iter (add_it, &sspo);
  101. if (LIKELY (add_rc == LSUP_OK)) rc = LSUP_OK;
  102. else if (add_rc < 0) return add_rc;
  103. }
  104. LSUP_graph_add_done (it);
  105. return rc;
  106. }
  107. LSUP_Graph *
  108. LSUP_graph_copy (const Graph *src)
  109. {
  110. LSUP_Graph *dest = LSUP_graph_new_env (src->env, src->store_type);
  111. if (UNLIKELY (!dest)) return NULL;
  112. LSUP_rc rc = graph_copy_contents (src, dest);
  113. if (UNLIKELY (rc != LSUP_OK)) return NULL;
  114. return dest;
  115. }
  116. LSUP_rc
  117. LSUP_graph_store (const LSUP_Graph *src, const LSUP_Env *env)
  118. {
  119. if (!env) env = LSUP_default_env;
  120. if (src->store_type == LSUP_STORE_MDB && src->env == env)
  121. return LSUP_NOACTION;
  122. LSUP_Graph *dest = LSUP_graph_new_env (env, LSUP_STORE_MDB);
  123. if (UNLIKELY (!dest)) return LSUP_DB_ERR;
  124. LSUP_rc rc = graph_copy_contents (src, dest);
  125. if (UNLIKELY (rc != LSUP_OK)) return LSUP_DB_ERR;
  126. return LSUP_OK;
  127. }
  128. // TODO support boolean ops between any types of graphs.
  129. Graph *
  130. LSUP_graph_bool_op(
  131. const LSUP_bool_op op, const Graph *gr1, const Graph *gr2)
  132. {
  133. if (UNLIKELY (gr1->store_type != LSUP_STORE_MEM)) {
  134. fprintf(
  135. stderr,
  136. "First operand %s is not an in-memory graph. "
  137. "Cannot perform boolean operation.",
  138. gr1->uri->data);
  139. return NULL;
  140. }
  141. if (UNLIKELY (gr2->store_type != LSUP_STORE_MEM)) {
  142. fprintf(
  143. stderr,
  144. "Second operand %s is not an in-memory graph. "
  145. "Cannot perform boolean operation.",
  146. gr2->uri->data);
  147. return NULL;
  148. }
  149. LSUP_Graph *res = LSUP_graph_new (LSUP_STORE_MEM);
  150. res->ht_store = LSUP_htstore_bool_op (op, gr1->ht_store, gr2->ht_store);
  151. return res;
  152. }
  153. void
  154. LSUP_graph_free (LSUP_Graph *gr)
  155. {
  156. if (LIKELY (gr != NULL)) {
  157. LSUP_term_free (gr->uri);
  158. if (gr->store_type == LSUP_STORE_MEM)
  159. LSUP_htstore_free (gr->ht_store);
  160. /*
  161. // NOTE This is not required bacause MDB store is only one for now,
  162. // cleared at exit.
  163. else
  164. LSUP_mdbstore_free (gr->mdb_store);
  165. */
  166. free (gr);
  167. }
  168. }
  169. LSUP_Term *
  170. LSUP_graph_uri (const LSUP_Graph *gr) { return gr->uri; }
  171. LSUP_rc
  172. LSUP_graph_set_uri (LSUP_Graph *gr, const char *uri)
  173. { return LSUP_uri_init (gr->uri, uri); }
  174. LSUP_NSMap *
  175. LSUP_graph_namespace (const Graph *gr)
  176. { return gr->nsm; }
  177. void
  178. LSUP_graph_set_namespace (Graph *gr, LSUP_NSMap *nsm)
  179. { if (gr->store_type == LSUP_STORE_MEM) gr->nsm = nsm; }
  180. size_t
  181. LSUP_graph_size (const Graph *gr)
  182. {
  183. if (gr->store_type == LSUP_STORE_MEM)
  184. return LSUP_htstore_size (gr->ht_store);
  185. else {
  186. size_t ct;
  187. LSUP_GraphIterator *it = LSUP_graph_lookup (gr, NULL, NULL, NULL, &ct);
  188. LSUP_graph_iter_free (it);
  189. return ct;
  190. }
  191. }
  192. bool
  193. LSUP_graph_equals (const Graph *gr1, const Graph *gr2)
  194. {
  195. LSUP_Graph *res = LSUP_graph_bool_op (LSUP_BOOL_XOR, gr1, gr2);
  196. return (LSUP_graph_size (res) == 0);
  197. }
  198. GraphIterator *
  199. LSUP_graph_add_init (LSUP_Graph *gr)
  200. {
  201. GraphIterator *it;
  202. CALLOC_GUARD (it, NULL);
  203. if (gr->store_type == LSUP_STORE_MEM) {
  204. it->ht_iter = LSUP_htstore_add_init (gr->ht_store);
  205. } else {
  206. LSUP_Buffer *sc = LSUP_buffer_new_from_term (gr->uri);
  207. it->mdb_iter = LSUP_mdbstore_add_init (gr->mdb_store, sc);
  208. LSUP_buffer_free (sc);
  209. }
  210. it->graph = gr;
  211. return it;
  212. }
  213. LSUP_rc
  214. LSUP_graph_add_iter (LSUP_GraphIterator *it, const LSUP_SerTriple *sspo)
  215. {
  216. if (it->graph->store_type == LSUP_STORE_MEM) {
  217. return LSUP_htstore_add_iter (it->ht_iter, sspo);
  218. } else {
  219. return LSUP_mdbstore_add_iter (it->mdb_iter, sspo);
  220. }
  221. }
  222. void
  223. LSUP_graph_add_done (LSUP_GraphIterator *it)
  224. {
  225. if (it->graph->store_type == LSUP_STORE_MEM) {
  226. LSUP_htstore_add_done (it->ht_iter);
  227. } else {
  228. LSUP_mdbstore_add_done (it->mdb_iter);
  229. }
  230. free (it);
  231. log_trace ("Done adding.");
  232. }
  233. LSUP_rc
  234. LSUP_graph_add (
  235. Graph *gr, const LSUP_Triple trp[],
  236. const LSUP_SerTriple strp[], size_t *inserted)
  237. {
  238. /*
  239. * NOTE It is possible to pass both sets of RDF triples and buffer triples.
  240. */
  241. LSUP_rc rc = LSUP_NOACTION;
  242. // Initialize iterator.
  243. LSUP_GraphIterator *it = LSUP_graph_add_init (gr);
  244. // Serialize and insert RDF triples.
  245. LSUP_SerTriple *sspo = LSUP_striple_new (BUF_DUMMY, BUF_DUMMY, BUF_DUMMY);
  246. if (UNLIKELY (!sspo)) return LSUP_MEM_ERR;
  247. if (trp) {
  248. for (size_t i = 0; trp[i].s != NULL; i++) {
  249. log_trace ("Inserting triple #%lu", i);
  250. LSUP_triple_serialize (trp + i, sspo);
  251. LSUP_rc db_rc = LSUP_graph_add_iter (it, sspo);
  252. if (db_rc == LSUP_OK) rc = LSUP_OK;
  253. if (UNLIKELY (db_rc < 0)) return db_rc;
  254. }
  255. }
  256. LSUP_striple_free (sspo);
  257. // Insert serialized triples.
  258. if (strp) {
  259. for (size_t i = 0; strp[i].s != NULL; i++) {
  260. log_trace ("Inserting serialized triple #%lu", i);
  261. LSUP_rc db_rc = LSUP_graph_add_iter (it, strp + i);
  262. if (db_rc == LSUP_OK) rc = LSUP_OK;
  263. if (UNLIKELY (db_rc < 0)) return db_rc;
  264. }
  265. }
  266. if (inserted) {
  267. if (gr->store_type == LSUP_STORE_MEM) {
  268. *inserted = LSUP_htiter_cur (it->ht_iter);
  269. } else {
  270. *inserted = LSUP_mdbiter_cur (it->mdb_iter);
  271. }
  272. }
  273. LSUP_graph_add_done (it);
  274. return rc;
  275. }
  276. LSUP_rc
  277. LSUP_graph_remove (
  278. LSUP_Graph *gr, const LSUP_Term *s, const LSUP_Term *p,
  279. const LSUP_Term *o, size_t *ct)
  280. {
  281. LSUP_rc rc;
  282. LSUP_Buffer *ss = LSUP_buffer_new_from_term (s);
  283. LSUP_Buffer *sp = LSUP_buffer_new_from_term (p);
  284. LSUP_Buffer *so = LSUP_buffer_new_from_term (o);
  285. LSUP_Buffer *sc = LSUP_buffer_new_from_term (gr->uri);
  286. if (gr->store_type == LSUP_STORE_MEM)
  287. rc = LSUP_htstore_remove (gr->ht_store, ss, sp, so, ct);
  288. else
  289. rc = LSUP_mdbstore_remove (gr->mdb_store, ss, sp, so, sc, ct);
  290. LSUP_buffer_free (ss);
  291. LSUP_buffer_free (sp);
  292. LSUP_buffer_free (so);
  293. LSUP_buffer_free (sc);
  294. return rc;
  295. }
  296. GraphIterator *
  297. LSUP_graph_lookup (const Graph *gr, const LSUP_Term *s, const LSUP_Term *p,
  298. const LSUP_Term *o, size_t *ct)
  299. {
  300. GraphIterator *it;
  301. MALLOC_GUARD (it, NULL);
  302. it->graph = gr;
  303. LSUP_Buffer *ss = LSUP_buffer_new_from_term (s);
  304. LSUP_Buffer *sp = LSUP_buffer_new_from_term (p);
  305. LSUP_Buffer *so = LSUP_buffer_new_from_term (o);
  306. LSUP_Buffer *sc = LSUP_buffer_new_from_term (gr->uri);
  307. if (it->graph->store_type == LSUP_STORE_MEM) {
  308. it->ht_iter = LSUP_htstore_lookup (it->graph->ht_store, ss, sp, so);
  309. if (ct) *ct = it->ct;
  310. } else it->mdb_iter = LSUP_mdbstore_lookup (
  311. it->graph->mdb_store, ss, sp, so, sc, ct);
  312. LSUP_buffer_free (ss);
  313. LSUP_buffer_free (sp);
  314. LSUP_buffer_free (so);
  315. LSUP_buffer_free (sc);
  316. return it;
  317. }
  318. /** @brief Advance iterator and return serialized triple.
  319. *
  320. * This is an internal function to pass raw buffers between higher-level
  321. * functions without serializing and deserializing triples.
  322. */
  323. inline static LSUP_rc
  324. graph_iter_next_buffer (GraphIterator *it, LSUP_SerTriple *sspo)
  325. {
  326. LSUP_rc rc;
  327. if (it->graph->store_type == LSUP_STORE_MEM)
  328. rc = LSUP_htiter_next (it->ht_iter, sspo);
  329. else rc = LSUP_mdbiter_next (it->mdb_iter, sspo);
  330. return rc;
  331. }
  332. LSUP_rc
  333. LSUP_graph_iter_next (GraphIterator *it, LSUP_Triple *spo)
  334. {
  335. /*
  336. * NOTE: Memory and MDB back ends treat sspo differently, whereas the
  337. * memory one owns the whole buffer structure, while the MDB one owns only
  338. * the data. Therefore they must be initialized and freed differently.
  339. */
  340. LSUP_SerTriple *sspo;
  341. LSUP_Buffer *ss, *sp, *so;
  342. if (it->graph->store_type == LSUP_STORE_MEM) {
  343. ss = sp = so = NULL;
  344. } else {
  345. // Craft buffers manually so that their addresses are NULL and need not
  346. // be freed.
  347. CALLOC_GUARD (ss, LSUP_MEM_ERR);
  348. CALLOC_GUARD (sp, LSUP_MEM_ERR);
  349. CALLOC_GUARD (so, LSUP_MEM_ERR);
  350. }
  351. sspo = LSUP_striple_new (ss, sp, so);
  352. LSUP_rc rc = graph_iter_next_buffer (it, sspo);
  353. if (rc == LSUP_OK) {
  354. spo->s = LSUP_term_new_from_buffer (sspo->s);
  355. spo->p = LSUP_term_new_from_buffer (sspo->p);
  356. spo->o = LSUP_term_new_from_buffer (sspo->o);
  357. }
  358. if (it->graph->store_type == LSUP_STORE_MEM) free (sspo);
  359. else LSUP_striple_free_shallow (sspo);
  360. return rc;
  361. }
  362. void
  363. LSUP_graph_iter_free (GraphIterator *it)
  364. {
  365. if (it->graph->store_type == LSUP_STORE_MEM)
  366. LSUP_htiter_free (it->ht_iter);
  367. else
  368. LSUP_mdbiter_free (it->mdb_iter);
  369. free (it);
  370. }
  371. size_t
  372. LSUP_graph_iter_cur (GraphIterator *it)
  373. { return LSUP_mdbiter_cur (it->mdb_iter); }
  374. bool
  375. LSUP_graph_contains (const LSUP_Graph *gr, const LSUP_Triple *spo)
  376. {
  377. GraphIterator *it = LSUP_graph_lookup (
  378. gr, spo->s, spo->p, spo->o, NULL);
  379. LSUP_Triple *tmp_spo = TRP_DUMMY;
  380. bool rc = LSUP_graph_iter_next (it, tmp_spo) != LSUP_END;
  381. LSUP_triple_free (tmp_spo);
  382. LSUP_graph_iter_free (it);
  383. return rc;
  384. }
  385. /* * * Static functions * * */