diff options
Diffstat (limited to 'src/plugin/namestore/plugin_namestore_sqlite.c')
-rw-r--r-- | src/plugin/namestore/plugin_namestore_sqlite.c | 196 |
1 files changed, 78 insertions, 118 deletions
diff --git a/src/plugin/namestore/plugin_namestore_sqlite.c b/src/plugin/namestore/plugin_namestore_sqlite.c index ada9ca25b..c38e9e08f 100644 --- a/src/plugin/namestore/plugin_namestore_sqlite.c +++ b/src/plugin/namestore/plugin_namestore_sqlite.c | |||
@@ -26,7 +26,6 @@ | |||
26 | 26 | ||
27 | #include "platform.h" | 27 | #include "platform.h" |
28 | #include "gnunet_namestore_plugin.h" | 28 | #include "gnunet_namestore_plugin.h" |
29 | #include "gnunet_namestore_service.h" | ||
30 | #include "gnunet_gnsrecord_lib.h" | 29 | #include "gnunet_gnsrecord_lib.h" |
31 | #include "gnunet_sq_lib.h" | 30 | #include "gnunet_sq_lib.h" |
32 | #include <sqlite3.h> | 31 | #include <sqlite3.h> |
@@ -50,13 +49,13 @@ | |||
50 | * with the message given by strerror(errno). | 49 | * with the message given by strerror(errno). |
51 | */ | 50 | */ |
52 | #define LOG_SQLITE(db, level, cmd) do { \ | 51 | #define LOG_SQLITE(db, level, cmd) do { \ |
53 | GNUNET_log_from (level, \ | 52 | GNUNET_log_from (level, \ |
54 | "namestore-sqlite", _ ( \ | 53 | "namestore-sqlite", _ ( \ |
55 | "`%s' failed at %s:%d with error: %s\n"), \ | 54 | "`%s' failed at %s:%d with error: %s\n"), \ |
56 | cmd, \ | 55 | cmd, \ |
57 | __FILE__, __LINE__, \ | 56 | __FILE__, __LINE__, \ |
58 | sqlite3_errmsg ( \ | 57 | sqlite3_errmsg ( \ |
59 | db->dbh)); \ | 58 | db->dbh)); \ |
60 | } while (0) | 59 | } while (0) |
61 | 60 | ||
62 | #define LOG(kind, ...) GNUNET_log_from (kind, "namestore-sqlite", __VA_ARGS__) | 61 | #define LOG(kind, ...) GNUNET_log_from (kind, "namestore-sqlite", __VA_ARGS__) |
@@ -142,32 +141,35 @@ database_prepare (struct Plugin *plugin) | |||
142 | }; | 141 | }; |
143 | struct GNUNET_SQ_PrepareStatement ps[] = { | 142 | struct GNUNET_SQ_PrepareStatement ps[] = { |
144 | GNUNET_SQ_make_prepare ("INSERT INTO ns098records " | 143 | GNUNET_SQ_make_prepare ("INSERT INTO ns098records " |
145 | "(zone_private_key,pkey,rvalue,record_count,record_data,label)" | 144 | "(zone_private_key,pkey,rvalue,record_count,record_data," |
146 | " VALUES (?, ?, ?, ?, ?, ?)", | 145 | "label,editor_hint)" |
146 | " VALUES (?, ?, ?, ?, ?, ?, '')", | ||
147 | &plugin->store_records), | 147 | &plugin->store_records), |
148 | GNUNET_SQ_make_prepare ("DELETE FROM ns098records " | 148 | GNUNET_SQ_make_prepare ("DELETE FROM ns098records " |
149 | "WHERE zone_private_key=? AND label=?", | 149 | "WHERE zone_private_key=? AND label=?", |
150 | &plugin->delete_records), | 150 | &plugin->delete_records), |
151 | GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label" | 151 | GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label,editor_hint" |
152 | " FROM ns098records" | 152 | " FROM ns098records" |
153 | " WHERE zone_private_key=? AND pkey=?", | 153 | " WHERE zone_private_key=? AND pkey=?", |
154 | &plugin->zone_to_name), | 154 | &plugin->zone_to_name), |
155 | GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label" | 155 | GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label,editor_hint" |
156 | " FROM ns098records" | 156 | " FROM ns098records" |
157 | " WHERE zone_private_key=? AND uid > ?" | 157 | " WHERE zone_private_key=? AND uid > ?" |
158 | " ORDER BY uid ASC" | 158 | " ORDER BY uid ASC" |
159 | " LIMIT ?", | 159 | " LIMIT ?", |
160 | &plugin->iterate_zone), | 160 | &plugin->iterate_zone), |
161 | GNUNET_SQ_make_prepare ( | 161 | GNUNET_SQ_make_prepare ( |
162 | "SELECT uid,record_count,record_data,label,zone_private_key" | 162 | "SELECT uid,record_count,record_data,label,editor_hint,zone_private_key" |
163 | " FROM ns098records" | 163 | " FROM ns098records" |
164 | " WHERE uid > ?" | 164 | " WHERE uid > ?" |
165 | " ORDER BY uid ASC" | 165 | " ORDER BY uid ASC" |
166 | " LIMIT ?", | 166 | " LIMIT ?", |
167 | &plugin->iterate_all_zones), | 167 | &plugin->iterate_all_zones), |
168 | GNUNET_SQ_make_prepare ("SELECT uid,record_count,record_data,label" | 168 | GNUNET_SQ_make_prepare ("UPDATE ns098records" |
169 | " FROM ns098records" | 169 | " SET editor_hint=?" |
170 | " WHERE zone_private_key=? AND label=?", | 170 | " FROM ns098records AS old_ns098records" |
171 | " WHERE ns098records.zone_private_key=? AND ns098records.label=?" | ||
172 | " RETURNING ns098records.uid,ns098records.record_count,ns098records.record_data,ns098records.label,editor_hint ", | ||
171 | &plugin->lookup_label), | 173 | &plugin->lookup_label), |
172 | GNUNET_SQ_PREPARE_END | 174 | GNUNET_SQ_PREPARE_END |
173 | }; | 175 | }; |
@@ -460,6 +462,7 @@ get_records_and_call_iterator (struct Plugin *plugin, | |||
460 | size_t data_size; | 462 | size_t data_size; |
461 | void *data; | 463 | void *data; |
462 | char *label; | 464 | char *label; |
465 | char *editor_hint; | ||
463 | struct GNUNET_CRYPTO_PrivateKey zk; | 466 | struct GNUNET_CRYPTO_PrivateKey zk; |
464 | struct GNUNET_SQ_ResultSpec rs[] = { | 467 | struct GNUNET_SQ_ResultSpec rs[] = { |
465 | GNUNET_SQ_result_spec_uint64 (&seq), | 468 | GNUNET_SQ_result_spec_uint64 (&seq), |
@@ -467,6 +470,7 @@ get_records_and_call_iterator (struct Plugin *plugin, | |||
467 | GNUNET_SQ_result_spec_variable_size (&data, | 470 | GNUNET_SQ_result_spec_variable_size (&data, |
468 | &data_size), | 471 | &data_size), |
469 | GNUNET_SQ_result_spec_string (&label), | 472 | GNUNET_SQ_result_spec_string (&label), |
473 | GNUNET_SQ_result_spec_string (&editor_hint), | ||
470 | GNUNET_SQ_result_spec_end | 474 | GNUNET_SQ_result_spec_end |
471 | }; | 475 | }; |
472 | struct GNUNET_SQ_ResultSpec rsx[] = { | 476 | struct GNUNET_SQ_ResultSpec rsx[] = { |
@@ -475,6 +479,7 @@ get_records_and_call_iterator (struct Plugin *plugin, | |||
475 | GNUNET_SQ_result_spec_variable_size (&data, | 479 | GNUNET_SQ_result_spec_variable_size (&data, |
476 | &data_size), | 480 | &data_size), |
477 | GNUNET_SQ_result_spec_string (&label), | 481 | GNUNET_SQ_result_spec_string (&label), |
482 | GNUNET_SQ_result_spec_string (&editor_hint), | ||
478 | GNUNET_SQ_result_spec_auto_from_type (&zk), | 483 | GNUNET_SQ_result_spec_auto_from_type (&zk), |
479 | GNUNET_SQ_result_spec_end | 484 | GNUNET_SQ_result_spec_end |
480 | }; | 485 | }; |
@@ -514,6 +519,7 @@ get_records_and_call_iterator (struct Plugin *plugin, | |||
514 | if (NULL != iter) | 519 | if (NULL != iter) |
515 | iter (iter_cls, | 520 | iter (iter_cls, |
516 | seq, | 521 | seq, |
522 | editor_hint, | ||
517 | &zk, | 523 | &zk, |
518 | label, | 524 | label, |
519 | record_count, | 525 | record_count, |
@@ -540,16 +546,18 @@ get_records_and_call_iterator (struct Plugin *plugin, | |||
540 | * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR | 546 | * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR |
541 | */ | 547 | */ |
542 | static enum GNUNET_GenericReturnValue | 548 | static enum GNUNET_GenericReturnValue |
543 | namestore_sqlite_lookup_records (void *cls, | 549 | lookup_records (void *cls, |
544 | const struct | 550 | const struct |
545 | GNUNET_CRYPTO_PrivateKey *zone, | 551 | GNUNET_CRYPTO_PrivateKey *zone, |
546 | const char *label, | 552 | const char *label, |
547 | GNUNET_NAMESTORE_RecordIterator iter, | 553 | GNUNET_NAMESTORE_RecordIterator iter, |
548 | void *iter_cls) | 554 | void *iter_cls, |
555 | const char *editor_hint) | ||
549 | { | 556 | { |
550 | struct Plugin *plugin = cls; | 557 | struct Plugin *plugin = cls; |
551 | GNUNET_assert (GNUNET_OK == database_prepare (plugin)); | 558 | GNUNET_assert (GNUNET_OK == database_prepare (plugin)); |
552 | struct GNUNET_SQ_QueryParam params[] = { | 559 | struct GNUNET_SQ_QueryParam params[] = { |
560 | GNUNET_SQ_query_param_string (editor_hint), | ||
553 | GNUNET_SQ_query_param_auto_from_type (zone), | 561 | GNUNET_SQ_query_param_auto_from_type (zone), |
554 | GNUNET_SQ_query_param_string (label), | 562 | GNUNET_SQ_query_param_string (label), |
555 | GNUNET_SQ_query_param_end | 563 | GNUNET_SQ_query_param_end |
@@ -580,6 +588,51 @@ namestore_sqlite_lookup_records (void *cls, | |||
580 | 588 | ||
581 | 589 | ||
582 | /** | 590 | /** |
591 | * Lookup records in the datastore for which we are the authority. | ||
592 | * | ||
593 | * @param cls closure (internal context for the plugin) | ||
594 | * @param zone private key of the zone | ||
595 | * @param label name of the record in the zone | ||
596 | * @param iter function to call with the result | ||
597 | * @param iter_cls closure for @a iter | ||
598 | * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR | ||
599 | */ | ||
600 | static enum GNUNET_GenericReturnValue | ||
601 | namestore_sqlite_lookup_records (void *cls, | ||
602 | const struct | ||
603 | GNUNET_CRYPTO_PrivateKey *zone, | ||
604 | const char *label, | ||
605 | GNUNET_NAMESTORE_RecordIterator iter, | ||
606 | void *iter_cls) | ||
607 | { | ||
608 | return lookup_records (cls, zone, label, iter, iter_cls, ""); | ||
609 | } | ||
610 | |||
611 | |||
612 | /** | ||
613 | * Lookup records in the datastore for which we are the authority. | ||
614 | * | ||
615 | * @param cls closure (internal context for the plugin) | ||
616 | * @param zone private key of the zone | ||
617 | * @param label name of the record in the zone | ||
618 | * @param iter function to call with the result | ||
619 | * @param iter_cls closure for @a iter | ||
620 | * @return #GNUNET_OK on success, #GNUNET_NO for no results, else #GNUNET_SYSERR | ||
621 | */ | ||
622 | static enum GNUNET_GenericReturnValue | ||
623 | namestore_sqlite_edit_records (void *cls, | ||
624 | const char *editor_hint, | ||
625 | const struct | ||
626 | GNUNET_CRYPTO_PrivateKey *zone, | ||
627 | const char *label, | ||
628 | GNUNET_NAMESTORE_RecordIterator iter, | ||
629 | void *iter_cls) | ||
630 | { | ||
631 | return lookup_records (cls, zone, label, iter, iter_cls, editor_hint); | ||
632 | } | ||
633 | |||
634 | |||
635 | /** | ||
583 | * Iterate over the results for a particular key and zone in the | 636 | * Iterate over the results for a particular key and zone in the |
584 | * datastore. Will return at most one result to the iterator. | 637 | * datastore. Will return at most one result to the iterator. |
585 | * | 638 | * |
@@ -698,92 +751,6 @@ namestore_sqlite_zone_to_name (void *cls, | |||
698 | } | 751 | } |
699 | 752 | ||
700 | 753 | ||
701 | /** | ||
702 | * Begin a transaction for a client. | ||
703 | * This locks the database. SQLite is unable to discern between different | ||
704 | * rows with a specific zone key but the API looks like this anyway. | ||
705 | * https://www.sqlite.org/lang_transaction.html | ||
706 | * | ||
707 | * @param cls closure (internal context for the plugin) | ||
708 | * @param emsg error message set of return code is #GNUNET_SYSERR | ||
709 | * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started. | ||
710 | */ | ||
711 | static enum GNUNET_GenericReturnValue | ||
712 | namestore_sqlite_transaction_begin (void *cls, | ||
713 | char **emsg) | ||
714 | { | ||
715 | struct Plugin *plugin = cls; | ||
716 | int rc; | ||
717 | char *sqlEmsg; | ||
718 | |||
719 | GNUNET_assert (GNUNET_OK == database_prepare (plugin)); | ||
720 | rc = sqlite3_exec (plugin->dbh, "BEGIN IMMEDIATE TRANSACTION;", | ||
721 | NULL, NULL, &sqlEmsg); | ||
722 | if (SQLITE_OK != rc) | ||
723 | { | ||
724 | *emsg = GNUNET_strdup (sqlEmsg); | ||
725 | sqlite3_free (sqlEmsg); | ||
726 | } | ||
727 | return (SQLITE_OK != rc) ? GNUNET_SYSERR : GNUNET_YES; | ||
728 | } | ||
729 | |||
730 | |||
731 | /** | ||
732 | * Commit a transaction for a client. | ||
733 | * This releases the lock on the database. | ||
734 | * | ||
735 | * @param cls closure (internal context for the plugin) | ||
736 | * @param emsg error message set of return code is #GNUNET_SYSERR | ||
737 | * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started. | ||
738 | */ | ||
739 | static enum GNUNET_GenericReturnValue | ||
740 | namestore_sqlite_transaction_rollback (void *cls, | ||
741 | char **emsg) | ||
742 | { | ||
743 | struct Plugin *plugin = cls; | ||
744 | int rc; | ||
745 | char *sqlEmsg; | ||
746 | |||
747 | GNUNET_assert (GNUNET_OK == database_prepare (plugin)); | ||
748 | rc = sqlite3_exec (plugin->dbh, "ROLLBACK;", | ||
749 | NULL, NULL, &sqlEmsg); | ||
750 | if (SQLITE_OK != rc) | ||
751 | { | ||
752 | *emsg = GNUNET_strdup (sqlEmsg); | ||
753 | sqlite3_free (sqlEmsg); | ||
754 | } | ||
755 | return (SQLITE_OK != rc) ? GNUNET_SYSERR : GNUNET_YES; | ||
756 | } | ||
757 | |||
758 | |||
759 | /** | ||
760 | * Roll back a transaction for a client. | ||
761 | * This releases the lock on the database. | ||
762 | * | ||
763 | * @param cls closure (internal context for the plugin) | ||
764 | * @param emsg error message set of return code is #GNUNET_SYSERR | ||
765 | * @return #GNUNET_YES on success, #GNUNET_SYSERR if transaction cannot be started. | ||
766 | */ | ||
767 | static enum GNUNET_GenericReturnValue | ||
768 | namestore_sqlite_transaction_commit (void *cls, | ||
769 | char **emsg) | ||
770 | { | ||
771 | struct Plugin *plugin = cls; | ||
772 | int rc; | ||
773 | char *sqlEmsg; | ||
774 | |||
775 | GNUNET_assert (GNUNET_OK == database_prepare (plugin)); | ||
776 | rc = sqlite3_exec (plugin->dbh, "END TRANSACTION;", | ||
777 | NULL, NULL, &sqlEmsg); | ||
778 | if (SQLITE_OK != rc) | ||
779 | { | ||
780 | *emsg = GNUNET_strdup (sqlEmsg); | ||
781 | sqlite3_free (sqlEmsg); | ||
782 | } | ||
783 | return (SQLITE_OK != rc) ? GNUNET_SYSERR : GNUNET_YES; | ||
784 | } | ||
785 | |||
786 | |||
787 | static enum GNUNET_GenericReturnValue | 754 | static enum GNUNET_GenericReturnValue |
788 | namestore_sqlite_create_tables (void *cls) | 755 | namestore_sqlite_create_tables (void *cls) |
789 | { | 756 | { |
@@ -804,7 +771,8 @@ namestore_sqlite_create_tables (void *cls) | |||
804 | " rvalue INT8 NOT NULL," | 771 | " rvalue INT8 NOT NULL," |
805 | " record_count INT NOT NULL," | 772 | " record_count INT NOT NULL," |
806 | " record_data BLOB NOT NULL," | 773 | " record_data BLOB NOT NULL," |
807 | " label TEXT NOT NULL" | 774 | " label TEXT NOT NULL," |
775 | " editor_hint TEXT NOT NULL" | ||
808 | ")"), | 776 | ")"), |
809 | GNUNET_SQ_make_try_execute ("CREATE INDEX ir_pkey_reverse " | 777 | GNUNET_SQ_make_try_execute ("CREATE INDEX ir_pkey_reverse " |
810 | "ON ns098records (zone_private_key,pkey)"), | 778 | "ON ns098records (zone_private_key,pkey)"), |
@@ -940,17 +908,9 @@ libgnunet_plugin_namestore_sqlite_init (void *cls) | |||
940 | api->iterate_records = &namestore_sqlite_iterate_records; | 908 | api->iterate_records = &namestore_sqlite_iterate_records; |
941 | api->zone_to_name = &namestore_sqlite_zone_to_name; | 909 | api->zone_to_name = &namestore_sqlite_zone_to_name; |
942 | api->lookup_records = &namestore_sqlite_lookup_records; | 910 | api->lookup_records = &namestore_sqlite_lookup_records; |
943 | api->transaction_begin = &namestore_sqlite_transaction_begin; | ||
944 | api->transaction_commit = &namestore_sqlite_transaction_commit; | ||
945 | api->transaction_rollback = &namestore_sqlite_transaction_rollback; | ||
946 | api->create_tables = &namestore_sqlite_create_tables; | 911 | api->create_tables = &namestore_sqlite_create_tables; |
947 | api->drop_tables = &namestore_sqlite_drop_tables; | 912 | api->drop_tables = &namestore_sqlite_drop_tables; |
948 | /** | 913 | api->edit_records = &namestore_sqlite_edit_records; |
949 | * NOTE: Since SQlite does not support SELECT ... FOR UPDATE this is | ||
950 | * just an alias to lookup_records. The BEGIN IMMEDIATE mechanic currently | ||
951 | * implicitly ensures this API behaves as it should | ||
952 | */ | ||
953 | api->edit_records = &namestore_sqlite_lookup_records; | ||
954 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 914 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
955 | _ ("SQlite database running\n")); | 915 | _ ("SQlite database running\n")); |
956 | return api; | 916 | return api; |