monotone

monotone Mtn Source Tree

Root/database.cc

1// Copyright (C) 2002 Graydon Hoare <graydon@pobox.com>
2//
3// This program is made available under the GNU GPL version 2.0 or
4// greater. See the accompanying file COPYING for details.
5//
6// This program is distributed WITHOUT ANY WARRANTY; without even the
7// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8// PURPOSE.
9
10#include "base.hh"
11#include <algorithm>
12#include <deque>
13#include <fstream>
14#include <iterator>
15#include <list>
16#include <set>
17#include <sstream>
18#include <vector>
19
20#include <string.h>
21
22#include <boost/shared_ptr.hpp>
23#include "lexical_cast.hh"
24
25#include "sqlite/sqlite3.h"
26
27#include "app_state.hh"
28#include "cert.hh"
29#include "cleanup.hh"
30#include "constants.hh"
31#include "database.hh"
32#include "hash_map.hh"
33#include "keys.hh"
34#include "platform-wrapped.hh"
35#include "revision.hh"
36#include "safe_map.hh"
37#include "sanity.hh"
38#include "schema_migration.hh"
39#include "transforms.hh"
40#include "ui.hh"
41#include "vocab.hh"
42#include "vocab_cast.hh"
43#include "xdelta.hh"
44#include "epoch.hh"
45#include "graph.hh"
46#include "roster_delta.hh"
47#include "rev_height.hh"
48#include "vocab_hash.hh"
49
50// defined in schema.c, generated from schema.sql:
51extern char const schema_constant[];
52
53// this file defines a public, typed interface to the database.
54// the database class encapsulates all knowledge about sqlite,
55// the schema, and all SQL statements used to access the schema.
56//
57// see file schema.sql for the text of the schema.
58
59using std::deque;
60using std::istream;
61using std::ifstream;
62using std::make_pair;
63using std::map;
64using std::multimap;
65using std::ostream;
66using std::pair;
67using std::set;
68using std::string;
69using std::vector;
70
71using boost::shared_ptr;
72using boost::lexical_cast;
73
74int const one_row = 1;
75int const one_col = 1;
76int const any_rows = -1;
77int const any_cols = -1;
78
79namespace
80{
81 struct query_param
82 {
83 enum arg_type { text, blob };
84 arg_type type;
85 string data;
86 };
87
88 query_param
89 text(string const & txt)
90 {
91 query_param q = {
92 query_param::text,
93 txt,
94 };
95 return q;
96 }
97
98 query_param
99 blob(string const & blb)
100 {
101 query_param q = {
102 query_param::blob,
103 blb,
104 };
105 return q;
106 }
107}
108
109struct query
110{
111 explicit query(string const & cmd)
112 : sql_cmd(cmd)
113 {}
114
115 query()
116 {}
117
118 query & operator %(query_param const & qp)
119 {
120 args.push_back(qp);
121 return *this;
122 }
123
124 vector<query_param> args;
125 string sql_cmd;
126};
127
128database::database(system_path const & fn) :
129 filename(fn),
130 __sql(NULL),
131 transaction_level(0),
132 roster_cache(constants::db_roster_cache_sz,
133 roster_writeback_manager(*this)),
134 delayed_writes_size(0)
135{}
136
137bool
138database::is_dbfile(any_path const & file)
139{
140 system_path fn(file);// why is this needed?
141 bool same = (filename.as_internal() == fn.as_internal());
142 if (same)
143 L(FL("'%s' is the database file") % file);
144 return same;
145}
146
147void
148database::check_is_not_rosterified()
149{
150 results res;
151 string rosters_query = "SELECT 1 FROM rosters LIMIT 1";
152 fetch(res, one_col, any_rows, query(rosters_query));
153 N(res.empty(),
154 F("this database already contains rosters"));
155}
156
157void
158database::check_format()
159{
160 results res;
161
162 // Check for manifests, revisions, rosters, and heights.
163 fetch(res, one_col, any_rows, query("SELECT 1 FROM manifests LIMIT 1"));
164 bool have_manifests = !res.empty();
165 fetch(res, one_col, any_rows, query("SELECT 1 FROM revisions LIMIT 1"));
166 bool have_revisions = !res.empty();
167 fetch(res, one_col, any_rows, query("SELECT 1 FROM rosters LIMIT 1"));
168 bool have_rosters = !res.empty();
169 fetch(res, one_col, any_rows, query("SELECT 1 FROM heights LIMIT 1"));
170 bool have_heights = !res.empty();
171
172
173 if (!have_manifests)
174 {
175 // Must have been changesetified and rosterified already.
176 // Or else the database was just created.
177 // Do we need to regenerate cached data?
178 E(!have_revisions || (have_rosters && have_heights),
179 F("database %s lacks some cached data\n"
180 "run '%s db regenerate_caches' to restore use of this database")
181 % filename % ui.prog_name);
182 }
183 else
184 {
185 // The rosters and heights tables should be empty.
186 I(!have_rosters && !have_heights);
187
188 // they need to either changesetify or rosterify. which?
189 if (have_revisions)
190 E(false,
191 F("database %s contains old-style revisions\n"
192 "if you are a project leader or doing local testing:\n"
193 " see the file UPGRADE for instructions on upgrading.\n"
194 "if you are not a project leader:\n"
195 " wait for a leader to migrate project data, and then\n"
196 " pull into a fresh database.\n"
197 "sorry about the inconvenience.")
198 % filename);
199 else
200 E(false,
201 F("database %s contains manifests but no revisions\n"
202 "this is a very old database; it needs to be upgraded\n"
203 "please see README.changesets for details")
204 % filename);
205 }
206}
207
208static void
209sqlite3_gunzip_fn(sqlite3_context *f, int nargs, sqlite3_value ** args)
210{
211 if (nargs != 1)
212 {
213 sqlite3_result_error(f, "need exactly 1 arg to gunzip()", -1);
214 return;
215 }
216 data unpacked;
217 const char *val = (const char*) sqlite3_value_blob(args[0]);
218 int bytes = sqlite3_value_bytes(args[0]);
219 decode_gzip(gzip<data>(string(val,val+bytes)), unpacked);
220 sqlite3_result_blob(f, unpacked().c_str(), unpacked().size(), SQLITE_TRANSIENT);
221}
222
223void
224database::set_app(app_state * app)
225{
226 __app = app;
227}
228
229struct sqlite3 *
230database::sql(enum open_mode mode)
231{
232 if (! __sql)
233 {
234 check_filename();
235 check_db_exists();
236 open();
237
238 if (mode != schema_bypass_mode)
239 {
240 check_sql_schema(__sql, filename);
241
242 if (mode != format_bypass_mode)
243 check_format();
244 }
245
246 install_functions(__app);
247 }
248 else
249 I(mode == normal_mode);
250
251 return __sql;
252}
253
254void
255database::initialize()
256{
257 check_filename();
258 check_db_nonexistent();
259 open();
260
261 sqlite3_exec(__sql, schema_constant, NULL, NULL, NULL);
262 assert_sqlite3_ok(__sql);
263
264 sqlite3_exec(__sql, (FL("PRAGMA user_version = %u;")
265 % mtn_creator_code).str().c_str(), NULL, NULL, NULL);
266 assert_sqlite3_ok(__sql);
267
268 // make sure what we wanted is what we got
269 check_sql_schema(__sql, filename);
270
271 close();
272}
273
274struct
275dump_request
276{
277 dump_request() : sql(), out() {};
278 struct sqlite3 *sql;
279 ostream *out;
280};
281
282static void
283dump_row(ostream &out, sqlite3_stmt *stmt, string const& table_name)
284{
285 out << FL("INSERT INTO %s VALUES(") % table_name;
286 unsigned n = sqlite3_data_count(stmt);
287 for (unsigned i = 0; i < n; ++i)
288 {
289 if (i != 0)
290 out << ',';
291
292 if (sqlite3_column_type(stmt, i) == SQLITE_BLOB)
293 {
294 out << "X'";
295 const char *val = (const char*) sqlite3_column_blob(stmt, i);
296 int bytes = sqlite3_column_bytes(stmt, i);
297 out << encode_hexenc(string(val,val+bytes));
298 out << '\'';
299 }
300 else
301 {
302 const unsigned char *val = sqlite3_column_text(stmt, i);
303 if (val == NULL)
304 out << "NULL";
305 else
306 {
307 out << '\'';
308 for (const unsigned char *cp = val; *cp; ++cp)
309 {
310 if (*cp == '\'')
311 out << "''";
312 else
313 out << *cp;
314 }
315 out << '\'';
316 }
317 }
318 }
319 out << ");\n";
320}
321
322static int
323dump_table_cb(void *data, int n, char **vals, char **cols)
324{
325 dump_request *dump = reinterpret_cast<dump_request *>(data);
326 I(dump != NULL);
327 I(dump->sql != NULL);
328 I(vals != NULL);
329 I(vals[0] != NULL);
330 I(vals[1] != NULL);
331 I(vals[2] != NULL);
332 I(n == 3);
333 I(string(vals[1]) == "table");
334 *(dump->out) << vals[2] << ";\n";
335 string table_name(vals[0]);
336 string query = "SELECT * FROM " + table_name;
337 sqlite3_stmt *stmt = 0;
338 sqlite3_prepare_v2(dump->sql, query.c_str(), -1, &stmt, NULL);
339 assert_sqlite3_ok(dump->sql);
340
341 int stepresult = SQLITE_DONE;
342 do
343 {
344 stepresult = sqlite3_step(stmt);
345 I(stepresult == SQLITE_DONE || stepresult == SQLITE_ROW);
346 if (stepresult == SQLITE_ROW)
347 dump_row(*(dump->out), stmt, table_name);
348 }
349 while (stepresult == SQLITE_ROW);
350
351 sqlite3_finalize(stmt);
352 assert_sqlite3_ok(dump->sql);
353 return 0;
354}
355
356static int
357dump_index_cb(void *data, int n, char **vals, char **cols)
358{
359 dump_request *dump = reinterpret_cast<dump_request *>(data);
360 I(dump != NULL);
361 I(dump->sql != NULL);
362 I(vals != NULL);
363 I(vals[0] != NULL);
364 I(vals[1] != NULL);
365 I(vals[2] != NULL);
366 I(n == 3);
367 I(string(vals[1]) == "index");
368 *(dump->out) << vals[2] << ";\n";
369 return 0;
370}
371
372static int
373dump_user_version_cb(void *data, int n, char **vals, char **cols)
374{
375 dump_request *dump = reinterpret_cast<dump_request *>(data);
376 I(dump != NULL);
377 I(dump->sql != NULL);
378 I(vals != NULL);
379 I(vals[0] != NULL);
380 I(n == 1);
381 *(dump->out) << "PRAGMA user_version = " << vals[0] << ";\n";
382 return 0;
383}
384
385void
386database::dump(ostream & out)
387{
388 ensure_open_for_maintenance();
389
390 {
391 transaction_guard guard(*this);
392 dump_request req;
393 req.out = &out;
394 req.sql = sql();
395 out << "BEGIN EXCLUSIVE;\n";
396 int res;
397 res = sqlite3_exec(req.sql,
398 "SELECT name, type, sql FROM sqlite_master "
399 "WHERE type='table' AND sql NOT NULL "
400 "AND name not like 'sqlite_stat%' "
401 "ORDER BY name",
402 dump_table_cb, &req, NULL);
403 assert_sqlite3_ok(req.sql);
404 res = sqlite3_exec(req.sql,
405 "SELECT name, type, sql FROM sqlite_master "
406 "WHERE type='index' AND sql NOT NULL "
407 "ORDER BY name",
408 dump_index_cb, &req, NULL);
409 assert_sqlite3_ok(req.sql);
410 res = sqlite3_exec(req.sql,
411 "PRAGMA user_version;",
412 dump_user_version_cb, &req, NULL);
413 assert_sqlite3_ok(req.sql);
414 out << "COMMIT;\n";
415 guard.commit();
416 }
417}
418
419void
420database::load(istream & in)
421{
422 string line;
423 string sql_stmt;
424
425 check_filename();
426 check_db_nonexistent();
427 open();
428
429 // the page size can only be set before any other commands have been executed
430 sqlite3_exec(__sql, "PRAGMA page_size=8192", NULL, NULL, NULL);
431 assert_sqlite3_ok(__sql);
432
433 while(in)
434 {
435 getline(in, line, ';');
436 sql_stmt += line + ';';
437
438 if (sqlite3_complete(sql_stmt.c_str()))
439 {
440 sqlite3_exec(__sql, sql_stmt.c_str(), NULL, NULL, NULL);
441 assert_sqlite3_ok(__sql);
442 sql_stmt.clear();
443 }
444 }
445
446 assert_sqlite3_ok(__sql);
447}
448
449
450void
451database::debug(string const & sql, ostream & out)
452{
453 ensure_open_for_maintenance();
454
455 results res;
456 fetch(res, any_cols, any_rows, query(sql));
457 out << '\'' << sql << "' -> " << res.size() << " rows\n\n";
458 for (size_t i = 0; i < res.size(); ++i)
459 {
460 for (size_t j = 0; j < res[i].size(); ++j)
461 {
462 if (j != 0)
463 out << " | ";
464 out << res[i][j];
465 }
466 out << '\n';
467 }
468}
469
470// Subroutine of info(). This compares strings that might either be numbers
471// or error messages surrounded by square brackets. We want the longest
472// number, even if there's an error message that's longer than that.
473static bool longest_number(string a, string b)
474{
475 if(a.length() > 0 && a[0] == '[')
476 return true; // b is longer
477 if(b.length() > 0 && b[0] == '[')
478 return false; // a is longer
479
480 return a.length() < b.length();
481}
482
483// Subroutine of info() and some things it calls.
484// Given an informative_failure which is believed to represent an SQLite
485// error, either return a string version of the error message (if it was an
486// SQLite error) or rethrow the execption (if it wasn't).
487static string
488format_sqlite_error_for_info(informative_failure const & e)
489{
490 string err(e.what());
491 string prefix = _("error: ");
492 prefix.append(_("sqlite error: "));
493 if (err.find(prefix) != 0)
494 throw;
495
496 err.replace(0, prefix.length(), "[");
497 string::size_type nl = err.find('\n');
498 if (nl != string::npos)
499 err.erase(nl);
500
501 err.append("]");
502 return err;
503}
504
505// Subroutine of info(). Pretty-print the database's "creator code", which
506// is a 32-bit unsigned number that we interpret as a four-character ASCII
507// string, provided that all four characters are graphic. (On disk, it's
508// stored in the "user version" field of the database.)
509static string
510format_creator_code(u32 code)
511{
512 char buf[5];
513 string result;
514
515 if (code == 0)
516 return _("not set");
517
518 buf[4] = '\0';
519 buf[3] = ((code & 0x000000ff) >> 0);
520 buf[2] = ((code & 0x0000ff00) >> 8);
521 buf[1] = ((code & 0x00ff0000) >> 16);
522 buf[0] = ((code & 0xff000000) >> 24);
523
524 if (isgraph(buf[0]) && isgraph(buf[1]) && isgraph(buf[2]) && isgraph(buf[3]))
525 result = (FL("%s (0x%08x)") % buf % code).str();
526 else
527 result = (FL("0x%08x") % code).str();
528 if (code != mtn_creator_code)
529 result += _(" (not a monotone database)");
530 return result;
531}
532
533
534void
535database::info(ostream & out)
536{
537 // don't check the schema
538 ensure_open_for_maintenance();
539
540 // do a dummy query to confirm that the database file is an sqlite3
541 // database. (this doesn't happen on open() because sqlite postpones the
542 // actual file open until the first access. we can't piggyback it on the
543 // query of the user version because there's a bug in sqlite 3.3.10:
544 // the routine that reads meta-values from the database header does not
545 // check the file format. reported as sqlite bug #2182.)
546 sqlite3_exec(__sql, "SELECT 1 FROM sqlite_master LIMIT 0", 0, 0, 0);
547 assert_sqlite3_ok(__sql);
548
549 u32 ccode;
550 {
551 results res;
552 fetch(res, one_col, one_row, query("PRAGMA user_version"));
553 I(res.size() == 1);
554 ccode = lexical_cast<u32>(res[0][0]);
555 }
556
557 vector<string> counts;
558 counts.push_back(count("rosters"));
559 counts.push_back(count("roster_deltas"));
560 counts.push_back(count("files"));
561 counts.push_back(count("file_deltas"));
562 counts.push_back(count("revisions"));
563 counts.push_back(count("revision_ancestry"));
564 counts.push_back(count("revision_certs"));
565
566 {
567 results res;
568 try
569 {
570 fetch(res, one_col, any_rows,
571 query("SELECT node FROM next_roster_node_number"));
572 if (res.empty())
573 counts.push_back("0");
574 else
575 {
576 I(res.size() == 1);
577 counts.push_back((F("%u")
578 % (lexical_cast<u64>(res[0][0]) - 1)).str());
579 }
580 }
581 catch (informative_failure const & e)
582 {
583 counts.push_back(format_sqlite_error_for_info(e));
584 }
585 }
586
587 vector<string> bytes;
588 {
589 u64 total = 0;
590 bytes.push_back(space("rosters",
591 "length(id) + length(checksum) + length(data)",
592 total));
593 bytes.push_back(space("roster_deltas",
594 "length(id) + length(checksum)"
595 "+ length(base) + length(delta)", total));
596 bytes.push_back(space("files", "length(id) + length(data)", total));
597 bytes.push_back(space("file_deltas",
598 "length(id) + length(base) + length(delta)", total));
599 bytes.push_back(space("revisions", "length(id) + length(data)", total));
600 bytes.push_back(space("revision_ancestry",
601 "length(parent) + length(child)", total));
602 bytes.push_back(space("revision_certs",
603 "length(hash) + length(id) + length(name)"
604 "+ length(value) + length(keypair)"
605 "+ length(signature)", total));
606 bytes.push_back(space("heights", "length(revision) + length(height)",
607 total));
608 bytes.push_back((F("%u") % total).str());
609 }
610
611 // pad each vector's strings on the left with spaces to make them all the
612 // same length
613 {
614 string::size_type width
615 = max_element(counts.begin(), counts.end(), longest_number)->length();
616 for(vector<string>::iterator i = counts.begin(); i != counts.end(); i++)
617 if (width > i->length() && (*i)[0] != '[')
618 i->insert(0, width - i->length(), ' ');
619
620 width = max_element(bytes.begin(), bytes.end(), longest_number)->length();
621 for(vector<string>::iterator i = bytes.begin(); i != bytes.end(); i++)
622 if (width > i->length() && (*i)[0] != '[')
623 i->insert(0, width - i->length(), ' ');
624 }
625
626 i18n_format form =
627 F("creator code : %s\n"
628 "schema version : %s\n"
629 "counts:\n"
630 " full rosters : %s\n"
631 " roster deltas : %s\n"
632 " full files : %s\n"
633 " file deltas : %s\n"
634 " revisions : %s\n"
635 " ancestry edges : %s\n"
636 " certs : %s\n"
637 " logical files : %s\n"
638 "bytes:\n"
639 " full rosters : %s\n"
640 " roster deltas : %s\n"
641 " full files : %s\n"
642 " file deltas : %s\n"
643 " revisions : %s\n"
644 " cached ancestry : %s\n"
645 " certs : %s\n"
646 " heights : %s\n"
647 " total : %s\n"
648 "database:\n"
649 " page size : %s\n"
650 " cache size : %s"
651 );
652
653 form = form % format_creator_code(ccode);
654 form = form % describe_sql_schema(__sql);
655
656 for (vector<string>::iterator i = counts.begin(); i != counts.end(); i++)
657 form = form % *i;
658
659 for (vector<string>::iterator i = bytes.begin(); i != bytes.end(); i++)
660 form = form % *i;
661
662 form = form % page_size();
663 form = form % cache_size();
664
665 out << form.str() << '\n'; // final newline is kept out of the translation
666}
667
668void
669database::version(ostream & out)
670{
671 ensure_open_for_maintenance();
672 out << (F("database schema version: %s") % describe_sql_schema(__sql)).str()
673 << '\n';
674}
675
676void
677database::migrate()
678{
679 ensure_open_for_maintenance();
680 migrate_sql_schema(__sql, *__app);
681}
682
683void
684database::test_migration_step(string const & schema)
685{
686 ensure_open_for_maintenance();
687 ::test_migration_step(__sql, *__app, schema);
688}
689
690void
691database::ensure_open()
692{
693 sql();
694}
695
696void
697database::ensure_open_for_format_changes()
698{
699 sql(format_bypass_mode);
700}
701
702void
703database::ensure_open_for_maintenance()
704{
705 sql(schema_bypass_mode);
706}
707
708database::~database()
709{
710 L(FL("statement cache statistics"));
711 L(FL("prepared %d statements") % statement_cache.size());
712
713 for (map<string, statement>::const_iterator i = statement_cache.begin();
714 i != statement_cache.end(); ++i)
715 L(FL("%d executions of %s") % i->second.count % i->first);
716 // trigger destructors to finalize cached statements
717 statement_cache.clear();
718
719 if (__sql)
720 close();
721}
722
723void
724database::execute(query const & query)
725{
726 results res;
727 fetch(res, 0, 0, query);
728}
729
730void
731database::fetch(results & res,
732 int const want_cols,
733 int const want_rows,
734 query const & query)
735{
736 int nrow;
737 int ncol;
738 int rescode;
739
740 res.clear();
741 res.resize(0);
742
743 map<string, statement>::iterator i = statement_cache.find(query.sql_cmd);
744 if (i == statement_cache.end())
745 {
746 statement_cache.insert(make_pair(query.sql_cmd, statement()));
747 i = statement_cache.find(query.sql_cmd);
748 I(i != statement_cache.end());
749
750 const char * tail;
751 sqlite3_prepare_v2(sql(), query.sql_cmd.c_str(), -1, i->second.stmt.paddr(), &tail);
752 assert_sqlite3_ok(sql());
753 L(FL("prepared statement %s") % query.sql_cmd);
754
755 // no support for multiple statements here
756 E(*tail == 0,
757 F("multiple statements in query: %s") % query.sql_cmd);
758 }
759
760 ncol = sqlite3_column_count(i->second.stmt());
761
762 E(want_cols == any_cols || want_cols == ncol,
763 F("wanted %d columns got %d in query: %s") % want_cols % ncol % query.sql_cmd);
764
765 // bind parameters for this execution
766
767 int params = sqlite3_bind_parameter_count(i->second.stmt());
768
769 // Ensure that exactly the right number of parameters were given
770 I(params == int(query.args.size()));
771
772 // profiling finds this logging to be quite expensive
773 if (global_sanity.debug)
774 L(FL("binding %d parameters for %s") % params % query.sql_cmd);
775
776 for (int param = 1; param <= params; param++)
777 {
778 // profiling finds this logging to be quite expensive
779 if (global_sanity.debug)
780 {
781 string log;
782 switch (query.args[param-1].type)
783 {
784 case query_param::text:
785 case query_param::blob:
786 log = query.args[param-1].data;
787 break;
788 }
789
790 if (log.size() > constants::log_line_sz)
791 log = log.substr(0, constants::log_line_sz);
792
793 L(FL("binding %d with value '%s'") % param % log);
794 }
795
796 switch (idx(query.args, param - 1).type)
797 {
798 case query_param::text:
799 sqlite3_bind_text(i->second.stmt(), param,
800 idx(query.args, param - 1).data.c_str(), -1,
801 SQLITE_STATIC);
802 break;
803 case query_param::blob:
804 {
805 string const & data = idx(query.args, param - 1).data;
806 sqlite3_bind_blob(i->second.stmt(), param,
807 data.data(), data.size(),
808 SQLITE_STATIC);
809 }
810 break;
811 default:
812 I(false);
813 }
814
815 assert_sqlite3_ok(sql());
816 }
817
818 // execute and process results
819
820 nrow = 0;
821 for (rescode = sqlite3_step(i->second.stmt()); rescode == SQLITE_ROW;
822 rescode = sqlite3_step(i->second.stmt()))
823 {
824 vector<string> row;
825 for (int col = 0; col < ncol; col++)
826 {
827 const char * value = (const char*)sqlite3_column_blob(i->second.stmt(), col);
828 int bytes = sqlite3_column_bytes(i->second.stmt(), col);
829 E(value, F("null result in query: %s") % query.sql_cmd);
830 row.push_back(string(value, value + bytes));
831 //L(FL("row %d col %d value='%s'") % nrow % col % value);
832 }
833 res.push_back(row);
834 }
835
836 if (rescode != SQLITE_DONE)
837 assert_sqlite3_ok(sql());
838
839 sqlite3_reset(i->second.stmt());
840 assert_sqlite3_ok(sql());
841
842 nrow = res.size();
843
844 i->second.count++;
845
846 E(want_rows == any_rows || want_rows == nrow,
847 F("wanted %d rows got %d in query: %s") % want_rows % nrow % query.sql_cmd);
848}
849
850bool
851database::table_has_entry(std::string const & key, std::string const & column,
852 std::string const & table)
853{
854 results res;
855 query q("SELECT 1 FROM " + table + " WHERE " + column + " = ? LIMIT 1");
856 fetch(res, one_col, any_rows, q % text(key));
857 return !res.empty();
858}
859
860// general application-level logic
861
862void
863database::set_filename(system_path const & file)
864{
865 I(!__sql);
866 filename = file;
867}
868
869system_path
870database::get_filename()
871{
872 return filename;
873}
874
875void
876database::begin_transaction(bool exclusive)
877{
878 if (transaction_level == 0)
879 {
880 I(delayed_files.empty());
881 I(roster_cache.all_clean());
882 if (exclusive)
883 execute(query("BEGIN EXCLUSIVE"));
884 else
885 execute(query("BEGIN DEFERRED"));
886 transaction_exclusive = exclusive;
887 }
888 else
889 {
890 // You can't start an exclusive transaction within a non-exclusive
891 // transaction
892 I(!exclusive || transaction_exclusive);
893 }
894 transaction_level++;
895}
896
897
898size_t
899database::size_delayed_file(file_id const & id, file_data const & dat)
900{
901 return id.inner()().size() + dat.inner()().size();
902}
903
904bool
905database::have_delayed_file(file_id const & id)
906{
907 return delayed_files.find(id) != delayed_files.end();
908}
909
910void
911database::load_delayed_file(file_id const & id, file_data & dat)
912{
913 dat = safe_get(delayed_files, id);
914}
915
916// precondition: have_delayed_file(an_id) == true
917void
918database::cancel_delayed_file(file_id const & an_id)
919{
920 file_data const & dat = safe_get(delayed_files, an_id);
921 size_t cancel_size = size_delayed_file(an_id, dat);
922 I(cancel_size <= delayed_writes_size);
923 delayed_writes_size -= cancel_size;
924
925 safe_erase(delayed_files, an_id);
926}
927
928void
929database::drop_or_cancel_file(file_id const & id)
930{
931 if (have_delayed_file(id))
932 cancel_delayed_file(id);
933 else
934 drop(id.inner()(), "files");
935}
936
937void
938database::schedule_delayed_file(file_id const & an_id,
939 file_data const & dat)
940{
941 if (!have_delayed_file(an_id))
942 {
943 safe_insert(delayed_files, make_pair(an_id, dat));
944 delayed_writes_size += size_delayed_file(an_id, dat);
945 }
946 if (delayed_writes_size > constants::db_max_delayed_file_bytes)
947 flush_delayed_writes();
948}
949
950void
951database::flush_delayed_writes()
952{
953 for (map<file_id, file_data>::const_iterator i = delayed_files.begin();
954 i != delayed_files.end(); ++i)
955 write_delayed_file(i->first, i->second);
956 clear_delayed_writes();
957}
958
959void
960database::clear_delayed_writes()
961{
962 delayed_files.clear();
963 delayed_writes_size = 0;
964}
965
966void
967database::roster_writeback_manager::writeout(revision_id const & id,
968 cached_roster const & cr)
969{
970 I(cr.first);
971 I(cr.second);
972 db.write_delayed_roster(id, *(cr.first), *(cr.second));
973}
974
975unsigned long
976database::roster_size_estimator::operator()(cached_roster const & cr)
977{
978 I(cr.first);
979 I(cr.second);
980 // do estimate using a totally made up multiplier, probably wildly off
981 return cr.first->all_nodes().size() * constants::db_estimated_roster_node_sz;
982}
983
984void
985database::commit_transaction()
986{
987 if (transaction_level == 1)
988 {
989 flush_delayed_writes();
990 roster_cache.clean_all();
991 execute(query("COMMIT"));
992 }
993 transaction_level--;
994}
995
996void
997database::rollback_transaction()
998{
999 if (transaction_level == 1)
1000 {
1001 clear_delayed_writes();
1002 roster_cache.clear_and_drop_writes();
1003 execute(query("ROLLBACK"));
1004 }
1005 transaction_level--;
1006}
1007
1008
1009bool
1010database::file_or_manifest_base_exists(hexenc<id> const & ident,
1011 std::string const & table)
1012{
1013 // just check for a delayed file, since there are no delayed manifests
1014 if (have_delayed_file(file_id(ident)))
1015 return true;
1016 return table_has_entry(ident(), "id", table);
1017}
1018
1019// returns true if we are currently storing (or planning to store) a
1020// full-text for 'ident'
1021bool
1022database::roster_base_stored(revision_id const & ident)
1023{
1024 if (roster_cache.exists(ident) && roster_cache.is_dirty(ident))
1025 return true;
1026 return table_has_entry(ident.inner()(), "id", "rosters");
1027}
1028
1029// returns true if we currently have a full-text for 'ident' available
1030// (possibly cached). Warning: the results of this method are invalidated
1031// by calling roster_cache.insert_{clean,dirty}, because they can trigger
1032// cache cleaning.
1033bool
1034database::roster_base_available(revision_id const & ident)
1035{
1036 if (roster_cache.exists(ident))
1037 return true;
1038 return table_has_entry(ident.inner()(), "id", "rosters");
1039}
1040
1041bool
1042database::delta_exists(string const & ident,
1043 string const & table)
1044{
1045 return table_has_entry(ident, "id", table);
1046}
1047
1048bool
1049database::delta_exists(string const & ident,
1050 string const & base,
1051 string const & table)
1052{
1053 results res;
1054 query q("SELECT 1 FROM " + table + " WHERE id = ? and base = ? LIMIT 1");
1055 fetch(res, one_col, any_rows, q % text(ident) % text(base));
1056 return !res.empty();
1057}
1058
1059string
1060database::count(string const & table)
1061{
1062 try
1063 {
1064 results res;
1065 query q("SELECT COUNT(*) FROM " + table);
1066 fetch(res, one_col, one_row, q);
1067 return (F("%u") % lexical_cast<u64>(res[0][0])).str();
1068 }
1069 catch (informative_failure const & e)
1070 {
1071 return format_sqlite_error_for_info(e);
1072 }
1073
1074}
1075
1076string
1077database::space(string const & table, string const & rowspace, u64 & total)
1078{
1079 try
1080 {
1081 results res;
1082 // SUM({empty set}) is NULL; TOTAL({empty set}) is 0.0
1083 query q("SELECT TOTAL(" + rowspace + ") FROM " + table);
1084 fetch(res, one_col, one_row, q);
1085 u64 bytes = static_cast<u64>(lexical_cast<double>(res[0][0]));
1086 total += bytes;
1087 return (F("%u") % bytes).str();
1088 }
1089 catch (informative_failure & e)
1090 {
1091 return format_sqlite_error_for_info(e);
1092 }
1093}
1094
1095unsigned int
1096database::page_size()
1097{
1098 results res;
1099 query q("PRAGMA page_size");
1100 fetch(res, one_col, one_row, q);
1101 return lexical_cast<unsigned int>(res[0][0]);
1102}
1103
1104unsigned int
1105database::cache_size()
1106{
1107 // This returns the persistent (default) cache size. It's possible to
1108 // override this setting transiently at runtime by setting PRAGMA
1109 // cache_size.
1110 results res;
1111 query q("PRAGMA default_cache_size");
1112 fetch(res, one_col, one_row, q);
1113 return lexical_cast<unsigned int>(res[0][0]);
1114}
1115
1116void
1117database::get_ids(string const & table, set< hexenc<id> > & ids)
1118{
1119 results res;
1120 query q("SELECT id FROM " + table);
1121 fetch(res, one_col, any_rows, q);
1122
1123 for (size_t i = 0; i < res.size(); ++i)
1124 {
1125 ids.insert(hexenc<id>(res[i][0]));
1126 }
1127}
1128
1129// for files and legacy manifest support
1130void
1131database::get_file_or_manifest_base_unchecked(hexenc<id> const & ident,
1132 data & dat,
1133 string const & table)
1134{
1135 if (have_delayed_file(file_id(ident)))
1136 {
1137 file_data tmp;
1138 load_delayed_file(file_id(ident), tmp);
1139 dat = tmp.inner();
1140 return;
1141 }
1142
1143 results res;
1144 query q("SELECT data FROM " + table + " WHERE id = ?");
1145 fetch(res, one_col, one_row, q % text(ident()));
1146
1147 gzip<data> rdata(res[0][0]);
1148 data rdata_unpacked;
1149 decode_gzip(rdata,rdata_unpacked);
1150
1151 dat = rdata_unpacked;
1152}
1153
1154// for files and legacy manifest support
1155void
1156database::get_file_or_manifest_delta_unchecked(hexenc<id> const & ident,
1157 hexenc<id> const & base,
1158 delta & del,
1159 string const & table)
1160{
1161 I(ident() != "");
1162 I(base() != "");
1163 results res;
1164 query q("SELECT delta FROM " + table + " WHERE id = ? AND base = ?");
1165 fetch(res, one_col, one_row, q % text(ident()) % text(base()));
1166
1167 gzip<delta> del_packed(res[0][0]);
1168 decode_gzip(del_packed, del);
1169}
1170
1171void
1172database::get_roster_base(string const & ident_str,
1173 roster_t & roster, marking_map & marking)
1174{
1175 revision_id ident(ident_str);
1176 if (roster_cache.exists(ident))
1177 {
1178 cached_roster cr;
1179 roster_cache.fetch(ident, cr);
1180 I(cr.first);
1181 roster = *(cr.first);
1182 I(cr.second);
1183 marking = *(cr.second);
1184 return;
1185 }
1186 results res;
1187 query q("SELECT checksum, data FROM rosters WHERE id = ?");
1188 fetch(res, 2, one_row, q % text(ident_str));
1189
1190 hexenc<id> checksum(res[0][0]);
1191 hexenc<id> calculated;
1192 calculate_ident(data(res[0][1]), calculated);
1193 I(calculated == checksum);
1194
1195 gzip<data> dat_packed(res[0][1]);
1196 data dat;
1197 decode_gzip(dat_packed, dat);
1198 read_roster_and_marking(roster_data(dat), roster, marking);
1199}
1200
1201void
1202database::get_roster_delta(string const & ident,
1203 string const & base,
1204 roster<delta> & del)
1205{
1206 results res;
1207 query q("SELECT checksum, delta FROM roster_deltas WHERE id = ? AND base = ?");
1208 fetch(res, 2, one_row, q % text(ident) % text(base));
1209
1210 hexenc<id> checksum(res[0][0]);
1211 hexenc<id> calculated;
1212 calculate_ident(data(res[0][1]), calculated);
1213 I(calculated == checksum);
1214
1215 gzip<delta> del_packed(res[0][1]);
1216 delta tmp;
1217 decode_gzip(del_packed, tmp);
1218 del = roster<delta>(tmp);
1219}
1220
1221void
1222database::write_delayed_file(file_id const & ident,
1223 file_data const & dat)
1224{
1225 gzip<data> dat_packed;
1226 encode_gzip(dat.inner(), dat_packed);
1227
1228 // ident is a hash, which we should check
1229 I(!null_id(ident));
1230 file_id tid;
1231 calculate_ident(dat, tid);
1232 MM(ident);
1233 MM(tid);
1234 I(tid == ident);
1235 // and then write things to the db
1236 query q("INSERT INTO files (id, data) VALUES (?, ?)");
1237 execute(q % text(ident.inner()()) % blob(dat_packed()));
1238}
1239
1240void
1241database::write_delayed_roster(revision_id const & ident,
1242 roster_t const & roster,
1243 marking_map const & marking)
1244{
1245 roster_data dat;
1246 write_roster_and_marking(roster, marking, dat);
1247 gzip<data> dat_packed;
1248 encode_gzip(dat.inner(), dat_packed);
1249
1250 // ident is a number, and we should calculate a checksum on what
1251 // we write
1252 hexenc<id> checksum;
1253 calculate_ident(data(dat_packed()), checksum);
1254
1255 // and then write it
1256 query q("INSERT INTO rosters (id, checksum, data) VALUES (?, ?, ?)");
1257 execute(q % text(ident.inner()()) % text(checksum()) % blob(dat_packed()));
1258}
1259
1260
1261void
1262database::put_file_delta(file_id const & ident,
1263 file_id const & base,
1264 file_delta const & del)
1265{
1266 // nb: delta schema is (id, base, delta)
1267 I(!null_id(ident));
1268 I(!null_id(base));
1269
1270 gzip<delta> del_packed;
1271 encode_gzip(del.inner(), del_packed);
1272
1273 query q("INSERT INTO file_deltas VALUES (?, ?, ?)");
1274 execute(q
1275 % text(ident.inner()())
1276 % text(base.inner()())
1277 % blob(del_packed()));
1278}
1279
1280void
1281database::put_roster_delta(revision_id const & ident,
1282 revision_id const & base,
1283 roster_delta const & del)
1284{
1285 gzip<delta> del_packed;
1286 encode_gzip(del.inner(), del_packed);
1287
1288 hexenc<id> checksum;
1289 calculate_ident(data(del_packed()), checksum);
1290
1291 query q("INSERT INTO roster_deltas (id, base, checksum, delta) VALUES (?, ?, ?, ?)");
1292 execute(q
1293 % text(ident.inner()())
1294 % text(base.inner()())
1295 % text(checksum())
1296 % blob(del_packed()));
1297}
1298
1299
1300// static ticker cache_hits("vcache hits", "h", 1);
1301
1302struct datasz
1303{
1304 unsigned long operator()(data const & t) { return t().size(); }
1305};
1306
1307static LRUWritebackCache<string, data, datasz>
1308vcache(constants::db_version_cache_sz);
1309
1310struct file_and_manifest_reconstruction_graph : public reconstruction_graph
1311{
1312 database & db;
1313 string const & data_table;
1314 string const & delta_table;
1315
1316 file_and_manifest_reconstruction_graph(database & db,
1317 string const & data_table,
1318 string const & delta_table)
1319 : db(db), data_table(data_table), delta_table(delta_table)
1320 {}
1321 virtual bool is_base(std::string const & node) const
1322 {
1323 return vcache.exists(node)
1324 || db.file_or_manifest_base_exists(hexenc<id>(node), data_table);
1325 }
1326 virtual void get_next(std::string const & from, std::set<std::string> & next) const
1327 {
1328 next.clear();
1329 database::results res;
1330 query q("SELECT base FROM " + delta_table + " WHERE id = ?");
1331 db.fetch(res, one_col, any_rows, q % text(from));
1332 for (database::results::const_iterator i = res.begin(); i != res.end(); ++i)
1333 next.insert((*i)[0]);
1334 }
1335};
1336
1337// used for files and legacy manifest migration
1338void
1339database::get_version(hexenc<id> const & ident,
1340 data & dat,
1341 string const & data_table,
1342 string const & delta_table)
1343{
1344 I(ident() != "");
1345
1346 reconstruction_path selected_path;
1347 {
1348 file_and_manifest_reconstruction_graph graph(*this, data_table, delta_table);
1349 get_reconstruction_path(ident(), graph, selected_path);
1350 }
1351
1352 I(!selected_path.empty());
1353
1354 hexenc<id> curr = hexenc<id>(selected_path.back());
1355 selected_path.pop_back();
1356 data begin;
1357
1358 if (vcache.exists(curr()))
1359 I(vcache.fetch(curr(), begin));
1360 else
1361 get_file_or_manifest_base_unchecked(curr, begin, data_table);
1362
1363 shared_ptr<delta_applicator> appl = new_piecewise_applicator();
1364 appl->begin(begin());
1365
1366 for (reconstruction_path::reverse_iterator i = selected_path.rbegin();
1367 i != selected_path.rend(); ++i)
1368 {
1369 hexenc<id> const nxt = hexenc<id>(*i);
1370
1371 if (!vcache.exists(curr()))
1372 {
1373 string tmp;
1374 appl->finish(tmp);
1375 vcache.insert_clean(curr(), data(tmp));
1376 }
1377
1378 L(FL("following delta %s -> %s") % curr % nxt);
1379 delta del;
1380 get_file_or_manifest_delta_unchecked(nxt, curr, del, delta_table);
1381 apply_delta(appl, del());
1382
1383 appl->next();
1384 curr = nxt;
1385 }
1386
1387 string tmp;
1388 appl->finish(tmp);
1389 dat = data(tmp);
1390
1391 hexenc<id> final;
1392 calculate_ident(dat, final);
1393 I(final == ident);
1394
1395 if (!vcache.exists(ident()))
1396 vcache.insert_clean(ident(), dat);
1397}
1398
1399struct roster_reconstruction_graph : public reconstruction_graph
1400{
1401 database & db;
1402 roster_reconstruction_graph(database & db) : db(db) {}
1403 virtual bool is_base(std::string const & node) const
1404 {
1405 return db.roster_base_available(revision_id(node));
1406 }
1407 virtual void get_next(std::string const & from, std::set<std::string> & next) const
1408 {
1409 next.clear();
1410 database::results res;
1411 query q("SELECT base FROM roster_deltas WHERE id = ?");
1412 db.fetch(res, one_col, any_rows, q % text(from));
1413 for (database::results::const_iterator i = res.begin(); i != res.end(); ++i)
1414 next.insert((*i)[0]);
1415 }
1416};
1417
1418struct database::extractor
1419{
1420 virtual bool look_at_delta(roster_delta const & del) = 0;
1421 virtual void look_at_roster(roster_t const & roster, marking_map const & mm) = 0;
1422 virtual ~extractor() {};
1423};
1424
1425struct database::markings_extractor : public database::extractor
1426{
1427private:
1428 node_id const & nid;
1429 marking_t & markings;
1430
1431public:
1432 markings_extractor(node_id const & _nid, marking_t & _markings) :
1433 nid(_nid), markings(_markings) {} ;
1434
1435 bool look_at_delta(roster_delta const & del)
1436 {
1437 return try_get_markings_from_roster_delta(del, nid, markings);
1438 }
1439
1440 void look_at_roster(roster_t const & roster, marking_map const & mm)
1441 {
1442 marking_map::const_iterator mmi =
1443 mm.find(nid);
1444 I(mmi != mm.end());
1445 markings = mmi->second;
1446 }
1447};
1448
1449struct database::file_content_extractor : database::extractor
1450{
1451private:
1452 node_id const & nid;
1453 file_id & content;
1454
1455public:
1456 file_content_extractor(node_id const & _nid, file_id & _content) :
1457 nid(_nid), content(_content) {} ;
1458
1459 bool look_at_delta(roster_delta const & del)
1460 {
1461 return try_get_content_from_roster_delta(del, nid, content);
1462 }
1463
1464 void look_at_roster(roster_t const & roster, marking_map const & mm)
1465 {
1466 if (roster.has_node(nid))
1467 content = downcast_to_file_t(roster.get_node(nid))->content;
1468 else
1469 content = file_id();
1470 }
1471};
1472
1473void
1474database::extract_from_deltas(revision_id const & id, extractor & x)
1475{
1476 reconstruction_path selected_path;
1477 {
1478 roster_reconstruction_graph graph(*this);
1479 {
1480 // we look at the nearest delta(s) first, without constructing the
1481 // whole path, as that would be a rather expensive operation.
1482 //
1483 // the reason why this strategy is worth the effort is, that in most
1484 // cases we are looking at the parent of a (content-)marked node, thus
1485 // the information we are for is right there in the delta leading to
1486 // this node.
1487 //
1488 // recording the deltas visited here in a set as to avoid inspecting
1489 // them later seems to be of little value, as it imposes a cost here,
1490 // but can seldom be exploited.
1491 set<string> deltas;
1492 graph.get_next(id.inner()(), deltas);
1493 for (set<string>::const_iterator i = deltas.begin();
1494 i != deltas.end(); ++i)
1495 {
1496 roster_delta del;
1497 get_roster_delta(id.inner()(), *i, del);
1498 bool found = x.look_at_delta(del);
1499 if (found)
1500 return;
1501 }
1502 }
1503 get_reconstruction_path(id.inner()(), graph, selected_path);
1504 }
1505
1506 int path_length(selected_path.size());
1507 int i(0);
1508 string target_rev;
1509
1510 for (reconstruction_path::const_iterator p = selected_path.begin();
1511 p != selected_path.end(); ++p)
1512 {
1513 if (i > 0)
1514 {
1515 roster_delta del;
1516 get_roster_delta(target_rev, *p, del);
1517 bool found = x.look_at_delta(del);
1518 if (found)
1519 return;
1520 }
1521 if (i == path_length-1)
1522 {
1523 // last iteration, we have reached a roster base
1524 roster_t roster;
1525 marking_map mm;
1526 get_roster_base(*p, roster, mm);
1527 x.look_at_roster(roster, mm);
1528 return;
1529 }
1530 target_rev = *p;
1531 ++i;
1532 }
1533}
1534
1535void
1536database::get_markings(revision_id const & id,
1537 node_id const & nid,
1538 marking_t & markings)
1539{
1540 markings_extractor x(nid, markings);
1541 extract_from_deltas(id, x);
1542}
1543
1544void
1545database::get_file_content(revision_id const & id,
1546 node_id const & nid,
1547 file_id & content)
1548{
1549 // the imaginary root revision doesn't have any file.
1550 if (null_id(id))
1551 {
1552 content = file_id();
1553 return;
1554 }
1555 file_content_extractor x(nid, content);
1556 extract_from_deltas(id, x);
1557}
1558
1559void
1560database::get_roster_version(revision_id const & id,
1561 cached_roster & cr)
1562{
1563 // if we already have it, exit early
1564 if (roster_cache.exists(id))
1565 {
1566 roster_cache.fetch(id, cr);
1567 return;
1568 }
1569
1570 reconstruction_path selected_path;
1571 {
1572 roster_reconstruction_graph graph(*this);
1573 get_reconstruction_path(id.inner()(), graph, selected_path);
1574 }
1575
1576 string curr = selected_path.back();
1577 selected_path.pop_back();
1578 // we know that this isn't already in the cache (because of the early exit
1579 // above), so we should create new objects and spend time filling them in.
1580 shared_ptr<roster_t> roster(new roster_t);
1581 shared_ptr<marking_map> marking(new marking_map);
1582 get_roster_base(curr, *roster, *marking);
1583
1584 for (reconstruction_path::reverse_iterator i = selected_path.rbegin();
1585 i != selected_path.rend(); ++i)
1586 {
1587 string const nxt = *i;
1588 L(FL("following delta %s -> %s") % curr % nxt);
1589 roster_delta del;
1590 get_roster_delta(nxt, curr, del);
1591 apply_roster_delta(del, *roster, *marking);
1592 curr = nxt;
1593 }
1594
1595 // Double-check that the thing we got out looks okay. We know that when
1596 // the roster was written to the database, it passed both of these tests,
1597 // and we also know that the data on disk has passed our checks for data
1598 // corruption -- so in theory, we know that what we got out is exactly
1599 // what we put in, and these checks are redundant. (They cannot catch all
1600 // possible errors in any case, e.g., they don't test that the marking is
1601 // correct.) What they can do, though, is serve as a sanity check on the
1602 // delta reconstruction code; if there is a bug where we put something
1603 // into the database and then later get something different back out, then
1604 // this is the only thing that can catch it.
1605 roster->check_sane_against(*marking);
1606 manifest_id expected_mid, actual_mid;
1607 get_revision_manifest(id, expected_mid);
1608 calculate_ident(*roster, actual_mid);
1609 I(expected_mid == actual_mid);
1610
1611 // const'ify the objects, to save them and pass them out
1612 cr.first = roster;
1613 cr.second = marking;
1614 roster_cache.insert_clean(id, cr);
1615}
1616
1617
1618void
1619database::drop(string const & ident,
1620 string const & table)
1621{
1622 string drop = "DELETE FROM " + table + " WHERE id = ?";
1623 execute(query(drop) % text(ident));
1624}
1625
1626// ------------------------------------------------------------
1627// -- --
1628// -- public interface follows --
1629// -- --
1630// ------------------------------------------------------------
1631
1632bool
1633database::file_version_exists(file_id const & id)
1634{
1635 return delta_exists(id.inner()(), "file_deltas")
1636 || file_or_manifest_base_exists(id.inner(), "files");
1637}
1638
1639bool
1640database::roster_version_exists(revision_id const & id)
1641{
1642 return delta_exists(id.inner()(), "roster_deltas")
1643 || roster_base_available(id);
1644}
1645
1646bool
1647database::revision_exists(revision_id const & id)
1648{
1649 results res;
1650 query q("SELECT id FROM revisions WHERE id = ?");
1651 fetch(res, one_col, any_rows, q % text(id.inner()()));
1652 I(res.size() <= 1);
1653 return res.size() == 1;
1654}
1655
1656void
1657database::get_file_ids(set<file_id> & ids)
1658{
1659 ids.clear();
1660 set< hexenc<id> > tmp;
1661 get_ids("files", tmp);
1662 get_ids("file_deltas", tmp);
1663 add_decoration_to_container(tmp, ids);
1664}
1665
1666void
1667database::get_revision_ids(set<revision_id> & ids)
1668{
1669 ids.clear();
1670 set< hexenc<id> > tmp;
1671 get_ids("revisions", tmp);
1672 add_decoration_to_container(tmp, ids);
1673}
1674
1675void
1676database::get_roster_ids(set<revision_id> & ids)
1677{
1678 ids.clear();
1679 set< hexenc<id> > tmp;
1680 get_ids("rosters", tmp);
1681 add_decoration_to_container(tmp, ids);
1682 get_ids("roster_deltas", tmp);
1683 add_decoration_to_container(tmp, ids);
1684}
1685
1686void
1687database::get_file_version(file_id const & id,
1688 file_data & dat)
1689{
1690 data tmp;
1691 get_version(id.inner(), tmp, "files", "file_deltas");
1692 dat = file_data(tmp);
1693}
1694
1695void
1696database::get_manifest_version(manifest_id const & id,
1697 manifest_data & dat)
1698{
1699 data tmp;
1700 get_version(id.inner(), tmp, "manifests", "manifest_deltas");
1701 dat = manifest_data(tmp);
1702}
1703
1704void
1705database::put_file(file_id const & id,
1706 file_data const & dat)
1707{
1708 if (file_version_exists(id))
1709 L(FL("file version '%s' already exists in db") % id);
1710 else
1711 schedule_delayed_file(id, dat);
1712}
1713
1714void
1715database::put_file_version(file_id const & old_id,
1716 file_id const & new_id,
1717 file_delta const & del)
1718{
1719 I(!(old_id == new_id));
1720 file_data old_data, new_data;
1721 file_delta reverse_delta;
1722
1723 if (!file_version_exists(old_id))
1724 {
1725 W(F("file preimage '%s' missing in db") % old_id);
1726 W(F("dropping delta '%s' -> '%s'") % old_id % new_id);
1727 return;
1728 }
1729
1730 get_file_version(old_id, old_data);
1731 {
1732 data tmp;
1733 patch(old_data.inner(), del.inner(), tmp);
1734 new_data = file_data(tmp);
1735 }
1736
1737 {
1738 string tmp;
1739 invert_xdelta(old_data.inner()(), del.inner()(), tmp);
1740 reverse_delta = file_delta(tmp);
1741 data old_tmp;
1742 patch(new_data.inner(), reverse_delta.inner(), old_tmp);
1743 // We already have the real old data, so compare the
1744 // reconstruction to that directly instead of hashing
1745 // the reconstruction and comparing hashes.
1746 I(old_tmp == old_data.inner());
1747 }
1748
1749 transaction_guard guard(*this);
1750 if (file_or_manifest_base_exists(old_id.inner(), "files"))
1751 {
1752 // descendent of a head version replaces the head, therefore old head
1753 // must be disposed of
1754 drop_or_cancel_file(old_id);
1755 }
1756 if (!file_or_manifest_base_exists(new_id.inner(), "files"))
1757 {
1758 schedule_delayed_file(new_id, new_data);
1759 drop(new_id.inner()(), "file_deltas");
1760 }
1761
1762 if (!delta_exists(old_id.inner()(), new_id.inner()(), "file_deltas"))
1763 {
1764 put_file_delta(old_id, new_id, reverse_delta);
1765 guard.commit();
1766 }
1767}
1768
1769void
1770database::get_arbitrary_file_delta(file_id const & src_id,
1771 file_id const & dst_id,
1772 file_delta & del)
1773{
1774 delta dtmp;
1775 // Deltas stored in the database go from base -> id.
1776 results res;
1777 query q1("SELECT delta FROM file_deltas "
1778 "WHERE base = ? AND id = ?");
1779 fetch(res, one_col, any_rows,
1780 q1 % text(src_id.inner()()) % text(dst_id.inner()()));
1781
1782 if (!res.empty())
1783 {
1784 // Exact hit: a plain delta from src -> dst.
1785 gzip<delta> del_packed(res[0][0]);
1786 decode_gzip(del_packed, dtmp);
1787 del = file_delta(dtmp);
1788 return;
1789 }
1790
1791 query q2("SELECT delta FROM file_deltas "
1792 "WHERE base = ? AND id = ?");
1793 fetch(res, one_col, any_rows,
1794 q2 % text(dst_id.inner()()) % text(src_id.inner()()));
1795
1796 if (!res.empty())
1797 {
1798 // We have a delta from dst -> src; we need to
1799 // invert this to a delta from src -> dst.
1800 gzip<delta> del_packed(res[0][0]);
1801 decode_gzip(del_packed, dtmp);
1802 string fwd_delta;
1803 file_data dst;
1804 get_file_version(dst_id, dst);
1805 invert_xdelta(dst.inner()(), dtmp(), fwd_delta);
1806 del = file_delta(fwd_delta);
1807 return;
1808 }
1809
1810 // No deltas of use; just load both versions and diff.
1811 file_data fd1, fd2;
1812 get_file_version(src_id, fd1);
1813 get_file_version(dst_id, fd2);
1814 diff(fd1.inner(), fd2.inner(), dtmp);
1815 del = file_delta(dtmp);
1816}
1817
1818
1819void
1820database::get_revision_ancestry(rev_ancestry_map & graph)
1821{
1822 // share some storage
1823 id::symtab id_syms;
1824
1825 results res;
1826 graph.clear();
1827 fetch(res, 2, any_rows,
1828 query("SELECT parent,child FROM revision_ancestry"));
1829 for (size_t i = 0; i < res.size(); ++i)
1830 graph.insert(make_pair(revision_id(res[i][0]),
1831 revision_id(res[i][1])));
1832}
1833
1834void
1835database::get_revision_parents(revision_id const & id,
1836 set<revision_id> & parents)
1837{
1838 I(!null_id(id));
1839 results res;
1840 parents.clear();
1841 fetch(res, one_col, any_rows,
1842 query("SELECT parent FROM revision_ancestry WHERE child = ?")
1843 % text(id.inner()()));
1844 for (size_t i = 0; i < res.size(); ++i)
1845 parents.insert(revision_id(res[i][0]));
1846}
1847
1848void
1849database::get_revision_children(revision_id const & id,
1850 set<revision_id> & children)
1851{
1852 results res;
1853 children.clear();
1854 fetch(res, one_col, any_rows,
1855 query("SELECT child FROM revision_ancestry WHERE parent = ?")
1856 % text(id.inner()()));
1857 for (size_t i = 0; i < res.size(); ++i)
1858 children.insert(revision_id(res[i][0]));
1859}
1860
1861void
1862database::get_revision_manifest(revision_id const & rid,
1863 manifest_id & mid)
1864{
1865 revision_t rev;
1866 get_revision(rid, rev);
1867 mid = rev.new_manifest;
1868}
1869
1870void
1871database::get_revision(revision_id const & id,
1872 revision_t & rev)
1873{
1874 revision_data d;
1875 get_revision(id, d);
1876 read_revision(d, rev);
1877}
1878
1879void
1880database::get_revision(revision_id const & id,
1881 revision_data & dat)
1882{
1883 I(!null_id(id));
1884 results res;
1885 fetch(res, one_col, one_row,
1886 query("SELECT data FROM revisions WHERE id = ?")
1887 % text(id.inner()()));
1888
1889 gzip<data> gzdata(res[0][0]);
1890 data rdat;
1891 decode_gzip(gzdata,rdat);
1892
1893 // verify that we got a revision with the right id
1894 {
1895 revision_id tmp;
1896 calculate_ident(revision_data(rdat), tmp);
1897 I(id == tmp);
1898 }
1899
1900 dat = revision_data(rdat);
1901}
1902
1903void
1904database::get_rev_height(revision_id const & id,
1905 rev_height & height)
1906{
1907 if (null_id(id))
1908 {
1909 height = rev_height::root_height();
1910 return;
1911 }
1912
1913 results res;
1914 fetch(res, one_col, one_row,
1915 query("SELECT height FROM heights WHERE revision = ?")
1916 % text(id.inner()()));
1917
1918 I(res.size() == 1);
1919
1920 height = rev_height(res[0][0]);
1921 I(height.valid());
1922}
1923
1924void
1925database::put_rev_height(revision_id const & id,
1926 rev_height const & height)
1927{
1928 I(!null_id(id));
1929 I(revision_exists(id));
1930 I(height.valid());
1931
1932 execute(query("INSERT INTO heights VALUES(?, ?)")
1933 % text(id.inner()())
1934 % blob(height()));
1935}
1936
1937bool
1938database::has_rev_height(rev_height const & height)
1939{
1940 results res;
1941 fetch(res, one_col, any_rows,
1942 query("SELECT height FROM heights WHERE height = ?")
1943 % blob(height()));
1944 I((res.size() == 1) || (res.size() == 0));
1945 return res.size() == 1;
1946}
1947
1948void
1949database::deltify_revision(revision_id const & rid)
1950{
1951 transaction_guard guard(*this);
1952 revision_t rev;
1953 MM(rev);
1954 MM(rid);
1955 get_revision(rid, rev);
1956 // Make sure that all parent revs have their files replaced with deltas
1957 // from this rev's files.
1958 {
1959 for (edge_map::const_iterator i = rev.edges.begin();
1960 i != rev.edges.end(); ++i)
1961 {
1962 for (map<file_path, pair<file_id, file_id> >::const_iterator
1963 j = edge_changes(i).deltas_applied.begin();
1964 j != edge_changes(i).deltas_applied.end(); ++j)
1965 {
1966 if (file_or_manifest_base_exists(delta_entry_src(j).inner(), "files") &&
1967 file_version_exists(delta_entry_dst(j)))
1968 {
1969 file_data old_data;
1970 file_data new_data;
1971 get_file_version(delta_entry_src(j), old_data);
1972 get_file_version(delta_entry_dst(j), new_data);
1973 delta delt;
1974 diff(old_data.inner(), new_data.inner(), delt);
1975 file_delta del(delt);
1976 drop_or_cancel_file(delta_entry_dst(j));
1977 drop(delta_entry_dst(j).inner()(), "file_deltas");
1978 put_file_version(delta_entry_src(j), delta_entry_dst(j), del);
1979 }
1980 }
1981 }
1982 }
1983 guard.commit();
1984}
1985
1986
1987bool
1988database::put_revision(revision_id const & new_id,
1989 revision_t const & rev)
1990{
1991 MM(new_id);
1992 MM(rev);
1993
1994 I(!null_id(new_id));
1995
1996 if (revision_exists(new_id))
1997 {
1998 L(FL("revision '%s' already exists in db") % new_id);
1999 return false;
2000 }
2001
2002 I(rev.made_for == made_for_database);
2003 rev.check_sane();
2004
2005 // Phase 1: confirm the revision makes sense, and we the required files
2006 // actually exist
2007 for (edge_map::const_iterator i = rev.edges.begin();
2008 i != rev.edges.end(); ++i)
2009 {
2010 if (!edge_old_revision(i).inner()().empty()
2011 && !revision_exists(edge_old_revision(i)))
2012 {
2013 W(F("missing prerequisite revision '%s'") % edge_old_revision(i));
2014 W(F("dropping revision '%s'") % new_id);
2015 return false;
2016 }
2017
2018 for (map<file_path, file_id>::const_iterator a
2019 = edge_changes(i).files_added.begin();
2020 a != edge_changes(i).files_added.end(); ++a)
2021 {
2022 if (! file_version_exists(a->second))
2023 {
2024 W(F("missing prerequisite file '%s'") % a->second);
2025 W(F("dropping revision '%s'") % new_id);
2026 return false;
2027 }
2028 }
2029
2030 for (map<file_path, pair<file_id, file_id> >::const_iterator d
2031 = edge_changes(i).deltas_applied.begin();
2032 d != edge_changes(i).deltas_applied.end(); ++d)
2033 {
2034 I(!delta_entry_src(d).inner()().empty());
2035 I(!delta_entry_dst(d).inner()().empty());
2036
2037 if (! file_version_exists(delta_entry_src(d)))
2038 {
2039 W(F("missing prerequisite file pre-delta '%s'")
2040 % delta_entry_src(d));
2041 W(F("dropping revision '%s'") % new_id);
2042 return false;
2043 }
2044
2045 if (! file_version_exists(delta_entry_dst(d)))
2046 {
2047 W(F("missing prerequisite file post-delta '%s'")
2048 % delta_entry_dst(d));
2049 W(F("dropping revision '%s'") % new_id);
2050 return false;
2051 }
2052 }
2053 }
2054
2055 transaction_guard guard(*this);
2056
2057 // Phase 2: Write the revision data (inside a transaction)
2058
2059 revision_data d;
2060 write_revision(rev, d);
2061 gzip<data> d_packed;
2062 encode_gzip(d.inner(), d_packed);
2063 execute(query("INSERT INTO revisions VALUES(?, ?)")
2064 % text(new_id.inner()())
2065 % blob(d_packed()));
2066
2067 for (edge_map::const_iterator e = rev.edges.begin();
2068 e != rev.edges.end(); ++e)
2069 {
2070 execute(query("INSERT INTO revision_ancestry VALUES(?, ?)")
2071 % text(edge_old_revision(e).inner()())
2072 % text(new_id.inner()()));
2073 }
2074
2075 // Phase 3: Construct and write the roster (which also checks the manifest
2076 // id as it goes)
2077
2078 put_roster_for_revision(new_id, rev);
2079
2080 // Phase 4: rewrite any files that need deltas added
2081
2082 deltify_revision(new_id);
2083
2084 // Phase 5: determine the revision height
2085
2086 put_height_for_revision(new_id, rev);
2087
2088 // Finally, commit.
2089
2090 guard.commit();
2091 return true;
2092}
2093
2094void
2095database::put_height_for_revision(revision_id const & new_id,
2096 revision_t const & rev)
2097{
2098 I(!null_id(new_id));
2099
2100 rev_height highest_parent;
2101 // we always branch off the highest parent ...
2102 for (edge_map::const_iterator e = rev.edges.begin();
2103 e != rev.edges.end(); ++e)
2104 {
2105 rev_height parent; MM(parent);
2106 get_rev_height(edge_old_revision(e), parent);
2107 if (parent > highest_parent)
2108 {
2109 highest_parent = parent;
2110 }
2111 }
2112
2113 // ... then find the first unused child
2114 u32 childnr(0);
2115 rev_height candidate; MM(candidate);
2116 while(true)
2117 {
2118 candidate = highest_parent.child_height(childnr);
2119 if (!has_rev_height(candidate))
2120 {
2121 break;
2122 }
2123 I(childnr < std::numeric_limits<u32>::max());
2124 ++childnr;
2125 }
2126 put_rev_height(new_id, candidate);
2127}
2128
2129void
2130database::put_roster_for_revision(revision_id const & new_id,
2131 revision_t const & rev)
2132{
2133 // Construct, the roster, sanity-check the manifest id, and then write it
2134 // to the db
2135 shared_ptr<roster_t> ros_writeable(new roster_t); MM(*ros_writeable);
2136 shared_ptr<marking_map> mm_writeable(new marking_map); MM(*mm_writeable);
2137 manifest_id roster_manifest_id;
2138 MM(roster_manifest_id);
2139 make_roster_for_revision(rev, new_id, *ros_writeable, *mm_writeable, *__app);
2140 calculate_ident(*ros_writeable, roster_manifest_id);
2141 I(rev.new_manifest == roster_manifest_id);
2142 // const'ify the objects, suitable for caching etc.
2143 roster_t_cp ros = ros_writeable;
2144 marking_map_cp mm = mm_writeable;
2145 put_roster(new_id, ros, mm);
2146}
2147
2148bool
2149database::put_revision(revision_id const & new_id,
2150 revision_data const & dat)
2151{
2152 revision_t rev;
2153 read_revision(dat, rev);
2154 return put_revision(new_id, rev);
2155}
2156
2157
2158void
2159database::delete_existing_revs_and_certs()
2160{
2161 execute(query("DELETE FROM revisions"));
2162 execute(query("DELETE FROM revision_ancestry"));
2163 execute(query("DELETE FROM revision_certs"));
2164}
2165
2166void
2167database::delete_existing_manifests()
2168{
2169 execute(query("DELETE FROM manifests"));
2170 execute(query("DELETE FROM manifest_deltas"));
2171}
2172
2173void
2174database::delete_existing_rosters()
2175{
2176 execute(query("DELETE FROM rosters"));
2177 execute(query("DELETE FROM roster_deltas"));
2178 execute(query("DELETE FROM next_roster_node_number"));
2179}
2180
2181void
2182database::delete_existing_heights()
2183{
2184 execute(query("DELETE FROM heights"));
2185}
2186
2187/// Deletes one revision from the local database.
2188/// @see kill_rev_locally
2189void
2190database::delete_existing_rev_and_certs(revision_id const & rid)
2191{
2192 transaction_guard guard (*this);
2193
2194 // Check that the revision exists and doesn't have any children.
2195 I(revision_exists(rid));
2196 set<revision_id> children;
2197 get_revision_children(rid, children);
2198 I(children.empty());
2199
2200
2201 L(FL("Killing revision %s locally") % rid);
2202
2203 // Kill the certs, ancestry, and revision.
2204 execute(query("DELETE from revision_certs WHERE id = ?")
2205 % text(rid.inner()()));
2206 cert_stamper.note_change();
2207
2208 execute(query("DELETE from revision_ancestry WHERE child = ?")
2209 % text(rid.inner()()));
2210
2211 execute(query("DELETE from heights WHERE revision = ?")
2212 % text(rid.inner()()));
2213
2214 execute(query("DELETE from revisions WHERE id = ?")
2215 % text(rid.inner()()));
2216
2217 guard.commit();
2218}
2219
2220/// Deletes all certs referring to a particular branch.
2221void
2222database::delete_branch_named(cert_value const & branch)
2223{
2224 L(FL("Deleting all references to branch %s") % branch);
2225 execute(query("DELETE FROM revision_certs WHERE name='branch' AND value =?")
2226 % blob(branch()));
2227 cert_stamper.note_change();
2228 execute(query("DELETE FROM branch_epochs WHERE branch=?")
2229 % blob(branch()));
2230}
2231
2232/// Deletes all certs referring to a particular tag.
2233void
2234database::delete_tag_named(cert_value const & tag)
2235{
2236 L(FL("Deleting all references to tag %s") % tag);
2237 execute(query("DELETE FROM revision_certs WHERE name='tag' AND value =?")
2238 % blob(tag()));
2239 cert_stamper.note_change();
2240}
2241
2242// crypto key management
2243
2244void
2245database::get_key_ids(string const & pattern,
2246 vector<rsa_keypair_id> & pubkeys)
2247{
2248 pubkeys.clear();
2249 results res;
2250
2251 if (pattern != "")
2252 fetch(res, one_col, any_rows,
2253 query("SELECT id FROM public_keys WHERE id GLOB ?")
2254 % text(pattern));
2255 else
2256 fetch(res, one_col, any_rows,
2257 query("SELECT id FROM public_keys"));
2258
2259 for (size_t i = 0; i < res.size(); ++i)
2260 pubkeys.push_back(rsa_keypair_id(res[i][0]));
2261}
2262
2263void
2264database::get_keys(string const & table, vector<rsa_keypair_id> & keys)
2265{
2266 keys.clear();
2267 results res;
2268 fetch(res, one_col, any_rows, query("SELECT id FROM " + table));
2269 for (size_t i = 0; i < res.size(); ++i)
2270 keys.push_back(rsa_keypair_id(res[i][0]));
2271}
2272
2273void
2274database::get_public_keys(vector<rsa_keypair_id> & keys)
2275{
2276 get_keys("public_keys", keys);
2277}
2278
2279bool
2280database::public_key_exists(hexenc<id> const & hash)
2281{
2282 results res;
2283 fetch(res, one_col, any_rows,
2284 query("SELECT id FROM public_keys WHERE hash = ?")
2285 % text(hash()));
2286 I((res.size() == 1) || (res.size() == 0));
2287 if (res.size() == 1)
2288 return true;
2289 return false;
2290}
2291
2292bool
2293database::public_key_exists(rsa_keypair_id const & id)
2294{
2295 results res;
2296 fetch(res, one_col, any_rows,
2297 query("SELECT id FROM public_keys WHERE id = ?")
2298 % text(id()));
2299 I((res.size() == 1) || (res.size() == 0));
2300 if (res.size() == 1)
2301 return true;
2302 return false;
2303}
2304
2305void
2306database::get_pubkey(hexenc<id> const & hash,
2307 rsa_keypair_id & id,
2308 base64<rsa_pub_key> & pub_encoded)
2309{
2310 results res;
2311 fetch(res, 2, one_row,
2312 query("SELECT id, keydata FROM public_keys WHERE hash = ?")
2313 % text(hash()));
2314 id = rsa_keypair_id(res[0][0]);
2315 encode_base64(rsa_pub_key(res[0][1]), pub_encoded);
2316}
2317
2318void
2319database::get_key(rsa_keypair_id const & pub_id,
2320 base64<rsa_pub_key> & pub_encoded)
2321{
2322 results res;
2323 fetch(res, one_col, one_row,
2324 query("SELECT keydata FROM public_keys WHERE id = ?")
2325 % text(pub_id()));
2326 encode_base64(rsa_pub_key(res[0][0]), pub_encoded);
2327}
2328
2329bool
2330database::put_key(rsa_keypair_id const & pub_id,
2331 base64<rsa_pub_key> const & pub_encoded)
2332{
2333 if (public_key_exists(pub_id))
2334 {
2335 base64<rsa_pub_key> tmp;
2336 get_key(pub_id, tmp);
2337 if (!keys_match(pub_id, tmp, pub_id, pub_encoded))
2338 W(F("key '%s' is not equal to key '%s' in database") % pub_id % pub_id);
2339 L(FL("skipping existing public key %s") % pub_id);
2340 return false;
2341 }
2342
2343 L(FL("putting public key %s") % pub_id);
2344
2345 hexenc<id> thash;
2346 key_hash_code(pub_id, pub_encoded, thash);
2347 I(!public_key_exists(thash));
2348
2349 rsa_pub_key pub_key;
2350 decode_base64(pub_encoded, pub_key);
2351 execute(query("INSERT INTO public_keys VALUES(?, ?, ?)")
2352 % text(thash())
2353 % text(pub_id())
2354 % blob(pub_key()));
2355
2356 return true;
2357}
2358
2359void
2360database::delete_public_key(rsa_keypair_id const & pub_id)
2361{
2362 execute(query("DELETE FROM public_keys WHERE id = ?")
2363 % text(pub_id()));
2364}
2365
2366// cert management
2367
2368bool
2369database::cert_exists(cert const & t,
2370 string const & table)
2371{
2372 results res;
2373 cert_value value;
2374 decode_base64(t.value, value);
2375 rsa_sha1_signature sig;
2376 decode_base64(t.sig, sig);
2377 query q = query("SELECT id FROM " + table + " WHERE id = ? "
2378 "AND name = ? "
2379 "AND value = ? "
2380 "AND keypair = ? "
2381 "AND signature = ?")
2382 % text(t.ident())
2383 % text(t.name())
2384 % blob(value())
2385 % text(t.key())
2386 % blob(sig());
2387
2388 fetch(res, 1, any_rows, q);
2389
2390 I(res.size() == 0 || res.size() == 1);
2391 return res.size() == 1;
2392}
2393
2394void
2395database::put_cert(cert const & t,
2396 string const & table)
2397{
2398 hexenc<id> thash;
2399 cert_hash_code(t, thash);
2400 cert_value value;
2401 decode_base64(t.value, value);
2402 rsa_sha1_signature sig;
2403 decode_base64(t.sig, sig);
2404
2405 string insert = "INSERT INTO " + table + " VALUES(?, ?, ?, ?, ?, ?)";
2406
2407 execute(query(insert)
2408 % text(thash())
2409 % text(t.ident())
2410 % text(t.name())
2411 % blob(value())
2412 % text(t.key())
2413 % blob(sig()));
2414}
2415
2416void
2417database::results_to_certs(results const & res,
2418 vector<cert> & certs)
2419{
2420 certs.clear();
2421 for (size_t i = 0; i < res.size(); ++i)
2422 {
2423 cert t;
2424 base64<cert_value> value;
2425 encode_base64(cert_value(res[i][2]), value);
2426 base64<rsa_sha1_signature> sig;
2427 encode_base64(rsa_sha1_signature(res[i][4]), sig);
2428 t = cert(hexenc<id>(res[i][0]),
2429 cert_name(res[i][1]),
2430 value,
2431 rsa_keypair_id(res[i][3]),
2432 sig);
2433 certs.push_back(t);
2434 }
2435}
2436
2437void
2438database::install_functions(app_state * app)
2439{
2440 // register any functions we're going to use
2441 I(sqlite3_create_function(sql(), "gunzip", -1,
2442 SQLITE_UTF8, NULL,
2443 &sqlite3_gunzip_fn,
2444 NULL, NULL) == 0);
2445}
2446
2447void
2448database::get_certs(vector<cert> & certs,
2449 string const & table)
2450{
2451 results res;
2452 query q("SELECT id, name, value, keypair, signature FROM " + table);
2453 fetch(res, 5, any_rows, q);
2454 results_to_certs(res, certs);
2455}
2456
2457
2458void
2459database::get_certs(hexenc<id> const & ident,
2460 vector<cert> & certs,
2461 string const & table)
2462{
2463 results res;
2464 query q("SELECT id, name, value, keypair, signature FROM " + table +
2465 " WHERE id = ?");
2466
2467 fetch(res, 5, any_rows, q % text(ident()));
2468 results_to_certs(res, certs);
2469}
2470
2471
2472void
2473database::get_certs(cert_name const & name,
2474 vector<cert> & certs,
2475 string const & table)
2476{
2477 results res;
2478 query q("SELECT id, name, value, keypair, signature FROM " + table +
2479 " WHERE name = ?");
2480 fetch(res, 5, any_rows, q % text(name()));
2481 results_to_certs(res, certs);
2482}
2483
2484
2485void
2486database::get_certs(hexenc<id> const & ident,
2487 cert_name const & name,
2488 vector<cert> & certs,
2489 string const & table)
2490{
2491 results res;
2492 query q("SELECT id, name, value, keypair, signature FROM " + table +
2493 " WHERE id = ? AND name = ?");
2494
2495 fetch(res, 5, any_rows,
2496 q % text(ident())
2497 % text(name()));
2498 results_to_certs(res, certs);
2499}
2500
2501void
2502database::get_certs(cert_name const & name,
2503 base64<cert_value> const & val,
2504 vector<cert> & certs,
2505 string const & table)
2506{
2507 results res;
2508 query q("SELECT id, name, value, keypair, signature FROM " + table +
2509 " WHERE name = ? AND value = ?");
2510
2511 cert_value binvalue;
2512 decode_base64(val, binvalue);
2513 fetch(res, 5, any_rows,
2514 q % text(name())
2515 % blob(binvalue()));
2516 results_to_certs(res, certs);
2517}
2518
2519
2520void
2521database::get_certs(hexenc<id> const & ident,
2522 cert_name const & name,
2523 base64<cert_value> const & value,
2524 vector<cert> & certs,
2525 string const & table)
2526{
2527 results res;
2528 query q("SELECT id, name, value, keypair, signature FROM " + table +
2529 " WHERE id = ? AND name = ? AND value = ?");
2530
2531 cert_value binvalue;
2532 decode_base64(value, binvalue);
2533 fetch(res, 5, any_rows,
2534 q % text(ident())
2535 % text(name())
2536 % blob(binvalue()));
2537 results_to_certs(res, certs);
2538}
2539
2540
2541
2542bool
2543database::revision_cert_exists(revision<cert> const & cert)
2544{
2545 return cert_exists(cert.inner(), "revision_certs");
2546}
2547
2548bool
2549database::put_revision_cert(revision<cert> const & cert)
2550{
2551 if (revision_cert_exists(cert))
2552 {
2553 L(FL("revision cert on '%s' already exists in db")
2554 % cert.inner().ident);
2555 return false;
2556 }
2557
2558 if (!revision_exists(revision_id(cert.inner().ident)))
2559 {
2560 W(F("cert revision '%s' does not exist in db")
2561 % cert.inner().ident);
2562 W(F("dropping cert"));
2563 return false;
2564 }
2565
2566 put_cert(cert.inner(), "revision_certs");
2567 cert_stamper.note_change();
2568 return true;
2569}
2570
2571outdated_indicator
2572database::get_revision_cert_nobranch_index(vector< pair<hexenc<id>,
2573 pair<revision_id, rsa_keypair_id> > > & idx)
2574{
2575 // share some storage
2576 id::symtab id_syms;
2577
2578 results res;
2579 fetch(res, 3, any_rows,
2580 query("SELECT hash, id, keypair "
2581 "FROM 'revision_certs' WHERE name != 'branch'"));
2582
2583 idx.clear();
2584 idx.reserve(res.size());
2585 for (results::const_iterator i = res.begin(); i != res.end(); ++i)
2586 {
2587 idx.push_back(make_pair(hexenc<id>((*i)[0]),
2588 make_pair(revision_id((*i)[1]),
2589 rsa_keypair_id((*i)[2]))));
2590 }
2591 return cert_stamper.get_indicator();
2592}
2593
2594outdated_indicator
2595database::get_revision_certs(vector< revision<cert> > & ts)
2596{
2597 vector<cert> certs;
2598 get_certs(certs, "revision_certs");
2599 ts.clear();
2600 add_decoration_to_container(certs, ts);
2601 return cert_stamper.get_indicator();
2602}
2603
2604outdated_indicator
2605database::get_revision_certs(cert_name const & name,
2606 vector< revision<cert> > & ts)
2607{
2608 vector<cert> certs;
2609 get_certs(name, certs, "revision_certs");
2610 ts.clear();
2611 add_decoration_to_container(certs, ts);
2612 return cert_stamper.get_indicator();
2613}
2614
2615outdated_indicator
2616database::get_revision_certs(revision_id const & id,
2617 cert_name const & name,
2618 vector< revision<cert> > & ts)
2619{
2620 vector<cert> certs;
2621 get_certs(id.inner(), name, certs, "revision_certs");
2622 ts.clear();
2623 add_decoration_to_container(certs, ts);
2624 return cert_stamper.get_indicator();
2625}
2626
2627outdated_indicator
2628database::get_revision_certs(revision_id const & id,
2629 cert_name const & name,
2630 base64<cert_value> const & val,
2631 vector< revision<cert> > & ts)
2632{
2633 vector<cert> certs;
2634 get_certs(id.inner(), name, val, certs, "revision_certs");
2635 ts.clear();
2636 add_decoration_to_container(certs, ts);
2637 return cert_stamper.get_indicator();
2638}
2639
2640outdated_indicator
2641database::get_revisions_with_cert(cert_name const & name,
2642 base64<cert_value> const & val,
2643 set<revision_id> & revisions)
2644{
2645 revisions.clear();
2646 results res;
2647 query q("SELECT id FROM revision_certs WHERE name = ? AND value = ?");
2648 cert_value binvalue;
2649 decode_base64(val, binvalue);
2650 fetch(res, one_col, any_rows, q % text(name()) % blob(binvalue()));
2651 for (results::const_iterator i = res.begin(); i != res.end(); ++i)
2652 revisions.insert(revision_id((*i)[0]));
2653 return cert_stamper.get_indicator();
2654}
2655
2656outdated_indicator
2657database::get_revision_certs(cert_name const & name,
2658 base64<cert_value> const & val,
2659 vector< revision<cert> > & ts)
2660{
2661 vector<cert> certs;
2662 get_certs(name, val, certs, "revision_certs");
2663 ts.clear();
2664 add_decoration_to_container(certs, ts);
2665 return cert_stamper.get_indicator();
2666}
2667
2668outdated_indicator
2669database::get_revision_certs(revision_id const & id,
2670 vector< revision<cert> > & ts)
2671{
2672 vector<cert> certs;
2673 get_certs(id.inner(), certs, "revision_certs");
2674 ts.clear();
2675 add_decoration_to_container(certs, ts);
2676 return cert_stamper.get_indicator();
2677}
2678
2679outdated_indicator
2680database::get_revision_certs(revision_id const & ident,
2681 vector< hexenc<id> > & ts)
2682{
2683 results res;
2684 vector<cert> certs;
2685 fetch(res, one_col, any_rows,
2686 query("SELECT hash "
2687 "FROM revision_certs "
2688 "WHERE id = ?")
2689 % text(ident.inner()()));
2690 ts.clear();
2691 for (size_t i = 0; i < res.size(); ++i)
2692 ts.push_back(hexenc<id>(res[i][0]));
2693 return cert_stamper.get_indicator();
2694}
2695
2696void
2697database::get_revision_cert(hexenc<id> const & hash,
2698 revision<cert> & c)
2699{
2700 results res;
2701 vector<cert> certs;
2702 fetch(res, 5, one_row,
2703 query("SELECT id, name, value, keypair, signature "
2704 "FROM revision_certs "
2705 "WHERE hash = ?")
2706 % text(hash()));
2707 results_to_certs(res, certs);
2708 I(certs.size() == 1);
2709 c = revision<cert>(certs[0]);
2710}
2711
2712bool
2713database::revision_cert_exists(hexenc<id> const & hash)
2714{
2715 results res;
2716 vector<cert> certs;
2717 fetch(res, one_col, any_rows,
2718 query("SELECT id "
2719 "FROM revision_certs "
2720 "WHERE hash = ?")
2721 % text(hash()));
2722 I(res.size() == 0 || res.size() == 1);
2723 return (res.size() == 1);
2724}
2725
2726void
2727database::get_manifest_certs(manifest_id const & id,
2728 vector< manifest<cert> > & ts)
2729{
2730 vector<cert> certs;
2731 get_certs(id.inner(), certs, "manifest_certs");
2732 ts.clear();
2733 add_decoration_to_container(certs, ts);
2734}
2735
2736
2737void
2738database::get_manifest_certs(cert_name const & name,
2739 vector< manifest<cert> > & ts)
2740{
2741 vector<cert> certs;
2742 get_certs(name, certs, "manifest_certs");
2743 ts.clear();
2744 add_decoration_to_container(certs, ts);
2745}
2746
2747
2748// completions
2749void
2750database::complete(string const & partial,
2751 set<revision_id> & completions)
2752{
2753 results res;
2754 completions.clear();
2755
2756 string pattern = partial + "*";
2757
2758 fetch(res, 1, any_rows,
2759 query("SELECT id FROM revisions WHERE id GLOB ?")
2760 % text(pattern));
2761
2762 for (size_t i = 0; i < res.size(); ++i)
2763 completions.insert(revision_id(res[i][0]));
2764}
2765
2766
2767void
2768database::complete(string const & partial,
2769 set<file_id> & completions)
2770{
2771 results res;
2772 completions.clear();
2773
2774 string pattern = partial + "*";
2775
2776 fetch(res, 1, any_rows,
2777 query("SELECT id FROM files WHERE id GLOB ?")
2778 % text(pattern));
2779
2780 for (size_t i = 0; i < res.size(); ++i)
2781 completions.insert(file_id(res[i][0]));
2782
2783 res.clear();
2784
2785 fetch(res, 1, any_rows,
2786 query("SELECT id FROM file_deltas WHERE id GLOB ?")
2787 % text(pattern));
2788
2789 for (size_t i = 0; i < res.size(); ++i)
2790 completions.insert(file_id(res[i][0]));
2791}
2792
2793void
2794database::complete(string const & partial,
2795 set< pair<key_id, utf8 > > & completions)
2796{
2797 results res;
2798 completions.clear();
2799
2800 string pattern = partial + "*";
2801
2802 fetch(res, 2, any_rows,
2803 query("SELECT hash, id FROM public_keys WHERE hash GLOB ?")
2804 % text(pattern));
2805
2806 for (size_t i = 0; i < res.size(); ++i)
2807 completions.insert(make_pair(key_id(res[i][0]), utf8(res[i][1])));
2808}
2809
2810using selectors::selector_type;
2811
2812static void selector_to_certname(selector_type ty,
2813 cert_name & name,
2814 string & prefix,
2815 string & suffix)
2816{
2817 prefix = suffix = "*";
2818 switch (ty)
2819 {
2820 case selectors::sel_author:
2821 prefix = suffix = "";
2822 name = author_cert_name;
2823 break;
2824 case selectors::sel_branch:
2825 prefix = suffix = "";
2826 name = branch_cert_name;
2827 break;
2828 case selectors::sel_head:
2829 prefix = suffix = "";
2830 name = branch_cert_name;
2831 break;
2832 case selectors::sel_date:
2833 case selectors::sel_later:
2834 case selectors::sel_earlier:
2835 name = date_cert_name;
2836 break;
2837 case selectors::sel_tag:
2838 prefix = suffix = "";
2839 name = tag_cert_name;
2840 break;
2841 case selectors::sel_ident:
2842 case selectors::sel_cert:
2843 case selectors::sel_unknown:
2844 I(false); // don't do this.
2845 break;
2846 }
2847}
2848
2849void database::complete(selector_type ty,
2850 string const & partial,
2851 vector<pair<selector_type, string> > const & limit,
2852 set<string> & completions)
2853{
2854 //L(FL("database::complete for partial '%s'") % partial);
2855 completions.clear();
2856
2857 // step 1: the limit is transformed into an SQL select statement which
2858 // selects a set of IDs from the revision_certs table which match the
2859 // limit. this is done by building an SQL select statement for each term
2860 // in the limit and then INTERSECTing them all.
2861
2862 query lim;
2863 lim.sql_cmd = "(";
2864 if (limit.empty())
2865 {
2866 lim.sql_cmd += "SELECT id FROM revision_certs";
2867 }
2868 else
2869 {
2870 bool first_limit = true;
2871 for (vector<pair<selector_type, string> >::const_iterator i = limit.begin();
2872 i != limit.end(); ++i)
2873 {
2874 if (first_limit)
2875 first_limit = false;
2876 else
2877 lim.sql_cmd += " INTERSECT ";
2878
2879 if (i->first == selectors::sel_ident)
2880 {
2881 lim.sql_cmd += "SELECT id FROM revision_certs WHERE id GLOB ?";
2882 lim % text(i->second + "*");
2883 }
2884 else if (i->first == selectors::sel_cert)
2885 {
2886 if (i->second.length() > 0)
2887 {
2888 size_t spot = i->second.find("=");
2889
2890 if (spot != (size_t)-1)
2891 {
2892 string certname;
2893 string certvalue;
2894
2895 certname = i->second.substr(0, spot);
2896 spot++;
2897 certvalue = i->second.substr(spot);
2898 lim.sql_cmd += "SELECT id FROM revision_certs WHERE name=? AND CAST(value AS TEXT) glob ?";
2899 lim % text(certname) % text(certvalue);
2900 }
2901 else
2902 {
2903 lim.sql_cmd += "SELECT id FROM revision_certs WHERE name=?";
2904 lim % text(i->second);
2905 }
2906
2907 }
2908 }
2909 else if (i->first == selectors::sel_unknown)
2910 {
2911 lim.sql_cmd += "SELECT id FROM revision_certs WHERE (name=? OR name=? OR name=?)";
2912 lim % text(author_cert_name()) % text(tag_cert_name()) % text(branch_cert_name());
2913 lim.sql_cmd += " AND CAST(value AS TEXT) glob ?";
2914 lim % text(i->second + "*");
2915 }
2916 else if (i->first == selectors::sel_head)
2917 {
2918 // get branch names
2919 set<branch_name> branch_names;
2920 if (i->second.size() == 0)
2921 {
2922 __app->require_workspace("the empty head selector h: refers to the head of the current branch");
2923 branch_names.insert(__app->opts.branchname);
2924 }
2925 else
2926 {
2927 __app->get_project().get_branch_list(globish(i->second), branch_names);
2928 }
2929
2930 // for each branch name, get the branch heads
2931 set<revision_id> heads;
2932 for (set<branch_name>::const_iterator bn = branch_names.begin();
2933 bn != branch_names.end(); bn++)
2934 {
2935 set<revision_id> branch_heads;
2936 __app->get_project().get_branch_heads(*bn, branch_heads);
2937 heads.insert(branch_heads.begin(), branch_heads.end());
2938 L(FL("after get_branch_heads for %s, heads has %d entries") % (*bn) % heads.size());
2939 }
2940
2941 lim.sql_cmd += "SELECT id FROM revision_certs WHERE id IN (";
2942 if (heads.size())
2943 {
2944 set<revision_id>::const_iterator r = heads.begin();
2945 lim.sql_cmd += "?";
2946 lim % text(r->inner()());
2947 r++;
2948 while (r != heads.end())
2949 {
2950 lim.sql_cmd += ", ?";
2951 lim % text(r->inner()());
2952 r++;
2953 }
2954 }
2955 lim.sql_cmd += ") ";
2956 }
2957 else
2958 {
2959 cert_name certname;
2960 string prefix;
2961 string suffix;
2962 selector_to_certname(i->first, certname, prefix, suffix);
2963 L(FL("processing selector type %d with i->second '%s'") % ty % i->second);
2964 if ((i->first == selectors::sel_branch) && (i->second.size() == 0))
2965 {
2966 __app->require_workspace("the empty branch selector b: refers to the current branch");
2967 lim.sql_cmd += "SELECT id FROM revision_certs WHERE name=? AND CAST(value AS TEXT) glob ?";
2968 lim % text(branch_cert_name()) % text(__app->opts.branchname());
2969 L(FL("limiting to current branch '%s'") % __app->opts.branchname);
2970 }
2971 else
2972 {
2973 lim.sql_cmd += "SELECT id FROM revision_certs WHERE name=? AND ";
2974 lim % text(certname());
2975 switch (i->first)
2976 {
2977 case selectors::sel_earlier:
2978 lim.sql_cmd += "value <= ?";
2979 lim % blob(i->second);
2980 break;
2981 case selectors::sel_later:
2982 lim.sql_cmd += "value > ?";
2983 lim % blob(i->second);
2984 break;
2985 default:
2986 lim.sql_cmd += "CAST(value AS TEXT) glob ?";
2987 lim % text(prefix + i->second + suffix);
2988 break;
2989 }
2990 }
2991 }
2992 //L(FL("found selector type %d, selecting_head is now %d") % i->first % selecting_head);
2993 }
2994 }
2995 lim.sql_cmd += ")";
2996
2997 // step 2: depending on what we've been asked to disambiguate, we
2998 // will complete either some idents, or cert values, or "unknown"
2999 // which generally means "author, tag or branch"
3000
3001 if (ty == selectors::sel_ident)
3002 {
3003 lim.sql_cmd = "SELECT id FROM " + lim.sql_cmd;
3004 }
3005 else
3006 {
3007 string prefix = "*";
3008 string suffix = "*";
3009 lim.sql_cmd = "SELECT value FROM revision_certs WHERE";
3010 if (ty == selectors::sel_unknown)
3011 {
3012 lim.sql_cmd += " (name=? OR name=? OR name=?)";
3013 lim % text(author_cert_name()) % text(tag_cert_name()) % text(branch_cert_name());
3014 }
3015 else
3016 {
3017 cert_name certname;
3018 selector_to_certname(ty, certname, prefix, suffix);
3019 lim.sql_cmd += " (name=?)";
3020 lim % text(certname());
3021 }
3022
3023 lim.sql_cmd += " AND (CAST(value AS TEXT) GLOB ?) AND (id IN " + lim.sql_cmd + ")";
3024 lim % text(prefix + partial + suffix);
3025 }
3026
3027 results res;
3028 fetch(res, one_col, any_rows, lim);
3029 for (size_t i = 0; i < res.size(); ++i)
3030 {
3031 if (ty == selectors::sel_ident)
3032 completions.insert(res[i][0]);
3033 else
3034 {
3035 data row_decoded(res[i][0]);
3036 completions.insert(row_decoded());
3037 }
3038 }
3039}
3040
3041// epochs
3042
3043void
3044database::get_epochs(map<branch_name, epoch_data> & epochs)
3045{
3046 epochs.clear();
3047 results res;
3048 fetch(res, 2, any_rows, query("SELECT branch, epoch FROM branch_epochs"));
3049 for (results::const_iterator i = res.begin(); i != res.end(); ++i)
3050 {
3051 branch_name decoded(idx(*i, 0));
3052 I(epochs.find(decoded) == epochs.end());
3053 epochs.insert(make_pair(decoded, epoch_data(idx(*i, 1))));
3054 }
3055}
3056
3057void
3058database::get_epoch(epoch_id const & eid,
3059 branch_name & branch, epoch_data & epo)
3060{
3061 I(epoch_exists(eid));
3062 results res;
3063 fetch(res, 2, any_rows,
3064 query("SELECT branch, epoch FROM branch_epochs"
3065 " WHERE hash = ?")
3066 % text(eid.inner()()));
3067 I(res.size() == 1);
3068 branch = branch_name(idx(idx(res, 0), 0));
3069 epo = epoch_data(idx(idx(res, 0), 1));
3070}
3071
3072bool
3073database::epoch_exists(epoch_id const & eid)
3074{
3075 results res;
3076 fetch(res, one_col, any_rows,
3077 query("SELECT hash FROM branch_epochs WHERE hash = ?")
3078 % text(eid.inner()()));
3079 I(res.size() == 1 || res.size() == 0);
3080 return res.size() == 1;
3081}
3082
3083void
3084database::set_epoch(branch_name const & branch, epoch_data const & epo)
3085{
3086 epoch_id eid;
3087 epoch_hash_code(branch, epo, eid);
3088 I(epo.inner()().size() == constants::epochlen);
3089 execute(query("INSERT OR REPLACE INTO branch_epochs VALUES(?, ?, ?)")
3090 % text(eid.inner()())
3091 % blob(branch())
3092 % text(epo.inner()()));
3093}
3094
3095void
3096database::clear_epoch(branch_name const & branch)
3097{
3098 execute(query("DELETE FROM branch_epochs WHERE branch = ?")
3099 % blob(branch()));
3100}
3101
3102bool
3103database::check_integrity()
3104{
3105 results res;
3106 fetch(res, one_col, any_rows, query("PRAGMA integrity_check"));
3107 I(res.size() == 1);
3108 I(res[0].size() == 1);
3109
3110 return res[0][0] == "ok";
3111}
3112
3113// vars
3114
3115void
3116database::get_vars(map<var_key, var_value> & vars)
3117{
3118 vars.clear();
3119 results res;
3120 fetch(res, 3, any_rows, query("SELECT domain, name, value FROM db_vars"));
3121 for (results::const_iterator i = res.begin(); i != res.end(); ++i)
3122 {
3123 var_domain domain(idx(*i, 0));
3124 var_name name(idx(*i, 1));
3125 var_value value(idx(*i, 2));
3126 I(vars.find(make_pair(domain, name)) == vars.end());
3127 vars.insert(make_pair(make_pair(domain, name), value));
3128 }
3129}
3130
3131void
3132database::get_var(var_key const & key, var_value & value)
3133{
3134 // FIXME: sillyly inefficient. Doesn't really matter, though.
3135 map<var_key, var_value> vars;
3136 get_vars(vars);
3137 map<var_key, var_value>::const_iterator i = vars.find(key);
3138 I(i != vars.end());
3139 value = i->second;
3140}
3141
3142bool
3143database::var_exists(var_key const & key)
3144{
3145 // FIXME: sillyly inefficient. Doesn't really matter, though.
3146 map<var_key, var_value> vars;
3147 get_vars(vars);
3148 map<var_key, var_value>::const_iterator i = vars.find(key);
3149 return i != vars.end();
3150}
3151
3152void
3153database::set_var(var_key const & key, var_value const & value)
3154{
3155 execute(query("INSERT OR REPLACE INTO db_vars VALUES(?, ?, ?)")
3156 % text(key.first())
3157 % blob(key.second())
3158 % blob(value()));
3159}
3160
3161void
3162database::clear_var(var_key const & key)
3163{
3164 execute(query("DELETE FROM db_vars WHERE domain = ? AND name = ?")
3165 % text(key.first())
3166 % blob(key.second()));
3167}
3168
3169// branches
3170
3171outdated_indicator
3172database::get_branches(vector<string> & names)
3173{
3174 results res;
3175 query q("SELECT DISTINCT value FROM revision_certs WHERE name = ?");
3176 string cert_name = "branch";
3177 fetch(res, one_col, any_rows, q % text(cert_name));
3178 for (size_t i = 0; i < res.size(); ++i)
3179 {
3180 names.push_back(res[i][0]);
3181 }
3182 return cert_stamper.get_indicator();
3183}
3184
3185outdated_indicator
3186database::get_branches(string const & glob,
3187 vector<string> & names)
3188{
3189 results res;
3190 query q("SELECT DISTINCT value FROM revision_certs WHERE name = ? AND CAST(value AS TEXT) glob ?");
3191 string cert_name = "branch";
3192 fetch(res, one_col, any_rows, q % text(cert_name) % text(glob));
3193 for (size_t i = 0; i < res.size(); ++i)
3194 {
3195 names.push_back(res[i][0]);
3196 }
3197 return cert_stamper.get_indicator();
3198}
3199
3200void
3201database::get_roster(revision_id const & rev_id,
3202 roster_t & roster)
3203{
3204 marking_map mm;
3205 get_roster(rev_id, roster, mm);
3206}
3207
3208void
3209database::get_roster(revision_id const & rev_id,
3210 roster_t & roster,
3211 marking_map & marking)
3212{
3213 if (rev_id.inner()().empty())
3214 {
3215 roster = roster_t();
3216 marking = marking_map();
3217 return;
3218 }
3219
3220 cached_roster cr;
3221 get_roster(rev_id, cr);
3222 roster = *cr.first;
3223 marking = *cr.second;
3224}
3225
3226void
3227database::get_roster(revision_id const & rev_id,
3228 cached_roster & cr)
3229{
3230 get_roster_version(rev_id, cr);
3231 I(cr.first);
3232 I(cr.second);
3233}
3234
3235void
3236database::put_roster(revision_id const & rev_id,
3237 roster_t_cp const & roster,
3238 marking_map_cp const & marking)
3239{
3240 I(roster);
3241 I(marking);
3242 MM(rev_id);
3243
3244 transaction_guard guard(*this);
3245
3246 // Our task is to add this roster, and deltify all the incoming edges (if
3247 // they aren't already).
3248
3249 roster_cache.insert_dirty(rev_id, make_pair(roster, marking));
3250
3251 set<revision_id> parents;
3252 get_revision_parents(rev_id, parents);
3253
3254 // Now do what deltify would do if we bothered
3255 for (set<revision_id>::const_iterator i = parents.begin();
3256 i != parents.end(); ++i)
3257 {
3258 if (null_id(*i))
3259 continue;
3260 revision_id old_rev = *i;
3261 if (roster_base_stored(old_rev))
3262 {
3263 cached_roster cr;
3264 get_roster_version(old_rev, cr);
3265 roster_delta reverse_delta;
3266 delta_rosters(*roster, *marking, *(cr.first), *(cr.second), reverse_delta);
3267 if (roster_cache.exists(old_rev))
3268 roster_cache.mark_clean(old_rev);
3269 drop(old_rev.inner()(), "rosters");
3270 put_roster_delta(old_rev, rev_id, reverse_delta);
3271 }
3272 }
3273 guard.commit();
3274}
3275
3276// for get_uncommon_ancestors
3277struct rev_height_graph : rev_graph
3278{
3279 typedef hashmap::hash_map<revision_id, set<revision_id> > parent_map;
3280 typedef hashmap::hash_map<revision_id, rev_height> height_map;
3281 static parent_map parent_cache;
3282 static height_map height_cache;
3283 rev_height_graph(database & db) : db(db) {}
3284 virtual void get_parents(revision_id const & rev, set<revision_id> & parents) const
3285 {
3286 parent_map::iterator i = parent_cache.find(rev);
3287 if (i == parent_cache.end())
3288 {
3289 db.get_revision_parents(rev, parents);
3290 parent_cache.insert(make_pair(rev, parents));
3291 }
3292 else
3293 {
3294 parents = i->second;
3295 }
3296 }
3297 virtual void get_children(revision_id const & rev, set<revision_id> & parents) const
3298 {
3299 // not required
3300 I(false);
3301 }
3302 virtual void get_height(revision_id const & rev, rev_height & h) const
3303 {
3304 height_map::iterator i = height_cache.find(rev);
3305 if (i == height_cache.end())
3306 {
3307 db.get_rev_height(rev, h);
3308 height_cache.insert(make_pair(rev, h));
3309 }
3310 else
3311 {
3312 h = i->second;
3313 }
3314 }
3315
3316 database & db;
3317};
3318rev_height_graph::parent_map rev_height_graph::parent_cache;
3319rev_height_graph::height_map rev_height_graph::height_cache;
3320
3321void
3322database::get_uncommon_ancestors(revision_id const & a,
3323 revision_id const & b,
3324 set<revision_id> & a_uncommon_ancs,
3325 set<revision_id> & b_uncommon_ancs)
3326{
3327
3328 rev_height_graph graph(*this);
3329 ::get_uncommon_ancestors(a, b, graph, a_uncommon_ancs, b_uncommon_ancs);
3330}
3331
3332
3333u64
3334database::next_id_from_table(string const & table)
3335{
3336 transaction_guard guard(*this);
3337 results res;
3338
3339 // We implement this as a fixed db var.
3340
3341 fetch(res, one_col, any_rows,
3342 query(string("SELECT node FROM ") + table));
3343
3344 u64 n;
3345 if (res.empty())
3346 {
3347 n = 1;
3348 execute (query(string("INSERT INTO ") + table + " VALUES(?)")
3349 % text(lexical_cast<string>(n)));
3350 }
3351 else
3352 {
3353 I(res.size() == 1);
3354 n = lexical_cast<u64>(res[0][0]);
3355 ++n;
3356 execute(query(string("UPDATE ") + table + " SET node = ?")
3357 % text(lexical_cast<string>(n)));
3358
3359 }
3360 guard.commit();
3361 return n;
3362}
3363
3364node_id
3365database::next_node_id()
3366{
3367 return static_cast<node_id>(next_id_from_table("next_roster_node_number"));
3368}
3369
3370void
3371database::check_filename()
3372{
3373 N(!filename.empty(), F("no database specified"));
3374}
3375
3376
3377void
3378database::check_db_exists()
3379{
3380 switch (get_path_status(filename))
3381 {
3382 case path::nonexistent:
3383 N(false, F("database %s does not exist") % filename);
3384 break;
3385 case path::file:
3386 return;
3387 case path::directory:
3388 {
3389 system_path database_option;
3390 branch_name branch_option;
3391 rsa_keypair_id key_option;
3392 system_path keydir_option;
3393 if (workspace::get_ws_options_from_path(
3394 filename,
3395 database_option,
3396 branch_option,
3397 key_option,
3398 keydir_option))
3399 {
3400 N(database_option.empty(),
3401 F("You gave a database option of: \n"
3402 "%s\n"
3403 "That is actually a workspace. Did you mean: \n"
3404 "%s") % filename % database_option );
3405 }
3406 N(false, F("%s is a directory, not a database") % filename);
3407 }
3408 break;
3409 }
3410}
3411
3412void
3413database::check_db_nonexistent()
3414{
3415 require_path_is_nonexistent(filename,
3416 F("database %s already exists")
3417 % filename);
3418
3419 system_path journal(filename.as_internal() + "-journal");
3420 require_path_is_nonexistent(journal,
3421 F("existing (possibly stale) journal file '%s' "
3422 "has same stem as new database '%s'\n"
3423 "cancelling database creation")
3424 % journal % filename);
3425
3426}
3427
3428bool
3429database::database_specified()
3430{
3431 return !filename.empty();
3432}
3433
3434
3435void
3436database::open()
3437{
3438 I(!__sql);
3439
3440 if (sqlite3_open(filename.as_external().c_str(), &__sql) == SQLITE_NOMEM)
3441 throw std::bad_alloc();
3442
3443 I(__sql);
3444 assert_sqlite3_ok(__sql);
3445}
3446
3447void
3448database::close()
3449{
3450 I(__sql);
3451
3452 sqlite3_close(__sql);
3453 __sql = 0;
3454
3455 I(!__sql);
3456}
3457
3458// transaction guards
3459
3460transaction_guard::transaction_guard(database & d, bool exclusive,
3461 size_t checkpoint_batch_size,
3462 size_t checkpoint_batch_bytes)
3463 : committed(false), db(d), exclusive(exclusive),
3464 checkpoint_batch_size(checkpoint_batch_size),
3465 checkpoint_batch_bytes(checkpoint_batch_bytes),
3466 checkpointed_calls(0),
3467 checkpointed_bytes(0)
3468{
3469 db.begin_transaction(exclusive);
3470}
3471
3472transaction_guard::~transaction_guard()
3473{
3474 if (committed)
3475 db.commit_transaction();
3476 else
3477 db.rollback_transaction();
3478}
3479
3480void
3481transaction_guard::do_checkpoint()
3482{
3483 db.commit_transaction();
3484 db.begin_transaction(exclusive);
3485 checkpointed_calls = 0;
3486 checkpointed_bytes = 0;
3487}
3488
3489void
3490transaction_guard::maybe_checkpoint(size_t nbytes)
3491{
3492 checkpointed_calls += 1;
3493 checkpointed_bytes += nbytes;
3494 if (checkpointed_calls >= checkpoint_batch_size
3495 || checkpointed_bytes >= checkpoint_batch_bytes)
3496 do_checkpoint();
3497}
3498
3499void
3500transaction_guard::commit()
3501{
3502 committed = true;
3503}
3504
3505// Local Variables:
3506// mode: C++
3507// fill-column: 76
3508// c-file-style: "gnu"
3509// indent-tabs-mode: nil
3510// End:
3511// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:

Archive Download this file

Branches

Tags

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