Add support for sqlite3_unlock_notify

This commit is contained in:
Mura Li 2017-07-14 14:23:40 +08:00 committed by Yasuhiro Matsumoto
parent 05548ff555
commit cf9f5ca0ef
3 changed files with 71 additions and 2 deletions

5
callback.c Normal file
View File

@ -0,0 +1,5 @@
void _unlock_notify_callback(void *arg, int argc)
{
extern void unlock_notify_callback(void *, int);
unlock_notify_callback(arg, argc);
}

View File

@ -20,6 +20,8 @@ package sqlite3
void _sqlite3_result_text(sqlite3_context* ctx, const char* s);
void _sqlite3_result_blob(sqlite3_context* ctx, const void* b, int l);
void _unlock_notify_callback(void *arg, int argc);
*/
import "C"
@ -362,3 +364,35 @@ func callbackSyntheticForTests(v reflect.Value, err error) callbackArgConverter
return v, err
}
}
type unlockNotification struct {
notify chan struct{}
lock sync.Mutex
}
//export unlock_notify_callback
func unlock_notify_callback(pargv unsafe.Pointer, argc C.int) {
argv := *(*uintptr)(pargv)
v := (*[1 << 30]uintptr)(unsafe.Pointer(argv))
for i := 0; i < int(argc); i++ {
un := lookupHandle(v[i]).(unlockNotification)
un.notify <- struct{}{}
}
}
var notifyMutex sync.Mutex
//export unlock_notify_wait
func unlock_notify_wait(db *C.sqlite3) C.int {
var un unlockNotification
un.notify = make(chan struct{})
defer close(un.notify)
argv := [1]uintptr{newHandle(nil, un)}
if rv := C.sqlite3_unlock_notify(db, (*[0]byte)(C._unlock_notify_callback), unsafe.Pointer(&argv)); rv != C.SQLITE_OK {
return rv
}
<-un.notify
return C.SQLITE_OK
}

View File

@ -11,6 +11,7 @@ package sqlite3
#cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS4_UNICODE61
#cgo CFLAGS: -DSQLITE_TRACE_SIZE_LIMIT=15
#cgo CFLAGS: -DSQLITE_DISABLE_INTRINSIC
#cgo CFLAGS: -DSQLITE_ENABLE_UNLOCK_NOTIFY
#cgo CFLAGS: -Wno-deprecated-declarations
#ifndef USE_LIBSQLITE3
#include <sqlite3-binding.h>
@ -70,8 +71,25 @@ _sqlite3_exec(sqlite3* db, const char* pcmd, long long* rowid, long long* change
static int
_sqlite3_step(sqlite3_stmt* stmt, long long* rowid, long long* changes)
{
int rv = sqlite3_step(stmt);
extern int unlock_notify_wait(sqlite3 *db);
int rv;
sqlite3* db = sqlite3_db_handle(stmt);
for (;;) {
rv = sqlite3_step(stmt);
if (rv!=SQLITE_LOCKED) {
break;
}
if (sqlite3_extended_errcode(db)!=SQLITE_LOCKED_SHAREDCACHE) {
break;
}
rv = unlock_notify_wait(db);
if (rv != SQLITE_OK) {
break;
}
sqlite3_reset(stmt);
}
*rowid = (long long) sqlite3_last_insert_rowid(db);
*changes = (long long) sqlite3_changes(db);
return rv;
@ -814,7 +832,19 @@ func (c *SQLiteConn) prepare(ctx context.Context, query string) (driver.Stmt, er
defer C.free(unsafe.Pointer(pquery))
var s *C.sqlite3_stmt
var tail *C.char
rv := C.sqlite3_prepare_v2(c.db, pquery, -1, &s, &tail)
var rv C.int
for {
rv = C.sqlite3_prepare_v2(c.db, pquery, -1, &s, &tail)
if rv == C.SQLITE_OK {
break
}
if rv == C.SQLITE_LOCKED {
rv = unlock_notify_wait(c.db)
if rv != C.SQLITE_OK {
break
}
}
}
if rv != C.SQLITE_OK {
return nil, c.lastError()
}