File: database.hh

package info (click to toggle)
monotone 0.18-1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 16,440 kB
  • ctags: 13,394
  • sloc: sh: 130,618; ansic: 70,657; cpp: 51,980; perl: 421; makefile: 359; python: 184; lisp: 132; sql: 83
file content (442 lines) | stat: -rw-r--r-- 15,758 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
#ifndef __DATABASE_HH__
#define __DATABASE_HH__

// copyright (C) 2002, 2003 graydon hoare <graydon@pobox.com>
// all rights reserved.
// licensed to the public under the terms of the GNU GPL (>= 2)
// see the file COPYING for details

struct sqlite3;
struct cert;

#include <vector>
#include <set>
#include <map>
#include <string>

#include <boost/filesystem/path.hpp>

#include "commands.hh"
#include "manifest.hh"
#include "numeric_vocab.hh"
#include "vocab.hh"

struct revision_set;

// this file defines a public, typed interface to the database.
// the database class encapsulates all knowledge about sqlite,
// the schema, and all SQL statements used to access the schema.
//
// one thing which is rather important to note is that this file
// deals with two sorts of version relationships. the versions
// stored in the database are all *backwards* from those the program
// sees. so for example if you have two versions of a file
// 
// file.1, file.2
//
// where file.2 was a modification of file.1, then as far as the rest of
// the application is concerned -- and the ancestry graph -- file.1 is the
// "old" version and file.2 is the "new" version. note the use of terms
// which describe time, and the sequence of edits a user makes to a
// file. those are ancestry terms. when the application composes a
// patchset, for example, it'll contain the diff delta(file.1, file.2)
//
// from the database's perspective, however, file.1 is the derived version,
// and file.2 is the base version. the base version is stored in the
// "files" table, and the *reverse* diff delta(file.2, file.1) is stored in
// the "file_deltas" table, under the id of file.1, with the id of file.2
// listed as its base. note the use of the terms which describe
// reconstruction; those are storage-system terms.
//
// the interface *to* the database, and the ancestry version graphs, use
// the old / new metaphor of ancestry, but within the database (including
// the private helper methods, and the storage version graphs) the
// base/derived storage metaphor is used. the only real way to tell which
// is which is to look at the parameter names and code. I might try to
// express this in the type system some day, but not presently.
//
// the key phrase to keep repeating when working on this code is:
// 
// "base files are new, derived files are old"
//
// it makes the code confusing, I know. this is possibly the worst part of
// the program. I don't know if there's any way to make it clearer.

class transaction_guard;
struct posting;
struct app_state;

class database
{
  fs::path filename;
  std::string const schema;
  void check_schema();

  struct app_state * __app;
  struct sqlite3 * __sql;
  struct sqlite3 * sql(bool init = false);
  int transaction_level;

  void install_functions(app_state * app);
  void install_views();

  typedef std::vector< std::vector<std::string> > results;
  void execute(char const * query, ...);
  void fetch(results & res, 
             int const want_cols, 
             int const want_rows, 
             char const * query, ...);

  bool exists(hexenc<id> const & ident, 
              std::string const & table);
  bool delta_exists(hexenc<id> const & ident,
                    std::string const & table);
  bool delta_exists(hexenc<id> const & ident,
                    hexenc<id> const & base,
                    std::string const & table);

  unsigned long count(std::string const & table);
  unsigned long space_usage(std::string const & table,
                            std::string const & concatenated_columns);

  void get_ids(std::string const & table, std::set< hexenc<id> > & ids); 

  void get(hexenc<id> const & new_id,
           base64< gzip<data> > & dat,
           std::string const & table);
  void get_delta(hexenc<id> const & ident,
                 hexenc<id> const & base,
                 base64< gzip<delta> > & del,
                 std::string const & table);
  void get_version(hexenc<id> const & id,
                   base64< gzip<data> > & dat,
                   std::string const & data_table,
                   std::string const & delta_table);
  
  void put(hexenc<id> const & new_id,
           base64< gzip<data> > const & dat,
           std::string const & table);
  void drop(hexenc<id> const & base,
            std::string const & table);
  void put_delta(hexenc<id> const & id,
                 hexenc<id> const & base,
                 base64< gzip<delta> > const & del,
                 std::string const & table);
  void put_version(hexenc<id> const & old_id,
                   hexenc<id> const & new_id,
                   base64< gzip<delta> > const & del,
                   std::string const & data_table,
                   std::string const & delta_table);
  void put_reverse_version(hexenc<id> const & new_id,
                           hexenc<id> const & old_id,
                           base64< gzip<delta> > const & reverse_del,
                           std::string const & data_table,
                           std::string const & delta_table);

  void get_keys(std::string const & table, std::vector<rsa_keypair_id> & keys);

