monotone

monotone Mtn Source Tree

Root/database.cc

1// copyright (C) 2002, 2003 graydon hoare <graydon@pobox.com>
2// all rights reserved.
3// licensed to the public under the terms of the GNU GPL (>= 2)
4// see the file COPYING for details
5
6#include <fstream>
7#include <iterator>
8#include <list>
9#include <set>
10#include <sstream>
11#include <vector>
12
13#include <stdarg.h>
14
15#include <boost/shared_ptr.hpp>
16#include <boost/lexical_cast.hpp>
17#include <boost/filesystem/path.hpp>
18#include <boost/filesystem/operations.hpp>
19
20#include <sqlite3.h>
21
22#include "app_state.hh"
23#include "cert.hh"
24#include "cleanup.hh"
25#include "constants.hh"
26#include "database.hh"
27#include "keys.hh"
28#include "sanity.hh"
29#include "schema_migration.hh"
30#include "transforms.hh"
31#include "ui.hh"
32#include "vocab.hh"
33#include "xdelta.hh"
34#include "epoch.hh"
35
36// defined in schema.sql, converted to header:
37#include "schema.h"
38
39// defined in views.sql, converted to header:
40#include "views.h"
41
42// this file defines a public, typed interface to the database.
43// the database class encapsulates all knowledge about sqlite,
44// the schema, and all SQL statements used to access the schema.
45//
46// see file schema.sql for the text of the schema.
47
48using boost::shared_ptr;
49using boost::lexical_cast;
50using namespace std;
51
52int const one_row = 1;
53int const one_col = 1;
54int const any_rows = -1;
55int const any_cols = -1;
56
57extern "C" {
58// some wrappers to ease migration
59 int sqlite3_exec_printf(sqlite3*,const char *sqlFormat,sqlite3_callback,
60 void *,char **errmsg,...);
61 int sqlite3_exec_vprintf(sqlite3*,const char *sqlFormat,sqlite3_callback,
62 void *,char **errmsg,va_list ap);
63 int sqlite3_get_table_vprintf(sqlite3*,const char *sqlFormat,char ***resultp,
64 int *nrow,int *ncolumn,char **errmsg,va_list ap);
65 const char *sqlite3_value_text_s(sqlite3_value *v);
66}
67
68int sqlite3_exec_printf(sqlite3 * db,
69 char const * sqlFormat,
70 sqlite3_callback cb,
71 void * user_data,
72 char ** errmsg,
73 ...)
74{
75 va_list ap;
76 va_start(ap, errmsg);
77 int result = sqlite3_exec_vprintf(db, sqlFormat, cb,
78 user_data, errmsg, ap);
79 va_end(ap);
80 return result;
81}
82
83int sqlite3_exec_vprintf(sqlite3 * db,
84 char const * sqlFormat,
85 sqlite3_callback cb,
86 void * user_data,
87 char ** errmsg,
88 va_list ap)
89{
90 char * formatted = sqlite3_vmprintf(sqlFormat, ap);
91 int result = sqlite3_exec(db, formatted, cb,
92 user_data, errmsg);
93 sqlite3_free(formatted);
94 return result;
95}
96
97int sqlite3_get_table_vprintf(sqlite3 * db,
98 char const * sqlFormat,
99 char *** resultp,
100 int * nrow,
101 int * ncolumn,
102 char ** errmsg,
103 va_list ap)
104{
105 char * formatted = sqlite3_vmprintf(sqlFormat, ap);
106 int result = sqlite3_get_table(db, formatted, resultp,
107 nrow, ncolumn, errmsg);
108 sqlite3_free(formatted);
109 return result;
110}
111
112database::database(fs::path const & fn) :
113 filename(fn),
114 // nb. update this if you change the schema. unfortunately we are not
115 // using self-digesting schemas due to comment irregularities and
116 // non-alphabetic ordering of tables in sql source files. we could create
117 // a temporary db, write our intended schema into it, and read it back,
118 // but this seems like it would be too rude. possibly revisit this issue.
119 schema("e372b508bea9b991816d1c74680f7ae10d2a6d94"),
120 __sql(NULL),
121 transaction_level(0)
122{}
123
124void
125database::check_schema()
126{
127 string db_schema_id;
128 calculate_schema_id (__sql, db_schema_id);
129 N (schema == db_schema_id,
130 F("database schemas do not match: "
131 "wanted %s, got %s. try migrating database")
132 % schema % db_schema_id);
133}
134
135// sqlite3_value_text gives a const unsigned char * but most of the time
136// we need a signed char
137const char *
138sqlite3_value_text_s(sqlite3_value *v)
139{
140 return (const char *)(sqlite3_value_text(v));
141}
142
143static void
144sqlite3_unbase64_fn(sqlite3_context *f, int nargs, sqlite3_value ** args)
145{
146 if (nargs != 1)
147 {
148 sqlite3_result_error(f, "need exactly 1 arg to unbase64()", -1);
149 return;
150 }
151 data decoded;
152 decode_base64(base64<data>(string(sqlite3_value_text_s(args[0]))), decoded);
153 sqlite3_result_blob(f, decoded().c_str(), decoded().size(), SQLITE_TRANSIENT);
154}
155
156static void
157sqlite3_unpack_fn(sqlite3_context *f, int nargs, sqlite3_value ** args)
158{
159 if (nargs != 1)
160 {
161 sqlite3_result_error(f, "need exactly 1 arg to unpack()", -1);
162 return;
163 }
164 data unpacked;
165 unpack(base64< gzip<data> >(string(sqlite3_value_text_s(args[0]))), unpacked);
166 sqlite3_result_blob(f, unpacked().c_str(), unpacked().size(), SQLITE_TRANSIENT);
167}
168
169void
170database::set_app(app_state * app)
171{
172 __app = app;
173}
174
175static void
176check_sqlite_format_version(fs::path const & filename)
177{
178 if (fs::exists(filename))
179 {
180 N(!fs::is_directory(filename),
181 F("database %s is a directory\n") % filename.string());
182
183 // sqlite 3 files begin with this constant string
184 // (version 2 files begin with a different one)
185 std::string version_string("SQLite format 3");
186
187 std::ifstream file(filename.string().c_str());
188 N(file, F("unable to probe database version in file %s") % filename.string());
189
190 for (std::string::const_iterator i = version_string.begin();
191 i != version_string.end(); ++i)
192 {
193 char c;
194 file.get(c);
195 N(c == *i, F("database %s is not an sqlite version 3 file, "
196 "try dump and reload") % filename.string());
197 }
198 }
199}
200
201
202struct sqlite3 *
203database::sql(bool init)
204{
205 if (! __sql)
206 {
207 N(!filename.empty(), F("no database specified"));
208
209 if (! init)
210 {
211 N(fs::exists(filename),
212 F("database %s does not exist") % filename.string());
213 N(!fs::is_directory(filename),
214 F("database %s is a directory") % filename.string());
215 }
216
217 check_sqlite_format_version(filename);
218 int error;
219 error = sqlite3_open(filename.string().c_str(), &__sql);
220 if (error)
221 throw oops(string("could not open database: ") + filename.string() +
222 (": " + string(sqlite3_errmsg(__sql))));
223 if (init)
224 execute(schema_constant);
225
226 check_schema();
227 install_functions(__app);
228 install_views();
229 }
230 return __sql;
231}
232
233void
234database::initialize()
235{
236 if (__sql)
237 throw oops("cannot initialize database while it is open");
238
239 N(!fs::exists(filename),
240 F("could not initialize database: %s: already exists")
241 % filename.string());
242
243 fs::path journal = mkpath(filename.string() + "-journal");
244 N(!fs::exists(journal),
245 F("existing (possibly stale) journal file '%s' "
246 "has same stem as new database '%s'")
247 % journal.string() % filename.string());
248
249 sqlite3 *s = sql(true);
250 I(s != NULL);
251}
252
253
254struct
255dump_request
256{
257 dump_request() {};
258 struct sqlite3 *sql;
259 string table_name;
260 ostream *out;
261};
262
263static int
264dump_row_cb(void *data, int n, char **vals, char **cols)
265{
266 dump_request *dump = reinterpret_cast<dump_request *>(data);
267 I(dump != NULL);
268 I(vals != NULL);
269 I(dump->out != NULL);
270 *(dump->out) << F("INSERT INTO %s VALUES(") % dump->table_name;
271 for (int i = 0; i < n; ++i)
272 {
273 if (i != 0)
274 *(dump->out) << ',';
275
276 if (vals[i] == NULL)
277 *(dump->out) << "NULL";
278 else
279 {
280 *(dump->out) << "'";
281 for (char *cp = vals[i]; *cp; ++cp)
282 {
283 if (*cp == '\'')
284 *(dump->out) << "''";
285 else
286 *(dump->out) << *cp;
287 }
288 *(dump->out) << "'";
289 }
290 }
291 *(dump->out) << ");\n";
292 return 0;
293}
294
295static int
296dump_table_cb(void *data, int n, char **vals, char **cols)
297{
298 dump_request *dump = reinterpret_cast<dump_request *>(data);
299 I(dump != NULL);
300 I(dump->sql != NULL);
301 I(vals != NULL);
302 I(vals[0] != NULL);
303 I(vals[1] != NULL);
304 I(vals[2] != NULL);
305 I(n == 3);
306 if (string(vals[1]) == "table")
307 {
308 *(dump->out) << vals[2] << ";\n";
309 dump->table_name = string(vals[0]);
310 sqlite3_exec_printf(dump->sql, "SELECT * FROM '%q'",
311 dump_row_cb, data, NULL, vals[0]);
312 }
313 return 0;
314}
315
316void
317database::dump(ostream & out)
318{
319 dump_request req;
320 req.out = &out;
321 req.sql = sql();
322 out << "BEGIN TRANSACTION;\n";
323 int res = sqlite3_exec(req.sql,
324 "SELECT name, type, sql FROM sqlite_master "
325 "WHERE type='table' AND sql NOT NULL "
326 "ORDER BY substr(type,2,1), name",
327 dump_table_cb, &req, NULL);
328 I(res == SQLITE_OK);
329 out << "COMMIT;\n";
330}
331
332void
333database::load(istream & in)
334{
335 char buf[constants::bufsz];
336 string tmp;
337
338 N(filename.string() != "",
339 F("need database name"));
340 N(!fs::exists(filename),
341 F("cannot create %s; it already exists\n") % filename.string());
342 int error = sqlite3_open(filename.string().c_str(), &__sql);
343 if (error)
344 throw oops(string("could not open database: ") + filename.string() +
345 (string(sqlite3_errmsg(__sql))));
346
347 while(in)
348 {
349 in.read(buf, constants::bufsz);
350 tmp.append(buf, in.gcount());
351 }
352
353 execute(tmp.c_str());
354}
355
356
357void
358database::debug(string const & sql, ostream & out)
359{
360 results res;
361 fetch(res, any_cols, any_rows, sql.c_str());
362 out << "'" << sql << "' -> " << res.size() << " rows\n" << endl;
363 for (size_t i = 0; i < res.size(); ++i)
364 {
365 for (size_t j = 0; j < res[i].size(); ++j)
366 {
367 if (j != 0)
368 out << " | ";
369 out << res[i][j];
370 }
371 out << endl;
372 }
373}
374
375void
376database::info(ostream & out)
377{
378 string id;
379 calculate_schema_id(sql(), id);
380 out << "schema version : " << id << endl;
381 out << "full manifests : " << count("manifests") << endl;
382 out << "manifest deltas : " << count("manifest_deltas") << endl;
383 out << "full files : " << count("files") << endl;
384 out << "file deltas : " << count("file_deltas") << endl;
385 out << "revisions : " << count("revisions") << endl;
386 out << "ancestry edges : " << count("revision_ancestry") << endl;
387 out << "certs : " << count("revision_certs") << endl;
388}
389
390void
391database::version(ostream & out)
392{
393 string id;
394 N(filename.string() != "",
395 F("need database name"));
396 int error = sqlite3_open(filename.string().c_str(), &__sql);
397 if (error)
398 {
399 sqlite3_close(__sql);
400 throw oops(string("could not open database: ") + filename.string() +
401 (": " + string(sqlite3_errmsg(__sql))));
402 }
403 calculate_schema_id(__sql, id);
404 sqlite3_close(__sql);
405 out << "database schema version: " << id << endl;
406}
407
408void
409database::migrate()
410{
411 N(filename.string() != "",
412 F("need database name"));
413 int error = sqlite3_open(filename.string().c_str(), &__sql);
414 if (error)
415 {
416 sqlite3_close(__sql);
417 throw oops(string("could not open database: ") + filename.string() +
418 (": " + string(sqlite3_errmsg(__sql))));
419 }
420 migrate_monotone_schema(__sql);
421 sqlite3_close(__sql);
422}
423
424void
425database::rehash()
426{
427 transaction_guard guard(*this);
428 ticker mcerts("mcerts", "m", 1);
429 ticker pubkeys("pubkeys", "+", 1);
430 ticker privkeys("privkeys", "!", 1);
431
432 {
433 // rehash all mcerts
434 results res;
435 vector<cert> certs;
436 fetch(res, 5, any_rows,
437 "SELECT id, name, value, keypair, signature "
438 "FROM manifest_certs");
439 results_to_certs(res, certs);
440 execute("DELETE FROM manifest_certs");
441 for(vector<cert>::const_iterator i = certs.begin(); i != certs.end(); ++i)
442 {
443 put_cert(*i, "manifest_certs");
444 ++mcerts;
445 }
446 }
447
448 {
449 // rehash all pubkeys
450 results res;
451 fetch(res, 2, any_rows, "SELECT id, keydata FROM public_keys");
452 execute("DELETE FROM public_keys");
453 for (size_t i = 0; i < res.size(); ++i)
454 {
455 hexenc<id> tmp;
456 key_hash_code(rsa_keypair_id(res[i][0]), base64<rsa_pub_key>(res[i][1]), tmp);
457 execute("INSERT INTO public_keys VALUES('%q', '%q', '%q')",
458 tmp().c_str(), res[i][0].c_str(), res[i][1].c_str());
459 ++pubkeys;
460 }
461 }
462
463 {
464 // rehash all privkeys
465 results res;
466 fetch(res, 2, any_rows, "SELECT id, keydata FROM private_keys");
467 execute("DELETE FROM private_keys");
468 for (size_t i = 0; i < res.size(); ++i)
469 {
470 hexenc<id> tmp;
471 key_hash_code(rsa_keypair_id(res[i][0]), base64< arc4<rsa_priv_key> >(res[i][1]), tmp);
472 execute("INSERT INTO private_keys VALUES('%q', '%q', '%q')",
473 tmp().c_str(), res[i][0].c_str(), res[i][1].c_str());
474 ++privkeys;
475 }
476 }
477
478 guard.commit();
479}
480
481void
482database::ensure_open()
483{
484 sqlite3 *s = sql();
485 I(s != NULL);
486}
487
488database::~database()
489{
490 if (__sql)
491 {
492 sqlite3_close(__sql);
493 __sql = 0;
494 }
495}
496
497static void
498assert_sqlite3_ok(int res)
499{
500 switch (res)
501 {
502 case SQLITE_OK:
503 break;
504
505 case SQLITE_ERROR:
506 throw oops("SQL error or missing database");
507 break;
508
509 case SQLITE_INTERNAL:
510 throw oops("An internal logic error in SQLite");
511 break;
512
513 case SQLITE_PERM:
514 throw oops("Access permission denied");
515 break;
516
517 case SQLITE_ABORT:
518 throw oops("Callback routine requested an abort");
519 break;
520
521 case SQLITE_BUSY:
522 throw oops("The database file is locked");
523 break;
524
525 case SQLITE_LOCKED:
526 throw oops("A table in the database is locked");
527 break;
528
529 case SQLITE_NOMEM:
530 throw oops("A malloc() failed");
531 break;
532
533 case SQLITE_READONLY:
534 throw oops("Attempt to write a readonly database");
535 break;
536
537 case SQLITE_INTERRUPT:
538 throw oops("Operation terminated by sqlite3_interrupt()");
539 break;
540
541 case SQLITE_IOERR:
542 throw oops("Some kind of disk I/O error occurred");
543 break;
544
545 case SQLITE_CORRUPT:
546 throw oops("The database disk image is malformed");
547 break;
548
549 case SQLITE_NOTFOUND:
550 throw oops("(Internal Only) Table or record not found");
551 break;
552
553 case SQLITE_FULL:
554 throw oops("Insertion failed because database is full");
555 break;
556
557 case SQLITE_CANTOPEN:
558 throw oops("Unable to open the database file");
559 break;
560
561 case SQLITE_PROTOCOL:
562 throw oops("database lock protocol error");
563 break;
564
565 case SQLITE_EMPTY:
566 throw oops("(Internal Only) database table is empty");
567 break;
568
569 case SQLITE_SCHEMA:
570 throw oops("The database schema changed");
571 break;
572
573 case SQLITE_TOOBIG:
574 throw oops("Too much data for one row of a table");
575 break;
576
577 case SQLITE_CONSTRAINT:
578 throw oops("Abort due to contraint violation");
579 break;
580
581 case SQLITE_MISMATCH:
582 throw oops("Data type mismatch");
583 break;
584
585 case SQLITE_MISUSE:
586 throw oops("Library used incorrectly");
587 break;
588
589 case SQLITE_NOLFS:
590 throw oops("Uses OS features not supported on host");
591 break;
592
593 case SQLITE_AUTH:
594 throw oops("Authorization denied");
595 break;
596
597 default:
598 throw oops(string("Unknown DB result code: ") + lexical_cast<string>(res));
599 break;
600 }
601}
602
603void
604database::execute(char const * query, ...)
605{
606 va_list ap;
607 int res;
608 char * errmsg = NULL;
609
610 va_start(ap, query);
611
612 // log it
613 char * formatted = sqlite3_vmprintf(query, ap);
614 string qq(formatted);
615 if (qq.size() > constants::db_log_line_sz)
616 qq = qq.substr(0, constants::db_log_line_sz) + string(" ...");
617 L(F("db.execute(\"%s\")\n") % qq);
618 sqlite3_free(formatted);
619
620 va_end(ap);
621 va_start(ap, query);
622
623 // do it
624 res = sqlite3_exec_vprintf(sql(), query, NULL, NULL, &errmsg, ap);
625
626 va_end(ap);
627
628 if (errmsg)
629 throw oops(string("sqlite exec error ") + errmsg);
630
631 assert_sqlite3_ok(res);
632
633}
634
635void
636database::fetch(results & res,
637 int const want_cols,
638 int const want_rows,
639 char const * query, ...)
640{
641 char ** result = NULL;
642 int nrow;
643 int ncol;
644 char * errmsg = NULL;
645 int rescode;
646
647 va_list ap;
648 res.clear();
649 res.resize(0);
650 va_start(ap, query);
651
652 // log it
653 char * formatted = sqlite3_vmprintf(query, ap);
654 string qq(formatted);
655 if (qq.size() > constants::log_line_sz)
656 qq = qq.substr(0, constants::log_line_sz) + string(" ...");
657 L(F("db.fetch(\"%s\")\n") % qq);
658 sqlite3_free(formatted);
659
660 va_end(ap);
661 va_start(ap, query);
662
663 // do it
664 rescode = sqlite3_get_table_vprintf(sql(), query, &result, &nrow, &ncol, &errmsg, ap);
665
666 va_end(ap);
667
668 cleanup_ptr<char **, void>
669 result_guard(result, &sqlite3_free_table);
670
671 string ctx = string("db query [") + string(query) + "]: ";
672
673 if (errmsg)
674 throw oops(ctx + string("sqlite error ") + errmsg);
675 assert_sqlite3_ok(rescode);
676
677 if (want_cols == 0 && ncol == 0) return;
678 if (want_rows == 0 && nrow == 0) return;
679 if (want_cols == any_rows && ncol == 0) return;
680 if (want_rows == any_rows && nrow == 0) return;
681
682 if (want_cols != any_cols &&
683 ncol != want_cols)
684 throw oops((F("%s wanted %d columns, got %s")
685 % ctx % want_cols % ncol).str());
686
687 if (want_rows != any_rows &&
688 nrow != want_rows)
689 throw oops((F("%s wanted %d rows, got %s")
690 % ctx % want_rows % nrow).str());
691
692 if (!result)
693 throw oops(ctx + "null result set");
694
695 for (int i = 0; i < ncol; ++i)
696 if (!result[i])
697 throw oops(ctx + "null column name");
698
699 for (int row = 0; row < nrow; ++row)
700 {
701 vector<string> rowvec;
702 for (int col = 0; col < ncol; ++col)
703 {
704 int i = ((1 + row) * ncol) + col;
705 if (!result[i])
706 throw oops(ctx + "null result value");
707 else
708 rowvec.push_back(result[i]);
709 }
710 res.push_back(rowvec);
711 }
712}
713
714// general application-level logic
715
716void
717database::set_filename(fs::path const & file)
718{
719 if (__sql)
720 {
721 throw oops("cannot change filename to " + file.string() + " while db is open");
722 }
723 filename = file;
724}
725
726void
727database::begin_transaction()
728{
729 if (transaction_level == 0)
730 execute("BEGIN");
731 transaction_level++;
732}
733
734void
735database::commit_transaction()
736{
737 if (transaction_level == 1)
738 execute("COMMIT");
739 transaction_level--;
740}
741
742void
743database::rollback_transaction()
744{
745 if (transaction_level == 1)
746 execute("ROLLBACK");
747 transaction_level--;
748}
749
750
751bool
752database::exists(hexenc<id> const & ident,
753 string const & table)
754{
755 results res;
756 fetch(res, one_col, any_rows,
757 "SELECT id FROM '%q' WHERE id = '%q'",
758 table.c_str(), ident().c_str());
759 I((res.size() == 1) || (res.size() == 0));
760 return res.size() == 1;
761}
762
763
764bool
765database::delta_exists(hexenc<id> const & ident,
766 string const & table)
767{
768 results res;
769 fetch(res, one_col, any_rows,
770 "SELECT id FROM '%q' WHERE id = '%q'",
771 table.c_str(), ident().c_str());
772 return res.size() > 0;
773}
774
775bool
776database::delta_exists(hexenc<id> const & ident,
777 hexenc<id> const & base,
778 string const & table)
779{
780 results res;
781 fetch(res, one_col, any_rows,
782 "SELECT id FROM '%q' WHERE id = '%q' AND base = '%q'",
783 table.c_str(), ident().c_str(), base().c_str());
784 I((res.size() == 1) || (res.size() == 0));
785 return res.size() == 1;
786}
787
788unsigned long
789database::count(string const & table)
790{
791 results res;
792 fetch(res, one_col, one_row,
793 "SELECT COUNT(*) FROM '%q'",
794 table.c_str());
795 return lexical_cast<unsigned long>(res[0][0]);
796}
797
798void
799database::get_ids(string const & table, set< hexenc<id> > & ids)
800{
801 results res;
802
803 fetch(res, one_col, any_rows, "SELECT id FROM %q", table.c_str());
804
805 for (size_t i = 0; i < res.size(); ++i)
806 {
807 ids.insert(hexenc<id>(res[i][0]));
808 }
809}
810
811void
812database::get(hexenc<id> const & ident,
813 base64< gzip<data> > & dat,
814 string const & table)
815{
816 results res;
817 fetch(res, one_col, one_row,
818 "SELECT data FROM '%q' WHERE id = '%q'",
819 table.c_str(), ident().c_str());
820
821 // consistency check
822 base64<gzip<data> > rdata(res[0][0]);
823 hexenc<id> tid;
824 calculate_ident(rdata, tid);
825 I(tid == ident);
826
827 dat = rdata;
828}
829
830void
831database::get_delta(hexenc<id> const & ident,
832 hexenc<id> const & base,
833 base64< gzip<delta> > & del,
834 string const & table)
835{
836 I(ident() != "");
837 I(base() != "");
838 results res;
839 fetch(res, one_col, one_row,
840 "SELECT delta FROM '%q' WHERE id = '%q' AND base = '%q'",
841 table.c_str(), ident().c_str(), base().c_str());
842 del = res[0][0];
843}
844
845void
846database::put(hexenc<id> const & ident,
847 base64< gzip<data> > const & dat,
848 string const & table)
849{
850 // consistency check
851 I(ident() != "");
852 hexenc<id> tid;
853 calculate_ident(dat, tid);
854 I(tid == ident);
855
856 execute("INSERT INTO '%q' VALUES('%q', '%q')",
857 table.c_str(), ident().c_str(), dat().c_str());
858}
859void
860database::put_delta(hexenc<id> const & ident,
861 hexenc<id> const & base,
862 base64<gzip<delta> > const & del,
863 string const & table)
864{
865 // nb: delta schema is (id, base, delta)
866 I(ident() != "");
867 I(base() != "");
868 execute("INSERT INTO '%q' VALUES('%q', '%q', '%q')",
869 table.c_str(),
870 ident().c_str(), base().c_str(), del().c_str());
871}
872
873// static ticker cache_hits("vcache hits", "h", 1);
874
875struct version_cache
876{
877 size_t capacity;
878 size_t use;
879 std::map<hexenc<id>, base64< gzip<data> > > cache;
880
881 version_cache() : capacity(constants::db_version_cache_sz), use(0)
882 {
883 srand(time(NULL));
884 }
885
886 void put(hexenc<id> const & ident,
887 base64< gzip<data> > const & dat)
888 {
889 while (!cache.empty()
890 && use + dat().size() > capacity)
891 {
892 std::string key = (F("%08.8x%08.8x%08.8x%08.8x%08.8x")
893 % rand() % rand() % rand() % rand() % rand()).str();
894 std::map<hexenc<id>, base64< gzip<data> > >::const_iterator i;
895 i = cache.lower_bound(hexenc<id>(key));
896 if (i == cache.end())
897 {
898 // we can't find a random entry, probably there's only one
899 // entry and we missed it. delete first entry instead.
900 i = cache.begin();
901 }
902 I(i != cache.end());
903 I(use >= i->second().size());
904 L(F("version cache expiring %s\n") % i->first);
905 use -= i->second().size();
906 cache.erase(i->first);
907 }
908 cache.insert(std::make_pair(ident, dat));
909 use += dat().size();
910 }
911
912 bool exists(hexenc<id> const & ident)
913 {
914 std::map<hexenc<id>, base64< gzip<data> > >::const_iterator i;
915 i = cache.find(ident);
916 return i != cache.end();
917 }
918
919 bool get(hexenc<id> const & ident,
920 base64< gzip<data> > & dat)
921 {
922 std::map<hexenc<id>, base64< gzip<data> > >::const_iterator i;
923 i = cache.find(ident);
924 if (i == cache.end())
925 return false;
926 // ++cache_hits;
927 L(F("version cache hit on %s\n") % ident);
928 dat = i->second;
929 return true;
930 }
931};
932
933static version_cache vcache;
934
935void
936database::get_version(hexenc<id> const & ident,
937 base64< gzip<data> > & dat,
938 string const & data_table,
939 string const & delta_table)
940{
941 I(ident() != "");
942
943 if (vcache.get(ident, dat))
944 {
945 return;
946 }
947 else if (exists(ident, data_table))
948 {
949 // easy path
950 get(ident, dat, data_table);
951 }
952 else
953 {
954 // tricky path
955
956 // we start from the file we want to reconstruct and work *forwards*
957 // through the database, until we get to a full data object. we then
958 // trace back through the list of edges we followed to get to the data
959 // object, applying reverse deltas.
960 //
961 // the effect of this algorithm is breadth-first search, backwards
962 // through the storage graph, to discover a forwards shortest path, and
963 // then following that shortest path with delta application.
964 //
965 // we used to do this with the boost graph library, but it invovled
966 // loading too much of the storage graph into memory at any moment. this
967 // imperative version only loads the descendents of the reconstruction
968 // node, so it much cheaper in terms of memory.
969 //
970 // we also maintain a cycle-detecting set, just to be safe
971
972 L(F("reconstructing %s in %s\n") % ident % delta_table);
973 I(delta_exists(ident, delta_table));
974
975 // nb: an edge map goes in the direction of the
976 // delta, *not* the direction we discover things in,
977 // i.e. each map is of the form [newid] -> [oldid]
978
979 typedef map< hexenc<id>, hexenc<id> > edgemap;
980 list< shared_ptr<edgemap> > paths;
981
982 set< hexenc<id> > frontier, cycles;
983 frontier.insert(ident);
984
985 bool found_root = false;
986 hexenc<id> root("");
987
988 while (! found_root)
989 {
990 set< hexenc<id> > next_frontier;
991 shared_ptr<edgemap> frontier_map(new edgemap());
992
993 I(!frontier.empty());
994
995 for (set< hexenc<id> >::const_iterator i = frontier.begin();
996 i != frontier.end(); ++i)
997 {
998 if (vcache.exists(*i) || exists(*i, data_table))
999 {
1000 root = *i;
1001 found_root = true;
1002 break;
1003 }
1004 else
1005 {
1006 cycles.insert(*i);
1007 results res;
1008 fetch(res, one_col, any_rows, "SELECT base from '%q' WHERE id = '%q'",
1009 delta_table.c_str(), (*i)().c_str());
1010 for (size_t k = 0; k < res.size(); ++k)
1011 {
1012 hexenc<id> const nxt(res[k][0]);
1013
1014 if (cycles.find(nxt) != cycles.end())
1015 throw oops("cycle in table '" + delta_table + "', at node "
1016 + (*i)() + " <- " + nxt());
1017
1018 next_frontier.insert(nxt);
1019
1020 if (frontier_map->find(nxt) == frontier_map->end())
1021 {
1022 L(F("inserting edge: %s <- %s\n") % (*i) % nxt);
1023 frontier_map->insert(make_pair(nxt, *i));
1024 }
1025 else
1026 L(F("skipping merge edge %s <- %s\n") % (*i) % nxt);
1027 }
1028 }
1029 }
1030 if (!found_root)
1031 {
1032 frontier = next_frontier;
1033 paths.push_front(frontier_map);
1034 }
1035 }
1036
1037 // path built, now all we need to do is follow it back
1038
1039 I(found_root);
1040 I(root() != "");
1041 base64< gzip<data> > begin_packed;
1042 data begin;
1043
1044 if (vcache.exists(root))
1045 {
1046 I(vcache.get(root, begin_packed));
1047 }
1048 else
1049 get(root, begin_packed, data_table);
1050
1051 unpack(begin_packed, begin);
1052 hexenc<id> curr = root;
1053
1054 boost::shared_ptr<delta_applicator> app = new_piecewise_applicator();
1055 app->begin(begin());
1056
1057 for (list< shared_ptr<edgemap> >::const_iterator p = paths.begin();
1058 p != paths.end(); ++p)
1059 {
1060 shared_ptr<edgemap> i = *p;
1061 I(i->find(curr) != i->end());
1062 hexenc<id> const nxt = i->find(curr)->second;
1063
1064 if (!vcache.exists(curr))
1065 {
1066 string tmp;
1067 base64< gzip<data> > tmp_packed;
1068 app->finish(tmp);
1069 pack(data(tmp), tmp_packed);
1070 vcache.put(curr, tmp_packed);
1071 }
1072
1073
1074 if (!vcache.exists(curr))
1075 {
1076 string tmp;
1077 base64< gzip<data> > tmp_packed;
1078 app->finish(tmp);
1079 pack(data(tmp), tmp_packed);
1080 vcache.put(curr, tmp_packed);
1081 }
1082
1083
1084 L(F("following delta %s -> %s\n") % curr % nxt);
1085 base64< gzip<delta> > del_packed;
1086 get_delta(nxt, curr, del_packed, delta_table);
1087 delta del;
1088 unpack(del_packed, del);
1089 apply_delta (app, del());
1090
1091 app->next();
1092 curr = nxt;
1093 }
1094
1095 string tmp;
1096 app->finish(tmp);
1097 data end(tmp);
1098
1099 hexenc<id> final;
1100 calculate_ident(end, final);
1101 I(final == ident);
1102 pack(end, dat);
1103 }
1104 vcache.put(ident, dat);
1105}
1106
1107
1108void
1109database::drop(hexenc<id> const & ident,
1110 string const & table)
1111{
1112 execute("DELETE FROM '%q' WHERE id = '%q'",
1113 table.c_str(),
1114 ident().c_str());
1115}
1116
1117void
1118database::put_version(hexenc<id> const & old_id,
1119 hexenc<id> const & new_id,
1120 base64< gzip<delta> > const & del,
1121 string const & data_table,
1122 string const & delta_table)
1123{
1124
1125 base64< gzip<data> > old_data, new_data;
1126 base64< gzip<delta> > reverse_delta;
1127
1128 get_version(old_id, old_data, data_table, delta_table);
1129 patch(old_data, del, new_data);
1130 diff(new_data, old_data, reverse_delta);
1131
1132 transaction_guard guard(*this);
1133 if (exists(old_id, data_table))
1134 {
1135 // descendent of a head version replaces the head, therefore old head
1136 // must be disposed of
1137 drop(old_id, data_table);
1138 }
1139 put(new_id, new_data, data_table);
1140 put_delta(old_id, new_id, reverse_delta, delta_table);
1141 guard.commit();
1142}
1143
1144void
1145database::put_reverse_version(hexenc<id> const & new_id,
1146 hexenc<id> const & old_id,
1147 base64< gzip<delta> > const & reverse_del,
1148 string const & data_table,
1149 string const & delta_table)
1150{
1151 base64< gzip<data> > old_data, new_data;
1152
1153 get_version(new_id, new_data, data_table, delta_table);
1154 patch(new_data, reverse_del, old_data);
1155 hexenc<id> check;
1156 calculate_ident(old_data, check);
1157 I(old_id == check);
1158
1159 transaction_guard guard(*this);
1160 put_delta(old_id, new_id, reverse_del, delta_table);
1161 guard.commit();
1162}
1163
1164
1165
1166// ------------------------------------------------------------
1167// -- --
1168// -- public interface follows --
1169// -- --
1170// ------------------------------------------------------------
1171
1172bool
1173database::file_version_exists(file_id const & id)
1174{
1175 return delta_exists(id.inner(), "file_deltas")
1176 || exists(id.inner(), "files");
1177}
1178
1179bool
1180database::manifest_version_exists(manifest_id const & id)
1181{
1182 return delta_exists(id.inner(), "manifest_deltas")
1183 || exists(id.inner(), "manifests");
1184}
1185
1186bool
1187database::revision_exists(revision_id const & id)
1188{
1189 return exists(id.inner(), "revisions");
1190}
1191
1192void
1193database::get_file_ids(set<file_id> & ids)
1194{
1195 ids.clear();
1196 set< hexenc<id> > tmp;
1197 get_ids("files", tmp);
1198 get_ids("file_deltas", tmp);
1199 ids.insert(tmp.begin(), tmp.end());
1200}
1201
1202void
1203database::get_manifest_ids(set<manifest_id> & ids)
1204{
1205 ids.clear();
1206 set< hexenc<id> > tmp;
1207 get_ids("manifests", tmp);
1208 get_ids("manifest_deltas", tmp);
1209 ids.insert(tmp.begin(), tmp.end());
1210}
1211
1212void
1213database::get_revision_ids(set<revision_id> & ids)
1214{
1215 ids.clear();
1216 set< hexenc<id> > tmp;
1217 get_ids("revisions", tmp);
1218 ids.insert(tmp.begin(), tmp.end());
1219}
1220
1221void
1222database::get_file_version(file_id const & id,
1223 file_data & dat)
1224{
1225 base64< gzip<data> > tmp;
1226 get_version(id.inner(), tmp, "files", "file_deltas");
1227 dat = tmp;
1228}
1229
1230void
1231database::get_manifest_version(manifest_id const & id,
1232 manifest_data & dat)
1233{
1234 base64< gzip<data> > tmp;
1235 get_version(id.inner(), tmp, "manifests", "manifest_deltas");
1236 dat = tmp;
1237}
1238
1239void
1240database::get_manifest(manifest_id const & id,
1241 manifest_map & mm)
1242{
1243 manifest_data mdat;
1244 get_manifest_version(id, mdat);
1245 read_manifest_map(mdat, mm);
1246}
1247
1248
1249void
1250database::put_file(file_id const & id,
1251 file_data const & dat)
1252{
1253 put(id.inner(), dat.inner(), "files");
1254}
1255
1256void
1257database::put_file_version(file_id const & old_id,
1258 file_id const & new_id,
1259 file_delta const & del)
1260{
1261 put_version(old_id.inner(), new_id.inner(), del.inner(),
1262 "files", "file_deltas");
1263}
1264
1265void
1266database::put_file_reverse_version(file_id const & new_id,
1267 file_id const & old_id,
1268 file_delta const & del)
1269{
1270 put_reverse_version(new_id.inner(), old_id.inner(), del.inner(),
1271 "files", "file_deltas");
1272}
1273
1274
1275void
1276database::put_manifest(manifest_id const & id,
1277 manifest_data const & dat)
1278{
1279 put(id.inner(), dat.inner(), "manifests");
1280}
1281
1282void
1283database::put_manifest_version(manifest_id const & old_id,
1284 manifest_id const & new_id,
1285 manifest_delta const & del)
1286{
1287 put_version(old_id.inner(), new_id.inner(), del.inner(),
1288 "manifests", "manifest_deltas");
1289}
1290
1291void
1292database::put_manifest_reverse_version(manifest_id const & new_id,
1293 manifest_id const & old_id,
1294 manifest_delta const & del)
1295{
1296 put_reverse_version(new_id.inner(), old_id.inner(), del.inner(),
1297 "manifests", "manifest_deltas");
1298}
1299
1300
1301void
1302database::get_revision_ancestry(std::multimap<revision_id, revision_id> & graph)
1303{
1304 results res;
1305 graph.clear();
1306 fetch(res, 2, any_rows,
1307 "SELECT parent,child FROM revision_ancestry");
1308 for (size_t i = 0; i < res.size(); ++i)
1309 graph.insert(std::make_pair(revision_id(res[i][0]),
1310 revision_id(res[i][1])));
1311}
1312
1313void
1314database::get_revision_parents(revision_id const & id,
1315 set<revision_id> & parents)
1316{
1317 I(!null_id(id));
1318 results res;
1319 parents.clear();
1320 fetch(res, one_col, any_rows,
1321 "SELECT parent FROM revision_ancestry WHERE child = '%q'",
1322 id.inner()().c_str());
1323 for (size_t i = 0; i < res.size(); ++i)
1324 parents.insert(revision_id(res[i][0]));
1325}
1326
1327void
1328database::get_revision_children(revision_id const & id,
1329 set<revision_id> & children)
1330{
1331 I(!null_id(id));
1332 results res;
1333 children.clear();
1334 fetch(res, one_col, any_rows,
1335 "SELECT child FROM revision_ancestry WHERE parent = '%q'",
1336 id.inner()().c_str());
1337 for (size_t i = 0; i < res.size(); ++i)
1338 children.insert(revision_id(res[i][0]));
1339}
1340
1341void
1342database::get_revision_manifest(revision_id const & rid,
1343 manifest_id & mid)
1344{
1345 revision_set rev;
1346 get_revision(rid, rev);
1347 mid = rev.new_manifest;
1348}
1349
1350void
1351database::get_revision(revision_id const & id,
1352 revision_set & rev)
1353{
1354 revision_data d;
1355 get_revision(id, d);
1356 read_revision_set(d, rev);
1357}
1358
1359void
1360database::get_revision(revision_id const & id,
1361 revision_data & dat)
1362{
1363 I(!null_id(id));
1364 results res;
1365 fetch(res, one_col, one_row,
1366 "SELECT data FROM revisions WHERE id = '%q'",
1367 id.inner()().c_str());
1368
1369 dat = revision_data(res[0][0]);
1370
1371 // verify that we got a revision with the right id
1372 {
1373 revision_id tmp;
1374 calculate_ident(dat, tmp);
1375 I(id == tmp);
1376 }
1377}
1378
1379void
1380database::put_revision(revision_id const & new_id,
1381 revision_set const & rev)
1382{
1383
1384 I(!null_id(new_id));
1385 I(!revision_exists(new_id));
1386 revision_data d;
1387
1388 rev.check_sane();
1389
1390 write_revision_set(rev, d);
1391 revision_id tmp;
1392 calculate_ident(d, tmp);
1393 I(tmp == new_id);
1394
1395 transaction_guard guard(*this);
1396
1397 execute("INSERT INTO revisions VALUES('%q', '%q')",
1398 new_id.inner()().c_str(),
1399 d.inner()().c_str());
1400
1401 for (edge_map::const_iterator e = rev.edges.begin();
1402 e != rev.edges.end(); ++e)
1403 {
1404 execute("INSERT INTO revision_ancestry VALUES('%q', '%q')",
1405 edge_old_revision(e).inner()().c_str(),
1406 new_id.inner()().c_str());
1407 }
1408
1409 check_sane_history(new_id, constants::verify_depth, *__app);
1410
1411 guard.commit();
1412}
1413
1414void
1415database::put_revision(revision_id const & new_id,
1416 revision_data const & dat)
1417{
1418 revision_set rev;
1419 read_revision_set(dat, rev);
1420 put_revision(new_id, rev);
1421}
1422
1423
1424void
1425database::delete_existing_revs_and_certs()
1426{
1427 execute("DELETE from revisions");
1428 execute("DELETE from revision_ancestry");
1429 execute("DELETE from revision_certs");
1430}
1431
1432
1433// crypto key management
1434
1435void
1436database::get_key_ids(string const & pattern,
1437 vector<rsa_keypair_id> & pubkeys,
1438 vector<rsa_keypair_id> & privkeys)
1439{
1440 pubkeys.clear();
1441 privkeys.clear();
1442 results res;
1443
1444 if (pattern != "")
1445 fetch(res, one_col, any_rows,
1446 "SELECT id from public_keys WHERE id GLOB '%q'",
1447 pattern.c_str());
1448 else
1449 fetch(res, one_col, any_rows,
1450 "SELECT id from public_keys");
1451
1452 for (size_t i = 0; i < res.size(); ++i)
1453 pubkeys.push_back(res[i][0]);
1454
1455 if (pattern != "")
1456 fetch(res, one_col, any_rows,
1457 "SELECT id from private_keys WHERE id GLOB '%q'",
1458 pattern.c_str());
1459 else
1460 fetch(res, one_col, any_rows,
1461 "SELECT id from private_keys");
1462
1463 for (size_t i = 0; i < res.size(); ++i)
1464 privkeys.push_back(res[i][0]);
1465}
1466
1467void
1468database::get_keys(string const & table, vector<rsa_keypair_id> & keys)
1469{
1470 keys.clear();
1471 results res;
1472 fetch(res, one_col, any_rows, "SELECT id from '%q'", table.c_str());
1473 for (size_t i = 0; i < res.size(); ++i)
1474 keys.push_back(res[i][0]);
1475}
1476
1477void
1478database::get_private_keys(vector<rsa_keypair_id> & keys)
1479{
1480 get_keys("private_keys", keys);
1481}
1482
1483void
1484database::get_public_keys(vector<rsa_keypair_id> & keys)
1485{
1486 get_keys("public_keys", keys);
1487}
1488
1489bool
1490database::public_key_exists(hexenc<id> const & hash)
1491{
1492 results res;
1493 fetch(res, one_col, any_rows,
1494 "SELECT id FROM public_keys WHERE hash = '%q'",
1495 hash().c_str());
1496 I((res.size() == 1) || (res.size() == 0));
1497 if (res.size() == 1)
1498 return true;
1499 return false;
1500}
1501
1502bool
1503database::public_key_exists(rsa_keypair_id const & id)
1504{
1505 results res;
1506 fetch(res, one_col, any_rows,
1507 "SELECT id FROM public_keys WHERE id = '%q'",
1508 id().c_str());
1509 I((res.size() == 1) || (res.size() == 0));
1510 if (res.size() == 1)
1511 return true;
1512 return false;
1513}
1514
1515bool
1516database::private_key_exists(rsa_keypair_id const & id)
1517{
1518 results res;
1519 fetch(res, one_col, any_rows,
1520 "SELECT id FROM private_keys WHERE id = '%q'",
1521 id().c_str());
1522 I((res.size() == 1) || (res.size() == 0));
1523 if (res.size() == 1)
1524 return true;
1525 return false;
1526}
1527
1528bool
1529database::key_exists(rsa_keypair_id const & id)
1530{
1531 return public_key_exists(id) || private_key_exists(id);
1532}
1533
1534void
1535database::get_pubkey(hexenc<id> const & hash,
1536 rsa_keypair_id & id,
1537 base64<rsa_pub_key> & pub_encoded)
1538{
1539 results res;
1540 fetch(res, 2, one_row,
1541 "SELECT id, keydata FROM public_keys where hash = '%q'",
1542 hash().c_str());
1543 id = res[0][0];
1544 pub_encoded = res[0][1];
1545}
1546
1547void
1548database::get_key(rsa_keypair_id const & pub_id,
1549 base64<rsa_pub_key> & pub_encoded)
1550{
1551 results res;
1552 fetch(res, one_col, one_row,
1553 "SELECT keydata FROM public_keys where id = '%q'",
1554 pub_id().c_str());
1555 pub_encoded = res[0][0];
1556}
1557
1558void
1559database::get_key(rsa_keypair_id const & priv_id,
1560 base64< arc4<rsa_priv_key> > & priv_encoded)
1561{
1562 results res;
1563 fetch(res, one_col, one_col,
1564 "SELECT keydata FROM private_keys where id = '%q'",
1565 priv_id().c_str());
1566 priv_encoded = res[0][0];
1567}
1568
1569void
1570database::put_key(rsa_keypair_id const & pub_id,
1571 base64<rsa_pub_key> const & pub_encoded)
1572{
1573 hexenc<id> thash;
1574 key_hash_code(pub_id, pub_encoded, thash);
1575 execute("INSERT INTO public_keys VALUES('%q', '%q', '%q')",
1576 thash().c_str(), pub_id().c_str(), pub_encoded().c_str());
1577}
1578
1579void
1580database::put_key(rsa_keypair_id const & priv_id,
1581 base64< arc4<rsa_priv_key> > const & priv_encoded)
1582{
1583
1584 hexenc<id> thash;
1585 key_hash_code(priv_id, priv_encoded, thash);
1586 execute("INSERT INTO private_keys VALUES('%q', '%q', '%q')",
1587 thash().c_str(), priv_id().c_str(), priv_encoded().c_str());
1588}
1589
1590void
1591database::put_key_pair(rsa_keypair_id const & id,
1592 base64<rsa_pub_key> const & pub_encoded,
1593 base64< arc4<rsa_priv_key> > const & priv_encoded)
1594{
1595 transaction_guard guard(*this);
1596 put_key(id, pub_encoded);
1597 put_key(id, priv_encoded);
1598 guard.commit();
1599}
1600
1601void
1602database::delete_private_key(rsa_keypair_id const & pub_id)
1603{
1604 execute("DELETE FROM private_keys WHERE id = '%q'",
1605 pub_id().c_str());
1606}
1607
1608void
1609database::delete_public_key(rsa_keypair_id const & pub_id)
1610{
1611 execute("DELETE FROM public_keys WHERE id = '%q'",
1612 pub_id().c_str());
1613}
1614
1615// cert management
1616
1617bool
1618database::cert_exists(cert const & t,
1619 string const & table)
1620{
1621 results res;
1622 fetch(res, 1, any_rows,
1623 "SELECT id FROM '%q' WHERE id = '%q' "
1624 "AND name = '%q' AND value = '%q' "
1625 "AND keypair = '%q' AND signature = '%q' ",
1626 table.c_str(),
1627 t.ident().c_str(),
1628 t.name().c_str(),
1629 t.value().c_str(),
1630 t.key().c_str(),
1631 t.sig().c_str());
1632 I(res.size() == 0 || res.size() == 1);
1633 return res.size() == 1;
1634}
1635
1636void
1637database::put_cert(cert const & t,
1638 string const & table)
1639{
1640 hexenc<id> thash;
1641 cert_hash_code(t, thash);
1642 execute("INSERT INTO '%q' VALUES('%q', '%q', '%q', '%q', '%q', '%q')",
1643 table.c_str(),
1644 thash().c_str(),
1645 t.ident().c_str(),
1646 t.name().c_str(),
1647 t.value().c_str(),
1648 t.key().c_str(),
1649 t.sig().c_str());
1650}
1651
1652void
1653database::results_to_certs(results const & res,
1654 vector<cert> & certs)
1655{
1656 certs.clear();
1657 for (size_t i = 0; i < res.size(); ++i)
1658 {
1659 cert t;
1660 t = cert(hexenc<id>(res[i][0]),
1661 cert_name(res[i][1]),
1662 base64<cert_value>(res[i][2]),
1663 rsa_keypair_id(res[i][3]),
1664 base64<rsa_sha1_signature>(res[i][4]));
1665 certs.push_back(t);
1666 }
1667}
1668
1669void
1670database::install_functions(app_state * app)
1671{
1672 // register any functions we're going to use
1673 I(sqlite3_create_function(sql(), "unbase64", -1,
1674 SQLITE_UTF8, NULL,
1675 &sqlite3_unbase64_fn,
1676 NULL, NULL) == 0);
1677
1678
1679 I(sqlite3_create_function(sql(), "unpack", -1,
1680 SQLITE_UTF8, NULL,
1681 &sqlite3_unpack_fn,
1682 NULL, NULL) == 0);
1683}
1684
1685void
1686database::install_views()
1687{
1688 // we don't currently use any views. re-enable this code if you find a
1689 // compelling reason to use views.
1690
1691 /*
1692 // delete any existing views
1693 results res;
1694 fetch(res, one_col, any_rows,
1695 "SELECT name FROM sqlite_master WHERE type='view'");
1696 for (size_t i = 0; i < res.size(); ++i)
1697 {
1698 execute("DROP VIEW '%q'", res[i][0].c_str());
1699 }
1700 // register any views we're going to use
1701 execute(views_constant);
1702 */
1703}
1704
1705void
1706database::get_certs(vector<cert> & certs,
1707 string const & table)
1708{
1709 results res;
1710 fetch(res, 5, any_rows,
1711 "SELECT id, name, value, keypair, signature FROM '%q' ",
1712 table.c_str());
1713 results_to_certs(res, certs);
1714}
1715
1716
1717void
1718database::get_certs(hexenc<id> const & ident,
1719 vector<cert> & certs,
1720 string const & table)
1721{
1722 results res;
1723 fetch(res, 5, any_rows,
1724 "SELECT id, name, value, keypair, signature FROM '%q' "
1725 "WHERE id = '%q'",
1726 table.c_str(),
1727 ident().c_str());
1728 results_to_certs(res, certs);
1729}
1730
1731
1732void
1733database::get_certs(cert_name const & name,
1734 vector<cert> & certs,
1735 string const & table)
1736{
1737 results res;
1738 fetch(res, 5, any_rows,
1739 "SELECT id, name, value, keypair, signature "
1740 "FROM '%q' WHERE name = '%q'",
1741 table.c_str(),
1742 name().c_str());
1743 results_to_certs(res, certs);
1744}
1745
1746
1747void
1748database::get_certs(hexenc<id> const & ident,
1749 cert_name const & name,
1750 vector<cert> & certs,
1751 string const & table)
1752{
1753 results res;
1754 fetch(res, 5, any_rows,
1755 "SELECT id, name, value, keypair, signature "
1756 "FROM '%q' "
1757 "WHERE id = '%q' AND name = '%q'",
1758 table.c_str(),
1759 ident().c_str(),
1760 name().c_str());
1761 results_to_certs(res, certs);
1762}
1763
1764void
1765database::get_certs(cert_name const & name,
1766 base64<cert_value> const & val,
1767 vector<cert> & certs,
1768 string const & table)
1769{
1770 results res;
1771 fetch(res, 5, any_rows,
1772 "SELECT id, name, value, keypair, signature "
1773 "FROM '%q' "
1774 "WHERE name = '%q' AND value = '%q'",
1775 table.c_str(),
1776 name().c_str(),
1777 val().c_str());
1778 results_to_certs(res, certs);
1779}
1780
1781
1782void
1783database::get_certs(hexenc<id> const & ident,
1784 cert_name const & name,
1785 base64<cert_value> const & value,
1786 vector<cert> & certs,
1787 string const & table)
1788{
1789 results res;
1790 fetch(res, 5, any_rows,
1791 "SELECT id, name, value, keypair, signature "
1792 "FROM '%q' "
1793 "WHERE id = '%q' AND name = '%q' AND value = '%q'",
1794 table.c_str(),
1795 ident().c_str(),
1796 name().c_str(),
1797 value().c_str());
1798 results_to_certs(res, certs);
1799}
1800
1801
1802
1803bool
1804database::revision_cert_exists(revision<cert> const & cert)
1805{
1806 return cert_exists(cert.inner(), "revision_certs");
1807}
1808
1809bool
1810database::manifest_cert_exists(manifest<cert> const & cert)
1811{
1812 return cert_exists(cert.inner(), "manifest_certs");
1813}
1814
1815void
1816database::put_manifest_cert(manifest<cert> const & cert)
1817{
1818 put_cert(cert.inner(), "manifest_certs");
1819}
1820
1821void
1822database::put_revision_cert(revision<cert> const & cert)
1823{
1824 put_cert(cert.inner(), "revision_certs");
1825}
1826
1827void database::get_revision_cert_index(std::vector< std::pair<hexenc<id>,
1828 std::pair<revision_id, rsa_keypair_id> > > & idx)
1829{
1830 results res;
1831 fetch(res, 3, any_rows,
1832 "SELECT hash, id, keypair "
1833 "FROM 'revision_certs'");
1834
1835 idx.clear();
1836 idx.resize(res.size());
1837 for (results::const_iterator i = res.begin(); i != res.end(); ++i)
1838 {
1839 idx.push_back(std::make_pair(hexenc<id>((*i)[0]),
1840 std::make_pair(revision_id((*i)[1]),
1841 rsa_keypair_id((*i)[2]))));
1842 }
1843}
1844
1845void
1846database::get_revision_certs(vector< revision<cert> > & ts)
1847{
1848 vector<cert> certs;
1849 get_certs(certs, "revision_certs");
1850 ts.clear();
1851 copy(certs.begin(), certs.end(), back_inserter(ts));
1852}
1853
1854void
1855database::get_revision_certs(cert_name const & name,
1856 vector< revision<cert> > & ts)
1857{
1858 vector<cert> certs;
1859 get_certs(name, certs, "revision_certs");
1860 ts.clear();
1861 copy(certs.begin(), certs.end(), back_inserter(ts));
1862}
1863
1864void
1865database::get_revision_certs(revision_id const & id,
1866 cert_name const & name,
1867 vector< revision<cert> > & ts)
1868{
1869 vector<cert> certs;
1870 get_certs(id.inner(), name, certs, "revision_certs");
1871 ts.clear();
1872 copy(certs.begin(), certs.end(), back_inserter(ts));
1873}
1874
1875void
1876database::get_revision_certs(revision_id const & id,
1877 cert_name const & name,
1878 base64<cert_value> const & val,
1879 vector< revision<cert> > & ts)
1880{
1881 vector<cert> certs;
1882 get_certs(id.inner(), name, val, certs, "revision_certs");
1883 ts.clear();
1884 copy(certs.begin(), certs.end(), back_inserter(ts));
1885}
1886
1887void
1888database::get_revision_certs(cert_name const & name,
1889 base64<cert_value> const & val,
1890 vector< revision<cert> > & ts)
1891{
1892 vector<cert> certs;
1893 get_certs(name, val, certs, "revision_certs");
1894 ts.clear();
1895 copy(certs.begin(), certs.end(), back_inserter(ts));
1896}
1897
1898void
1899database::get_revision_certs(revision_id const & id,
1900 vector< revision<cert> > & ts)
1901{
1902 vector<cert> certs;
1903 get_certs(id.inner(), certs, "revision_certs");
1904 ts.clear();
1905 copy(certs.begin(), certs.end(), back_inserter(ts));
1906}
1907
1908void
1909database::get_revision_cert(hexenc<id> const & hash,
1910 revision<cert> & c)
1911{
1912 results res;
1913 vector<cert> certs;
1914 fetch(res, 5, one_row,
1915 "SELECT id, name, value, keypair, signature "
1916 "FROM revision_certs "
1917 "WHERE hash = '%q'",
1918 hash().c_str());
1919 results_to_certs(res, certs);
1920 I(certs.size() == 1);
1921 c = revision<cert>(certs[0]);
1922}
1923
1924bool
1925database::revision_cert_exists(hexenc<id> const & hash)
1926{
1927 results res;
1928 vector<cert> certs;
1929 fetch(res, one_col, any_rows,
1930 "SELECT id "
1931 "FROM revision_certs "
1932 "WHERE hash = '%q'",
1933 hash().c_str());
1934 I(res.size() == 0 || res.size() == 1);
1935 return (res.size() == 1);
1936}
1937
1938bool
1939database::manifest_cert_exists(hexenc<id> const & hash)
1940{
1941 results res;
1942 vector<cert> certs;
1943 fetch(res, one_col, any_rows,
1944 "SELECT id "
1945 "FROM manifest_certs "
1946 "WHERE hash = '%q'",
1947 hash().c_str());
1948 I(res.size() == 0 || res.size() == 1);
1949 return (res.size() == 1);
1950}
1951
1952void
1953database::get_manifest_cert(hexenc<id> const & hash,
1954 manifest<cert> & c)
1955{
1956 results res;
1957 vector<cert> certs;
1958 fetch(res, 5, one_row,
1959 "SELECT id, name, value, keypair, signature "
1960 "FROM manifest_certs "
1961 "WHERE hash = '%q'",
1962 hash().c_str());
1963 results_to_certs(res, certs);
1964 I(certs.size() == 1);
1965 c = manifest<cert>(certs[0]);
1966}
1967
1968void
1969database::get_manifest_certs(manifest_id const & id,
1970 vector< manifest<cert> > & ts)
1971{
1972 vector<cert> certs;
1973 get_certs(id.inner(), certs, "manifest_certs");
1974 ts.clear();
1975 copy(certs.begin(), certs.end(), back_inserter(ts));
1976}
1977
1978
1979void
1980database::get_manifest_certs(cert_name const & name,
1981 vector< manifest<cert> > & ts)
1982{
1983 vector<cert> certs;
1984 get_certs(name, certs, "manifest_certs");
1985 ts.clear();
1986 copy(certs.begin(), certs.end(), back_inserter(ts));
1987}
1988
1989void
1990database::get_manifest_certs(manifest_id const & id,
1991 cert_name const & name,
1992 vector< manifest<cert> > & ts)
1993{
1994 vector<cert> certs;
1995 get_certs(id.inner(), name, certs, "manifest_certs");
1996 ts.clear();
1997 copy(certs.begin(), certs.end(), back_inserter(ts));
1998}
1999
2000
2001// completions
2002void
2003database::complete(string const & partial,
2004 set<revision_id> & completions)
2005{
2006 results res;
2007 completions.clear();
2008
2009 fetch(res, 1, any_rows,
2010 "SELECT id FROM revisions WHERE id GLOB '%q*'",
2011 partial.c_str());
2012
2013 for (size_t i = 0; i < res.size(); ++i)
2014 completions.insert(revision_id(res[i][0]));
2015}
2016
2017
2018void
2019database::complete(string const & partial,
2020 set<manifest_id> & completions)
2021{
2022 results res;
2023 completions.clear();
2024
2025 fetch(res, 1, any_rows,
2026 "SELECT id FROM manifests WHERE id GLOB '%q*'",
2027 partial.c_str());
2028
2029 for (size_t i = 0; i < res.size(); ++i)
2030 completions.insert(manifest_id(res[i][0]));
2031
2032 res.clear();
2033
2034 fetch(res, 1, any_rows,
2035 "SELECT id FROM manifest_deltas WHERE id GLOB '%q*'",
2036 partial.c_str());
2037
2038 for (size_t i = 0; i < res.size(); ++i)
2039 completions.insert(manifest_id(res[i][0]));
2040}
2041
2042void
2043database::complete(string const & partial,
2044 set<file_id> & completions)
2045{
2046 results res;
2047 completions.clear();
2048
2049 fetch(res, 1, any_rows,
2050 "SELECT id FROM files WHERE id GLOB '%q*'",
2051 partial.c_str());
2052
2053 for (size_t i = 0; i < res.size(); ++i)
2054 completions.insert(file_id(res[i][0]));
2055
2056 res.clear();
2057
2058 fetch(res, 1, any_rows,
2059 "SELECT id FROM file_deltas WHERE id GLOB '%q*'",
2060 partial.c_str());
2061
2062 for (size_t i = 0; i < res.size(); ++i)
2063 completions.insert(file_id(res[i][0]));
2064}
2065
2066using commands::selector_type;
2067
2068static void selector_to_certname(selector_type ty,
2069 string & s)
2070{
2071 switch (ty)
2072 {
2073 case commands::sel_author:
2074 s = author_cert_name;
2075 break;
2076 case commands::sel_branch:
2077 s = branch_cert_name;
2078 break;
2079 case commands::sel_date:
2080 s = date_cert_name;
2081 break;
2082 case commands::sel_tag:
2083 s = tag_cert_name;
2084 break;
2085 case commands::sel_ident:
2086 case commands::sel_unknown:
2087 I(false); // don't do this.
2088 break;
2089 }
2090}
2091
2092void database::complete(selector_type ty,
2093 string const & partial,
2094 vector<pair<selector_type, string> > const & limit,
2095 set<string> & completions)
2096{
2097 completions.clear();
2098
2099 // step 1: the limit is transformed into an SQL select statement which
2100 // selects a set of IDs from the manifest_certs table which match the
2101 // limit. this is done by building an SQL select statement for each term
2102 // in the limit and then INTERSECTing them all.
2103
2104 string lim = "(";
2105 if (limit.empty())
2106 {
2107 lim += "SELECT id FROM revision_certs";
2108 }
2109 else
2110 {
2111 bool first_limit = true;
2112 for (vector<pair<selector_type, string> >::const_iterator i = limit.begin();
2113 i != limit.end(); ++i)
2114 {
2115 if (first_limit)
2116 first_limit = false;
2117 else
2118 lim += " INTERSECT ";
2119
2120 if (i->first == commands::sel_ident)
2121 {
2122 lim += "SELECT id FROM revision_certs ";
2123 lim += (F("WHERE id GLOB '%s*'")
2124 % i->second).str();
2125 }
2126 else if (i->first == commands::sel_unknown)
2127 {
2128 lim += "SELECT id FROM revision_certs ";
2129 lim += (F(" WHERE (name='%s' OR name='%s' OR name='%s')")
2130 % author_cert_name
2131 % tag_cert_name
2132 % branch_cert_name).str();
2133 lim += (F(" AND unbase64(value) glob '*%s*'")
2134 % i->second).str();
2135 }
2136 else
2137 {
2138 string certname;
2139 selector_to_certname(i->first, certname);
2140 lim += "SELECT id FROM revision_certs ";
2141 lim += (F("WHERE name='%s' AND unbase64(value) glob '*%s*'")
2142 % certname % i->second).str();
2143 }
2144 }
2145 }
2146 lim += ")";
2147
2148 // step 2: depending on what we've been asked to disambiguate, we
2149 // will complete either some idents, or cert values, or "unknown"
2150 // which generally means "author, tag or branch"
2151
2152 string query;
2153 if (ty == commands::sel_ident)
2154 {
2155 query = (F("SELECT id FROM %s") % lim).str();
2156 }
2157 else
2158 {
2159 query = "SELECT value FROM revision_certs WHERE";
2160 if (ty == commands::sel_unknown)
2161 {
2162 query +=
2163 (F(" (name='%s' OR name='%s' OR name='%s')")
2164 % author_cert_name
2165 % tag_cert_name
2166 % branch_cert_name).str();
2167 }
2168 else
2169 {
2170 string certname;
2171 selector_to_certname(ty, certname);
2172 query +=
2173 (F(" (name='%s')") % certname).str();
2174 }
2175
2176 query += (F(" AND (unbase64(value) GLOB '*%s*')") % partial).str();
2177 query += (F(" AND (id IN %s)") % lim).str();
2178 }
2179
2180 results res;
2181 fetch(res, one_col, any_rows, query.c_str());
2182 for (size_t i = 0; i < res.size(); ++i)
2183 {
2184 if (ty == commands::sel_ident)
2185 completions.insert(res[i][0]);
2186 else
2187 {
2188 base64<data> row_encoded(res[i][0]);
2189 data row_decoded;
2190 decode_base64(row_encoded, row_decoded);
2191 completions.insert(row_decoded());
2192 }
2193 }
2194}
2195
2196// epochs
2197
2198void
2199database::get_epochs(std::map<cert_value, epoch_data> & epochs)
2200{
2201 epochs.clear();
2202 results res;
2203 fetch(res, 2, any_rows, "SELECT branch, epoch FROM branch_epochs");
2204 for (results::const_iterator i = res.begin(); i != res.end(); ++i)
2205 {
2206 base64<cert_value> encoded(idx(*i, 0));
2207 cert_value decoded;
2208 decode_base64(encoded, decoded);
2209 I(epochs.find(decoded) == epochs.end());
2210 epochs.insert(std::make_pair(decoded, epoch_data(idx(*i, 1))));
2211 }
2212}
2213
2214void
2215database::get_epoch(epoch_id const & eid,
2216 cert_value & branch, epoch_data & epo)
2217{
2218 I(epoch_exists(eid));
2219 results res;
2220 fetch(res, 2, any_rows,
2221 "SELECT branch, epoch FROM branch_epochs"
2222 " WHERE hash = '%q'",
2223 eid.inner()().c_str());
2224 I(res.size() == 1);
2225 base64<cert_value> encoded(idx(idx(res, 0), 0));
2226 decode_base64(encoded, branch);
2227 epo = epoch_data(idx(idx(res, 0), 1));
2228}
2229
2230bool
2231database::epoch_exists(epoch_id const & eid)
2232{
2233 results res;
2234 fetch(res, one_col, any_rows,
2235 "SELECT hash FROM branch_epochs WHERE hash = '%q'",
2236 eid.inner()().c_str());
2237 I(res.size() == 1 || res.size() == 0);
2238 return res.size() == 1;
2239}
2240
2241void
2242database::set_epoch(cert_value const & branch, epoch_data const & epo)
2243{
2244 epoch_id eid;
2245 base64<cert_value> encoded;
2246 encode_base64(branch, encoded);
2247 epoch_hash_code(branch, epo, eid);
2248 I(epo.inner()().size() == constants::epochlen);
2249 execute("INSERT OR REPLACE INTO branch_epochs VALUES('%q', '%q', '%q')",
2250 eid.inner()().c_str(), encoded().c_str(), epo.inner()().c_str());
2251}
2252
2253void
2254database::clear_epoch(cert_value const & branch)
2255{
2256 base64<cert_value> encoded;
2257 encode_base64(branch, encoded);
2258 execute("DELETE FROM branch_epochs WHERE branch = '%q'", encoded().c_str());
2259}
2260
2261// vars
2262
2263void
2264database::get_vars(std::map<var_key, var_value> & vars)
2265{
2266 vars.clear();
2267 results res;
2268 fetch(res, 3, any_rows, "SELECT domain, name, value FROM db_vars");
2269 for (results::const_iterator i = res.begin(); i != res.end(); ++i)
2270 {
2271 var_domain domain(idx(*i, 0));
2272 base64<var_name> name_encoded(idx(*i, 1));
2273 var_name name;
2274 decode_base64(name_encoded, name);
2275 base64<var_value> value_encoded(idx(*i, 2));
2276 var_value value;
2277 decode_base64(value_encoded, value);
2278 I(vars.find(std::make_pair(domain, name)) == vars.end());
2279 vars.insert(std::make_pair(std::make_pair(domain, name), value));
2280 }
2281}
2282
2283void
2284database::get_var(var_key const & key, var_value & value)
2285{
2286 // FIXME: sillyly inefficient. Doesn't really matter, though.
2287 std::map<var_key, var_value> vars;
2288 get_vars(vars);
2289 std::map<var_key, var_value>::const_iterator i = vars.find(key);
2290 I(i != vars.end());
2291 value = i->second;
2292}
2293
2294bool
2295database::var_exists(var_key const & key)
2296{
2297 // FIXME: sillyly inefficient. Doesn't really matter, though.
2298 std::map<var_key, var_value> vars;
2299 get_vars(vars);
2300 std::map<var_key, var_value>::const_iterator i = vars.find(key);
2301 return i != vars.end();
2302}
2303
2304void
2305database::set_var(var_key const & key, var_value const & value)
2306{
2307 base64<var_name> name_encoded;
2308 encode_base64(key.second, name_encoded);
2309 base64<var_value> value_encoded;
2310 encode_base64(value, value_encoded);
2311 execute("INSERT OR REPLACE INTO db_vars VALUES('%q', '%q', '%q')",
2312 key.first().c_str(),
2313 name_encoded().c_str(),
2314 value_encoded().c_str());
2315}
2316
2317void
2318database::clear_var(var_key const & key)
2319{
2320 base64<var_name> name_encoded;
2321 encode_base64(key.second, name_encoded);
2322 execute("DELETE FROM db_vars WHERE domain = '%q' AND name = '%q'",
2323 key.first().c_str(), name_encoded().c_str());
2324}
2325
2326// transaction guards
2327
2328transaction_guard::transaction_guard(database & d) : committed(false), db(d)
2329{
2330 db.begin_transaction();
2331}
2332transaction_guard::~transaction_guard()
2333{
2334 if (committed)
2335 db.commit_transaction();
2336 else
2337 db.rollback_transaction();
2338}
2339
2340void
2341transaction_guard::commit()
2342{
2343 committed = true;
2344}
2345

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status