graph.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. #include "store_htable.h"
  2. #include "store_mdb.h"
  3. #include "graph.h"
  4. /*
  5. * Data types.
  6. */
  7. typedef struct Graph {
  8. const LSUP_Env * env; // LSUP environment.
  9. LSUP_store_type store_type; // Back end type: in-memory or MDB.
  10. LSUP_Term *uri; // Graph "name" (URI)
  11. union {
  12. LSUP_HTStore * ht_store;
  13. LSUP_MDBStore * mdb_store;
  14. }; // Back end, defined by store_type.
  15. LSUP_NSMap * nsm; // Namespace map. NOTE: This is
  16. // NULL for MDB* stores. To get a
  17. // proper NSMap, always call
  18. // #LSUP_graph_namespace() for all
  19. // types of graphs.
  20. } Graph;
  21. typedef struct GraphIterator {
  22. const Graph * graph; // Parent graph.
  23. union { // Internal store iterator.
  24. LSUP_HTIterator * ht_iter;
  25. LSUP_MDBIterator * mdb_iter;
  26. };
  27. size_t ct; // Total matches.
  28. } GraphIterator;
  29. /*
  30. * Static prototypes.
  31. */
  32. inline static LSUP_rc
  33. graph_iter_next_buffer (GraphIterator *it, LSUP_BufferTriple *sspo);
  34. static LSUP_rc
  35. graph_copy_contents (const LSUP_Graph *src, LSUP_Graph *dest);
  36. #define ENTRY(a, b) (be) == (LSUP_STORE_##a) ||
  37. static inline bool
  38. check_backend (LSUP_store_type be)
  39. { return (BACKEND_TBL false); }
  40. #undef ENTRY
  41. /*
  42. * Graph API.
  43. */
  44. Graph *
  45. LSUP_graph_new_env (
  46. const LSUP_Env *env, LSUP_Term *uri, const LSUP_store_type store_type)
  47. {
  48. if (UNLIKELY (!env)) {
  49. log_error ("No valid environment passed. Did you call LSUP_init()?");
  50. return NULL;
  51. }
  52. if (UNLIKELY (!check_backend (store_type))) return NULL;
  53. LSUP_Graph *gr;
  54. MALLOC_GUARD (gr, NULL);
  55. gr->uri = uri;
  56. gr->store_type = store_type;
  57. gr->env = env;
  58. gr->nsm = env->nsm;
  59. if (gr->store_type == LSUP_STORE_MEM) {
  60. gr->ht_store = LSUP_htstore_new();
  61. if (UNLIKELY (!gr->ht_store)) return NULL;
  62. } else if (gr->store_type == LSUP_STORE_MDB) {
  63. gr->mdb_store = env->mdb_store;
  64. } else { // LSUP_STORE_MDB_TMP
  65. gr->mdb_store = env->mdb_store_ramdisk;
  66. }
  67. log_debug ("Graph created.");
  68. return gr;
  69. }
  70. LSUP_Graph **
  71. LSUP_graph_new_lookup_env (
  72. const LSUP_Env *env, const LSUP_Term *s,
  73. const LSUP_Term *p, const LSUP_Term *o)
  74. {
  75. if (UNLIKELY (!env)) {
  76. log_error ("No valid environment passed. Did you call LSUP_init()?");
  77. return NULL;
  78. }
  79. LSUP_Buffer *ss = LSUP_term_serialize (s);
  80. LSUP_Buffer *sp = LSUP_term_serialize (p);
  81. LSUP_Buffer *so = LSUP_term_serialize (o);
  82. LSUP_Buffer **ctx_a = LSUP_mdbstore_lookup_contexts (
  83. env->mdb_store, ss, sp, so);
  84. if (UNLIKELY (!ctx_a)) return NULL;
  85. LSUP_buffer_free (ss);
  86. LSUP_buffer_free (sp);
  87. LSUP_buffer_free (so);
  88. // Count for allocation.
  89. size_t i;
  90. for (i = 0; ctx_a[i] != NULL; i++) {}
  91. LSUP_Graph **gr_a = calloc (i + 1, sizeof (*gr_a));
  92. if (UNLIKELY (!gr_a)) return NULL;
  93. for (i = 0; ctx_a[i] != NULL; i++) {
  94. gr_a[i] = LSUP_graph_new (
  95. LSUP_iriref_new (NULL, NULL), LSUP_STORE_MDB);
  96. LSUP_Term *uri = LSUP_term_new_from_buffer (ctx_a[i]);
  97. gr_a[i]->uri = uri;
  98. LSUP_buffer_free (ctx_a[i]);
  99. }
  100. free (ctx_a);
  101. return gr_a;
  102. }
  103. LSUP_Graph *
  104. LSUP_graph_copy (const Graph *src)
  105. {
  106. LSUP_Graph *dest = LSUP_graph_new_env (
  107. src->env, LSUP_iriref_new (NULL, NULL), src->store_type);
  108. if (UNLIKELY (!dest)) return NULL;
  109. LSUP_rc rc = graph_copy_contents (src, dest);
  110. if (UNLIKELY (rc != LSUP_OK)) return NULL;
  111. return dest;
  112. }
  113. LSUP_rc
  114. LSUP_graph_store (
  115. const LSUP_Graph *src, LSUP_Graph **dest_p, const LSUP_Env *env)
  116. {
  117. if (!env) env = LSUP_default_env;
  118. if (src->store_type == LSUP_STORE_MDB && src->env == env)
  119. return LSUP_NOACTION;
  120. LSUP_Graph *dest = LSUP_graph_new_env (
  121. env, LSUP_iriref_new (src->uri->data, LSUP_iriref_nsm (src->uri)),
  122. LSUP_STORE_MDB);
  123. if (UNLIKELY (!dest)) return LSUP_DB_ERR;
  124. LSUP_rc rc;
  125. rc = graph_copy_contents (src, dest);
  126. if (UNLIKELY (rc < 0)) return LSUP_DB_ERR;
  127. if (src->store_type == LSUP_STORE_MEM) {
  128. rc = LSUP_mdbstore_nsm_store (dest->mdb_store, src->nsm);
  129. if (UNLIKELY (rc < 0)) return LSUP_DB_ERR;
  130. }
  131. *dest_p = dest;
  132. return LSUP_OK;
  133. }
  134. // TODO support boolean ops between any types of graphs.
  135. Graph *
  136. LSUP_graph_bool_op(
  137. const LSUP_bool_op op, const Graph *gr1, const Graph *gr2)
  138. {
  139. if (UNLIKELY (gr1->store_type != LSUP_STORE_MEM)) {
  140. fprintf(
  141. stderr,
  142. "First operand %s is not an in-memory graph. "
  143. "Cannot perform boolean operation.",
  144. gr1->uri->data);
  145. return NULL;
  146. }
  147. if (UNLIKELY (gr2->store_type != LSUP_STORE_MEM)) {
  148. fprintf(
  149. stderr,
  150. "Second operand %s is not an in-memory graph. "
  151. "Cannot perform boolean operation.",
  152. gr2->uri->data);
  153. return NULL;
  154. }
  155. LSUP_Graph *res = LSUP_graph_new (
  156. LSUP_iriref_new (NULL, NULL), LSUP_STORE_MEM);
  157. res->ht_store = LSUP_htstore_bool_op (op, gr1->ht_store, gr2->ht_store);
  158. return res;
  159. }
  160. void
  161. LSUP_graph_free (LSUP_Graph *gr)
  162. {
  163. if (LIKELY (gr != NULL)) {
  164. LSUP_term_free (gr->uri);
  165. if (gr->store_type == LSUP_STORE_MEM)
  166. LSUP_htstore_free (gr->ht_store);
  167. free (gr);
  168. }
  169. }
  170. LSUP_Term *
  171. LSUP_graph_uri (const LSUP_Graph *gr) { return gr->uri; }
  172. LSUP_rc
  173. LSUP_graph_set_uri (LSUP_Graph *gr, LSUP_Term *uri)
  174. {
  175. if (!LSUP_IS_IRI (uri)) {
  176. log_error ("Term provided is not a IRI.");
  177. return LSUP_VALUE_ERR;
  178. }
  179. LSUP_term_free (gr->uri);
  180. gr->uri = LSUP_iriref_new (uri->data, LSUP_iriref_nsm (uri));
  181. return LSUP_OK;
  182. }
  183. LSUP_NSMap *
  184. LSUP_graph_namespace (const Graph *gr)
  185. {
  186. if (gr->store_type == LSUP_STORE_MEM) return gr->nsm;
  187. LSUP_NSMap *nsm;
  188. if (LSUP_mdbstore_nsm_get (gr->mdb_store, &nsm) < 0) return NULL;
  189. return nsm;
  190. }
  191. void
  192. LSUP_graph_set_namespace (Graph *gr, LSUP_NSMap *nsm)
  193. { if (gr->store_type == LSUP_STORE_MEM) gr->nsm = nsm; }
  194. size_t
  195. LSUP_graph_size (const Graph *gr)
  196. {
  197. if (gr->store_type == LSUP_STORE_MEM)
  198. return LSUP_htstore_size (gr->ht_store);
  199. else {
  200. size_t ct;
  201. LSUP_GraphIterator *it = LSUP_graph_lookup (gr, NULL, NULL, NULL, &ct);
  202. LSUP_graph_iter_free (it);
  203. return ct;
  204. }
  205. }
  206. bool
  207. LSUP_graph_equals (const Graph *gr1, const Graph *gr2)
  208. {
  209. LSUP_Graph *res = LSUP_graph_bool_op (LSUP_BOOL_XOR, gr1, gr2);
  210. return (LSUP_graph_size (res) == 0);
  211. }
  212. GraphIterator *
  213. LSUP_graph_add_init (LSUP_Graph *gr)
  214. {
  215. GraphIterator *it;
  216. CALLOC_GUARD (it, NULL);
  217. if (gr->store_type == LSUP_STORE_MEM) {
  218. it->ht_iter = LSUP_htstore_add_init (gr->ht_store);
  219. } else {
  220. LSUP_Buffer *sc = LSUP_term_serialize (gr->uri);
  221. it->mdb_iter = LSUP_mdbstore_add_init (gr->mdb_store, sc);
  222. LSUP_buffer_free (sc);
  223. }
  224. it->graph = gr;
  225. return it;
  226. }
  227. LSUP_rc
  228. LSUP_graph_add_iter (LSUP_GraphIterator *it, const LSUP_Triple *spo)
  229. {
  230. LSUP_rc rc;
  231. LSUP_BufferTriple *sspo = LSUP_triple_serialize (spo);
  232. if (UNLIKELY (!sspo)) return LSUP_MEM_ERR;
  233. if (it->graph->store_type == LSUP_STORE_MEM) {
  234. rc = LSUP_htstore_add_iter (it->ht_iter, sspo);
  235. for (int i = 0; i < 3; i++) {
  236. LSUP_htstore_add_term (
  237. it->graph->ht_store, LSUP_btriple_pos (sspo, i));
  238. // HT store uses term keys from tcache.
  239. }
  240. } else {
  241. rc = LSUP_mdbstore_add_iter (it->mdb_iter, sspo);
  242. for (int i = 0; i < 3; i++) {
  243. LSUP_mdbstore_add_term (
  244. it->graph->mdb_store, LSUP_btriple_pos (sspo, i));
  245. // Store datatype term permanently.
  246. LSUP_Term *term = LSUP_triple_pos (spo, i);
  247. if (
  248. term->type == LSUP_TERM_LITERAL
  249. && !LSUP_mdbstore_tkey_exists (
  250. it->graph->mdb_store, LSUP_term_hash (term->datatype))
  251. ) {
  252. LSUP_Buffer *ser_dtype = LSUP_term_serialize (term->datatype);
  253. LSUP_mdbstore_add_term (it->graph->mdb_store, ser_dtype);
  254. LSUP_buffer_free (ser_dtype);
  255. }
  256. }
  257. }
  258. LSUP_btriple_free (sspo);
  259. return rc;
  260. }
  261. void
  262. LSUP_graph_add_done (LSUP_GraphIterator *it)
  263. {
  264. if (it->graph->store_type == LSUP_STORE_MEM)
  265. LSUP_htstore_add_done (it->ht_iter);
  266. else LSUP_mdbstore_add_done (it->mdb_iter);
  267. free (it);
  268. log_trace ("Done adding.");
  269. }
  270. LSUP_rc
  271. LSUP_graph_add (Graph *gr, const LSUP_Triple trp[], size_t *inserted)
  272. {
  273. LSUP_rc rc = LSUP_NOACTION;
  274. // Initialize iterator.
  275. LSUP_GraphIterator *it = LSUP_graph_add_init (gr);
  276. // Serialize and insert RDF triples.
  277. for (size_t i = 0; trp[i].s != NULL; i++) {
  278. log_trace ("Inserting triple #%lu", i);
  279. LSUP_rc db_rc = LSUP_graph_add_iter (it, trp + i);
  280. if (db_rc == LSUP_OK) rc = LSUP_OK;
  281. if (UNLIKELY (db_rc < 0)) return db_rc;
  282. }
  283. if (inserted) {
  284. if (gr->store_type == LSUP_STORE_MEM) {
  285. *inserted = LSUP_htiter_cur (it->ht_iter);
  286. } else {
  287. *inserted = LSUP_mdbiter_cur (it->mdb_iter);
  288. }
  289. }
  290. LSUP_graph_add_done (it);
  291. return rc;
  292. }
  293. LSUP_rc
  294. LSUP_graph_remove (
  295. LSUP_Graph *gr, const LSUP_Term *s, const LSUP_Term *p,
  296. const LSUP_Term *o, size_t *ct)
  297. {
  298. LSUP_rc rc;
  299. LSUP_Buffer *ss = LSUP_term_serialize (s);
  300. LSUP_Buffer *sp = LSUP_term_serialize (p);
  301. LSUP_Buffer *so = LSUP_term_serialize (o);
  302. LSUP_Buffer *sc = LSUP_term_serialize (gr->uri);
  303. if (gr->store_type == LSUP_STORE_MEM)
  304. rc = LSUP_htstore_remove (gr->ht_store, ss, sp, so, ct);
  305. else
  306. rc = LSUP_mdbstore_remove (gr->mdb_store, ss, sp, so, sc, ct);
  307. LSUP_buffer_free (ss);
  308. LSUP_buffer_free (sp);
  309. LSUP_buffer_free (so);
  310. LSUP_buffer_free (sc);
  311. return rc;
  312. }
  313. GraphIterator *
  314. LSUP_graph_lookup (const Graph *gr, const LSUP_Term *s, const LSUP_Term *p,
  315. const LSUP_Term *o, size_t *ct)
  316. {
  317. GraphIterator *it;
  318. MALLOC_GUARD (it, NULL);
  319. it->graph = gr;
  320. LSUP_Buffer *ss = LSUP_term_serialize (s);
  321. LSUP_Buffer *sp = LSUP_term_serialize (p);
  322. LSUP_Buffer *so = LSUP_term_serialize (o);
  323. LSUP_Buffer *sc = LSUP_term_serialize (gr->uri);
  324. if (it->graph->store_type == LSUP_STORE_MEM) {
  325. it->ht_iter = LSUP_htstore_lookup (it->graph->ht_store, ss, sp, so);
  326. if (ct) *ct = it->ct;
  327. } else it->mdb_iter = LSUP_mdbstore_lookup (
  328. it->graph->mdb_store, ss, sp, so, sc, ct);
  329. LSUP_buffer_free (ss);
  330. LSUP_buffer_free (sp);
  331. LSUP_buffer_free (so);
  332. LSUP_buffer_free (sc);
  333. return it;
  334. }
  335. LSUP_rc
  336. LSUP_graph_iter_next (GraphIterator *it, LSUP_Triple *spo)
  337. {
  338. /*
  339. * NOTE: Memory and MDB back ends treat sspo differently, whereas the
  340. * memory one owns the whole buffer structure, while the MDB one owns only
  341. * the data. Therefore they must be initialized and freed differently.
  342. */
  343. LSUP_BufferTriple *sspo;
  344. LSUP_Buffer *ss, *sp, *so;
  345. if (it->graph->store_type == LSUP_STORE_MEM) {
  346. ss = sp = so = NULL;
  347. } else {
  348. // Craft buffers manually so that their addresses are NULL and need not
  349. // be freed.
  350. CALLOC_GUARD (ss, LSUP_MEM_ERR);
  351. CALLOC_GUARD (sp, LSUP_MEM_ERR);
  352. CALLOC_GUARD (so, LSUP_MEM_ERR);
  353. }
  354. sspo = LSUP_btriple_new (ss, sp, so);
  355. LSUP_rc rc = graph_iter_next_buffer (it, sspo);
  356. if (rc == LSUP_OK) {
  357. spo->s = LSUP_term_new_from_buffer (sspo->s);
  358. if (!spo->s) return LSUP_ERROR;
  359. spo->p = LSUP_term_new_from_buffer (sspo->p);
  360. if (!spo->p) return LSUP_ERROR;
  361. spo->o = LSUP_term_new_from_buffer (sspo->o);
  362. if (!spo->o) return LSUP_ERROR;
  363. }
  364. if (it->graph->store_type == LSUP_STORE_MEM) free (sspo);
  365. else LSUP_btriple_free_shallow (sspo);
  366. return rc;
  367. }
  368. void
  369. LSUP_graph_iter_free (GraphIterator *it)
  370. {
  371. if (it->graph->store_type == LSUP_STORE_MEM)
  372. LSUP_htiter_free (it->ht_iter);
  373. else
  374. LSUP_mdbiter_free (it->mdb_iter);
  375. free (it);
  376. }
  377. size_t
  378. LSUP_graph_iter_cur (GraphIterator *it)
  379. { return LSUP_mdbiter_cur (it->mdb_iter); }
  380. bool
  381. LSUP_graph_contains (const LSUP_Graph *gr, const LSUP_Triple *spo)
  382. {
  383. GraphIterator *it = LSUP_graph_lookup (
  384. gr, spo->s, spo->p, spo->o, NULL);
  385. LSUP_Triple *tmp_spo = TRP_DUMMY;
  386. bool rc = LSUP_graph_iter_next (it, tmp_spo) != LSUP_END;
  387. LSUP_triple_free (tmp_spo);
  388. LSUP_graph_iter_free (it);
  389. return rc;
  390. }
  391. /*
  392. * Static functions.
  393. */
  394. /** @brief Advance iterator and return serialized triple.
  395. *
  396. * This is an internal function to pass raw buffers between higher-level
  397. * functions without serializing and deserializing triples.
  398. */
  399. inline static LSUP_rc
  400. graph_iter_next_buffer (GraphIterator *it, LSUP_BufferTriple *sspo)
  401. {
  402. LSUP_rc rc;
  403. if (it->graph->store_type == LSUP_STORE_MEM)
  404. rc = LSUP_htiter_next (it->ht_iter, sspo);
  405. else rc = LSUP_mdbiter_next (it->mdb_iter, sspo, NULL);
  406. return rc;
  407. }
  408. /**
  409. * Copy triples from a source graph into a destination one.
  410. *
  411. * The destination graph is not initialized here, so the copy is cumulative.
  412. */
  413. static LSUP_rc
  414. graph_copy_contents (const LSUP_Graph *src, LSUP_Graph *dest)
  415. {
  416. LSUP_rc rc = LSUP_NOACTION;
  417. GraphIterator *it = LSUP_graph_lookup (src, NULL, NULL, NULL, NULL);
  418. LSUP_Triple spo;
  419. LSUP_GraphIterator *add_it = LSUP_graph_add_init (dest);
  420. while (LSUP_graph_iter_next (it, &spo) != LSUP_END) {
  421. LSUP_rc add_rc = LSUP_graph_add_iter (add_it, &spo);
  422. LSUP_triple_done (&spo);
  423. if (LIKELY (add_rc == LSUP_OK)) rc = LSUP_OK;
  424. else if (add_rc < 0) {
  425. rc = add_rc;
  426. break;
  427. }
  428. }
  429. LSUP_graph_add_done (add_it);
  430. LSUP_graph_iter_free (it);
  431. return rc;
  432. }
  433. /**
  434. * Extern inline definitions.
  435. */
  436. size_t LSUP_graph_size (const LSUP_Graph *gr);