--- /dev/null
+/*
+** 2017-10-11
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+******************************************************************************
+**
+*/
+
+#if !defined(SQLITE_TEST) || defined(SQLITE_OS_UNIX)
+
+#include "sqlite3.h"
+#include <string.h>
+#include <pthread.h>
+
+/*
+** API declarations.
+*/
+typedef struct Checkpointer Checkpointer;
+int sqlite3_bgckpt_create(const char *zFilename, Checkpointer **pp);
+int sqlite3_bgckpt_checkpoint(Checkpointer *p, int bBlock);
+void sqlite3_bgckpt_destroy(Checkpointer *p);
+
+
+struct Checkpointer {
+ sqlite3 *db; /* Database handle */
+
+ pthread_t thread; /* Background thread */
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+
+ int rc; /* Error from "PRAGMA wal_checkpoint" */
+ int bCkpt; /* True if checkpoint requested */
+ int bExit; /* True if exit requested */
+};
+
+static void *bgckptThreadMain(void *pCtx){
+ int rc = SQLITE_OK;
+ Checkpointer *p = (Checkpointer*)pCtx;
+
+ while( rc==SQLITE_OK ){
+ int bExit;
+
+ pthread_mutex_lock(&p->mutex);
+ if( p->bCkpt==0 && p->bExit==0 ){
+ pthread_cond_wait(&p->cond, &p->mutex);
+ }
+ p->bCkpt = 0;
+ bExit = p->bExit;
+ pthread_mutex_unlock(&p->mutex);
+
+ if( bExit ) break;
+ rc = sqlite3_exec(p->db, "PRAGMA wal_checkpoint", 0, 0, 0);
+ if( rc==SQLITE_BUSY ){
+ rc = SQLITE_OK;
+ }
+ }
+
+ pthread_mutex_lock(&p->mutex);
+ p->rc = rc;
+ pthread_mutex_unlock(&p->mutex);
+ return 0;
+}
+
+void sqlite3_bgckpt_destroy(Checkpointer *p){
+ if( p ){
+ void *ret = 0;
+
+ /* Signal the background thread to exit */
+ pthread_mutex_lock(&p->mutex);
+ p->bExit = 1;
+ pthread_cond_broadcast(&p->cond);
+ pthread_mutex_unlock(&p->mutex);
+
+ pthread_join(p->thread, &ret);
+ sqlite3_close(p->db);
+ sqlite3_free(p);
+ }
+}
+
+
+int sqlite3_bgckpt_create(const char *zFilename, Checkpointer **pp){
+ Checkpointer *pNew = 0;
+ int rc;
+
+ pNew = (Checkpointer*)sqlite3_malloc(sizeof(Checkpointer));
+ if( pNew==0 ){
+ rc = SQLITE_NOMEM;
+ }else{
+ memset(pNew, 0, sizeof(Checkpointer));
+ rc = sqlite3_open(zFilename, &pNew->db);
+ }
+
+ if( rc==SQLITE_OK ){
+ pthread_mutex_init(&pNew->mutex, 0);
+ pthread_cond_init(&pNew->cond, 0);
+ pthread_create(&pNew->thread, 0, bgckptThreadMain, (void*)pNew);
+ }
+
+ if( rc!=SQLITE_OK ){
+ sqlite3_bgckpt_destroy(pNew);
+ pNew = 0;
+ }
+ *pp = pNew;
+ return rc;
+}
+
+int sqlite3_bgckpt_checkpoint(Checkpointer *p, int bBlock){
+ int rc;
+ pthread_mutex_lock(&p->mutex);
+ rc = p->rc;
+ if( rc==SQLITE_OK ){
+ p->bCkpt = 1;
+ pthread_cond_broadcast(&p->cond);
+ }
+ pthread_mutex_unlock(&p->mutex);
+ return rc;
+}
+
+#ifdef SQLITE_TEST
+
+#if defined(INCLUDE_SQLITE_TCL_H)
+# include "sqlite_tcl.h"
+#else
+# include "tcl.h"
+# ifndef SQLITE_TCLAPI
+# define SQLITE_TCLAPI
+# endif
+#endif
+
+const char *sqlite3ErrName(int rc);
+
+static void SQLITE_TCLAPI bgckpt_del(void * clientData){
+ Checkpointer *pCkpt = (Checkpointer*)clientData;
+ sqlite3_bgckpt_destroy(pCkpt);
+}
+
+/*
+** Tclcmd: $ckpt SUBCMD ...
+*/
+static int SQLITE_TCLAPI bgckpt_obj_cmd(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ Checkpointer *pCkpt = (Checkpointer*)clientData;
+ const char *aCmd[] = { "checkpoint", "destroy", 0 };
+ int iCmd;
+
+ if( objc<2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "SUBCMD ...");
+ return TCL_ERROR;
+ }
+
+ if( Tcl_GetIndexFromObj(interp, objv[1], aCmd, "sub-command", 0, &iCmd) ){
+ return TCL_ERROR;
+ }
+
+ switch( iCmd ){
+ case 0: {
+ int rc;
+ int bBlock = 0;
+
+ if( objc>3 ){
+ Tcl_WrongNumArgs(interp, 2, objv, "?BLOCKING?");
+ return TCL_ERROR;
+ }
+ if( objc==3 && Tcl_GetBooleanFromObj(interp, objv[2], &bBlock) ){
+ return TCL_ERROR;
+ }
+
+ rc = sqlite3_bgckpt_checkpoint(pCkpt, bBlock);
+ if( rc!=SQLITE_OK ){
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
+ return TCL_ERROR;
+ }
+ break;
+ }
+
+ case 1: {
+ Tcl_DeleteCommand(interp, Tcl_GetString(objv[0]));
+ break;
+ }
+ }
+
+ return TCL_OK;
+}
+
+/*
+** Tclcmd: bgckpt CMDNAME FILENAME
+*/
+static int SQLITE_TCLAPI bgckpt_cmd(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ const char *zCmd;
+ const char *zFilename;
+ int rc;
+ Checkpointer *pCkpt;
+
+ if( objc!=3 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "CMDNAME FILENAME");
+ return TCL_ERROR;
+ }
+ zCmd = Tcl_GetString(objv[1]);
+ zFilename = Tcl_GetString(objv[2]);
+
+ rc = sqlite3_bgckpt_create(zFilename, &pCkpt);
+ if( rc!=SQLITE_OK ){
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
+ return TCL_ERROR;
+ }
+
+ Tcl_CreateObjCommand(interp, zCmd, bgckpt_obj_cmd, (void*)pCkpt, bgckpt_del);
+ Tcl_SetObjResult(interp, objv[1]);
+ return TCL_OK;
+}
+
+int Bgckpt_Init(Tcl_Interp *interp){
+ Tcl_CreateObjCommand(interp, "bgckpt", bgckpt_cmd, 0, 0);
+ return TCL_OK;
+}
+#endif /* SQLITE_TEST */
+
+#else
+int Bgckpt_Init(Tcl_Interp *interp){
+ return TCL_OK;
+}
+#endif
+
-C Merge\slatest\strunk\schanges\swith\sthis\sbranch.
-D 2017-10-09T19:50:09.728
+C Add\snew\sextension\s"bgckpt"\sin\sext/misc/bgckpt.c.\sFor\sexperimenting\swith\nrunning\swal2\smode\scheckpoints\sin\sa\sbackground\sthread.
+D 2017-10-10T20:11:10.809
F Makefile.in 4bc36d913c2e3e2d326d588d72f618ac9788b2fd4b7efda61102611a6495c3ff
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 6033b51b6aea702ea059f6ab2d47b1d3cef648695f787247dd4fb395fe60673f
F ext/misc/README.md 8e008c8d2b02e09096b31dfba033253ac27c6c06a18aa5826e299fa7601d90b2
F ext/misc/amatch.c 6db4607cb17c54b853a2d7c7c36046d004853f65b9b733e6f019d543d5dfae87
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
+F ext/misc/bgckpt.c 1e0178c1d9f44d44f45c731ebff45854194ca59a41d33f078f10a3a714bf4532
F ext/misc/carray.c ed96c218ea940b85c9a274c4d9c59fe9491c299147a38a8bba537687bd6c6005
F ext/misc/closure.c 0d2a038df8fbae7f19de42e7c7d71f2e4dc88704
F ext/misc/completion.c 52c3f01523e3e387eb321b4739a89d1fe47cbe6025aa1f2d8d3685e9e365df0f
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk d0145f02deb67d65c4822225847cba112c237cdb62f4905eeb4b648e82bfc222
+F main.mk 8dcd78e5977c6e220ec0ab9a00aa2469ca38380d1553cb3eff18469a28e04654
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c 9737ed017279a9e0c5da748701c3c7bf1e8ae0dae459aad20dd64fcff97a7e35
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
-F src/tclsqlite.c 487951d81f9704800fd9f0ffdaa2f935a83ccb6be3575c2c4ef83e4789b4c828
+F src/tclsqlite.c 37be19e8ea1b4ec1e632d86272ada77bbb93f20b033df258ad3ed63dc4d40fa4
F src/test1.c 8ef15f7a357f85dfc41c6c748ce9c947b4f676e01bb5ae6a45bee4923dff8b51
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c b8434949dfb8aff8dfa082c8b592109e77844c2135ed3c492113839b6956255b
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 9c80cd202f1c966929b279e18f19c663912686fcf92f03b85a02b9c7e55a0fc6 5594a121bf132a98d0ecb4cf86d9f2681925c9416206096bf11c9370a5dae22f
-R 23a883a99c179b06ab669012d3314db6
+P d218d815f89cb1368fdb5e3f774b7adaaf02560a367ba0f3e54987e08dd6241a
+R 7d8085c250f90df872ed6ab275626e25
U dan
-Z c8f907ef387c1600d03d31327cf9ed02
+Z bca32e00ecb94225e888df6bb3b83e85