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_leaves(set<revision_id> & leaves)
1864{
1865 results res;
1866 leaves.clear();
1867 fetch(res, one_col, any_rows,
1868 query("SELECT revisions.id FROM revisions "
1869 "LEFT JOIN revision_ancestry "
1870 "ON revisions.id = revision_ancestry.parent "
1871 "WHERE revision_ancestry.child IS null"));
1872 for (size_t i = 0; i < res.size(); ++i)
1873 leaves.insert(revision_id(res[i][0]));
1874}
1875
1876
1877void
1878database::get_revision_manifest(revision_id const & rid,
1879 manifest_id & mid)
1880{
1881 revision_t rev;
1882 get_revision(rid, rev);
1883 mid = rev.new_manifest;
1884}
1885
1886void
1887database::get_revision(revision_id const & id,
1888 revision_t & rev)
1889{
1890 revision_data d;
1891 get_revision(id, d);
1892 read_revision(d, rev);
1893}
1894
1895void
1896database::get_revision(revision_id const & id,
1897 revision_data & dat)
1898{
1899 I(!null_id(id));
1900 results res;
1901 fetch(res, one_col, one_row,
1902 query("SELECT data FROM revisions WHERE id = ?")
1903 % text(id.inner()()));
1904
1905 gzip<data> gzdata(res[0][0]);
1906 data rdat;
1907 decode_gzip(gzdata,rdat);
1908
1909 // verify that we got a revision with the right id
1910 {
1911 revision_id tmp;
1912 calculate_ident(revision_data(rdat), tmp);
1913 I(id == tmp);
1914 }
1915
1916 dat = revision_data(rdat);
1917}
1918
1919typedef std::map<revision_id, rev_height> height_map;
1920static height_map height_cache;
1921
1922void
1923database::get_rev_height(revision_id const & id,
1924 rev_height & height)
1925{
1926 if (null_id(id))
1927 {
1928 height = rev_height::root_height();
1929 return;
1930 }
1931
1932 height_map::const_iterator i = height_cache.find(id);
1933 if (i == height_cache.end())
1934 {
1935 results res;
1936 fetch(res, one_col, one_row,
1937 query("SELECT height FROM heights WHERE revision = ?")
1938 % text(id.inner()()));
1939
1940 I(res.size() == 1);
1941
1942 height = rev_height(res[0][0]);
1943 height_cache.insert(make_pair(id, height));
1944 }
1945 else
1946 {
1947 height = i->second;
1948 }
1949
1950 I(height.valid());
1951}
1952
1953void
1954database::put_rev_height(revision_id const & id,
1955 rev_height const & height)
1956{
1957 I(!null_id(id));
1958 I(revision_exists(id));
1959 I(height.valid());
1960
1961 height_cache.erase(id);
1962
1963 execute(query("INSERT INTO heights VALUES(?, ?)")
1964 % text(id.inner()())
1965 % blob(height()));
1966}
1967
1968bool
1969database::has_rev_height(rev_height const & height)
1970{
1971 results res;
1972 fetch(res, one_col, any_rows,
1973 query("SELECT height FROM heights WHERE height = ?")
1974 % blob(height()));
1975 I((res.size() == 1) || (res.size() == 0));
1976 return res.size() == 1;
1977}
1978
1979void
1980database::deltify_revision(revision_id const & rid)
1981{
1982 transaction_guard guard(*this);
1983 revision_t rev;
1984 MM(rev);
1985 MM(rid);
1986 get_revision(rid, rev);
1987 // Make sure that all parent revs have their files replaced with deltas
1988 // from this rev's files.
1989 {
1990 for (edge_map::const_iterator i = rev.edges.begin();
1991 i != rev.edges.end(); ++i)
1992 {
1993 for (map<file_path, pair<file_id, file_id> >::const_iterator
1994 j = edge_changes(i).deltas_applied.begin();
1995 j != edge_changes(i).deltas_applied.end(); ++j)
1996 {
1997 if (file_or_manifest_base_exists(delta_entry_src(j).inner(), "files") &&
1998 file_version_exists(delta_entry_dst(j)))
1999 {
2000 file_data old_data;
2001 file_data new_data;
2002 get_file_version(delta_entry_src(j), old_data);
2003 get_file_version(delta_entry_dst(j), new_data);
2004 delta delt;
2005 diff(old_data.inner(), new_data.inner(), delt);
2006 file_delta del(delt);
2007 drop_or_cancel_file(delta_entry_dst(j));
2008 drop(delta_entry_dst(j).inner()(), "file_deltas");
2009 put_file_version(delta_entry_src(j), delta_entry_dst(j), del);
2010 }
2011 }
2012 }
2013 }
2014 guard.commit();
2015}
2016
2017
2018bool
2019database::put_revision(revision_id const & new_id,
2020 revision_t const & rev)
2021{
2022 MM(new_id);
2023 MM(rev);
2024
2025 I(!null_id(new_id));
2026
2027 if (revision_exists(new_id))
2028 {
2029 L(FL("revision '%s' already exists in db") % new_id);
2030 return false;
2031 }
2032
2033 I(rev.made_for == made_for_database);
2034 rev.check_sane();
2035
2036 // Phase 1: confirm the revision makes sense, and we the required files
2037 // actually exist
2038 for (edge_map::const_iterator i = rev.edges.begin();
2039 i != rev.edges.end(); ++i)
2040 {
2041 if (!edge_old_revision(i).inner()().empty()
2042 && !revision_exists(edge_old_revision(i)))
2043 {
2044 W(F("missing prerequisite revision '%s'") % edge_old_revision(i));
2045 W(F("dropping revision '%s'") % new_id);
2046 return false;
2047 }
2048
2049 for (map<file_path, file_id>::const_iterator a
2050 = edge_changes(i).files_added.begin();
2051 a != edge_changes(i).files_added.end(); ++a)
2052 {
2053 if (! file_version_exists(a->second))
2054 {
2055 W(F("missing prerequisite file '%s'") % a->second);
2056 W(F("dropping revision '%s'") % new_id);
2057 return false;
2058 }
2059 }
2060
2061 for (map<file_path, pair<file_id, file_id> >::const_iterator d
2062 = edge_changes(i).deltas_applied.begin();
2063 d != edge_changes(i).deltas_applied.end(); ++d)
2064 {
2065 I(!delta_entry_src(d).inner()().empty());
2066 I(!delta_entry_dst(d).inner()().empty());
2067
2068 if (! file_version_exists(delta_entry_src(d)))
2069 {
2070 W(F("missing prerequisite file pre-delta '%s'")
2071 % delta_entry_src(d));
2072 W(F("dropping revision '%s'") % new_id);
2073 return false;
2074 }
2075
2076 if (! file_version_exists(delta_entry_dst(d)))
2077 {
2078 W(F("missing prerequisite file post-delta '%s'")
2079 % delta_entry_dst(d));
2080 W(F("dropping revision '%s'") % new_id);
2081 return false;
2082 }
2083 }
2084 }
2085
2086 transaction_guard guard(*this);
2087
2088 // Phase 2: Write the revision data (inside a transaction)
2089
2090 revision_data d;
2091 write_revision(rev, d);
2092 gzip<data> d_packed;
2093 encode_gzip(d.inner(), d_packed);
2094 execute(query("INSERT INTO revisions VALUES(?, ?)")
2095 % text(new_id.inner()())
2096 % blob(d_packed()));
2097
2098 for (edge_map::const_iterator e = rev.edges.begin();
2099 e != rev.edges.end(); ++e)
2100 {
2101 execute(query("INSERT INTO revision_ancestry VALUES(?, ?)")
2102 % text(edge_old_revision(e).inner()())
2103 % text(new_id.inner()()));
2104 }
2105
2106 // Phase 3: Construct and write the roster (which also checks the manifest
2107 // id as it goes), but only if the roster does not already exist in the db
2108 // (i.e. because it was left over by a kill_rev_locally)
2109 // FIXME: there is no knowledge yet on speed implications for commands which
2110 // put a lot of revisions in a row (i.e. tailor or cvs_import)!
2111
2112 if (!roster_version_exists(new_id))
2113 {
2114 put_roster_for_revision(new_id, rev);
2115 }
2116 else
2117 {
2118 L(FL("roster for revision '%s' already exists in db") % new_id);
2119 }
2120
2121 // Phase 4: rewrite any files that need deltas added
2122
2123 deltify_revision(new_id);
2124
2125 // Phase 5: determine the revision height
2126
2127 put_height_for_revision(new_id, rev);
2128
2129 // Finally, commit.
2130
2131 guard.commit();
2132 return true;
2133}
2134
2135void
2136database::put_height_for_revision(revision_id const & new_id,
2137 revision_t const & rev)
2138{
2139 I(!null_id(new_id));
2140
2141 rev_height highest_parent;
2142 // we always branch off the highest parent ...
2143 for (edge_map::const_iterator e = rev.edges.begin();
2144 e != rev.edges.end(); ++e)
2145 {
2146 rev_height parent; MM(parent);
2147 get_rev_height(edge_old_revision(e), parent);
2148 if (parent > highest_parent)
2149 {
2150 highest_parent = parent;
2151 }
2152 }
2153
2154 // ... then find the first unused child
2155 u32 childnr(0);
2156 rev_height candidate; MM(candidate);
2157 while(true)
2158 {
2159 candidate = highest_parent.child_height(childnr);
2160 if (!has_rev_height(candidate))
2161 {
2162 break;
2163 }
2164 I(childnr < std::numeric_limits<u32>::max());
2165 ++childnr;
2166 }
2167 put_rev_height(new_id, candidate);
2168}
2169
2170void
2171database::put_roster_for_revision(revision_id const & new_id,
2172 revision_t const & rev)
2173{
2174 // Construct, the roster, sanity-check the manifest id, and then write it
2175 // to the db
2176 shared_ptr<roster_t> ros_writeable(new roster_t); MM(*ros_writeable);
2177 shared_ptr<marking_map> mm_writeable(new marking_map); MM(*mm_writeable);
2178 manifest_id roster_manifest_id;
2179 MM(roster_manifest_id);
2180 make_roster_for_revision(rev, new_id, *ros_writeable, *mm_writeable, *__app);
2181 calculate_ident(*ros_writeable, roster_manifest_id);
2182 I(rev.new_manifest == roster_manifest_id);
2183 // const'ify the objects, suitable for caching etc.
2184 roster_t_cp ros = ros_writeable;
2185 marking_map_cp mm = mm_writeable;
2186 put_roster(new_id, ros, mm);
2187}
2188
2189bool
2190database::put_revision(revision_id const & new_id,
2191 revision_data const & dat)
2192{
2193 revision_t rev;
2194 read_revision(dat, rev);
2195 return put_revision(new_id, rev);
2196}
2197
2198
2199void
2200database::delete_existing_revs_and_certs()
2201{
2202 execute(query("DELETE FROM revisions"));
2203 execute(query("DELETE FROM revision_ancestry"));
2204 execute(query("DELETE FROM revision_certs"));
2205}
2206
2207void
2208database::delete_existing_manifests()
2209{
2210 execute(query("DELETE FROM manifests"));
2211 execute(query("DELETE FROM manifest_deltas"));
2212}
2213
2214void
2215database::delete_existing_rosters()
2216{
2217 execute(query("DELETE FROM rosters"));
2218 execute(query("DELETE FROM roster_deltas"));
2219 execute(query("DELETE FROM next_roster_node_number"));
2220}
2221
2222void
2223database::delete_existing_heights()
2224{
2225 execute(query("DELETE FROM heights"));
2226}
2227
2228/// Deletes one revision from the local database.
2229/// @see kill_rev_locally
2230void
2231database::delete_existing_rev_and_certs(revision_id const & rid)
2232{
2233 transaction_guard guard (*this);
2234
2235 // Check that the revision exists and doesn't have any children.
2236 I(revision_exists(rid));
2237 set<revision_id> children;
2238 get_revision_children(rid, children);
2239 I(children.empty());
2240
2241
2242 L(FL("Killing revision %s locally") % rid);
2243
2244 // Kill the certs, ancestry, and revision.
2245 execute(query("DELETE from revision_certs WHERE id = ?")
2246 % text(rid.inner()()));
2247 cert_stamper.note_change();
2248
2249 execute(query("DELETE from revision_ancestry WHERE child = ?")
2250 % text(rid.inner()()));
2251
2252 execute(query("DELETE from heights WHERE revision = ?")
2253 % text(rid.inner()()));
2254
2255 execute(query("DELETE from revisions WHERE id = ?")
2256 % text(rid.inner()()));
2257
2258 guard.commit();
2259}
2260
2261/// Deletes all certs referring to a particular branch.
2262void
2263database::delete_branch_named(cert_value const & branch)
2264{
2265 L(FL("Deleting all references to branch %s") % branch);
2266 execute(query("DELETE FROM revision_certs WHERE name='branch' AND value =?")
2267 % blob(branch()));
2268 cert_stamper.note_change();
2269 execute(query("DELETE FROM branch_epochs WHERE branch=?")
2270 % blob(branch()));
2271}
2272
2273/// Deletes all certs referring to a particular tag.
2274void
2275database::delete_tag_named(cert_value const & tag)
2276{
2277 L(FL("Deleting all references to tag %s") % tag);
2278 execute(query("DELETE FROM revision_certs WHERE name='tag' AND value =?")
2279 % blob(tag()));
2280 cert_stamper.note_change();
2281}
2282
2283// crypto key management
2284
2285void
2286database::get_key_ids(vector<rsa_keypair_id> & pubkeys)
2287{
2288 pubkeys.clear();
2289 results res;
2290
2291 fetch(res, one_col, any_rows, query("SELECT id FROM public_keys"));
2292
2293 for (size_t i = 0; i < res.size(); ++i)
2294 pubkeys.push_back(rsa_keypair_id(res[i][0]));
2295}
2296
2297void
2298database::get_key_ids(globish const & pattern,
2299 vector<rsa_keypair_id> & pubkeys)
2300{
2301 pubkeys.clear();
2302 results res;
2303
2304 fetch(res, one_col, any_rows, query("SELECT id FROM public_keys"));
2305
2306 for (size_t i = 0; i < res.size(); ++i)
2307 if (pattern.matches(res[i][0]))
2308 pubkeys.push_back(rsa_keypair_id(res[i][0]));
2309}
2310
2311void
2312database::get_keys(string const & table, vector<rsa_keypair_id> & keys)
2313{
2314 keys.clear();
2315 results res;
2316 fetch(res, one_col, any_rows, query("SELECT id FROM " + table));
2317 for (size_t i = 0; i < res.size(); ++i)
2318 keys.push_back(rsa_keypair_id(res[i][0]));
2319}
2320
2321void
2322database::get_public_keys(vector<rsa_keypair_id> & keys)
2323{
2324 get_keys("public_keys", keys);
2325}
2326
2327bool
2328database::public_key_exists(hexenc<id> const & hash)
2329{
2330 results res;
2331 fetch(res, one_col, any_rows,
2332 query("SELECT id FROM public_keys WHERE hash = ?")
2333 % text(hash()));
2334 I((res.size() == 1) || (res.size() == 0));
2335 if (res.size() == 1)
2336 return true;
2337 return false;
2338}
2339
2340bool
2341database::public_key_exists(rsa_keypair_id const & id)
2342{
2343 results res;
2344 fetch(res, one_col, any_rows,
2345 query("SELECT id FROM public_keys WHERE id = ?")
2346 % text(id()));
2347 I((res.size() == 1) || (res.size() == 0));
2348 if (res.size() == 1)
2349 return true;
2350 return false;
2351}
2352
2353void
2354database::get_pubkey(hexenc<id> const & hash,
2355 rsa_keypair_id & id,
2356 base64<rsa_pub_key> & pub_encoded)
2357{
2358 results res;
2359 fetch(res, 2, one_row,
2360 query("SELECT id, keydata FROM public_keys WHERE hash = ?")
2361 % text(hash()));
2362 id = rsa_keypair_id(res[0][0]);
2363 encode_base64(rsa_pub_key(res[0][1]), pub_encoded);
2364}
2365
2366void
2367database::get_key(rsa_keypair_id const & pub_id,
2368 base64<rsa_pub_key> & pub_encoded)
2369{
2370 results res;
2371 fetch(res, one_col, one_row,
2372 query("SELECT keydata FROM public_keys WHERE id = ?")
2373 % text(pub_id()));
2374 encode_base64(rsa_pub_key(res[0][0]), pub_encoded);
2375}
2376
2377bool
2378database::put_key(rsa_keypair_id const & pub_id,
2379 base64<rsa_pub_key> const & pub_encoded)
2380{
2381 if (public_key_exists(pub_id))
2382 {
2383 base64<rsa_pub_key> tmp;
2384 get_key(pub_id, tmp);
2385 if (!keys_match(pub_id, tmp, pub_id, pub_encoded))
2386 W(F("key '%s' is not equal to key '%s' in database") % pub_id % pub_id);
2387 L(FL("skipping existing public key %s") % pub_id);
2388 return false;
2389 }
2390
2391 L(FL("putting public key %s") % pub_id);
2392
2393 hexenc<id> thash;
2394 key_hash_code(pub_id, pub_encoded, thash);
2395 I(!public_key_exists(thash));
2396
2397 rsa_pub_key pub_key;
2398 decode_base64(pub_encoded, pub_key);
2399 execute(query("INSERT INTO public_keys VALUES(?, ?, ?)")
2400 % text(thash())
2401 % text(pub_id())
2402 % blob(pub_key()));
2403
2404 return true;
2405}
2406
2407void
2408database::delete_public_key(rsa_keypair_id const & pub_id)
2409{
2410 execute(query("DELETE FROM public_keys WHERE id = ?")
2411 % text(pub_id()));
2412}
2413
2414// cert management
2415
2416bool
2417database::cert_exists(cert const & t,
2418 string const & table)
2419{
2420 results res;
2421 cert_value value;
2422 decode_base64(t.value, value);
2423 rsa_sha1_signature sig;
2424 decode_base64(t.sig, sig);
2425 query q = query("SELECT id FROM " + table + " WHERE id = ? "
2426 "AND name = ? "
2427 "AND value = ? "
2428 "AND keypair = ? "
2429 "AND signature = ?")
2430 % text(t.ident())
2431 % text(t.name())
2432 % blob(value())
2433 % text(t.key())
2434 % blob(sig());
2435
2436 fetch(res, 1, any_rows, q);
2437
2438 I(res.size() == 0 || res.size() == 1);
2439 return res.size() == 1;
2440}
2441
2442void
2443database::put_cert(cert const & t,
2444 string const & table)
2445{
2446 hexenc<id> thash;
2447 cert_hash_code(t, thash);
2448 cert_value value;
2449 decode_base64(t.value, value);
2450 rsa_sha1_signature sig;
2451 decode_base64(t.sig, sig);
2452
2453 string insert = "INSERT INTO " + table + " VALUES(?, ?, ?, ?, ?, ?)";
2454
2455 execute(query(insert)
2456 % text(thash())
2457 % text(t.ident())
2458 % text(t.name())
2459 % blob(value())
2460 % text(t.key())
2461 % blob(sig()));
2462}
2463
2464void
2465database::results_to_certs(results const & res,
2466 vector<cert> & certs)
2467{
2468 certs.clear();
2469 for (size_t i = 0; i < res.size(); ++i)
2470 {
2471 cert t;
2472 base64<cert_value> value;
2473 encode_base64(cert_value(res[i][2]), value);
2474 base64<rsa_sha1_signature> sig;
2475 encode_base64(rsa_sha1_signature(res[i][4]), sig);
2476 t = cert(hexenc<id>(res[i][0]),
2477 cert_name(res[i][1]),
2478 value,
2479 rsa_keypair_id(res[i][3]),
2480 sig);
2481 certs.push_back(t);
2482 }
2483}
2484
2485void
2486database::install_functions(app_state * app)
2487{
2488 // register any functions we're going to use
2489 I(sqlite3_create_function(sql(), "gunzip", -1,
2490 SQLITE_UTF8, NULL,
2491 &sqlite3_gunzip_fn,
2492 NULL, NULL) == 0);
2493}
2494
2495void
2496database::get_certs(vector<cert> & certs,
2497 string const & table)
2498{
2499 results res;
2500 query q("SELECT id, name, value, keypair, signature FROM " + table);
2501 fetch(res, 5, any_rows, q);
2502 results_to_certs(res, certs);
2503}
2504
2505
2506void
2507database::get_certs(hexenc<id> const & ident,
2508 vector<cert> & certs,
2509 string const & table)
2510{
2511 results res;
2512 query q("SELECT id, name, value, keypair, signature FROM " + table +
2513 " WHERE id = ?");
2514
2515 fetch(res, 5, any_rows, q % text(ident()));
2516 results_to_certs(res, certs);
2517}
2518
2519
2520void
2521database::get_certs(cert_name const & name,
2522 vector<cert> & certs,
2523 string const & table)
2524{
2525 results res;
2526 query q("SELECT id, name, value, keypair, signature FROM " + table +
2527 " WHERE name = ?");
2528 fetch(res, 5, any_rows, q % text(name()));
2529 results_to_certs(res, certs);
2530}
2531
2532
2533void
2534database::get_certs(hexenc<id> const & ident,
2535 cert_name const & name,
2536 vector<cert> & certs,
2537 string const & table)
2538{
2539 results res;
2540 query q("SELECT id, name, value, keypair, signature FROM " + table +
2541 " WHERE id = ? AND name = ?");
2542
2543 fetch(res, 5, any_rows,
2544 q % text(ident())
2545 % text(name()));
2546 results_to_certs(res, certs);
2547}
2548
2549void
2550database::get_certs(cert_name const & name,
2551 base64<cert_value> const & val,
2552 vector<cert> & certs,
2553 string const & table)
2554{
2555 results res;
2556 query q("SELECT id, name, value, keypair, signature FROM " + table +
2557 " WHERE name = ? AND value = ?");
2558
2559 cert_value binvalue;
2560 decode_base64(val, binvalue);
2561 fetch(res, 5, any_rows,
2562 q % text(name())
2563 % blob(binvalue()));
2564 results_to_certs(res, certs);
2565}
2566
2567
2568void
2569database::get_certs(hexenc<id> const & ident,
2570 cert_name const & name,
2571 base64<cert_value> const & value,
2572 vector<cert> & certs,
2573 string const & table)
2574{
2575 results res;
2576 query q("SELECT id, name, value, keypair, signature FROM " + table +
2577 " WHERE id = ? AND name = ? AND value = ?");
2578
2579 cert_value binvalue;
2580 decode_base64(value, binvalue);
2581 fetch(res, 5, any_rows,
2582 q % text(ident())
2583 % text(name())
2584 % blob(binvalue()));
2585 results_to_certs(res, certs);
2586}
2587
2588
2589
2590bool
2591database::revision_cert_exists(revision<cert> const & cert)
2592{
2593 return cert_exists(cert.inner(), "revision_certs");
2594}
2595
2596bool
2597database::put_revision_cert(revision<cert> const & cert)
2598{
2599 if (revision_cert_exists(cert))
2600 {
2601 L(FL("revision cert on '%s' already exists in db")
2602 % cert.inner().ident);
2603 return false;
2604 }
2605
2606 if (!revision_exists(revision_id(cert.inner().ident)))
2607 {
2608 W(F("cert revision '%s' does not exist in db")
2609 % cert.inner().ident);
2610 W(F("dropping cert"));
2611 return false;
2612 }
2613
2614 put_cert(cert.inner(), "revision_certs");
2615 cert_stamper.note_change();
2616 return true;
2617}
2618
2619outdated_indicator
2620database::get_revision_cert_nobranch_index(vector< pair<hexenc<id>,
2621 pair<revision_id, rsa_keypair_id> > > & idx)
2622{
2623 // share some storage
2624 id::symtab id_syms;
2625
2626 results res;
2627 fetch(res, 3, any_rows,
2628 query("SELECT hash, id, keypair "
2629 "FROM 'revision_certs' WHERE name != 'branch'"));
2630
2631 idx.clear();
2632 idx.reserve(res.size());
2633 for (results::const_iterator i = res.begin(); i != res.end(); ++i)
2634 {
2635 idx.push_back(make_pair(hexenc<id>((*i)[0]),
2636 make_pair(revision_id((*i)[1]),
2637 rsa_keypair_id((*i)[2]))));
2638 }
2639 return cert_stamper.get_indicator();
2640}
2641
2642outdated_indicator
2643database::get_revision_certs(vector< revision<cert> > & ts)
2644{
2645 vector<cert> certs;
2646 get_certs(certs, "revision_certs");
2647 ts.clear();
2648 add_decoration_to_container(certs, ts);
2649 return cert_stamper.get_indicator();
2650}
2651
2652outdated_indicator
2653database::get_revision_certs(cert_name const & name,
2654 vector< revision<cert> > & ts)
2655{
2656 vector<cert> certs;
2657 get_certs(name, certs, "revision_certs");
2658 ts.clear();
2659 add_decoration_to_container(certs, ts);
2660 return cert_stamper.get_indicator();
2661}
2662
2663outdated_indicator
2664database::get_revision_certs(revision_id const & id,
2665 cert_name const & name,
2666 vector< revision<cert> > & ts)
2667{
2668 vector<cert> certs;
2669 get_certs(id.inner(), name, certs, "revision_certs");
2670 ts.clear();
2671 add_decoration_to_container(certs, ts);
2672 return cert_stamper.get_indicator();
2673}
2674
2675outdated_indicator
2676database::get_revision_certs(revision_id const & id,
2677 cert_name const & name,
2678 base64<cert_value> const & val,
2679 vector< revision<cert> > & ts)
2680{
2681 vector<cert> certs;
2682 get_certs(id.inner(), name, val, certs, "revision_certs");
2683 ts.clear();
2684 add_decoration_to_container(certs, ts);
2685 return cert_stamper.get_indicator();
2686}
2687
2688outdated_indicator
2689database::get_revisions_with_cert(cert_name const & name,
2690 base64<cert_value> const & val,
2691 set<revision_id> & revisions)
2692{
2693 revisions.clear();
2694 results res;
2695 query q("SELECT id FROM revision_certs WHERE name = ? AND value = ?");
2696 cert_value binvalue;
2697 decode_base64(val, binvalue);
2698 fetch(res, one_col, any_rows, q % text(name()) % blob(binvalue()));
2699 for (results::const_iterator i = res.begin(); i != res.end(); ++i)
2700 revisions.insert(revision_id((*i)[0]));
2701 return cert_stamper.get_indicator();
2702}
2703
2704outdated_indicator
2705database::get_revision_certs(cert_name const & name,
2706 base64<cert_value> const & val,
2707 vector< revision<cert> > & ts)
2708{
2709 vector<cert> certs;
2710 get_certs(name, val, certs, "revision_certs");
2711 ts.clear();
2712 add_decoration_to_container(certs, ts);
2713 return cert_stamper.get_indicator();
2714}
2715
2716outdated_indicator
2717database::get_revision_certs(revision_id const & id,
2718 vector< revision<cert> > & ts)
2719{
2720 vector<cert> certs;
2721 get_certs(id.inner(), certs, "revision_certs");
2722 ts.clear();
2723 add_decoration_to_container(certs, ts);
2724 return cert_stamper.get_indicator();
2725}
2726
2727outdated_indicator
2728database::get_revision_certs(revision_id const & ident,
2729 vector< hexenc<id> > & ts)
2730{
2731 results res;
2732 vector<cert> certs;
2733 fetch(res, one_col, any_rows,
2734 query("SELECT hash "
2735 "FROM revision_certs "
2736 "WHERE id = ?")
2737 % text(ident.inner()()));
2738 ts.clear();
2739 for (size_t i = 0; i < res.size(); ++i)
2740 ts.push_back(hexenc<id>(res[i][0]));
2741 return cert_stamper.get_indicator();
2742}
2743
2744void
2745database::get_revision_cert(hexenc<id> const & hash,
2746 revision<cert> & c)
2747{
2748 results res;
2749 vector<cert> certs;
2750 fetch(res, 5, one_row,
2751 query("SELECT id, name, value, keypair, signature "
2752 "FROM revision_certs "
2753 "WHERE hash = ?")
2754 % text(hash()));
2755 results_to_certs(res, certs);
2756 I(certs.size() == 1);
2757 c = revision<cert>(certs[0]);
2758}
2759
2760bool
2761database::revision_cert_exists(hexenc<id> const & hash)
2762{
2763 results res;
2764 vector<cert> certs;
2765 fetch(res, one_col, any_rows,
2766 query("SELECT id "
2767 "FROM revision_certs "
2768 "WHERE hash = ?")
2769 % text(hash()));
2770 I(res.size() == 0 || res.size() == 1);
2771 return (res.size() == 1);
2772}
2773
2774void
2775database::get_manifest_certs(manifest_id const & id,
2776 vector< manifest<cert> > & ts)
2777{
2778 vector<cert> certs;
2779 get_certs(id.inner(), certs, "manifest_certs");
2780 ts.clear();
2781 add_decoration_to_container(certs, ts);
2782}
2783
2784
2785void
2786database::get_manifest_certs(cert_name const & name,
2787 vector< manifest<cert> > & ts)
2788{
2789 vector<cert> certs;
2790 get_certs(name, certs, "manifest_certs");
2791 ts.clear();
2792 add_decoration_to_container(certs, ts);
2793}
2794
2795
2796// completions
2797void
2798database::complete(string const & partial,
2799 set<revision_id> & completions)
2800{
2801 results res;
2802 completions.clear();
2803
2804 string pattern = partial + "*";
2805
2806 fetch(res, 1, any_rows,
2807 query("SELECT id FROM revisions WHERE id GLOB ?")
2808 % text(pattern));
2809
2810 for (size_t i = 0; i < res.size(); ++i)
2811 completions.insert(revision_id(res[i][0]));
2812}
2813
2814
2815void
2816database::complete(string const & partial,
2817 set<file_id> & completions)
2818{
2819 results res;
2820 completions.clear();
2821
2822 string pattern = partial + "*";
2823
2824 fetch(res, 1, any_rows,
2825 query("SELECT id FROM files WHERE id GLOB ?")
2826 % text(pattern));
2827
2828 for (size_t i = 0; i < res.size(); ++i)
2829 completions.insert(file_id(res[i][0]));
2830
2831 res.clear();
2832
2833 fetch(res, 1, any_rows,
2834 query("SELECT id FROM file_deltas WHERE id GLOB ?")
2835 % text(pattern));
2836
2837 for (size_t i = 0; i < res.size(); ++i)
2838 completions.insert(file_id(res[i][0]));
2839}
2840
2841void
2842database::complete(string const & partial,
2843 set< pair<key_id, utf8 > > & completions)
2844{
2845 results res;
2846 completions.clear();
2847
2848 string pattern = partial + "*";
2849
2850 fetch(res, 2, any_rows,
2851 query("SELECT hash, id FROM public_keys WHERE hash GLOB ?")
2852 % text(pattern));
2853
2854 for (size_t i = 0; i < res.size(); ++i)
2855 completions.insert(make_pair(key_id(res[i][0]), utf8(res[i][1])));
2856}
2857
2858using selectors::selector_type;
2859
2860static void selector_to_certname(selector_type ty,
2861 cert_name & name,
2862 string & prefix,
2863 string & suffix)
2864{
2865 prefix = suffix = "*";
2866 switch (ty)
2867 {
2868 case selectors::sel_author:
2869 prefix = suffix = "";
2870 name = author_cert_name;
2871 break;
2872 case selectors::sel_branch:
2873 prefix = suffix = "";
2874 name = branch_cert_name;
2875 break;
2876 case selectors::sel_head:
2877 prefix = suffix = "";
2878 name = branch_cert_name;
2879 break;
2880 case selectors::sel_date:
2881 case selectors::sel_later:
2882 case selectors::sel_earlier:
2883 name = date_cert_name;
2884 break;
2885 case selectors::sel_tag:
2886 prefix = suffix = "";
2887 name = tag_cert_name;
2888 break;
2889 case selectors::sel_ident:
2890 case selectors::sel_cert:
2891 case selectors::sel_unknown:
2892 case selectors::sel_parent:
2893 I(false); // don't do this.
2894 break;
2895 }
2896}
2897
2898void database::complete(selector_type ty,
2899 string const & partial,
2900 vector<pair<selector_type, string> > const & limit,
2901 set<string> & completions)
2902{
2903 //L(FL("database::complete for partial '%s'") % partial);
2904 completions.clear();
2905
2906 // step 1: the limit is transformed into an SQL select statement which
2907 // selects a set of IDs from the revision_certs table which match the
2908 // limit. this is done by building an SQL select statement for each term
2909 // in the limit and then INTERSECTing them all.
2910
2911 query lim;
2912 lim.sql_cmd = "(";
2913 if (limit.empty())
2914 {
2915 lim.sql_cmd += "SELECT id FROM revision_certs";
2916 }
2917 else
2918 {
2919 bool first_limit = true;
2920 for (vector<pair<selector_type, string> >::const_iterator i = limit.begin();
2921 i != limit.end(); ++i)
2922 {
2923 if (first_limit)
2924 first_limit = false;
2925 else
2926 lim.sql_cmd += " INTERSECT ";
2927
2928 if (i->first == selectors::sel_ident)
2929 {
2930 lim.sql_cmd += "SELECT id FROM revision_certs WHERE id GLOB ?";
2931 lim % text(i->second + "*");
2932 }
2933 else if (i->first == selectors::sel_parent)
2934 {
2935 lim.sql_cmd += "SELECT parent AS id FROM revision_ancestry WHERE child GLOB ?";
2936 lim % text(i->second + "*");
2937 }
2938 else if (i->first == selectors::sel_cert)
2939 {
2940 if (i->second.length() > 0)
2941 {
2942 size_t spot = i->second.find("=");
2943
2944 if (spot != (size_t)-1)
2945 {
2946 string certname;
2947 string certvalue;
2948
2949 certname = i->second.substr(0, spot);
2950 spot++;
2951 certvalue = i->second.substr(spot);
2952 lim.sql_cmd += "SELECT id FROM revision_certs WHERE name=? AND CAST(value AS TEXT) glob ?";
2953 lim % text(certname) % text(certvalue);
2954 }
2955 else
2956 {
2957 lim.sql_cmd += "SELECT id FROM revision_certs WHERE name=?";
2958 lim % text(i->second);
2959 }
2960
2961 }
2962 }
2963 else if (i->first == selectors::sel_unknown)
2964 {
2965 lim.sql_cmd += "SELECT id FROM revision_certs WHERE (name=? OR name=? OR name=?)";
2966 lim % text(author_cert_name()) % text(tag_cert_name()) % text(branch_cert_name());
2967 lim.sql_cmd += " AND CAST(value AS TEXT) glob ?";
2968 lim % text(i->second + "*");
2969 }
2970 else if (i->first == selectors::sel_head)
2971 {
2972 // get branch names
2973 set<branch_name> branch_names;
2974 if (i->second.size() == 0)
2975 {
2976 __app->require_workspace("the empty head selector h: refers to the head of the current branch");
2977 branch_names.insert(__app->opts.branchname);
2978 }
2979 else
2980 {
2981 __app->get_project().get_branch_list(globish(i->second), branch_names, true);
2982 }
2983
2984 L(FL("found %d matching branches") % branch_names.size());
2985
2986 // for each branch name, get the branch heads
2987 set<revision_id> heads;
2988 for (set<branch_name>::const_iterator bn = branch_names.begin();
2989 bn != branch_names.end(); bn++)
2990 {
2991 set<revision_id> branch_heads;
2992 __app->get_project().get_branch_heads(*bn, branch_heads);
2993 heads.insert(branch_heads.begin(), branch_heads.end());
2994 L(FL("after get_branch_heads for %s, heads has %d entries") % (*bn) % heads.size());
2995 }
2996
2997 lim.sql_cmd += "SELECT id FROM revision_certs WHERE id IN (";
2998 if (heads.size())
2999 {
3000 set<revision_id>::const_iterator r = heads.begin();
3001 lim.sql_cmd += "?";
3002 lim % text(r->inner()());
3003 r++;
3004 while (r != heads.end())
3005 {
3006 lim.sql_cmd += ", ?";
3007 lim % text(r->inner()());
3008 r++;
3009 }
3010 }
3011 lim.sql_cmd += ") ";
3012 }
3013 else
3014 {
3015 cert_name certname;
3016 string prefix;
3017 string suffix;
3018 selector_to_certname(i->first, certname, prefix, suffix);
3019 L(FL("processing selector type %d with i->second '%s'") % ty % i->second);
3020 if ((i->first == selectors::sel_branch) && (i->second.size() == 0))
3021 {
3022 __app->require_workspace("the empty branch selector b: refers to the current branch");
3023 lim.sql_cmd += "SELECT id FROM revision_certs WHERE name=? AND CAST(value AS TEXT) glob ?";
3024 lim % text(branch_cert_name()) % text(__app->opts.branchname());
3025 L(FL("limiting to current branch '%s'") % __app->opts.branchname);
3026 }
3027 else
3028 {
3029 lim.sql_cmd += "SELECT id FROM revision_certs WHERE name=? AND ";
3030 lim % text(certname());
3031 switch (i->first)
3032 {
3033 case selectors::sel_earlier:
3034 lim.sql_cmd += "value <= ?";
3035 lim % blob(i->second);
3036 break;
3037 case selectors::sel_later:
3038 lim.sql_cmd += "value > ?";
3039 lim % blob(i->second);
3040 break;
3041 default:
3042 lim.sql_cmd += "CAST(value AS TEXT) glob ?";
3043 lim % text(prefix + i->second + suffix);
3044 break;
3045 }
3046 }
3047 }
3048 //L(FL("found selector type %d, selecting_head is now %d") % i->first % selecting_head);
3049 }
3050 }
3051 lim.sql_cmd += ")";
3052
3053 // step 2: depending on what we've been asked to disambiguate, we
3054 // will complete either some idents, or cert values, or "unknown"
3055 // which generally means "author, tag or branch"
3056
3057 if (ty == selectors::sel_ident || ty == selectors::sel_parent)
3058 {
3059 lim.sql_cmd = "SELECT id FROM " + lim.sql_cmd;
3060 }
3061 else
3062 {
3063 string prefix = "*";
3064 string suffix = "*";
3065 lim.sql_cmd = "SELECT value FROM revision_certs WHERE";
3066 if (ty == selectors::sel_unknown)
3067 {
3068 lim.sql_cmd += " (name=? OR name=? OR name=?)";
3069 lim % text(author_cert_name()) % text(tag_cert_name()) % text(branch_cert_name());
3070 }
3071 else
3072 {
3073 cert_name certname;
3074 selector_to_certname(ty, certname, prefix, suffix);
3075 lim.sql_cmd += " (name=?)";
3076 lim % text(certname());
3077 }
3078
3079 lim.sql_cmd += " AND (CAST(value AS TEXT) GLOB ?) AND (id IN " + lim.sql_cmd + ")";
3080 lim % text(prefix + partial + suffix);
3081 }
3082
3083 results res;
3084 fetch(res, one_col, any_rows, lim);
3085 for (size_t i = 0; i < res.size(); ++i)
3086 {
3087 if (ty == selectors::sel_ident)
3088 completions.insert(res[i][0]);
3089 else
3090 {
3091 data row_decoded(res[i][0]);
3092 completions.insert(row_decoded());
3093 }
3094 }
3095}
3096
3097// epochs
3098
3099void
3100database::get_epochs(map<branch_name, epoch_data> & epochs)
3101{
3102 epochs.clear();
3103 results res;
3104 fetch(res, 2, any_rows, query("SELECT branch, epoch FROM branch_epochs"));
3105 for (results::const_iterator i = res.begin(); i != res.end(); ++i)
3106 {
3107 branch_name decoded(idx(*i, 0));
3108 I(epochs.find(decoded) == epochs.end());
3109 epochs.insert(make_pair(decoded, epoch_data(idx(*i, 1))));
3110 }
3111}
3112
3113void
3114database::get_epoch(epoch_id const & eid,
3115 branch_name & branch, epoch_data & epo)
3116{
3117 I(epoch_exists(eid));
3118 results res;
3119 fetch(res, 2, any_rows,
3120 query("SELECT branch, epoch FROM branch_epochs"
3121 " WHERE hash = ?")
3122 % text(eid.inner()()));
3123 I(res.size() == 1);
3124 branch = branch_name(idx(idx(res, 0), 0));
3125 epo = epoch_data(idx(idx(res, 0), 1));
3126}
3127
3128bool
3129database::epoch_exists(epoch_id const & eid)
3130{
3131 results res;
3132 fetch(res, one_col, any_rows,
3133 query("SELECT hash FROM branch_epochs WHERE hash = ?")
3134 % text(eid.inner()()));
3135 I(res.size() == 1 || res.size() == 0);
3136 return res.size() == 1;
3137}
3138
3139void
3140database::set_epoch(branch_name const & branch, epoch_data const & epo)
3141{
3142 epoch_id eid;
3143 epoch_hash_code(branch, epo, eid);
3144 I(epo.inner()().size() == constants::epochlen);
3145 execute(query("INSERT OR REPLACE INTO branch_epochs VALUES(?, ?, ?)")
3146 % text(eid.inner()())
3147 % blob(branch())
3148 % text(epo.inner()()));
3149}
3150
3151void
3152database::clear_epoch(branch_name const & branch)
3153{
3154 execute(query("DELETE FROM branch_epochs WHERE branch = ?")
3155 % blob(branch()));
3156}
3157
3158bool
3159database::check_integrity()
3160{
3161 results res;
3162 fetch(res, one_col, any_rows, query("PRAGMA integrity_check"));
3163 I(res.size() == 1);
3164 I(res[0].size() == 1);
3165
3166 return res[0][0] == "ok";
3167}
3168
3169// vars
3170
3171void
3172database::get_vars(map<var_key, var_value> & vars)
3173{
3174 vars.clear();
3175 results res;
3176 fetch(res, 3, any_rows, query("SELECT domain, name, value FROM db_vars"));
3177 for (results::const_iterator i = res.begin(); i != res.end(); ++i)
3178 {
3179 var_domain domain(idx(*i, 0));
3180 var_name name(idx(*i, 1));
3181 var_value value(idx(*i, 2));
3182 I(vars.find(make_pair(domain, name)) == vars.end());
3183 vars.insert(make_pair(make_pair(domain, name), value));
3184 }
3185}
3186
3187void
3188database::get_var(var_key const & key, var_value & value)
3189{
3190 // FIXME: sillyly inefficient. Doesn't really matter, though.
3191 map<var_key, var_value> vars;
3192 get_vars(vars);
3193 map<var_key, var_value>::const_iterator i = vars.find(key);
3194 I(i != vars.end());
3195 value = i->second;
3196}
3197
3198bool
3199database::var_exists(var_key const & key)
3200{
3201 // FIXME: sillyly inefficient. Doesn't really matter, though.
3202 map<var_key, var_value> vars;
3203 get_vars(vars);
3204 map<var_key, var_value>::const_iterator i = vars.find(key);
3205 return i != vars.end();
3206}
3207
3208void
3209database::set_var(var_key const & key, var_value const & value)
3210{
3211 execute(query("INSERT OR REPLACE INTO db_vars VALUES(?, ?, ?)")
3212 % text(key.first())
3213 % blob(key.second())
3214 % blob(value()));
3215}
3216
3217void
3218database::clear_var(var_key const & key)
3219{
3220 execute(query("DELETE FROM db_vars WHERE domain = ? AND name = ?")
3221 % text(key.first())
3222 % blob(key.second()));
3223}
3224
3225// branches
3226
3227outdated_indicator
3228database::get_branches(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 names.push_back(res[i][0]);
3237 }
3238 return cert_stamper.get_indicator();
3239}
3240
3241outdated_indicator
3242database::get_branches(globish const & glob,
3243 vector<string> & names)
3244{
3245 results res;
3246 query q("SELECT DISTINCT value FROM revision_certs WHERE name = ?");
3247 string cert_name = "branch";
3248 fetch(res, one_col, any_rows, q % text(cert_name));
3249 for (size_t i = 0; i < res.size(); ++i)
3250 {
3251 if (glob.matches(res[i][0]))
3252 names.push_back(res[i][0]);
3253 }
3254 return cert_stamper.get_indicator();
3255}
3256
3257void
3258database::get_roster(revision_id const & rev_id,
3259 roster_t & roster)
3260{
3261 marking_map mm;
3262 get_roster(rev_id, roster, mm);
3263}
3264
3265void
3266database::get_roster(revision_id const & rev_id,
3267 roster_t & roster,
3268 marking_map & marking)
3269{
3270 if (rev_id.inner()().empty())
3271 {
3272 roster = roster_t();
3273 marking = marking_map();
3274 return;
3275 }
3276
3277 cached_roster cr;
3278 get_roster(rev_id, cr);
3279 roster = *cr.first;
3280 marking = *cr.second;
3281}
3282
3283void
3284database::get_roster(revision_id const & rev_id,
3285 cached_roster & cr)
3286{
3287 get_roster_version(rev_id, cr);
3288 I(cr.first);
3289 I(cr.second);
3290}
3291
3292void
3293database::put_roster(revision_id const & rev_id,
3294 roster_t_cp const & roster,
3295 marking_map_cp const & marking)
3296{
3297 I(roster);
3298 I(marking);
3299 MM(rev_id);
3300
3301 transaction_guard guard(*this);
3302
3303 // Our task is to add this roster, and deltify all the incoming edges (if
3304 // they aren't already).
3305
3306 roster_cache.insert_dirty(rev_id, make_pair(roster, marking));
3307
3308 set<revision_id> parents;
3309 get_revision_parents(rev_id, parents);
3310
3311 // Now do what deltify would do if we bothered
3312 for (set<revision_id>::const_iterator i = parents.begin();
3313 i != parents.end(); ++i)
3314 {
3315 if (null_id(*i))
3316 continue;
3317 revision_id old_rev = *i;
3318 if (roster_base_stored(old_rev))
3319 {
3320 cached_roster cr;
3321 get_roster_version(old_rev, cr);
3322 roster_delta reverse_delta;
3323 delta_rosters(*roster, *marking, *(cr.first), *(cr.second), reverse_delta);
3324 if (roster_cache.exists(old_rev))
3325 roster_cache.mark_clean(old_rev);
3326 drop(old_rev.inner()(), "rosters");
3327 put_roster_delta(old_rev, rev_id, reverse_delta);
3328 }
3329 }
3330 guard.commit();
3331}
3332
3333// for get_uncommon_ancestors
3334struct rev_height_graph : rev_graph
3335{
3336 typedef hashmap::hash_map<revision_id, set<revision_id> > parent_map;
3337 typedef hashmap::hash_map<revision_id, rev_height> height_map;
3338 static parent_map parent_cache;
3339 static height_map height_cache;
3340 rev_height_graph(database & db) : db(db) {}
3341 virtual void get_parents(revision_id const & rev, set<revision_id> & parents) const
3342 {
3343 parent_map::iterator i = parent_cache.find(rev);
3344 if (i == parent_cache.end())
3345 {
3346 db.get_revision_parents(rev, parents);
3347 parent_cache.insert(make_pair(rev, parents));
3348 }
3349 else
3350 {
3351 parents = i->second;
3352 }
3353 }
3354 virtual void get_children(revision_id const & rev, set<revision_id> & parents) const
3355 {
3356 // not required
3357 I(false);
3358 }
3359 virtual void get_height(revision_id const & rev, rev_height & h) const
3360 {
3361 height_map::iterator i = height_cache.find(rev);
3362 if (i == height_cache.end())
3363 {
3364 db.get_rev_height(rev, h);
3365 height_cache.insert(make_pair(rev, h));
3366 }
3367 else
3368 {
3369 h = i->second;
3370 }
3371 }
3372
3373 database & db;
3374};
3375rev_height_graph::parent_map rev_height_graph::parent_cache;
3376rev_height_graph::height_map rev_height_graph::height_cache;
3377
3378void
3379database::get_uncommon_ancestors(revision_id const & a,
3380 revision_id const & b,
3381 set<revision_id> & a_uncommon_ancs,
3382 set<revision_id> & b_uncommon_ancs)
3383{
3384
3385 rev_height_graph graph(*this);
3386 ::get_uncommon_ancestors(a, b, graph, a_uncommon_ancs, b_uncommon_ancs);
3387}
3388
3389
3390u64
3391database::next_id_from_table(string const & table)
3392{
3393 transaction_guard guard(*this);
3394 results res;
3395
3396 // We implement this as a fixed db var.
3397
3398 fetch(res, one_col, any_rows,
3399 query(string("SELECT node FROM ") + table));
3400
3401 u64 n;
3402 if (res.empty())
3403 {
3404 n = 1;
3405 execute (query(string("INSERT INTO ") + table + " VALUES(?)")
3406 % text(lexical_cast<string>(n)));
3407 }
3408 else
3409 {
3410 I(res.size() == 1);
3411 n = lexical_cast<u64>(res[0][0]);
3412 ++n;
3413 execute(query(string("UPDATE ") + table + " SET node = ?")
3414 % text(lexical_cast<string>(n)));
3415
3416 }
3417 guard.commit();
3418 return n;
3419}
3420
3421node_id
3422database::next_node_id()
3423{
3424 return static_cast<node_id>(next_id_from_table("next_roster_node_number"));
3425}
3426
3427void
3428database::check_filename()
3429{
3430 N(!filename.empty(), F("no database specified"));
3431}
3432
3433
3434void
3435database::check_db_exists()
3436{
3437 switch (get_path_status(filename))
3438 {
3439 case path::nonexistent:
3440 N(false, F("database %s does not exist") % filename);
3441 break;
3442 case path::file:
3443 return;
3444 case path::directory:
3445 {
3446 system_path database_option;
3447 branch_name branch_option;
3448 rsa_keypair_id key_option;
3449 system_path keydir_option;
3450 if (workspace::get_ws_options_from_path(
3451 filename,
3452 database_option,
3453 branch_option,
3454 key_option,
3455 keydir_option))
3456 {
3457 N(database_option.empty(),
3458 F("You gave a database option of: \n"
3459 "%s\n"
3460 "That is actually a workspace. Did you mean: \n"
3461 "%s") % filename % database_option );
3462 }
3463 N(false, F("%s is a directory, not a database") % filename);
3464 }
3465 break;
3466 }
3467}
3468
3469void
3470database::check_db_nonexistent()
3471{
3472 require_path_is_nonexistent(filename,
3473 F("database %s already exists")
3474 % filename);
3475
3476 system_path journal(filename.as_internal() + "-journal");
3477 require_path_is_nonexistent(journal,
3478 F("existing (possibly stale) journal file '%s' "
3479 "has same stem as new database '%s'\n"
3480 "cancelling database creation")
3481 % journal % filename);
3482
3483}
3484
3485bool
3486database::database_specified()
3487{
3488 return !filename.empty();
3489}
3490
3491
3492void
3493database::open()
3494{
3495 I(!__sql);
3496
3497 if (sqlite3_open(filename.as_external().c_str(), &__sql) == SQLITE_NOMEM)
3498 throw std::bad_alloc();
3499
3500 I(__sql);
3501 assert_sqlite3_ok(__sql);
3502}
3503
3504void
3505database::close()
3506{
3507 I(__sql);
3508
3509 sqlite3_close(__sql);
3510 __sql = 0;
3511
3512 I(!__sql);
3513}
3514
3515// transaction guards
3516
3517transaction_guard::transaction_guard(database & d, bool exclusive,
3518 size_t checkpoint_batch_size,
3519 size_t checkpoint_batch_bytes)
3520 : committed(false), db(d), exclusive(exclusive),
3521 checkpoint_batch_size(checkpoint_batch_size),
3522 checkpoint_batch_bytes(checkpoint_batch_bytes),
3523 checkpointed_calls(0),
3524 checkpointed_bytes(0)
3525{
3526 db.begin_transaction(exclusive);
3527}
3528
3529transaction_guard::~transaction_guard()
3530{
3531 if (committed)
3532 db.commit_transaction();
3533 else
3534 db.rollback_transaction();
3535}
3536
3537void
3538transaction_guard::do_checkpoint()
3539{
3540 db.commit_transaction();
3541 db.begin_transaction(exclusive);
3542 checkpointed_calls = 0;
3543 checkpointed_bytes = 0;
3544}
3545
3546void
3547transaction_guard::maybe_checkpoint(size_t nbytes)
3548{
3549 checkpointed_calls += 1;
3550 checkpointed_bytes += nbytes;
3551 if (checkpointed_calls >= checkpoint_batch_size
3552 || checkpointed_bytes >= checkpoint_batch_bytes)
3553 do_checkpoint();
3554}
3555
3556void
3557transaction_guard::commit()
3558{
3559 committed = true;
3560}
3561
3562// Local Variables:
3563// mode: C++
3564// fill-column: 76
3565// c-file-style: "gnu"
3566// indent-tabs-mode: nil
3567// End:
3568// 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