1*33e1ec22Sdrh /*
2*33e1ec22Sdrh ** 2021-01-01
3*33e1ec22Sdrh **
4*33e1ec22Sdrh ** The author disclaims copyright to this source code. In place of
5*33e1ec22Sdrh ** a legal notice, here is a blessing:
6*33e1ec22Sdrh **
7*33e1ec22Sdrh ** May you do good and not evil.
8*33e1ec22Sdrh ** May you find forgiveness for yourself and forgive others.
9*33e1ec22Sdrh ** May you share freely, never taking more than you give.
10*33e1ec22Sdrh **
11*33e1ec22Sdrh *************************************************************************
12*33e1ec22Sdrh **
13*33e1ec22Sdrh ** This file implements a program used to measure the start-up performance
14*33e1ec22Sdrh ** of SQLite.
15*33e1ec22Sdrh **
16*33e1ec22Sdrh ** To use:
17*33e1ec22Sdrh **
18*33e1ec22Sdrh ** ./startup init
19*33e1ec22Sdrh ** valgrind --tool=cachegrind ./startup run
20*33e1ec22Sdrh **
21*33e1ec22Sdrh **
22*33e1ec22Sdrh ** The "./startup init" command creates the test database file named
23*33e1ec22Sdrh ** "startup.db". The performance test is run by the "./startup run"
24*33e1ec22Sdrh ** command. That command does nothing but open the database file and
25*33e1ec22Sdrh ** parse the entire schema.
26*33e1ec22Sdrh */
27*33e1ec22Sdrh #include <stdio.h>
28*33e1ec22Sdrh #include <unistd.h>
29*33e1ec22Sdrh #include <string.h>
30*33e1ec22Sdrh #include <stdlib.h>
31*33e1ec22Sdrh #include <ctype.h>
32*33e1ec22Sdrh #include "sqlite3.h"
33*33e1ec22Sdrh
34*33e1ec22Sdrh static const char zHelp[] =
35*33e1ec22Sdrh "Usage: %s COMMAND\n"
36*33e1ec22Sdrh "Commands:\n"
37*33e1ec22Sdrh " init Initialized the startup.db database file\n"
38*33e1ec22Sdrh " run Run the startup performance test\n"
39*33e1ec22Sdrh "Options:\n"
40*33e1ec22Sdrh " --dbname NAME Set the name of the test database file\n"
41*33e1ec22Sdrh " --heap SZ MIN Memory allocator uses SZ bytes & min allocation MIN\n"
42*33e1ec22Sdrh " --stats Show statistics at the end\n"
43*33e1ec22Sdrh /* TBD
44*33e1ec22Sdrh " --journal M Set the journal_mode to M\n"
45*33e1ec22Sdrh " --lookaside N SZ Configure lookaside for N slots of SZ bytes each\n"
46*33e1ec22Sdrh " --mmap SZ MMAP the first SZ bytes of the database file\n"
47*33e1ec22Sdrh " --multithread Set multithreaded mode\n"
48*33e1ec22Sdrh " --nomemstat Disable memory statistics\n"
49*33e1ec22Sdrh " --pagesize N Set the page size to N\n"
50*33e1ec22Sdrh " --pcache N SZ Configure N pages of pagecache each of size SZ bytes\n"
51*33e1ec22Sdrh " --serialized Set serialized threading mode\n"
52*33e1ec22Sdrh " --singlethread Set single-threaded mode - disables all mutexing\n"
53*33e1ec22Sdrh " --utf16be Set text encoding to UTF-16BE\n"
54*33e1ec22Sdrh " --utf16le Set text encoding to UTF-16LE\n"
55*33e1ec22Sdrh " --utf8 Set text encoding to UTF-8\n"
56*33e1ec22Sdrh */
57*33e1ec22Sdrh ;
58*33e1ec22Sdrh
usage(const char * argv0)59*33e1ec22Sdrh static void usage(const char *argv0){
60*33e1ec22Sdrh printf(zHelp, argv0);
61*33e1ec22Sdrh exit(1);
62*33e1ec22Sdrh }
63*33e1ec22Sdrh
64*33e1ec22Sdrh /*
65*33e1ec22Sdrh ** The test schema is derived from the Fossil repository for SQLite itself.
66*33e1ec22Sdrh ** The schema covers the repository, the local checkout database, and
67*33e1ec22Sdrh ** the global configuration database.
68*33e1ec22Sdrh */
69*33e1ec22Sdrh static const char zTestSchema[] =
70*33e1ec22Sdrh "CREATE TABLE repo_blob(\n"
71*33e1ec22Sdrh " rid INTEGER PRIMARY KEY,\n"
72*33e1ec22Sdrh " rcvid INTEGER,\n"
73*33e1ec22Sdrh " size INTEGER,\n"
74*33e1ec22Sdrh " uuid TEXT UNIQUE NOT NULL,\n"
75*33e1ec22Sdrh " content BLOB,\n"
76*33e1ec22Sdrh " CHECK( length(uuid)>=40 AND rid>0 )\n"
77*33e1ec22Sdrh ");\n"
78*33e1ec22Sdrh "CREATE TABLE repo_delta(\n"
79*33e1ec22Sdrh " rid INTEGER PRIMARY KEY,\n"
80*33e1ec22Sdrh " srcid INTEGER NOT NULL REFERENCES blob\n"
81*33e1ec22Sdrh ");\n"
82*33e1ec22Sdrh "CREATE TABLE repo_rcvfrom(\n"
83*33e1ec22Sdrh " rcvid INTEGER PRIMARY KEY,\n"
84*33e1ec22Sdrh " uid INTEGER REFERENCES user,\n"
85*33e1ec22Sdrh " mtime DATETIME,\n"
86*33e1ec22Sdrh " nonce TEXT UNIQUE,\n"
87*33e1ec22Sdrh " ipaddr TEXT\n"
88*33e1ec22Sdrh ");\n"
89*33e1ec22Sdrh "CREATE TABLE repo_private(rid INTEGER PRIMARY KEY);\n"
90*33e1ec22Sdrh "CREATE TABLE repo_accesslog(\n"
91*33e1ec22Sdrh " uname TEXT,\n"
92*33e1ec22Sdrh " ipaddr TEXT,\n"
93*33e1ec22Sdrh " success BOOLEAN,\n"
94*33e1ec22Sdrh " mtime TIMESTAMP);\n"
95*33e1ec22Sdrh "CREATE TABLE repo_user(\n"
96*33e1ec22Sdrh " uid INTEGER PRIMARY KEY,\n"
97*33e1ec22Sdrh " login TEXT UNIQUE,\n"
98*33e1ec22Sdrh " pw TEXT,\n"
99*33e1ec22Sdrh " cap TEXT,\n"
100*33e1ec22Sdrh " cookie TEXT,\n"
101*33e1ec22Sdrh " ipaddr TEXT,\n"
102*33e1ec22Sdrh " cexpire DATETIME,\n"
103*33e1ec22Sdrh " info TEXT,\n"
104*33e1ec22Sdrh " mtime DATE,\n"
105*33e1ec22Sdrh " photo BLOB\n"
106*33e1ec22Sdrh ");\n"
107*33e1ec22Sdrh "CREATE TABLE repo_reportfmt(\n"
108*33e1ec22Sdrh " rn INTEGER PRIMARY KEY,\n"
109*33e1ec22Sdrh " owner TEXT,\n"
110*33e1ec22Sdrh " title TEXT UNIQUE,\n"
111*33e1ec22Sdrh " mtime INTEGER,\n"
112*33e1ec22Sdrh " cols TEXT,\n"
113*33e1ec22Sdrh " sqlcode TEXT\n"
114*33e1ec22Sdrh ");\n"
115*33e1ec22Sdrh "CREATE TABLE repo_sqlite_stat2(tbl,idx,sampleno,sample);\n"
116*33e1ec22Sdrh "CREATE TABLE repo_sqlite_stat1(tbl,idx,stat);\n"
117*33e1ec22Sdrh "CREATE TABLE repo_sqlite_stat3(tbl,idx,neq,nlt,ndlt,sample);\n"
118*33e1ec22Sdrh "CREATE TABLE repo_config(\n"
119*33e1ec22Sdrh " name TEXT PRIMARY KEY NOT NULL,\n"
120*33e1ec22Sdrh " value CLOB, mtime INTEGER,\n"
121*33e1ec22Sdrh " CHECK( typeof(name)='text' AND length(name)>=1 )\n"
122*33e1ec22Sdrh ") WITHOUT ROWID;\n"
123*33e1ec22Sdrh "CREATE TABLE repo_shun(uuid PRIMARY KEY,\n"
124*33e1ec22Sdrh " mtime INTEGER,\n"
125*33e1ec22Sdrh " scom TEXT) WITHOUT ROWID;\n"
126*33e1ec22Sdrh "CREATE TABLE repo_concealed(\n"
127*33e1ec22Sdrh " hash TEXT PRIMARY KEY,\n"
128*33e1ec22Sdrh " content TEXT\n"
129*33e1ec22Sdrh ", mtime INTEGER) WITHOUT ROWID;\n"
130*33e1ec22Sdrh "CREATE TABLE repo_admin_log(\n"
131*33e1ec22Sdrh " id INTEGER PRIMARY KEY,\n"
132*33e1ec22Sdrh " time INTEGER, -- Seconds since 1970\n"
133*33e1ec22Sdrh " page TEXT, -- path of page\n"
134*33e1ec22Sdrh " who TEXT, -- User who made the change\n"
135*33e1ec22Sdrh " what TEXT -- What changed\n"
136*33e1ec22Sdrh ");\n"
137*33e1ec22Sdrh "CREATE TABLE repo_unversioned(\n"
138*33e1ec22Sdrh " name TEXT PRIMARY KEY,\n"
139*33e1ec22Sdrh " rcvid INTEGER,\n"
140*33e1ec22Sdrh " mtime DATETIME,\n"
141*33e1ec22Sdrh " hash TEXT,\n"
142*33e1ec22Sdrh " sz INTEGER,\n"
143*33e1ec22Sdrh " encoding INT,\n"
144*33e1ec22Sdrh " content BLOB\n"
145*33e1ec22Sdrh ") WITHOUT ROWID;\n"
146*33e1ec22Sdrh "CREATE TABLE repo_subscriber(\n"
147*33e1ec22Sdrh " subscriberId INTEGER PRIMARY KEY,\n"
148*33e1ec22Sdrh " subscriberCode BLOB DEFAULT (randomblob(32)) UNIQUE,\n"
149*33e1ec22Sdrh " semail TEXT UNIQUE COLLATE nocase,\n"
150*33e1ec22Sdrh " suname TEXT,\n"
151*33e1ec22Sdrh " sverified BOOLEAN DEFAULT true,\n"
152*33e1ec22Sdrh " sdonotcall BOOLEAN,\n"
153*33e1ec22Sdrh " sdigest BOOLEAN,\n"
154*33e1ec22Sdrh " ssub TEXT,\n"
155*33e1ec22Sdrh " sctime INTDATE,\n"
156*33e1ec22Sdrh " mtime INTDATE,\n"
157*33e1ec22Sdrh " smip TEXT\n"
158*33e1ec22Sdrh ");\n"
159*33e1ec22Sdrh "CREATE TABLE repo_pending_alert(\n"
160*33e1ec22Sdrh " eventid TEXT PRIMARY KEY,\n"
161*33e1ec22Sdrh " sentSep BOOLEAN DEFAULT false,\n"
162*33e1ec22Sdrh " sentDigest BOOLEAN DEFAULT false\n"
163*33e1ec22Sdrh ", sentMod BOOLEAN DEFAULT false) WITHOUT ROWID;\n"
164*33e1ec22Sdrh "CREATE INDEX repo_delta_i1 ON repo_delta(srcid);\n"
165*33e1ec22Sdrh "CREATE INDEX repo_blob_rcvid ON repo_blob(rcvid);\n"
166*33e1ec22Sdrh "CREATE INDEX repo_subscriberUname\n"
167*33e1ec22Sdrh " ON repo_subscriber(suname) WHERE suname IS NOT NULL;\n"
168*33e1ec22Sdrh "CREATE VIEW repo_artifact(rid,rcvid,size,atype,srcid,hash,content) AS\n"
169*33e1ec22Sdrh " SELECT blob.rid,rcvid,size,1,srcid,uuid,content\n"
170*33e1ec22Sdrh " FROM repo_blob LEFT JOIN repo_delta ON (blob.rid=delta.rid);\n"
171*33e1ec22Sdrh "CREATE TABLE repo_filename(\n"
172*33e1ec22Sdrh " fnid INTEGER PRIMARY KEY,\n"
173*33e1ec22Sdrh " name TEXT UNIQUE\n"
174*33e1ec22Sdrh ");\n"
175*33e1ec22Sdrh "CREATE TABLE repo_mlink(\n"
176*33e1ec22Sdrh " mid INTEGER,\n"
177*33e1ec22Sdrh " fid INTEGER,\n"
178*33e1ec22Sdrh " pmid INTEGER,\n"
179*33e1ec22Sdrh " pid INTEGER,\n"
180*33e1ec22Sdrh " fnid INTEGER REFERENCES filename,\n"
181*33e1ec22Sdrh " pfnid INTEGER,\n"
182*33e1ec22Sdrh " mperm INTEGER,\n"
183*33e1ec22Sdrh " isaux BOOLEAN DEFAULT 0\n"
184*33e1ec22Sdrh ");\n"
185*33e1ec22Sdrh "CREATE INDEX repo_mlink_i1 ON repo_mlink(mid);\n"
186*33e1ec22Sdrh "CREATE INDEX repo_mlink_i2 ON repo_mlink(fnid);\n"
187*33e1ec22Sdrh "CREATE INDEX repo_mlink_i3 ON repo_mlink(fid);\n"
188*33e1ec22Sdrh "CREATE INDEX repo_mlink_i4 ON repo_mlink(pid);\n"
189*33e1ec22Sdrh "CREATE TABLE repo_plink(\n"
190*33e1ec22Sdrh " pid INTEGER REFERENCES blob,\n"
191*33e1ec22Sdrh " cid INTEGER REFERENCES blob,\n"
192*33e1ec22Sdrh " isprim BOOLEAN,\n"
193*33e1ec22Sdrh " mtime DATETIME,\n"
194*33e1ec22Sdrh " baseid INTEGER REFERENCES blob,\n"
195*33e1ec22Sdrh " UNIQUE(pid, cid)\n"
196*33e1ec22Sdrh ");\n"
197*33e1ec22Sdrh "CREATE INDEX repo_plink_i2 ON repo_plink(cid,pid);\n"
198*33e1ec22Sdrh "CREATE TABLE repo_leaf(rid INTEGER PRIMARY KEY);\n"
199*33e1ec22Sdrh "CREATE TABLE repo_event(\n"
200*33e1ec22Sdrh " type TEXT,\n"
201*33e1ec22Sdrh " mtime DATETIME,\n"
202*33e1ec22Sdrh " objid INTEGER PRIMARY KEY,\n"
203*33e1ec22Sdrh " tagid INTEGER,\n"
204*33e1ec22Sdrh " uid INTEGER REFERENCES user,\n"
205*33e1ec22Sdrh " bgcolor TEXT,\n"
206*33e1ec22Sdrh " euser TEXT,\n"
207*33e1ec22Sdrh " user TEXT,\n"
208*33e1ec22Sdrh " ecomment TEXT,\n"
209*33e1ec22Sdrh " comment TEXT,\n"
210*33e1ec22Sdrh " brief TEXT,\n"
211*33e1ec22Sdrh " omtime DATETIME\n"
212*33e1ec22Sdrh ");\n"
213*33e1ec22Sdrh "CREATE INDEX repo_event_i1 ON repo_event(mtime);\n"
214*33e1ec22Sdrh "CREATE TABLE repo_phantom(\n"
215*33e1ec22Sdrh " rid INTEGER PRIMARY KEY\n"
216*33e1ec22Sdrh ");\n"
217*33e1ec22Sdrh "CREATE TABLE repo_orphan(\n"
218*33e1ec22Sdrh " rid INTEGER PRIMARY KEY,\n"
219*33e1ec22Sdrh " baseline INTEGER\n"
220*33e1ec22Sdrh ");\n"
221*33e1ec22Sdrh "CREATE INDEX repo_orphan_baseline ON repo_orphan(baseline);\n"
222*33e1ec22Sdrh "CREATE TABLE repo_unclustered(\n"
223*33e1ec22Sdrh " rid INTEGER PRIMARY KEY\n"
224*33e1ec22Sdrh ");\n"
225*33e1ec22Sdrh "CREATE TABLE repo_unsent(\n"
226*33e1ec22Sdrh " rid INTEGER PRIMARY KEY\n"
227*33e1ec22Sdrh ");\n"
228*33e1ec22Sdrh "CREATE TABLE repo_tag(\n"
229*33e1ec22Sdrh " tagid INTEGER PRIMARY KEY,\n"
230*33e1ec22Sdrh " tagname TEXT UNIQUE\n"
231*33e1ec22Sdrh ");\n"
232*33e1ec22Sdrh "CREATE TABLE repo_tagxref(\n"
233*33e1ec22Sdrh " tagid INTEGER REFERENCES tag,\n"
234*33e1ec22Sdrh " tagtype INTEGER,\n"
235*33e1ec22Sdrh " srcid INTEGER REFERENCES blob,\n"
236*33e1ec22Sdrh " origid INTEGER REFERENCES blob,\n"
237*33e1ec22Sdrh " value TEXT,\n"
238*33e1ec22Sdrh " mtime TIMESTAMP,\n"
239*33e1ec22Sdrh " rid INTEGER REFERENCE blob,\n"
240*33e1ec22Sdrh " UNIQUE(rid, tagid)\n"
241*33e1ec22Sdrh ");\n"
242*33e1ec22Sdrh "CREATE INDEX repo_tagxref_i1 ON repo_tagxref(tagid, mtime);\n"
243*33e1ec22Sdrh "CREATE TABLE repo_backlink(\n"
244*33e1ec22Sdrh " target TEXT,\n"
245*33e1ec22Sdrh " srctype INT,\n"
246*33e1ec22Sdrh " srcid INT,\n"
247*33e1ec22Sdrh " mtime TIMESTAMP,\n"
248*33e1ec22Sdrh " UNIQUE(target, srctype, srcid)\n"
249*33e1ec22Sdrh ");\n"
250*33e1ec22Sdrh "CREATE INDEX repo_backlink_src ON repo_backlink(srcid, srctype);\n"
251*33e1ec22Sdrh "CREATE TABLE repo_attachment(\n"
252*33e1ec22Sdrh " attachid INTEGER PRIMARY KEY,\n"
253*33e1ec22Sdrh " isLatest BOOLEAN DEFAULT 0,\n"
254*33e1ec22Sdrh " mtime TIMESTAMP,\n"
255*33e1ec22Sdrh " src TEXT,\n"
256*33e1ec22Sdrh " target TEXT,\n"
257*33e1ec22Sdrh " filename TEXT,\n"
258*33e1ec22Sdrh " comment TEXT,\n"
259*33e1ec22Sdrh " user TEXT\n"
260*33e1ec22Sdrh ");\n"
261*33e1ec22Sdrh "CREATE INDEX repo_attachment_idx1\n"
262*33e1ec22Sdrh " ON repo_attachment(target, filename, mtime);\n"
263*33e1ec22Sdrh "CREATE INDEX repo_attachment_idx2 ON repo_attachment(src);\n"
264*33e1ec22Sdrh "CREATE TABLE repo_cherrypick(\n"
265*33e1ec22Sdrh " parentid INT,\n"
266*33e1ec22Sdrh " childid INT,\n"
267*33e1ec22Sdrh " isExclude BOOLEAN DEFAULT false,\n"
268*33e1ec22Sdrh " PRIMARY KEY(parentid, childid)\n"
269*33e1ec22Sdrh ") WITHOUT ROWID;\n"
270*33e1ec22Sdrh "CREATE INDEX repo_cherrypick_cid ON repo_cherrypick(childid);\n"
271*33e1ec22Sdrh "CREATE TABLE repo_ticket(\n"
272*33e1ec22Sdrh " -- Do not change any column that begins with tkt_\n"
273*33e1ec22Sdrh " tkt_id INTEGER PRIMARY KEY,\n"
274*33e1ec22Sdrh " tkt_uuid TEXT UNIQUE,\n"
275*33e1ec22Sdrh " tkt_mtime DATE,\n"
276*33e1ec22Sdrh " tkt_ctime DATE,\n"
277*33e1ec22Sdrh " -- Add as many fields as required below this line\n"
278*33e1ec22Sdrh " type TEXT,\n"
279*33e1ec22Sdrh " status TEXT,\n"
280*33e1ec22Sdrh " subsystem TEXT,\n"
281*33e1ec22Sdrh " priority TEXT,\n"
282*33e1ec22Sdrh " severity TEXT,\n"
283*33e1ec22Sdrh " foundin TEXT,\n"
284*33e1ec22Sdrh " private_contact TEXT,\n"
285*33e1ec22Sdrh " resolution TEXT,\n"
286*33e1ec22Sdrh " title TEXT,\n"
287*33e1ec22Sdrh " comment TEXT\n"
288*33e1ec22Sdrh ");\n"
289*33e1ec22Sdrh "CREATE TABLE repo_ticketchng(\n"
290*33e1ec22Sdrh " -- Do not change any column that begins with tkt_\n"
291*33e1ec22Sdrh " tkt_id INTEGER REFERENCES ticket,\n"
292*33e1ec22Sdrh " tkt_rid INTEGER REFERENCES blob,\n"
293*33e1ec22Sdrh " tkt_mtime DATE,\n"
294*33e1ec22Sdrh " -- Add as many fields as required below this line\n"
295*33e1ec22Sdrh " login TEXT,\n"
296*33e1ec22Sdrh " username TEXT,\n"
297*33e1ec22Sdrh " mimetype TEXT,\n"
298*33e1ec22Sdrh " icomment TEXT\n"
299*33e1ec22Sdrh ");\n"
300*33e1ec22Sdrh "CREATE INDEX repo_ticketchng_idx1 ON repo_ticketchng(tkt_id, tkt_mtime);\n"
301*33e1ec22Sdrh "CREATE TRIGGER repo_alert_trigger1\n"
302*33e1ec22Sdrh "AFTER INSERT ON repo_event BEGIN\n"
303*33e1ec22Sdrh " INSERT INTO repo_pending_alert(eventid)\n"
304*33e1ec22Sdrh " SELECT printf('%.1c%d',new.type,new.objid) WHERE true\n"
305*33e1ec22Sdrh " ON CONFLICT(eventId) DO NOTHING;\n"
306*33e1ec22Sdrh "END;\n"
307*33e1ec22Sdrh "CREATE TABLE repo_vcache(\n"
308*33e1ec22Sdrh " vid INTEGER, -- check-in ID\n"
309*33e1ec22Sdrh " fname TEXT, -- filename\n"
310*33e1ec22Sdrh " rid INTEGER, -- artifact ID\n"
311*33e1ec22Sdrh " PRIMARY KEY(vid,fname)\n"
312*33e1ec22Sdrh ") WITHOUT ROWID;\n"
313*33e1ec22Sdrh "CREATE TABLE localdb_vvar(\n"
314*33e1ec22Sdrh " name TEXT PRIMARY KEY NOT NULL,\n"
315*33e1ec22Sdrh " value CLOB,\n"
316*33e1ec22Sdrh " CHECK( typeof(name)='text' AND length(name)>=1 )\n"
317*33e1ec22Sdrh ");\n"
318*33e1ec22Sdrh "CREATE TABLE localdb_vfile(\n"
319*33e1ec22Sdrh " id INTEGER PRIMARY KEY,\n"
320*33e1ec22Sdrh " vid INTEGER REFERENCES blob,\n"
321*33e1ec22Sdrh " chnged INT DEFAULT 0,\n"
322*33e1ec22Sdrh " deleted BOOLEAN DEFAULT 0,\n"
323*33e1ec22Sdrh " isexe BOOLEAN,\n"
324*33e1ec22Sdrh " islink BOOLEAN,\n"
325*33e1ec22Sdrh " rid INTEGER,\n"
326*33e1ec22Sdrh " mrid INTEGER,\n"
327*33e1ec22Sdrh " mtime INTEGER,\n"
328*33e1ec22Sdrh " pathname TEXT,\n"
329*33e1ec22Sdrh " origname TEXT, mhash,\n"
330*33e1ec22Sdrh " UNIQUE(pathname,vid)\n"
331*33e1ec22Sdrh ");\n"
332*33e1ec22Sdrh "CREATE TABLE localdb_sqlite_stat1(tbl,idx,stat);\n"
333*33e1ec22Sdrh "CREATE TABLE localdb_vcache(\n"
334*33e1ec22Sdrh " vid INTEGER, -- check-in ID\n"
335*33e1ec22Sdrh " fname TEXT, -- filename\n"
336*33e1ec22Sdrh " rid INTEGER, -- artifact ID\n"
337*33e1ec22Sdrh " PRIMARY KEY(vid,fname)\n"
338*33e1ec22Sdrh ") WITHOUT ROWID;\n"
339*33e1ec22Sdrh "CREATE TABLE localdb_stash(\n"
340*33e1ec22Sdrh " stashid INTEGER PRIMARY KEY,\n"
341*33e1ec22Sdrh " vid INTEGER,\n"
342*33e1ec22Sdrh " hash TEXT,\n"
343*33e1ec22Sdrh " comment TEXT,\n"
344*33e1ec22Sdrh " ctime TIMESTAMP\n"
345*33e1ec22Sdrh ");\n"
346*33e1ec22Sdrh "CREATE TABLE localdb_stashfile(\n"
347*33e1ec22Sdrh " stashid INTEGER REFERENCES stash,\n"
348*33e1ec22Sdrh " isAdded BOOLEAN,\n"
349*33e1ec22Sdrh " isRemoved BOOLEAN,\n"
350*33e1ec22Sdrh " isExec BOOLEAN,\n"
351*33e1ec22Sdrh " isLink BOOLEAN,\n"
352*33e1ec22Sdrh " rid INTEGER,\n"
353*33e1ec22Sdrh " hash TEXT,\n"
354*33e1ec22Sdrh " origname TEXT,\n"
355*33e1ec22Sdrh " newname TEXT,\n"
356*33e1ec22Sdrh " delta BLOB,\n"
357*33e1ec22Sdrh " PRIMARY KEY(newname, stashid)\n"
358*33e1ec22Sdrh ");\n"
359*33e1ec22Sdrh "CREATE TABLE localdb_vmerge(\n"
360*33e1ec22Sdrh " id INTEGER REFERENCES vfile,\n"
361*33e1ec22Sdrh " merge INTEGER,\n"
362*33e1ec22Sdrh " mhash TEXT\n"
363*33e1ec22Sdrh ");\n"
364*33e1ec22Sdrh "CREATE UNIQUE INDEX localdb_vmergex1 ON localdb_vmerge(id,mhash);\n"
365*33e1ec22Sdrh "CREATE TRIGGER localdb_vmerge_ck1 AFTER INSERT ON localdb_vmerge\n"
366*33e1ec22Sdrh "WHEN new.mhash IS NULL BEGIN\n"
367*33e1ec22Sdrh " SELECT raise(FAIL,\n"
368*33e1ec22Sdrh " 'trying to update a newer checkout with an older version of Fossil');\n"
369*33e1ec22Sdrh "END;\n"
370*33e1ec22Sdrh "CREATE TABLE configdb_global_config(\n"
371*33e1ec22Sdrh " name TEXT PRIMARY KEY,\n"
372*33e1ec22Sdrh " value TEXT\n"
373*33e1ec22Sdrh ");\n"
374*33e1ec22Sdrh "CREATE TABLE configdb_sqlite_stat1(tbl,idx,stat);\n"
375*33e1ec22Sdrh ;
376*33e1ec22Sdrh
377*33e1ec22Sdrh #ifdef __linux__
378*33e1ec22Sdrh #include <sys/types.h>
379*33e1ec22Sdrh #include <unistd.h>
380*33e1ec22Sdrh
381*33e1ec22Sdrh /*
382*33e1ec22Sdrh ** Attempt to display I/O stats on Linux using /proc/PID/io
383*33e1ec22Sdrh */
displayLinuxIoStats(FILE * out)384*33e1ec22Sdrh static void displayLinuxIoStats(FILE *out){
385*33e1ec22Sdrh FILE *in;
386*33e1ec22Sdrh char z[200];
387*33e1ec22Sdrh sqlite3_snprintf(sizeof(z), z, "/proc/%d/io", getpid());
388*33e1ec22Sdrh in = fopen(z, "rb");
389*33e1ec22Sdrh if( in==0 ) return;
390*33e1ec22Sdrh while( fgets(z, sizeof(z), in)!=0 ){
391*33e1ec22Sdrh static const struct {
392*33e1ec22Sdrh const char *zPattern;
393*33e1ec22Sdrh const char *zDesc;
394*33e1ec22Sdrh } aTrans[] = {
395*33e1ec22Sdrh { "rchar: ", "Bytes received by read():" },
396*33e1ec22Sdrh { "wchar: ", "Bytes sent to write():" },
397*33e1ec22Sdrh { "syscr: ", "Read() system calls:" },
398*33e1ec22Sdrh { "syscw: ", "Write() system calls:" },
399*33e1ec22Sdrh { "read_bytes: ", "Bytes rcvd from storage:" },
400*33e1ec22Sdrh { "write_bytes: ", "Bytes sent to storage:" },
401*33e1ec22Sdrh { "cancelled_write_bytes: ", "Cancelled write bytes:" },
402*33e1ec22Sdrh };
403*33e1ec22Sdrh int i;
404*33e1ec22Sdrh for(i=0; i<sizeof(aTrans)/sizeof(aTrans[0]); i++){
405*33e1ec22Sdrh int n = (int)strlen(aTrans[i].zPattern);
406*33e1ec22Sdrh if( strncmp(aTrans[i].zPattern, z, n)==0 ){
407*33e1ec22Sdrh fprintf(out, "-- %-28s %s", aTrans[i].zDesc, &z[n]);
408*33e1ec22Sdrh break;
409*33e1ec22Sdrh }
410*33e1ec22Sdrh }
411*33e1ec22Sdrh }
412*33e1ec22Sdrh fclose(in);
413*33e1ec22Sdrh }
414*33e1ec22Sdrh #endif
415*33e1ec22Sdrh
416*33e1ec22Sdrh /*
417*33e1ec22Sdrh ** Return the value of a hexadecimal digit. Return -1 if the input
418*33e1ec22Sdrh ** is not a hex digit.
419*33e1ec22Sdrh */
hexDigitValue(char c)420*33e1ec22Sdrh static int hexDigitValue(char c){
421*33e1ec22Sdrh if( c>='0' && c<='9' ) return c - '0';
422*33e1ec22Sdrh if( c>='a' && c<='f' ) return c - 'a' + 10;
423*33e1ec22Sdrh if( c>='A' && c<='F' ) return c - 'A' + 10;
424*33e1ec22Sdrh return -1;
425*33e1ec22Sdrh }
426*33e1ec22Sdrh
427*33e1ec22Sdrh /*
428*33e1ec22Sdrh ** Interpret zArg as an integer value, possibly with suffixes.
429*33e1ec22Sdrh */
integerValue(const char * zArg)430*33e1ec22Sdrh static int integerValue(const char *zArg){
431*33e1ec22Sdrh sqlite3_int64 v = 0;
432*33e1ec22Sdrh static const struct { char *zSuffix; int iMult; } aMult[] = {
433*33e1ec22Sdrh { "KiB", 1024 },
434*33e1ec22Sdrh { "MiB", 1024*1024 },
435*33e1ec22Sdrh { "GiB", 1024*1024*1024 },
436*33e1ec22Sdrh { "KB", 1000 },
437*33e1ec22Sdrh { "MB", 1000000 },
438*33e1ec22Sdrh { "GB", 1000000000 },
439*33e1ec22Sdrh { "K", 1000 },
440*33e1ec22Sdrh { "M", 1000000 },
441*33e1ec22Sdrh { "G", 1000000000 },
442*33e1ec22Sdrh };
443*33e1ec22Sdrh int i;
444*33e1ec22Sdrh int isNeg = 0;
445*33e1ec22Sdrh if( zArg[0]=='-' ){
446*33e1ec22Sdrh isNeg = 1;
447*33e1ec22Sdrh zArg++;
448*33e1ec22Sdrh }else if( zArg[0]=='+' ){
449*33e1ec22Sdrh zArg++;
450*33e1ec22Sdrh }
451*33e1ec22Sdrh if( zArg[0]=='0' && zArg[1]=='x' ){
452*33e1ec22Sdrh int x;
453*33e1ec22Sdrh zArg += 2;
454*33e1ec22Sdrh while( (x = hexDigitValue(zArg[0]))>=0 ){
455*33e1ec22Sdrh v = (v<<4) + x;
456*33e1ec22Sdrh zArg++;
457*33e1ec22Sdrh }
458*33e1ec22Sdrh }else{
459*33e1ec22Sdrh while( isdigit(zArg[0]) ){
460*33e1ec22Sdrh v = v*10 + zArg[0] - '0';
461*33e1ec22Sdrh zArg++;
462*33e1ec22Sdrh }
463*33e1ec22Sdrh }
464*33e1ec22Sdrh for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){
465*33e1ec22Sdrh if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
466*33e1ec22Sdrh v *= aMult[i].iMult;
467*33e1ec22Sdrh break;
468*33e1ec22Sdrh }
469*33e1ec22Sdrh }
470*33e1ec22Sdrh if( v>0x7fffffff ){
471*33e1ec22Sdrh printf("ERROR: parameter too large - max 2147483648\n");
472*33e1ec22Sdrh exit(1);
473*33e1ec22Sdrh }
474*33e1ec22Sdrh return (int)(isNeg? -v : v);
475*33e1ec22Sdrh }
476*33e1ec22Sdrh
477*33e1ec22Sdrh
main(int argc,char ** argv)478*33e1ec22Sdrh int main(int argc, char **argv){
479*33e1ec22Sdrh const char *zCmd = 0;
480*33e1ec22Sdrh int i;
481*33e1ec22Sdrh int bAutovac = 0;
482*33e1ec22Sdrh int showStats = 0;
483*33e1ec22Sdrh const char *zDbName = "./startup.db";
484*33e1ec22Sdrh int nHeap = 0;
485*33e1ec22Sdrh int mnHeap = 0;
486*33e1ec22Sdrh
487*33e1ec22Sdrh for(i=1; i<argc; i++){
488*33e1ec22Sdrh const char *z = argv[i];
489*33e1ec22Sdrh if( z[0]!='-' ){
490*33e1ec22Sdrh if( zCmd ){
491*33e1ec22Sdrh usage(argv[0]);
492*33e1ec22Sdrh }
493*33e1ec22Sdrh zCmd = z;
494*33e1ec22Sdrh continue;
495*33e1ec22Sdrh }
496*33e1ec22Sdrh if( z[1]=='-' ) z++;
497*33e1ec22Sdrh if( strcmp(z, "-autovacuum")==0 ){
498*33e1ec22Sdrh bAutovac = 1;
499*33e1ec22Sdrh }else
500*33e1ec22Sdrh if( strcmp(z, "-dbname")==0 ){
501*33e1ec22Sdrh if( i==argc-1 ){
502*33e1ec22Sdrh printf("ERROR: missing argument on \"%s\"\n", argv[0]);
503*33e1ec22Sdrh exit(1);
504*33e1ec22Sdrh }
505*33e1ec22Sdrh zDbName = argv[++i];
506*33e1ec22Sdrh }else
507*33e1ec22Sdrh if( strcmp(z,"-heap")==0 ){
508*33e1ec22Sdrh if( i>=argc-2 ){
509*33e1ec22Sdrh printf("ERROR: missing arguments on %s\n", argv[i]);
510*33e1ec22Sdrh exit(1);
511*33e1ec22Sdrh }
512*33e1ec22Sdrh nHeap = integerValue(argv[i+1]);
513*33e1ec22Sdrh mnHeap = integerValue(argv[i+2]);
514*33e1ec22Sdrh i += 2;
515*33e1ec22Sdrh }else
516*33e1ec22Sdrh if( strcmp(z,"-stats")==0 ){
517*33e1ec22Sdrh showStats = 1;
518*33e1ec22Sdrh }else
519*33e1ec22Sdrh {
520*33e1ec22Sdrh printf("ERROR: unknown option \"%s\"\n", argv[i]);
521*33e1ec22Sdrh usage(argv[0]);
522*33e1ec22Sdrh }
523*33e1ec22Sdrh }
524*33e1ec22Sdrh if( zCmd==0 ){
525*33e1ec22Sdrh printf("ERROR: no COMMAND specified\n");
526*33e1ec22Sdrh usage(argv[0]);
527*33e1ec22Sdrh }
528*33e1ec22Sdrh if( strcmp(zCmd, "run")==0 ){
529*33e1ec22Sdrh sqlite3 *db;
530*33e1ec22Sdrh int rc;
531*33e1ec22Sdrh char *zErr = 0;
532*33e1ec22Sdrh void *pHeap = 0;
533*33e1ec22Sdrh if( nHeap>0 ){
534*33e1ec22Sdrh pHeap = malloc( nHeap );
535*33e1ec22Sdrh if( pHeap==0 ){
536*33e1ec22Sdrh printf("ERROR: cannot allocate %d-byte heap\n", nHeap);
537*33e1ec22Sdrh exit(1);
538*33e1ec22Sdrh }
539*33e1ec22Sdrh rc = sqlite3_config(SQLITE_CONFIG_HEAP, pHeap, nHeap, mnHeap);
540*33e1ec22Sdrh if( rc ){
541*33e1ec22Sdrh printf("ERROR: heap configuration failed: %d\n", rc);
542*33e1ec22Sdrh exit(1);
543*33e1ec22Sdrh }
544*33e1ec22Sdrh }
545*33e1ec22Sdrh rc = sqlite3_open(zDbName, &db);
546*33e1ec22Sdrh if( rc ){
547*33e1ec22Sdrh printf("SQLite error: %s\n", sqlite3_errmsg(db));
548*33e1ec22Sdrh }else{
549*33e1ec22Sdrh sqlite3_exec(db, "PRAGMA synchronous", 0, 0, &zErr);
550*33e1ec22Sdrh }
551*33e1ec22Sdrh if( zErr ){
552*33e1ec22Sdrh printf("ERROR: %s\n", zErr);
553*33e1ec22Sdrh sqlite3_free(zErr);
554*33e1ec22Sdrh }
555*33e1ec22Sdrh if( showStats ){
556*33e1ec22Sdrh int iCur, iHi;
557*33e1ec22Sdrh sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_USED, &iCur, &iHi, 0);
558*33e1ec22Sdrh printf("-- Lookaside Slots Used: %d (max %d)\n", iCur,iHi);
559*33e1ec22Sdrh sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_HIT, &iCur, &iHi, 0);
560*33e1ec22Sdrh printf("-- Successful lookasides: %d\n", iHi);
561*33e1ec22Sdrh sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE, &iCur,&iHi,0);
562*33e1ec22Sdrh printf("-- Lookaside size faults: %d\n", iHi);
563*33e1ec22Sdrh sqlite3_db_status(db, SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL, &iCur,&iHi,0);
564*33e1ec22Sdrh printf("-- Lookaside OOM faults: %d\n", iHi);
565*33e1ec22Sdrh sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_USED, &iCur, &iHi, 0);
566*33e1ec22Sdrh printf("-- Pager Heap Usage: %d bytes\n", iCur);
567*33e1ec22Sdrh sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_HIT, &iCur, &iHi, 1);
568*33e1ec22Sdrh printf("-- Page cache hits: %d\n", iCur);
569*33e1ec22Sdrh sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_MISS, &iCur, &iHi, 1);
570*33e1ec22Sdrh printf("-- Page cache misses: %d\n", iCur);
571*33e1ec22Sdrh sqlite3_db_status(db, SQLITE_DBSTATUS_CACHE_WRITE, &iCur, &iHi, 1);
572*33e1ec22Sdrh printf("-- Page cache writes: %d\n", iCur);
573*33e1ec22Sdrh sqlite3_db_status(db, SQLITE_DBSTATUS_SCHEMA_USED, &iCur, &iHi, 0);
574*33e1ec22Sdrh printf("-- Schema Heap Usage: %d bytes\n", iCur);
575*33e1ec22Sdrh sqlite3_db_status(db, SQLITE_DBSTATUS_STMT_USED, &iCur, &iHi, 0);
576*33e1ec22Sdrh printf("-- Statement Heap Usage: %d bytes\n", iCur);
577*33e1ec22Sdrh }
578*33e1ec22Sdrh sqlite3_close(db);
579*33e1ec22Sdrh free(pHeap);
580*33e1ec22Sdrh /* Global memory usage statistics printed after the database connection
581*33e1ec22Sdrh ** has closed. Memory usage should be zero at this point. */
582*33e1ec22Sdrh if( showStats ){
583*33e1ec22Sdrh int iCur, iHi;
584*33e1ec22Sdrh sqlite3_status(SQLITE_STATUS_MEMORY_USED, &iCur, &iHi, 0);
585*33e1ec22Sdrh printf("-- Memory Used (bytes): %d (max %d)\n", iCur,iHi);
586*33e1ec22Sdrh sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &iCur, &iHi, 0);
587*33e1ec22Sdrh printf("-- Outstanding Allocations: %d (max %d)\n", iCur,iHi);
588*33e1ec22Sdrh sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW, &iCur, &iHi, 0);
589*33e1ec22Sdrh printf("-- Pcache Overflow Bytes: %d (max %d)\n", iCur,iHi);
590*33e1ec22Sdrh sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &iCur, &iHi, 0);
591*33e1ec22Sdrh printf("-- Largest Allocation: %d bytes\n",iHi);
592*33e1ec22Sdrh sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &iCur, &iHi, 0);
593*33e1ec22Sdrh printf("-- Largest Pcache Allocation: %d bytes\n",iHi);
594*33e1ec22Sdrh #ifdef __linux__
595*33e1ec22Sdrh displayLinuxIoStats(stdout);
596*33e1ec22Sdrh #endif
597*33e1ec22Sdrh }
598*33e1ec22Sdrh return 0;
599*33e1ec22Sdrh }
600*33e1ec22Sdrh if( strcmp(zCmd, "init")==0 ){
601*33e1ec22Sdrh sqlite3 *db;
602*33e1ec22Sdrh char *zAux;
603*33e1ec22Sdrh char *zErr = 0;
604*33e1ec22Sdrh int rc;
605*33e1ec22Sdrh unlink(zDbName);
606*33e1ec22Sdrh zAux = sqlite3_mprintf("%s-journal", zDbName);
607*33e1ec22Sdrh unlink(zAux);
608*33e1ec22Sdrh sqlite3_free(zAux);
609*33e1ec22Sdrh zAux = sqlite3_mprintf("%s-wal", zDbName);
610*33e1ec22Sdrh unlink(zAux);
611*33e1ec22Sdrh sqlite3_free(zAux);
612*33e1ec22Sdrh rc = sqlite3_open(zDbName, &db);
613*33e1ec22Sdrh if( rc ){
614*33e1ec22Sdrh printf("SQLite error: %s\n", sqlite3_errmsg(db));
615*33e1ec22Sdrh }else{
616*33e1ec22Sdrh sqlite3_exec(db, "BEGIN", 0, 0, 0);
617*33e1ec22Sdrh sqlite3_exec(db, zTestSchema, 0, 0, &zErr);
618*33e1ec22Sdrh sqlite3_exec(db, "COMMIT", 0, 0, 0);
619*33e1ec22Sdrh }
620*33e1ec22Sdrh if( zErr ){
621*33e1ec22Sdrh printf("ERROR: %s\n", zErr);
622*33e1ec22Sdrh sqlite3_free(zErr);
623*33e1ec22Sdrh }
624*33e1ec22Sdrh sqlite3_close(db);
625*33e1ec22Sdrh return 0;
626*33e1ec22Sdrh
627*33e1ec22Sdrh }
628*33e1ec22Sdrh }
629