-C Ensure\sthat\swrite-locks\son\spages\sare\sdropped\sat\sthe\send\sof\seach\nwrite\stransaction,\seven\sif\sthere\sis\sstill\sa\sread\stransaction\sopen.
-D 2017-08-19T15:50:45.975
+C Add\sa\sTcl\sscript\sto\srun\sthe\sperformance\stests\sdescribed\sin\nREADME-server-edition.html.
+D 2017-08-29T17:52:14.719
F Makefile.in d9873c9925917cca9990ee24be17eb9613a668012c85a343aef7e5536ae266e8
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 02b469e9dcd5b7ee63fc1fb05babc174260ee4cfa4e0ef2e48c3c6801567a016
F src/resolve.c 4324a94573b1e29286f8121e4881db59eaedc014afeb274c8d3e07ed282e0e20
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c c9b3d8444bbf6f167d84f41ca6f3672e2521cb163a8c706b19058dc82fffe9b8
-F src/server.c 4215bc2287c28f37e2bc79521eb8163e1340be2ca45f0fe4b2566f5faec9300c
+F src/server.c 9af69ec201823023bfa6f52b2b8262611f2e14698cb7d5e79e7791f0e7fd7139
F src/server.h f46be129ffe407cac9b7018e6d4851b04e685d59b6837c73a1fb69e6aab52e3a
F src/shell.c bd6a37cbe8bf64ef6a6a74fdc50f067d3148149b4ce2b4d03154663e66ded55f
F src/shell.c.in b5725acacba95ccefa57b6d068f710e29ba8239c3aa704628a1902a1f729c175
F tool/restore_jrnl.tcl 6957a34f8f1f0f8285e07536225ec3b292a9024a
F tool/rollback-test.c 9fc98427d1e23e84429d7e6d07d9094fbdec65a5
F tool/run-speed-test.sh f95d19fd669b68c4c38b6b475242841d47c66076
+F tool/se_perf_test.tcl e2a5081f9378f188a431c4a85c5f3f9e99719027df5a6faa405c981b267ad8fd
F tool/showdb.c e6bc9dba233bf1b57ca0a525a2bba762db4e223de84990739db3f09c46151b1e
F tool/showjournal.c 5bad7ae8784a43d2b270d953060423b8bd480818
F tool/showlocks.c 9920bcc64f58378ff1118caead34147201f48c68
F tool/symbols-mingw.sh 4dbcea7e74768305384c9fd2ed2b41bbf9f0414d
F tool/symbols.sh c5a617b8c61a0926747a56c65f5671ef8ac0e148
F tool/tostr.tcl 96022f35ada2194f6f8ccf6fd95809e90ed277c4
-F tool/tserver.c d6b4e074dc9d11edf9aac79cfd925cf1ea71f823b00344bc443e1aaea1f16d5b
+F tool/tserver.c ac67b8fe175850b780c5bd1888c2bb2f0f5e24096f040db7fc1a2af7a4908f2b
F tool/varint.c 5d94cb5003db9dbbcbcc5df08d66f16071aee003
F tool/vdbe-compress.tcl 5926c71f9c12d2ab73ef35c29376e756eb68361c
F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P abb6e076c851c0b10f62c02d0d7e54f24d86c75f01036dddbc0a8a7dfc627a0d
-R aa6e06e084e3c3d3595864687ba9477a
+P 2dd36ade9ea948de27b217b83cbf704e071e6ea5dddb8566165a645143b0f846
+R 090737ae736ae0ec45491b46ad6ddffe
U dan
-Z 571fa6db3e131de25960c3e8f380a0b4
+Z 196af7197d18e14a39d9e416f4edfb10
--- /dev/null
+#!/usr/bin/tclsh
+#
+# This script is used to run the performance test cases described in
+# README-server-edition.html.
+#
+
+
+package require sqlite3
+
+# Default values for command line switches:
+set O(-database) ""
+set O(-mode) "server"
+set O(-rows) [expr 5000000]
+set O(-tserver) "./tserver"
+set O(-seconds) 20
+set O(-writers) 2
+set O(-readers) 1
+set O(-verbose) 0
+
+
+proc error_out {err} {
+ puts stderr $err
+ exit -1
+}
+
+proc usage {} {
+ puts stderr "Usage: $::argv0 ?OPTIONS?"
+ puts stderr ""
+ puts stderr "Where OPTIONS are:"
+ puts stderr " -database <database file> (default: test.$mode.db)"
+ puts stderr " -mode server|begin-concurrent (default: server)"
+ puts stderr " -rows <number of rows> (default: 5000000)"
+ puts stderr " -tserver <path to tserver executable> (default: ./tserver)"
+ puts stderr " -seconds <time to run for in seconds> (default: 20)"
+ puts stderr " -writers <number of writer clients> (default: 2)"
+ puts stderr " -readers <number of reader clients> (default: 1)"
+ puts stderr " -verbose 0|1 (default: 0)"
+ exit -1
+}
+
+for {set i 0} {$i < [llength $argv]} {incr i} {
+ set opt ""
+ set arg [lindex $argv $i]
+ set n [expr [string length $arg]-1]
+ foreach k [array names ::O] {
+ if {[string range $k 0 $n]==$arg} {
+ if {$opt==""} {
+ set opt $k
+ } else {
+ error_out "ambiguous option: $arg ($k or $opt)"
+ }
+ }
+ }
+ if {$opt==""} { usage }
+ if {$i==[llength $argv]-1} {
+ error_out "option requires an argument: $opt"
+ }
+ incr i
+ set val [lindex $argv $i]
+ switch -- $opt {
+ -mode {
+ if {$val != "server" && $val != "begin-concurrent"
+ && $val != "wal" && $val != "persist"
+ } {
+ set xyz "\"server\", \"begin-concurrent\", \"wal\" or \"persist\""
+ error_out "Found \"$val\" - expected $xyz"
+ }
+ }
+ }
+ set O($opt) [lindex $argv $i]
+}
+if {$O(-database)==""} {
+ set O(-database) "test.$O(-mode).db"
+}
+
+set O(-rows) [expr $O(-rows)]
+
+#--------------------------------------------------------------------------
+# Create and populate the required test database, if it is not already
+# present in the file-system.
+#
+proc create_test_database {} {
+ global O
+
+ if {[file exists $O(-database)]} {
+ sqlite3 db $O(-database)
+
+ # Check the schema looks Ok.
+ set s [db one {
+ SELECT group_concat(name||pk, '.') FROM pragma_table_info('t1');
+ }]
+ if {$s != "a1.b0.c0.d0"} {
+ error_out "Database $O(-database) exists but is not usable (schema)"
+ }
+
+ # Check that the row count matches.
+ set n [db one { SELECT count(*) FROM t1 }]
+ if {$n != $O(-rows)} {
+ error_out "Database $O(-database) exists but is not usable (row-count)"
+ }
+ db close
+ } else {
+ catch { file delete -force $O(-database)-journal }
+ catch { file delete -force $O(-database)-wal }
+
+ if {$O(-verbose)} {
+ puts "Building database $O(-database)..."
+ }
+
+ sqlite3 db $O(-database)
+ db eval {
+ CREATE TABLE t1(
+ a INTEGER PRIMARY KEY,
+ b BLOB(16),
+ c BLOB(16),
+ d BLOB(400)
+ );
+ CREATE INDEX i1 ON t1(b);
+ CREATE INDEX i2 ON t1(c);
+
+ WITH s(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<$O(-rows))
+ INSERT INTO t1
+ SELECT i-1, randomblob(16), randomblob(16), randomblob(400) FROM s;
+ }
+ if {$O(-mode)=="server"} {
+ db eval "PRAGMA freelist_format = 2"
+ }
+ db close
+ switch -- $O(-mode) {
+ server {
+ if {![file exists $O(-database)-journal]} {
+ file mkdir $O(-database)-journal
+ }
+ }
+
+ wal {
+ sqlite3 db $O(-database)
+ db eval {PRAGMA journal_mode = wal}
+ db close
+ }
+
+ begin-concurrent {
+ sqlite3 db $O(-database)
+ db eval {PRAGMA journal_mode = wal}
+ db close
+ }
+ }
+ }
+}
+
+#-------------------------------------------------------------------------
+# Functions to start and stop the tserver process:
+#
+# tserver_start
+# tserver_stop
+#
+set ::tserver {}
+proc tserver_start {} {
+ global O
+ set ::tserver [open "|$O(-tserver) -vfs unix-excl $O(-database)"]
+ fconfigure $::tserver -blocking 0
+ fileevent $::tserver readable tserver_data
+}
+
+proc tserver_data {} {
+ global O
+ if {[eof $::tserver]} {
+ error_out "tserver has exited"
+ }
+ set line [gets $::tserver]
+ if {$line != "" && $O(-verbose)} {
+ puts "tserver: $line"
+ }
+}
+
+proc tserver_stop {} {
+ close $::tserver
+ set fd [socket localhost 9999]
+ puts $fd ".stop"
+ close $fd
+}
+#-------------------------------------------------------------------------
+
+set ::nClient 0
+set ::client_output [list]
+
+proc client_data {name fd} {
+ global O
+ if {[eof $fd]} {
+ incr ::nClient -1
+ close $fd
+ return
+ }
+ set str [gets $fd]
+ if {[string trim $str]!=""} {
+ if {[string range $str 0 3]=="### "} {
+ lappend ::client_output [concat [list name $name] [lrange $str 1 end]]
+ }
+ if {$O(-verbose)} {
+ puts "$name: $str"
+ }
+ }
+}
+
+proc client_launch {name script} {
+ global O
+ set fd [socket localhost 9999]
+ fconfigure $fd -blocking 0
+ switch -- $O(-mode) {
+ persist {
+ puts $fd "PRAGMA journal_mode = PERSIST;"
+ }
+ }
+ puts $fd "PRAGMA synchronous = OFF;"
+ puts $fd ".repeat 1"
+ puts $fd ".run"
+ puts $fd $script
+ puts $fd ".seconds $O(-seconds)"
+ puts $fd ".run"
+ puts $fd ".quit"
+ flush $fd
+ incr ::nClient
+ fileevent $fd readable [list client_data $name $fd]
+}
+
+proc client_wait {} {
+ while {$::nClient>0} {vwait ::nClient}
+}
+
+proc script_writer {} {
+ global O
+ set commit "COMMIT;"
+ set begin "BEGIN;"
+ if {$O(-mode)=="begin-concurrent" || $O(-mode)=="wal"} {
+ set commit ".mutex_commit"
+ set begin "BEGIN CONCURRENT;"
+ }
+
+ if {$O(-mode)=="server"} { set beginarg "READONLY" }
+
+ set tail "randomblob(16), randomblob(16), randomblob(400));"
+ return [subst -nocommands {
+ $begin
+ REPLACE INTO t1 VALUES(abs(random() % $O(-rows)), $tail
+ REPLACE INTO t1 VALUES(abs(random() % $O(-rows)), $tail
+ REPLACE INTO t1 VALUES(abs(random() % $O(-rows)), $tail
+ REPLACE INTO t1 VALUES(abs(random() % $O(-rows)), $tail
+ REPLACE INTO t1 VALUES(abs(random() % $O(-rows)), $tail
+ $commit
+ }]
+}
+
+proc script_reader {} {
+ global O
+
+ set beginarg ""
+ if {$O(-mode)=="server"} { set beginarg "READONLY" }
+
+ return [subst -nocommands {
+ BEGIN $beginarg;
+ SELECT * FROM t1 WHERE a>abs((random()%$O(-rows))) LIMIT 10;
+ SELECT * FROM t1 WHERE a>abs((random()%$O(-rows))) LIMIT 10;
+ SELECT * FROM t1 WHERE a>abs((random()%$O(-rows))) LIMIT 10;
+ SELECT * FROM t1 WHERE a>abs((random()%$O(-rows))) LIMIT 10;
+ SELECT * FROM t1 WHERE a>abs((random()%$O(-rows))) LIMIT 10;
+ END;
+ }]
+}
+
+
+create_test_database
+tserver_start
+
+for {set i 0} {$i < $O(-writers)} {incr i} {
+ client_launch w.$i [script_writer]
+}
+for {set i 0} {$i < $O(-readers)} {incr i} {
+ client_launch r.$i [script_reader]
+}
+client_wait
+
+set name(w) "Writers"
+set name(r) "Readers"
+foreach r $::client_output {
+ array set a $r
+ set type [string range $a(name) 0 0]
+ incr x($type.ok) $a(ok);
+ incr x($type.busy) $a(busy);
+ incr x($type.n) 1
+ set t($type) 1
+}
+
+foreach type [array names t] {
+ set nTPS [expr $x($type.ok) / $O(-seconds)]
+ set nC [expr $nTPS / $x($type.n)]
+ set nTotal [expr $x($type.ok) + $x($type.busy)]
+ set bp [format %.2f [expr $x($type.busy) * 100.0 / $nTotal]]
+ puts "$name($type): $nTPS transactions/second ($nC per client) ($bp% busy)"
+}
+
+tserver_stop
+
+
** .seconds N Configure the number of seconds to ".run" for.
** .mutex_commit Add a "COMMIT" protected by a g.commit_mutex
** to the current SQL.
+** .stop Stop the tserver process - exit(0).
**
** Example input:
**
char *zDatabaseName; /* Database used by this server */
char *zVfs;
sqlite3_mutex *commit_mutex;
+ sqlite3 *db; /* Global db handle */
/* The following use native pthreads instead of a portable interface. This
** is because a condition variable, as well as a mutex, is required. */
}
if( rc==SQLITE_OK ){
+ int nMs = (int)(get_timer() - t0);
send_message(p, "ok (%d/%d SQLITE_BUSY)\n", nBusy, j);
+ if( p->nRepeat<=0 ){
+ send_message(p, "### ok %d busy %d ms %d\n", j-nBusy, nBusy, nMs);
+ }
}
clear_sql(p);
rc = handle_run_command(p);
}
- else if( n>=1 && n<=7 && 0==strncmp(z, "seconds", n) ){
+ else if( n>=2 && n<=7 && 0==strncmp(z, "seconds", n) ){
if( nArg ){
p->nSecond = strtol(zArg, 0, 0);
if( p->nSecond>0 ) p->nRepeat = 0;
}
}
+ else if( n>=2 && n<=4 && 0==strncmp(z, "stop", n) ){
+ sqlite3_close(g.db);
+ exit(0);
+ }
+
else{
send_message(p,
"unrecognized dot command: %.*s\n"
}
fprintf(stdout, "Client %d disconnects\n", ctx.fd);
+ fflush(stdout);
close(ctx.fd);
clear_sql(&ctx);
sqlite3_free(ctx.aPrepare);
}
int main(int argc, char *argv[]) {
- sqlite3 *db;
int sfd;
int rc;
int yes = 1;
pthread_mutex_init(&g.ckpt_mutex, 0);
pthread_cond_init(&g.ckpt_cond, 0);
- rc = sqlite3_open_v2(g.zDatabaseName, &db,
+ rc = sqlite3_open_v2(g.zDatabaseName, &g.db,
SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, g.zVfs
);
if( rc!=SQLITE_OK ){
- fprintf(stderr, "sqlite3_open(): %s\n", sqlite3_errmsg(db));
+ fprintf(stderr, "sqlite3_open(): %s\n", sqlite3_errmsg(g.db));
return 1;
}
- rc = sqlite3_exec(db, "SELECT * FROM sqlite_master", 0, 0, 0);
+ rc = sqlite3_exec(g.db, "SELECT * FROM sqlite_master", 0, 0, 0);
if( rc!=SQLITE_OK ){
- fprintf(stderr, "sqlite3_exec(): %s\n", sqlite3_errmsg(db));
+ fprintf(stderr, "sqlite3_exec(): %s\n", sqlite3_errmsg(g.db));
return 1;
}
}
fprintf(stdout, "Client %d connects\n", cfd);
+ fflush(stdout);
rc = pthread_create(&tid, NULL, handle_client, (void*)(intptr_t)cfd);
if( rc!=0 ){
perror("pthread_create()");