  bool cert_exists(cert const & t,
                  std::string const & table);
  void put_cert(cert const & t, std::string const & table);  
  void results_to_certs(results const & res,
                       std::vector<cert> & certs);

  void get_certs(std::vector< cert > & certs,
                 std::string const & table);  

  void get_certs(hexenc<id> const & id, 
                 std::vector< cert > & certs,
                 std::string const & table);  

  void get_certs(cert_name const & name,              
                 std::vector< cert > & certs,
                 std::string const & table);

  void get_certs(hexenc<id> const & id,
                 cert_name const & name,
                 std::vector< cert > & certs,
                 std::string const & table);  

  void get_certs(hexenc<id> const & id,
                 cert_name const & name,
                 base64<cert_value> const & val, 
                 std::vector< cert > & certs,
                 std::string const & table);  

  void get_certs(cert_name const & name,
                 base64<cert_value> const & val, 
                 std::vector<cert> & certs,
                 std::string const & table);

  void begin_transaction();
  void commit_transaction();
  void rollback_transaction();
  friend class transaction_guard;
  friend void rcs_put_raw_file_edge(hexenc<id> const & old_id,
                                    hexenc<id> const & new_id,
                                    base64< gzip<delta> > const & del,
                                    database & db);
  friend void rcs_put_raw_manifest_edge(hexenc<id> const & old_id,
                                        hexenc<id> const & new_id,
                                        base64< gzip<delta> > const & del,
                                        database & db);

public:

  database(fs::path const & file);

  void set_filename(fs::path const & file);
  void initialize();
  void debug(std::string const & sql, std::ostream & out);
  void dump(std::ostream &);
  void load(std::istream &);
  void info(std::ostream &);
  void version(std::ostream &);
  void migrate();
  void rehash();
  void ensure_open();
  
  bool file_version_exists(file_id const & id);
  bool manifest_version_exists(manifest_id const & id);
  bool revision_exists(revision_id const & id);

  void get_file_ids(std::set<file_id> & ids);
  void get_manifest_ids(std::set<manifest_id> & ids);
  void get_revision_ids(std::set<revision_id> & ids);

  void set_app(app_state * app);
  
  // get plain version if it exists, or reconstruct version
  // from deltas (if they exist)
  void get_file_version(file_id const & id,
                        file_data & dat);

  // get file delta if it exists, else calculate it.
  // both manifests must exist.
  void get_file_delta(file_id const & src,
                      file_id const & dst,
                      file_delta & del);

  // put file w/o predecessor into db
  void put_file(file_id const & new_id,
                file_data const & dat);

  // store new version and update old version to be a delta
  void put_file_version(file_id const & old_id,
                        file_id const & new_id,
                        file_delta const & del);

  // load in a "direct" new -> old reverse edge (used during
  // netsync and CVS load-in)
  void put_file_reverse_version(file_id const & old_id,
                                file_id const & new_id,
                                file_delta const & del);

  // get plain version if it exists, or reconstruct version
  // from deltas (if they exist). 
  void get_manifest_version(manifest_id const & id,
                            manifest_data & dat);

  // get a constructed manifest
  void get_manifest(manifest_id const & id,
                    manifest_map & mm);

  // get manifest delta if it exists, else calculate it.
  // both manifests must exist.
  void get_manifest_delta(manifest_id const & src,
                          manifest_id const & dst,
                          manifest_delta & del);

  // put manifest w/o predecessor into db
  void put_manifest(manifest_id const & new_id,
                    manifest_data const & dat);

  // store new version and update old version to be a delta
  void put_manifest_version(manifest_id const & old_id,
                            manifest_id const & new_id,
                            manifest_delta const & del);

  // load in a "direct" new -> old reverse edge (used during
  // netsync and CVS load-in)
  void put_manifest_reverse_version(manifest_id const & old_id,
                                    manifest_id const & new_id,
                                    manifest_delta const & del);


  void get_revision_ancestry(std::multimap<revision_id, revision_id> & graph);

  void get_revision_parents(revision_id const & id,
                           std::set<revision_id> & parents);

  void get_revision_children(revision_id const & id,
                             std::set<revision_id> & children);

  void get_revision_manifest(revision_id const & cid,
                            manifest_id & mid);

  void get_revision(revision_id const & id,
                   revision_set & cs);

  void get_revision(revision_id const & id,
                   revision_data & dat);

  void put_revision(revision_id const & new_id,
                   revision_set const & cs);

  void put_revision(revision_id const & new_id,
                    revision_data const & dat);
  
  void delete_existing_revs_and_certs();

  // crypto key / cert operations

  void get_key_ids(std::string const & pattern,
                   std::vector<rsa_keypair_id> & pubkeys,
                   std::vector<rsa_keypair_id> & privkeys);

