plugin_datacache_postgres.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. /*
  2. This file is part of GNUnet
  3. Copyright (C) 2006, 2009, 2010, 2012, 2015, 2017, 2018 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file datacache/plugin_datacache_postgres.c
  18. * @brief postgres for an implementation of a database backend for the datacache
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "gnunet_util_lib.h"
  23. #include "gnunet_pq_lib.h"
  24. #include "gnunet_datacache_plugin.h"
  25. #define LOG(kind, ...) GNUNET_log_from (kind, "datacache-postgres", __VA_ARGS__)
  26. /**
  27. * Per-entry overhead estimate
  28. */
  29. #define OVERHEAD (sizeof(struct GNUNET_HashCode) + 24)
  30. /**
  31. * Context for all functions in this plugin.
  32. */
  33. struct Plugin
  34. {
  35. /**
  36. * Our execution environment.
  37. */
  38. struct GNUNET_DATACACHE_PluginEnvironment *env;
  39. /**
  40. * Native Postgres database handle.
  41. */
  42. struct GNUNET_PQ_Context *dbh;
  43. /**
  44. * Number of key-value pairs in the database.
  45. */
  46. unsigned int num_items;
  47. };
  48. /**
  49. * @brief Get a database handle
  50. *
  51. * @param plugin global context
  52. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  53. */
  54. static int
  55. init_connection (struct Plugin *plugin)
  56. {
  57. struct GNUNET_PQ_ExecuteStatement es[] = {
  58. GNUNET_PQ_make_try_execute ("CREATE TEMPORARY SEQUENCE IF NOT EXISTS gn011dc_oid_seq"),
  59. GNUNET_PQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS gn011dc ("
  60. " oid OID NOT NULL DEFAULT nextval('gn011dc_oid_seq'),"
  61. " type INTEGER NOT NULL,"
  62. " prox INTEGER NOT NULL,"
  63. " discard_time BIGINT NOT NULL,"
  64. " key BYTEA NOT NULL,"
  65. " value BYTEA NOT NULL,"
  66. " path BYTEA DEFAULT NULL)"),
  67. GNUNET_PQ_make_try_execute (
  68. "ALTER SEQUENCE gnu011dc_oid_seq OWNED BY gn011dc.oid"),
  69. GNUNET_PQ_make_try_execute (
  70. "CREATE INDEX IF NOT EXISTS idx_oid ON gn011dc (oid)"),
  71. GNUNET_PQ_make_try_execute (
  72. "CREATE INDEX IF NOT EXISTS idx_key ON gn011dc (key)"),
  73. GNUNET_PQ_make_try_execute (
  74. "CREATE INDEX IF NOT EXISTS idx_dt ON gn011dc (discard_time)"),
  75. GNUNET_PQ_make_execute (
  76. "ALTER TABLE gn011dc ALTER value SET STORAGE EXTERNAL"),
  77. GNUNET_PQ_make_execute ("ALTER TABLE gn011dc ALTER key SET STORAGE PLAIN"),
  78. GNUNET_PQ_EXECUTE_STATEMENT_END
  79. };
  80. struct GNUNET_PQ_PreparedStatement ps[] = {
  81. GNUNET_PQ_make_prepare ("getkt",
  82. "SELECT discard_time,type,value,path FROM gn011dc "
  83. "WHERE key=$1 AND type=$2 AND discard_time >= $3",
  84. 3),
  85. GNUNET_PQ_make_prepare ("getk",
  86. "SELECT discard_time,type,value,path FROM gn011dc "
  87. "WHERE key=$1 AND discard_time >= $2",
  88. 2),
  89. GNUNET_PQ_make_prepare ("getex",
  90. "SELECT length(value) AS len,oid,key FROM gn011dc"
  91. " WHERE discard_time < $1"
  92. " ORDER BY discard_time ASC LIMIT 1",
  93. 1),
  94. GNUNET_PQ_make_prepare ("getm",
  95. "SELECT length(value) AS len,oid,key FROM gn011dc"
  96. " ORDER BY prox ASC, discard_time ASC LIMIT 1",
  97. 0),
  98. GNUNET_PQ_make_prepare ("get_random",
  99. "SELECT discard_time,type,value,path,key FROM gn011dc"
  100. " WHERE discard_time >= $1"
  101. " ORDER BY key ASC LIMIT 1 OFFSET $2",
  102. 2),
  103. GNUNET_PQ_make_prepare ("get_closest",
  104. "SELECT discard_time,type,value,path,key FROM gn011dc "
  105. "WHERE key>=$1 AND discard_time >= $2 ORDER BY key ASC LIMIT $3",
  106. 3),
  107. GNUNET_PQ_make_prepare ("delrow",
  108. "DELETE FROM gn011dc WHERE oid=$1",
  109. 1),
  110. GNUNET_PQ_make_prepare ("put",
  111. "INSERT INTO gn011dc (type, prox, discard_time, key, value, path) "
  112. "VALUES ($1, $2, $3, $4, $5, $6)",
  113. 6),
  114. GNUNET_PQ_PREPARED_STATEMENT_END
  115. };
  116. plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->env->cfg,
  117. "datacache-postgres",
  118. NULL,
  119. es,
  120. ps);
  121. if (NULL == plugin->dbh)
  122. return GNUNET_SYSERR;
  123. return GNUNET_OK;
  124. }
  125. /**
  126. * Store an item in the datastore.
  127. *
  128. * @param cls closure (our `struct Plugin`)
  129. * @param key key to store @a data under
  130. * @param prox proximity of @a key to my PID
  131. * @param data_size number of bytes in @a data
  132. * @param data data to store
  133. * @param type type of the value
  134. * @param discard_time when to discard the value in any case
  135. * @param path_info_len number of entries in @a path_info
  136. * @param path_info a path through the network
  137. * @return 0 if duplicate, -1 on error, number of bytes used otherwise
  138. */
  139. static ssize_t
  140. postgres_plugin_put (void *cls,
  141. const struct GNUNET_HashCode *key,
  142. uint32_t prox,
  143. size_t data_size,
  144. const char *data,
  145. enum GNUNET_BLOCK_Type type,
  146. struct GNUNET_TIME_Absolute discard_time,
  147. unsigned int path_info_len,
  148. const struct GNUNET_PeerIdentity *path_info)
  149. {
  150. struct Plugin *plugin = cls;
  151. uint32_t type32 = (uint32_t) type;
  152. struct GNUNET_PQ_QueryParam params[] = {
  153. GNUNET_PQ_query_param_uint32 (&type32),
  154. GNUNET_PQ_query_param_uint32 (&prox),
  155. GNUNET_PQ_query_param_absolute_time (&discard_time),
  156. GNUNET_PQ_query_param_auto_from_type (key),
  157. GNUNET_PQ_query_param_fixed_size (data, data_size),
  158. GNUNET_PQ_query_param_fixed_size (path_info,
  159. path_info_len * sizeof(struct
  160. GNUNET_PeerIdentity)),
  161. GNUNET_PQ_query_param_end
  162. };
  163. enum GNUNET_DB_QueryStatus ret;
  164. ret = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
  165. "put",
  166. params);
  167. if (0 > ret)
  168. return -1;
  169. plugin->num_items++;
  170. return data_size + OVERHEAD;
  171. }
  172. /**
  173. * Closure for #handle_results.
  174. */
  175. struct HandleResultContext
  176. {
  177. /**
  178. * Function to call on each result, may be NULL.
  179. */
  180. GNUNET_DATACACHE_Iterator iter;
  181. /**
  182. * Closure for @e iter.
  183. */
  184. void *iter_cls;
  185. /**
  186. * Key used.
  187. */
  188. const struct GNUNET_HashCode *key;
  189. };
  190. /**
  191. * Function to be called with the results of a SELECT statement
  192. * that has returned @a num_results results. Parse the result
  193. * and call the callback given in @a cls
  194. *
  195. * @param cls closure of type `struct HandleResultContext`
  196. * @param result the postgres result
  197. * @param num_result the number of results in @a result
  198. */
  199. static void
  200. handle_results (void *cls,
  201. PGresult *result,
  202. unsigned int num_results)
  203. {
  204. struct HandleResultContext *hrc = cls;
  205. for (unsigned int i = 0; i < num_results; i++)
  206. {
  207. struct GNUNET_TIME_Absolute expiration_time;
  208. uint32_t type;
  209. void *data;
  210. size_t data_size;
  211. struct GNUNET_PeerIdentity *path;
  212. size_t path_len;
  213. struct GNUNET_PQ_ResultSpec rs[] = {
  214. GNUNET_PQ_result_spec_absolute_time ("discard_time",
  215. &expiration_time),
  216. GNUNET_PQ_result_spec_uint32 ("type",
  217. &type),
  218. GNUNET_PQ_result_spec_variable_size ("value",
  219. &data,
  220. &data_size),
  221. GNUNET_PQ_result_spec_variable_size ("path",
  222. (void **) &path,
  223. &path_len),
  224. GNUNET_PQ_result_spec_end
  225. };
  226. if (GNUNET_YES !=
  227. GNUNET_PQ_extract_result (result,
  228. rs,
  229. i))
  230. {
  231. GNUNET_break (0);
  232. return;
  233. }
  234. if (0 != (path_len % sizeof(struct GNUNET_PeerIdentity)))
  235. {
  236. GNUNET_break (0);
  237. path_len = 0;
  238. }
  239. path_len %= sizeof(struct GNUNET_PeerIdentity);
  240. LOG (GNUNET_ERROR_TYPE_DEBUG,
  241. "Found result of size %u bytes and type %u in database\n",
  242. (unsigned int) data_size,
  243. (unsigned int) type);
  244. if ((NULL != hrc->iter) &&
  245. (GNUNET_SYSERR ==
  246. hrc->iter (hrc->iter_cls,
  247. hrc->key,
  248. data_size,
  249. data,
  250. (enum GNUNET_BLOCK_Type) type,
  251. expiration_time,
  252. path_len,
  253. path)))
  254. {
  255. LOG (GNUNET_ERROR_TYPE_DEBUG,
  256. "Ending iteration (client error)\n");
  257. GNUNET_PQ_cleanup_result (rs);
  258. return;
  259. }
  260. GNUNET_PQ_cleanup_result (rs);
  261. }
  262. }
  263. /**
  264. * Iterate over the results for a particular key
  265. * in the datastore.
  266. *
  267. * @param cls closure (our `struct Plugin`)
  268. * @param key key to look for
  269. * @param type entries of which type are relevant?
  270. * @param iter maybe NULL (to just count)
  271. * @param iter_cls closure for @a iter
  272. * @return the number of results found
  273. */
  274. static unsigned int
  275. postgres_plugin_get (void *cls,
  276. const struct GNUNET_HashCode *key,
  277. enum GNUNET_BLOCK_Type type,
  278. GNUNET_DATACACHE_Iterator iter,
  279. void *iter_cls)
  280. {
  281. struct Plugin *plugin = cls;
  282. uint32_t type32 = (uint32_t) type;
  283. struct GNUNET_TIME_Absolute now;
  284. struct GNUNET_PQ_QueryParam paramk[] = {
  285. GNUNET_PQ_query_param_auto_from_type (key),
  286. GNUNET_PQ_query_param_absolute_time (&now),
  287. GNUNET_PQ_query_param_end
  288. };
  289. struct GNUNET_PQ_QueryParam paramkt[] = {
  290. GNUNET_PQ_query_param_auto_from_type (key),
  291. GNUNET_PQ_query_param_uint32 (&type32),
  292. GNUNET_PQ_query_param_absolute_time (&now),
  293. GNUNET_PQ_query_param_end
  294. };
  295. enum GNUNET_DB_QueryStatus res;
  296. struct HandleResultContext hr_ctx;
  297. now = GNUNET_TIME_absolute_get ();
  298. hr_ctx.iter = iter;
  299. hr_ctx.iter_cls = iter_cls;
  300. hr_ctx.key = key;
  301. res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
  302. (0 == type) ? "getk" : "getkt",
  303. (0 == type) ? paramk : paramkt,
  304. &handle_results,
  305. &hr_ctx);
  306. if (res < 0)
  307. return 0;
  308. return res;
  309. }
  310. /**
  311. * Delete the entry with the lowest expiration value
  312. * from the datacache right now.
  313. *
  314. * @param cls closure (our `struct Plugin`)
  315. * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
  316. */
  317. static int
  318. postgres_plugin_del (void *cls)
  319. {
  320. struct Plugin *plugin = cls;
  321. struct GNUNET_PQ_QueryParam pempty[] = {
  322. GNUNET_PQ_query_param_end
  323. };
  324. uint32_t size;
  325. uint32_t oid;
  326. struct GNUNET_HashCode key;
  327. struct GNUNET_PQ_ResultSpec rs[] = {
  328. GNUNET_PQ_result_spec_uint32 ("len",
  329. &size),
  330. GNUNET_PQ_result_spec_uint32 ("oid",
  331. &oid),
  332. GNUNET_PQ_result_spec_auto_from_type ("key",
  333. &key),
  334. GNUNET_PQ_result_spec_end
  335. };
  336. enum GNUNET_DB_QueryStatus res;
  337. struct GNUNET_PQ_QueryParam dparam[] = {
  338. GNUNET_PQ_query_param_uint32 (&oid),
  339. GNUNET_PQ_query_param_end
  340. };
  341. struct GNUNET_TIME_Absolute now;
  342. struct GNUNET_PQ_QueryParam xparam[] = {
  343. GNUNET_PQ_query_param_absolute_time (&now),
  344. GNUNET_PQ_query_param_end
  345. };
  346. now = GNUNET_TIME_absolute_get ();
  347. res = GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh,
  348. "getex",
  349. xparam,
  350. rs);
  351. if (0 >= res)
  352. res = GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh,
  353. "getm",
  354. pempty,
  355. rs);
  356. if (0 > res)
  357. return GNUNET_SYSERR;
  358. if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == res)
  359. {
  360. /* no result */
  361. LOG (GNUNET_ERROR_TYPE_DEBUG,
  362. "Ending iteration (no more results)\n");
  363. return 0;
  364. }
  365. res = GNUNET_PQ_eval_prepared_non_select (plugin->dbh,
  366. "delrow",
  367. dparam);
  368. if (0 > res)
  369. {
  370. GNUNET_PQ_cleanup_result (rs);
  371. return GNUNET_SYSERR;
  372. }
  373. plugin->num_items--;
  374. plugin->env->delete_notify (plugin->env->cls,
  375. &key,
  376. size + OVERHEAD);
  377. GNUNET_PQ_cleanup_result (rs);
  378. return GNUNET_OK;
  379. }
  380. /**
  381. * Obtain a random key-value pair from the datacache.
  382. *
  383. * @param cls closure (our `struct Plugin`)
  384. * @param iter maybe NULL (to just count)
  385. * @param iter_cls closure for @a iter
  386. * @return the number of results found, zero (datacache empty) or one
  387. */
  388. static unsigned int
  389. postgres_plugin_get_random (void *cls,
  390. GNUNET_DATACACHE_Iterator iter,
  391. void *iter_cls)
  392. {
  393. struct Plugin *plugin = cls;
  394. uint32_t off;
  395. struct GNUNET_TIME_Absolute now;
  396. struct GNUNET_TIME_Absolute expiration_time;
  397. size_t data_size;
  398. void *data;
  399. size_t path_len;
  400. struct GNUNET_PeerIdentity *path;
  401. struct GNUNET_HashCode key;
  402. uint32_t type;
  403. enum GNUNET_DB_QueryStatus res;
  404. struct GNUNET_PQ_QueryParam params[] = {
  405. GNUNET_PQ_query_param_absolute_time (&now),
  406. GNUNET_PQ_query_param_uint32 (&off),
  407. GNUNET_PQ_query_param_end
  408. };
  409. struct GNUNET_PQ_ResultSpec rs[] = {
  410. GNUNET_PQ_result_spec_absolute_time ("discard_time",
  411. &expiration_time),
  412. GNUNET_PQ_result_spec_uint32 ("type",
  413. &type),
  414. GNUNET_PQ_result_spec_variable_size ("value",
  415. &data,
  416. &data_size),
  417. GNUNET_PQ_result_spec_variable_size ("path",
  418. (void **) &path,
  419. &path_len),
  420. GNUNET_PQ_result_spec_auto_from_type ("key",
  421. &key),
  422. GNUNET_PQ_result_spec_end
  423. };
  424. if (0 == plugin->num_items)
  425. return 0;
  426. if (NULL == iter)
  427. return 1;
  428. now = GNUNET_TIME_absolute_get ();
  429. off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
  430. plugin->num_items);
  431. res = GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh,
  432. "get_random",
  433. params,
  434. rs);
  435. if (0 > res)
  436. {
  437. GNUNET_break (0);
  438. return 0;
  439. }
  440. if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == res)
  441. {
  442. GNUNET_break (0);
  443. return 0;
  444. }
  445. if (0 != (path_len % sizeof(struct GNUNET_PeerIdentity)))
  446. {
  447. GNUNET_break (0);
  448. path_len = 0;
  449. }
  450. path_len %= sizeof(struct GNUNET_PeerIdentity);
  451. LOG (GNUNET_ERROR_TYPE_DEBUG,
  452. "Found random value with key %s of size %u bytes and type %u in database\n",
  453. GNUNET_h2s (&key),
  454. (unsigned int) data_size,
  455. (unsigned int) type);
  456. (void) iter (iter_cls,
  457. &key,
  458. data_size,
  459. data,
  460. (enum GNUNET_BLOCK_Type) type,
  461. expiration_time,
  462. path_len,
  463. path);
  464. GNUNET_PQ_cleanup_result (rs);
  465. return 1;
  466. }
  467. /**
  468. * Closure for #extract_result_cb.
  469. */
  470. struct ExtractResultContext
  471. {
  472. /**
  473. * Function to call for each result found.
  474. */
  475. GNUNET_DATACACHE_Iterator iter;
  476. /**
  477. * Closure for @e iter.
  478. */
  479. void *iter_cls;
  480. };
  481. /**
  482. * Function to be called with the results of a SELECT statement
  483. * that has returned @a num_results results. Calls the `iter`
  484. * from @a cls for each result.
  485. *
  486. * @param cls closure with the `struct ExtractResultContext`
  487. * @param result the postgres result
  488. * @param num_result the number of results in @a result
  489. */
  490. static void
  491. extract_result_cb (void *cls,
  492. PGresult *result,
  493. unsigned int num_results)
  494. {
  495. struct ExtractResultContext *erc = cls;
  496. if (NULL == erc->iter)
  497. return;
  498. for (unsigned int i = 0; i < num_results; i++)
  499. {
  500. struct GNUNET_TIME_Absolute expiration_time;
  501. uint32_t type;
  502. void *data;
  503. size_t data_size;
  504. struct GNUNET_PeerIdentity *path;
  505. size_t path_len;
  506. struct GNUNET_HashCode key;
  507. struct GNUNET_PQ_ResultSpec rs[] = {
  508. GNUNET_PQ_result_spec_absolute_time ("",
  509. &expiration_time),
  510. GNUNET_PQ_result_spec_uint32 ("type",
  511. &type),
  512. GNUNET_PQ_result_spec_variable_size ("value",
  513. &data,
  514. &data_size),
  515. GNUNET_PQ_result_spec_variable_size ("path",
  516. (void **) &path,
  517. &path_len),
  518. GNUNET_PQ_result_spec_auto_from_type ("key",
  519. &key),
  520. GNUNET_PQ_result_spec_end
  521. };
  522. if (GNUNET_YES !=
  523. GNUNET_PQ_extract_result (result,
  524. rs,
  525. i))
  526. {
  527. GNUNET_break (0);
  528. return;
  529. }
  530. if (0 != (path_len % sizeof(struct GNUNET_PeerIdentity)))
  531. {
  532. GNUNET_break (0);
  533. path_len = 0;
  534. }
  535. path_len %= sizeof(struct GNUNET_PeerIdentity);
  536. LOG (GNUNET_ERROR_TYPE_DEBUG,
  537. "Found result of size %u bytes and type %u in database\n",
  538. (unsigned int) data_size,
  539. (unsigned int) type);
  540. if (GNUNET_SYSERR ==
  541. erc->iter (erc->iter_cls,
  542. &key,
  543. data_size,
  544. data,
  545. (enum GNUNET_BLOCK_Type) type,
  546. expiration_time,
  547. path_len,
  548. path))
  549. {
  550. LOG (GNUNET_ERROR_TYPE_DEBUG,
  551. "Ending iteration (client error)\n");
  552. GNUNET_PQ_cleanup_result (rs);
  553. break;
  554. }
  555. GNUNET_PQ_cleanup_result (rs);
  556. }
  557. }
  558. /**
  559. * Iterate over the results that are "close" to a particular key in
  560. * the datacache. "close" is defined as numerically larger than @a
  561. * key (when interpreted as a circular address space), with small
  562. * distance.
  563. *
  564. * @param cls closure (internal context for the plugin)
  565. * @param key area of the keyspace to look into
  566. * @param num_results number of results that should be returned to @a iter
  567. * @param iter maybe NULL (to just count)
  568. * @param iter_cls closure for @a iter
  569. * @return the number of results found
  570. */
  571. static unsigned int
  572. postgres_plugin_get_closest (void *cls,
  573. const struct GNUNET_HashCode *key,
  574. unsigned int num_results,
  575. GNUNET_DATACACHE_Iterator iter,
  576. void *iter_cls)
  577. {
  578. struct Plugin *plugin = cls;
  579. uint32_t num_results32 = (uint32_t) num_results;
  580. struct GNUNET_TIME_Absolute now;
  581. struct GNUNET_PQ_QueryParam params[] = {
  582. GNUNET_PQ_query_param_auto_from_type (key),
  583. GNUNET_PQ_query_param_absolute_time (&now),
  584. GNUNET_PQ_query_param_uint32 (&num_results32),
  585. GNUNET_PQ_query_param_end
  586. };
  587. enum GNUNET_DB_QueryStatus res;
  588. struct ExtractResultContext erc;
  589. erc.iter = iter;
  590. erc.iter_cls = iter_cls;
  591. now = GNUNET_TIME_absolute_get ();
  592. res = GNUNET_PQ_eval_prepared_multi_select (plugin->dbh,
  593. "get_closest",
  594. params,
  595. &extract_result_cb,
  596. &erc);
  597. if (0 > res)
  598. {
  599. LOG (GNUNET_ERROR_TYPE_DEBUG,
  600. "Ending iteration (postgres error)\n");
  601. return 0;
  602. }
  603. if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == res)
  604. {
  605. /* no result */
  606. LOG (GNUNET_ERROR_TYPE_DEBUG,
  607. "Ending iteration (no more results)\n");
  608. return 0;
  609. }
  610. return res;
  611. }
  612. /**
  613. * Entry point for the plugin.
  614. *
  615. * @param cls closure (the `struct GNUNET_DATACACHE_PluginEnvironmnet`)
  616. * @return the plugin's closure (our `struct Plugin`)
  617. */
  618. void *
  619. libgnunet_plugin_datacache_postgres_init (void *cls)
  620. {
  621. struct GNUNET_DATACACHE_PluginEnvironment *env = cls;
  622. struct GNUNET_DATACACHE_PluginFunctions *api;
  623. struct Plugin *plugin;
  624. plugin = GNUNET_new (struct Plugin);
  625. plugin->env = env;
  626. if (GNUNET_OK != init_connection (plugin))
  627. {
  628. GNUNET_free (plugin);
  629. return NULL;
  630. }
  631. api = GNUNET_new (struct GNUNET_DATACACHE_PluginFunctions);
  632. api->cls = plugin;
  633. api->get = &postgres_plugin_get;
  634. api->put = &postgres_plugin_put;
  635. api->del = &postgres_plugin_del;
  636. api->get_random = &postgres_plugin_get_random;
  637. api->get_closest = &postgres_plugin_get_closest;
  638. LOG (GNUNET_ERROR_TYPE_INFO,
  639. "Postgres datacache running\n");
  640. return api;
  641. }
  642. /**
  643. * Exit point from the plugin.
  644. *
  645. * @param cls closure (our `struct Plugin`)
  646. * @return NULL
  647. */
  648. void *
  649. libgnunet_plugin_datacache_postgres_done (void *cls)
  650. {
  651. struct GNUNET_DATACACHE_PluginFunctions *api = cls;
  652. struct Plugin *plugin = api->cls;
  653. GNUNET_PQ_disconnect (plugin->dbh);
  654. GNUNET_free (plugin);
  655. GNUNET_free (api);
  656. return NULL;
  657. }
  658. /* end of plugin_datacache_postgres.c */