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