  void get_private_keys(std::vector<rsa_keypair_id> & privkeys);
  void get_public_keys(std::vector<rsa_keypair_id> & pubkeys);

  bool key_exists(rsa_keypair_id const & id);

  bool public_key_exists(hexenc<id> const & hash);
  bool public_key_exists(rsa_keypair_id const & id);
  bool private_key_exists(rsa_keypair_id const & id);
  
  void get_pubkey(hexenc<id> const & hash, 
                  rsa_keypair_id & id,
                  base64<rsa_pub_key> & pub_encoded);

  void get_key(rsa_keypair_id const & id, 
               base64<rsa_pub_key> & pub_encoded);

  void get_key(rsa_keypair_id const & id, 
               base64< arc4<rsa_priv_key> > & priv_encoded);

  void put_key(rsa_keypair_id const & id, 
               base64<rsa_pub_key> const & pub_encoded);
  
  void put_key(rsa_keypair_id const & id, 
               base64< arc4<rsa_priv_key> > const & priv_encoded);
  
  void put_key_pair(rsa_keypair_id const & pub_id, 
                    base64<rsa_pub_key> const & pub_encoded,
                    base64< arc4<rsa_priv_key> > const & priv_encoded);

  void delete_private_key(rsa_keypair_id const & pub_id);
  void delete_public_key(rsa_keypair_id const & pub_id);
  
  // note: this section is ridiculous. please do something about it.

  bool manifest_cert_exists(manifest<cert> const & cert);
  bool manifest_cert_exists(hexenc<id> const & hash);
  void put_manifest_cert(manifest<cert> const & cert);

  bool revision_cert_exists(revision<cert> const & cert);
  bool revision_cert_exists(hexenc<id> const & hash);

  void put_revision_cert(revision<cert> const & cert);

  // this variant has to be rather coarse and fast, for netsync's use
  void get_revision_cert_index(std::vector< std::pair<hexenc<id>,
                               std::pair<revision_id, rsa_keypair_id> > > & idx);

  void get_revision_certs(std::vector< revision<cert> > & certs);

  void get_revision_certs(cert_name const & name, 
                          std::vector< revision<cert> > & certs);

  void get_revision_certs(revision_id const & id, 
                          cert_name const & name, 
                          std::vector< revision<cert> > & certs);

  void get_revision_certs(cert_name const & name,
                          base64<cert_value> const & val, 
                          std::vector< revision<cert> > & certs);

  void get_revision_certs(revision_id const & id, 
                          cert_name const & name, 
                          base64<cert_value> const & value,
                          std::vector< revision<cert> > & certs);

  void get_revision_certs(revision_id const & id, 
                          std::vector< revision<cert> > & certs);

  void get_revision_cert(hexenc<id> const & hash,
                         revision<cert> & cert);
  
  void get_manifest_certs(manifest_id const & id, 
                          std::vector< manifest<cert> > & certs);

  void get_manifest_certs(cert_name const & name, 
                          std::vector< manifest<cert> > & certs);

  void get_manifest_certs(manifest_id const & id, 
                          cert_name const & name, 
                          std::vector< manifest<cert> > & certs);
  
  void get_manifest_cert(hexenc<id> const & hash,
                         manifest<cert> & cert);

  // epochs 

  void get_epochs(std::map<cert_value, epoch_data> & epochs);

  void get_epoch(epoch_id const & eid, cert_value & branch, epoch_data & epo);
  
  bool epoch_exists(epoch_id const & eid);

  void set_epoch(cert_value const & branch, epoch_data const & epo);  

  void clear_epoch(cert_value const & branch);
 
  // vars

  void get_vars(std::map<var_key, var_value > & vars);

  void get_var(var_key const & key, var_value & value);

  bool var_exists(var_key const & key);

  void set_var(var_key const & key, var_value const & value);

  void clear_var(var_key const & key);

  // completion stuff

  void complete(std::string const & partial,
                std::set<revision_id> & completions);

  void complete(std::string const & partial,
                std::set<manifest_id> & completions);
  
  void complete(std::string const & partial,
                std::set<file_id> & completions);

  void complete(commands::selector_type ty,
                std::string const & partial,
                std::vector<std::pair<commands::selector_type, 
                                      std::string> > const & limit,
                std::set<std::string> & completions);
  
  ~database();

};

// transaction guards nest. acquire one in any scope you'd like
// transaction-protected, and it'll make sure the db aborts a
// txn if there's any exception before you call commit()

class transaction_guard
{
  bool committed;
  database & db;
public:
  transaction_guard(database & d);
  ~transaction_guard();
  void commit();
};



#endif // __DATABASE_HH__