1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Add a mutex for auto-extensions, tied in to the open() process since that's the route into auto-extensions.

FossilOrigin-Name: 8da97e0db4eeacf91aa6fd909fd7cb73b050d194dfc7739a502b55f7eca6d7b1
This commit is contained in:
stephan
2023-08-13 12:40:27 +00:00
parent 4b4a911c5f
commit 88381e53fc
4 changed files with 140 additions and 115 deletions

View File

@@ -400,8 +400,6 @@ static void S3JniNphCache_clear(JNIEnv * const env, S3JniNphCache * const p){
memset(p, 0, sizeof(S3JniNphCache)); memset(p, 0, sizeof(S3JniNphCache));
} }
#define S3JNI_ENABLE_AUTOEXT 1
#if S3JNI_ENABLE_AUTOEXT
/* /*
Whether auto extensions are feasible here is currently unknown due Whether auto extensions are feasible here is currently unknown due
to... to...
@@ -430,7 +428,6 @@ struct S3JniAutoExtension {
S3JniAutoExtension *pNext /* next linked-list entry */; S3JniAutoExtension *pNext /* next linked-list entry */;
S3JniAutoExtension *pPrev /* previous linked-list entry */; S3JniAutoExtension *pPrev /* previous linked-list entry */;
}; };
#endif
/** State for various hook callbacks. */ /** State for various hook callbacks. */
typedef struct S3JniHook S3JniHook; typedef struct S3JniHook S3JniHook;
@@ -518,6 +515,7 @@ static struct {
unsigned envCacheMisses; unsigned envCacheMisses;
unsigned nMutexEnv /* number of times envCache.mutex was entered */; unsigned nMutexEnv /* number of times envCache.mutex was entered */;
unsigned nMutexPerDb /* number of times perDb.mutex was entered */; unsigned nMutexPerDb /* number of times perDb.mutex was entered */;
unsigned nMutexAutoExt /* number of times autoExt.mutex was entered */;
unsigned nDestroy /* xDestroy() calls across all types */; unsigned nDestroy /* xDestroy() calls across all types */;
struct { struct {
/* Number of calls for each type of UDF callback. */ /* Number of calls for each type of UDF callback. */
@@ -528,10 +526,9 @@ static struct {
unsigned nInverse; unsigned nInverse;
} udf; } udf;
} metrics; } metrics;
#if S3JNI_ENABLE_AUTOEXT
struct { struct {
S3JniAutoExtension *pHead /* Head of the auto-extension list */; S3JniAutoExtension *pHead /* Head of the auto-extension list */;
S3JniDb * psOpening /* FIXME: move into envCache. Handle to the S3JniDb * pdbOpening /* FIXME: move into envCache. Handle to the
being-opened db. We need this so that auto being-opened db. We need this so that auto
extensions can have a consistent view of extensions can have a consistent view of
the cross-language db connection and the cross-language db connection and
@@ -542,8 +539,9 @@ static struct {
manipulation of the auto-extension manipulation of the auto-extension
list while extensions are list while extensions are
running. */; running. */;
sqlite3_mutex * mutex /* mutex for aUsed and aFree */;
void const * locker /* Mutex is locked on this object's behalf */;
} autoExt; } autoExt;
#endif
} S3JniGlobal; } S3JniGlobal;
#define MUTEX_ASSERT_LOCKER_ENV \ #define MUTEX_ASSERT_LOCKER_ENV \
@@ -572,6 +570,19 @@ static struct {
/*MARKER(("Leaving PerDb mutex@%p %s.\n", env, __func__));*/ \ /*MARKER(("Leaving PerDb mutex@%p %s.\n", env, __func__));*/ \
S3JniGlobal.perDb.locker = 0; \ S3JniGlobal.perDb.locker = 0; \
sqlite3_mutex_leave( S3JniGlobal.perDb.mutex ) sqlite3_mutex_leave( S3JniGlobal.perDb.mutex )
#define MUTEX_ENTER_EXT \
/*MARKER(("Entering autoExt mutex@%p %s.\n", env, __func__));*/ \
sqlite3_mutex_enter( S3JniGlobal.autoExt.mutex ); \
++S3JniGlobal.metrics.nMutexAutoExt
#define MUTEX_TRY_EXT(FAIL_EXPR) \
/*MARKER(("Leaving PerDb mutex@%p %s.\n", env, __func__));*/ \
if( sqlite3_mutex_try( S3JniGlobal.autoExt.mutex ) ){ FAIL_EXPR; } \
S3JniGlobal.autoExt.locker = env; \
++S3JniGlobal.metrics.nMutexAutoExt
#define MUTEX_LEAVE_EXT \
/*MARKER(("Leaving PerDb mutex@%p %s.\n", env, __func__));*/ \
S3JniGlobal.autoExt.locker = 0; \
sqlite3_mutex_leave( S3JniGlobal.autoExt.mutex )
#define OOM_CHECK(VAR) if(!(VAR)) s3jni_oom(env) #define OOM_CHECK(VAR) if(!(VAR)) s3jni_oom(env)
static void s3jni_oom(JNIEnv * const env){ static void s3jni_oom(JNIEnv * const env){
@@ -1023,7 +1034,6 @@ static int S3JniGlobal_env_uncache(JNIEnv * const env){
This simple cache catches >99% of searches in the current This simple cache catches >99% of searches in the current
(2023-07-31) tests. (2023-07-31) tests.
*/ */
FIXME_THREADING(S3JniEnvCache)
static S3JniNphCache * S3JniGlobal_nph_cache(JNIEnv * const env, const char *zClassName){ static S3JniNphCache * S3JniGlobal_nph_cache(JNIEnv * const env, const char *zClassName){
/** /**
According to: According to:
@@ -1041,8 +1051,8 @@ static S3JniNphCache * S3JniGlobal_nph_cache(JNIEnv * const env, const char *zCl
cached as well. cached as well.
Reminder: we do not need a mutex for the envRow->nph cache Reminder: we do not need a mutex for the envRow->nph cache
because all nph entries are per-thread and envCache.mutex because all nph entries are per-thread and envCache.mutex already
already guards the fetching of envRow. guards the fetching of envRow.
*/ */
struct S3JniEnvCache * const envRow = S3JniGlobal_env_cache(env); struct S3JniEnvCache * const envRow = S3JniGlobal_env_cache(env);
S3JniNphCache * freeSlot = 0; S3JniNphCache * freeSlot = 0;
@@ -1221,8 +1231,6 @@ static void S3JniDb_dump(S3JniDb *s){
Returns NULL if jDb and pDb are both NULL or if there is no Returns NULL if jDb and pDb are both NULL or if there is no
matching S3JniDb entry for pDb or the pointer fished out of jDb. matching S3JniDb entry for pDb or the pointer fished out of jDb.
*/ */
FIXME_THREADING(S3JniEnvCache)
FIXME_THREADING(perDb)
static S3JniDb * S3JniDb_for_db(JNIEnv * const env, jobject jDb, sqlite3 *pDb){ static S3JniDb * S3JniDb_for_db(JNIEnv * const env, jobject jDb, sqlite3 *pDb){
S3JniDb * s = 0; S3JniDb * s = 0;
if(jDb || pDb){ if(jDb || pDb){
@@ -1242,7 +1250,6 @@ static S3JniDb * S3JniDb_for_db(JNIEnv * const env, jobject jDb, sqlite3 *pDb){
return s; return s;
} }
#if S3JNI_ENABLE_AUTOEXT
/** /**
Unlink ax from S3JniGlobal.autoExt and free it. Unlink ax from S3JniGlobal.autoExt and free it.
*/ */
@@ -1292,7 +1299,6 @@ static S3JniAutoExtension * S3JniAutoExtension_alloc(JNIEnv *const env,
} }
return ax; return ax;
} }
#endif /* S3JNI_ENABLE_AUTOEXT */
/** /**
Requires that jCx be a Java-side sqlite3_context wrapper for pCx. Requires that jCx be a Java-side sqlite3_context wrapper for pCx.
@@ -1881,35 +1887,37 @@ WRAP_INT_SVALUE(1value_1numeric_1type, sqlite3_value_numeric_type)
WRAP_INT_SVALUE(1value_1subtype, sqlite3_value_subtype) WRAP_INT_SVALUE(1value_1subtype, sqlite3_value_subtype)
WRAP_INT_SVALUE(1value_1type, sqlite3_value_type) WRAP_INT_SVALUE(1value_1type, sqlite3_value_type)
#if S3JNI_ENABLE_AUTOEXT static JNIEnv * s3jni_get_env(void){
JNIEnv * env = 0;
if( (*S3JniGlobal.jvm)->GetEnv(S3JniGlobal.jvm, (void **)&env,
JNI_VERSION_1_8) ){
fprintf(stderr, "Fatal error: cannot get current JNIEnv.\n");
abort();
}
return env;
}
/* Central auto-extension handler. */ /* Central auto-extension handler. */
FIXME_THREADING(autoExt) static int s3jni_run_java_auto_extensions(sqlite3 *pDb, const char **pzErr,
static int s3jni_auto_extension(sqlite3 *pDb, const char **pzErr,
const struct sqlite3_api_routines *ignored){ const struct sqlite3_api_routines *ignored){
S3JniAutoExtension const * pAX = S3JniGlobal.autoExt.pHead; S3JniAutoExtension const * pAX = S3JniGlobal.autoExt.pHead;
int rc; int rc;
JNIEnv * env = 0; JNIEnv * env = 0;
S3JniDb * const ps = S3JniGlobal.autoExt.psOpening; S3JniDb * const ps = S3JniGlobal.autoExt.pdbOpening;
//MARKER(("auto-extension on open()ing ps@%p db@%p\n", ps, pDb));
S3JniGlobal.autoExt.psOpening = 0; assert( S3JniGlobal.autoExt.locker );
assert( S3JniGlobal.autoExt.locker == ps );
S3JniGlobal.autoExt.pdbOpening = 0;
if( !pAX ){ if( !pAX ){
assert( 0==S3JniGlobal.autoExt.isRunning ); assert( 0==S3JniGlobal.autoExt.isRunning );
return 0; return 0;
} }else if( S3JniGlobal.autoExt.locker != ps ) {
else if( S3JniGlobal.autoExt.isRunning ){ *pzErr = sqlite3_mprintf("Internal error: unexpected path lead to "
/* Necessary to avoid certain endless loop/stack overflow cases. */ "running an auto-extension.");
*pzErr = sqlite3_mprintf("Auto-extensions must not be triggered while "
"auto-extensions are running.");
return SQLITE_MISUSE;
}
else if(!ps){
MARKER(("Internal error: cannot find S3JniDb for auto-extension\n"));
return SQLITE_ERROR;
}else if( (*S3JniGlobal.jvm)->GetEnv(S3JniGlobal.jvm, (void **)&env, JNI_VERSION_1_8) ){
assert(!"Cannot get JNIEnv");
*pzErr = sqlite3_mprintf("Could not get current JNIEnv.");
return SQLITE_ERROR; return SQLITE_ERROR;
} }
env = s3jni_get_env();
//MARKER(("auto-extension on open()ing ps@%p db@%p\n", ps, pDb));
assert( !ps->pDb /* it's still being opened */ ); assert( !ps->pDb /* it's still being opened */ );
ps->pDb = pDb; ps->pDb = pDb;
assert( ps->jDb ); assert( ps->jDb );
@@ -1941,8 +1949,9 @@ JDECL(jint,1auto_1extension)(JENV_OSELF, jobject jAutoExt){
S3JniAutoExtension * ax; S3JniAutoExtension * ax;
if( !jAutoExt ) return SQLITE_MISUSE; if( !jAutoExt ) return SQLITE_MISUSE;
else if( 0==once && ++once ){ MUTEX_ENTER_EXT;
sqlite3_auto_extension( (void(*)(void))s3jni_auto_extension ); if( 0==once && ++once ){
sqlite3_auto_extension( (void(*)(void))s3jni_run_java_auto_extensions );
} }
ax = S3JniGlobal.autoExt.pHead; ax = S3JniGlobal.autoExt.pHead;
for( ; ax; ax = ax->pNext ){ for( ; ax; ax = ax->pNext ){
@@ -1950,9 +1959,10 @@ JDECL(jint,1auto_1extension)(JENV_OSELF, jobject jAutoExt){
return 0 /* C API treats this as a no-op. */; return 0 /* C API treats this as a no-op. */;
} }
} }
return S3JniAutoExtension_alloc(env, jAutoExt) ? 0 : SQLITE_NOMEM; ax = S3JniAutoExtension_alloc(env, jAutoExt);
MUTEX_LEAVE_EXT;
return ax ? 0 : SQLITE_NOMEM;
} }
#endif /* S3JNI_ENABLE_AUTOEXT */
FIXME_THREADING(S3JniEnvCache) FIXME_THREADING(S3JniEnvCache)
JDECL(jint,1bind_1blob)(JENV_CSELF, jobject jpStmt, JDECL(jint,1bind_1blob)(JENV_CSELF, jobject jpStmt,
@@ -2088,20 +2098,23 @@ JDECL(jint,1busy_1timeout)(JENV_CSELF, jobject jDb, jint ms){
return SQLITE_MISUSE; return SQLITE_MISUSE;
} }
#if S3JNI_ENABLE_AUTOEXT
FIXME_THREADING(autoExt) FIXME_THREADING(autoExt)
JDECL(jboolean,1cancel_1auto_1extension)(JENV_CSELF, jobject jAutoExt){ JDECL(jboolean,1cancel_1auto_1extension)(JENV_CSELF, jobject jAutoExt){
S3JniAutoExtension * ax;; S3JniAutoExtension * ax;
if( S3JniGlobal.autoExt.isRunning ) return JNI_FALSE; jboolean rc = JNI_FALSE;
MUTEX_ENTER_EXT;
if( !S3JniGlobal.autoExt.isRunning ) {
for( ax = S3JniGlobal.autoExt.pHead; ax; ax = ax->pNext ){ for( ax = S3JniGlobal.autoExt.pHead; ax; ax = ax->pNext ){
if( (*env)->IsSameObject(env, ax->jObj, jAutoExt) ){ if( (*env)->IsSameObject(env, ax->jObj, jAutoExt) ){
S3JniAutoExtension_free(env, ax); S3JniAutoExtension_free(env, ax);
return JNI_TRUE; rc = JNI_TRUE;
break;
} }
} }
return JNI_FALSE; }
MUTEX_LEAVE_EXT;
return rc;
} }
#endif /* S3JNI_ENABLE_AUTOEXT */
/** /**
@@ -2649,27 +2662,41 @@ JDECL(jlong,1last_1insert_1rowid)(JENV_CSELF, jobject jpDb){
static int s3jni_open_pre(JNIEnv * const env, S3JniEnvCache **jc, static int s3jni_open_pre(JNIEnv * const env, S3JniEnvCache **jc,
jstring jDbName, char **zDbName, jstring jDbName, char **zDbName,
S3JniDb ** ps, jobject *jDb){ S3JniDb ** ps, jobject *jDb){
int rc = 0;
MUTEX_TRY_EXT(return SQLITE_BUSY);
*jc = S3JniGlobal_env_cache(env); *jc = S3JniGlobal_env_cache(env);
if(!*jc) return SQLITE_NOMEM; if(!*jc){
rc = SQLITE_NOMEM;
goto end;
}
*zDbName = jDbName ? s3jni_jstring_to_utf8(*jc, jDbName, 0) : 0; *zDbName = jDbName ? s3jni_jstring_to_utf8(*jc, jDbName, 0) : 0;
if(jDbName && !*zDbName) return SQLITE_NOMEM; if(jDbName && !*zDbName){
rc = SQLITE_NOMEM;
goto end;
}
*jDb = new_sqlite3_wrapper(env, 0); *jDb = new_sqlite3_wrapper(env, 0);
if( !*jDb ){ if( !*jDb ){
sqlite3_free(*zDbName); sqlite3_free(*zDbName);
*zDbName = 0; *zDbName = 0;
return SQLITE_NOMEM; rc = SQLITE_NOMEM;
goto end;
} }
MUTEX_ENTER_PDB; MUTEX_ENTER_PDB;
*ps = S3JniDb_alloc(env, 0, *jDb); *ps = S3JniDb_alloc(env, 0, *jDb);
MUTEX_LEAVE_PDB; MUTEX_LEAVE_PDB;
#if S3JNI_ENABLE_AUTOEXT
if(*ps){ if(*ps){
assert(!S3JniGlobal.autoExt.psOpening); S3JniGlobal.autoExt.pdbOpening = *ps;
S3JniGlobal.autoExt.psOpening = *ps; S3JniGlobal.autoExt.locker = *ps;
}else{
rc = SQLITE_NOMEM;
} }
#endif
//MARKER(("pre-open ps@%p\n", *ps)); //MARKER(("pre-open ps@%p\n", *ps));
return *ps ? 0 : SQLITE_NOMEM; end:
/* Remain in autoExt.mutex until s3jni_open_post(). */
if(rc){
MUTEX_LEAVE_EXT;
}
return rc;
} }
/** /**
@@ -2686,10 +2713,8 @@ static int s3jni_open_pre(JNIEnv * const env, S3JniEnvCache **jc,
static int s3jni_open_post(JNIEnv * const env, S3JniDb * ps, static int s3jni_open_post(JNIEnv * const env, S3JniDb * ps,
sqlite3 **ppDb, jobject jOut, int theRc){ sqlite3 **ppDb, jobject jOut, int theRc){
//MARKER(("post-open() ps@%p db@%p\n", ps, *ppDb)); //MARKER(("post-open() ps@%p db@%p\n", ps, *ppDb));
#if S3JNI_ENABLE_AUTOEXT assert( S3JniGlobal.autoExt.locker == ps );
assert( S3JniGlobal.autoExt.pHead ? ps!=S3JniGlobal.autoExt.psOpening : 1 ); S3JniGlobal.autoExt.pdbOpening = 0;
S3JniGlobal.autoExt.psOpening = 0;
#endif
if(*ppDb){ if(*ppDb){
assert(ps->jDb); assert(ps->jDb);
ps->pDb = *ppDb; ps->pDb = *ppDb;
@@ -2701,6 +2726,7 @@ static int s3jni_open_post(JNIEnv * const env, S3JniDb * ps,
ps = 0; ps = 0;
} }
OutputPointer_set_sqlite3(env, jOut, ps ? ps->jDb : 0); OutputPointer_set_sqlite3(env, jOut, ps ? ps->jDb : 0);
MUTEX_LEAVE_EXT;
return theRc; return theRc;
} }
@@ -2710,8 +2736,8 @@ JDECL(jint,1open)(JENV_CSELF, jstring strName, jobject jOut){
jobject jDb = 0; jobject jDb = 0;
S3JniDb * ps = 0; S3JniDb * ps = 0;
S3JniEnvCache * jc = 0; S3JniEnvCache * jc = 0;
S3JniDb * const prevOpening = S3JniGlobal.autoExt.psOpening; S3JniDb * const prevOpening = S3JniGlobal.autoExt.pdbOpening;
int rc = s3jni_open_pre(env, &jc, strName, &zName, &ps, &jDb); int rc= s3jni_open_pre(env, &jc, strName, &zName, &ps, &jDb);
if( 0==rc ){ if( 0==rc ){
rc = sqlite3_open(zName, &pOut); rc = sqlite3_open(zName, &pOut);
//MARKER(("env=%p, *env=%p\n", env, *env)); //MARKER(("env=%p, *env=%p\n", env, *env));
@@ -2720,7 +2746,7 @@ JDECL(jint,1open)(JENV_CSELF, jstring strName, jobject jOut){
assert(rc==0 ? pOut!=0 : 1); assert(rc==0 ? pOut!=0 : 1);
sqlite3_free(zName); sqlite3_free(zName);
} }
S3JniGlobal.autoExt.psOpening = prevOpening; S3JniGlobal.autoExt.pdbOpening = prevOpening;
return (jint)rc; return (jint)rc;
} }
@@ -2732,7 +2758,7 @@ JDECL(jint,1open_1v2)(JENV_CSELF, jstring strName,
S3JniDb * ps = 0; S3JniDb * ps = 0;
S3JniEnvCache * jc = 0; S3JniEnvCache * jc = 0;
char *zVfs = 0; char *zVfs = 0;
S3JniDb * const prevOpening = S3JniGlobal.autoExt.psOpening; S3JniDb * const prevOpening = S3JniGlobal.autoExt.pdbOpening;
int rc = s3jni_open_pre(env, &jc, strName, &zName, &ps, &jDb); int rc = s3jni_open_pre(env, &jc, strName, &zName, &ps, &jDb);
if( 0==rc && strVfs ){ if( 0==rc && strVfs ){
zVfs = s3jni_jstring_to_utf8(jc, strVfs, 0); zVfs = s3jni_jstring_to_utf8(jc, strVfs, 0);
@@ -2747,10 +2773,10 @@ JDECL(jint,1open_1v2)(JENV_CSELF, jstring strName,
/*MARKER(("zName=%s, zVfs=%s, pOut=%p, flags=%d, nrc=%d\n", /*MARKER(("zName=%s, zVfs=%s, pOut=%p, flags=%d, nrc=%d\n",
zName, zVfs, pOut, (int)flags, nrc));*/ zName, zVfs, pOut, (int)flags, nrc));*/
rc = s3jni_open_post(env, ps, &pOut, jOut, rc); rc = s3jni_open_post(env, ps, &pOut, jOut, rc);
S3JniGlobal.autoExt.pdbOpening = prevOpening;
assert(rc==0 ? pOut!=0 : 1); assert(rc==0 ? pOut!=0 : 1);
sqlite3_free(zName); sqlite3_free(zName);
sqlite3_free(zVfs); sqlite3_free(zVfs);
S3JniGlobal.autoExt.psOpening = prevOpening;
return (jint)rc; return (jint)rc;
} }
@@ -2886,15 +2912,13 @@ JDECL(jint,1reset)(JENV_CSELF, jobject jpStmt){
return rc; return rc;
} }
#if S3JNI_ENABLE_AUTOEXT
JDECL(void,1reset_1auto_1extension)(JENV_CSELF){ JDECL(void,1reset_1auto_1extension)(JENV_CSELF){
if(!S3JniGlobal.autoExt.isRunning){ MUTEX_ENTER_EXT;
while( S3JniGlobal.autoExt.pHead ){ while( S3JniGlobal.autoExt.pHead ){
S3JniAutoExtension_free(env, S3JniGlobal.autoExt.pHead); S3JniAutoExtension_free(env, S3JniGlobal.autoExt.pHead);
} }
} MUTEX_LEAVE_EXT;
} }
#endif /* S3JNI_ENABLE_AUTOEXT */
/* sqlite3_result_text/blob() and friends. */ /* sqlite3_result_text/blob() and friends. */
static void result_blob_text(int asBlob, int as64, static void result_blob_text(int asBlob, int as64,
@@ -3504,9 +3528,10 @@ JDECL(void,1do_1something_1for_1developer)(JENV_CSELF){
printf("\tJNIEnv cache %u misses, %u hits\n", printf("\tJNIEnv cache %u misses, %u hits\n",
S3JniGlobal.metrics.envCacheMisses, S3JniGlobal.metrics.envCacheMisses,
S3JniGlobal.metrics.envCacheHits); S3JniGlobal.metrics.envCacheHits);
printf("\tMutex entry: %u env, %u perDb\n", printf("Mutex entry:\n\t%u env\n\t%u perDb\n\t%u autoExt (mostly via open[_v2]())\n",
S3JniGlobal.metrics.nMutexEnv, S3JniGlobal.metrics.nMutexEnv,
S3JniGlobal.metrics.nMutexPerDb); S3JniGlobal.metrics.nMutexPerDb,
S3JniGlobal.metrics.nMutexAutoExt);
puts("Java-side UDF calls:"); puts("Java-side UDF calls:");
#define UDF(T) printf("\t%-8s = %u\n", "x" #T, S3JniGlobal.metrics.udf.n##T) #define UDF(T) printf("\t%-8s = %u\n", "x" #T, S3JniGlobal.metrics.udf.n##T)
UDF(Func); UDF(Step); UDF(Final); UDF(Value); UDF(Inverse); UDF(Func); UDF(Step); UDF(Final); UDF(Value); UDF(Inverse);
@@ -4418,6 +4443,8 @@ Java_org_sqlite_jni_SQLite3Jni_init(JENV_CSELF){
OOM_CHECK( S3JniGlobal.envCache.mutex ); OOM_CHECK( S3JniGlobal.envCache.mutex );
S3JniGlobal.perDb.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); S3JniGlobal.perDb.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
OOM_CHECK( S3JniGlobal.perDb.mutex ); OOM_CHECK( S3JniGlobal.perDb.mutex );
S3JniGlobal.autoExt.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
OOM_CHECK( S3JniGlobal.autoExt.mutex );
#if 0 #if 0
/* Just for sanity checking... */ /* Just for sanity checking... */
(void)S3JniGlobal_env_cache(env); (void)S3JniGlobal_env_cache(env);

View File

@@ -178,24 +178,25 @@ public final class SQLite3Jni {
not have access to the sqlite3_api object which native not have access to the sqlite3_api object which native
auto-extensions do. auto-extensions do.
- If an auto-extension opens a db, thereby triggering recursion - If an auto-extension opens a db, opening will fail with SQLITE_BUSY.
in the auto-extension handler, it will fail with a message The alternative would be endless recursion into the auto-extension.
explaining that recursion is not permitted.
- All of the other auto extension routines will fail without side - The list of auto-extensions must not be manipulated from within
effects if invoked from within the execution of an an auto-extension. Auto extensions can neither be added,
auto-extension. i.e. auto extensions can neither be added,
removed, nor cleared while one registered with this function is removed, nor cleared while one registered with this function is
running. Auto-extensions registered directly with the library running. Attempting to do so may lead to a deadlock.
via C code, as opposed to indirectly via Java, do not have that
limitation.
See the AutoExtension class docs for more information. See the AutoExtension class docs for more information.
Achtung: it is as yet unknown whether auto extensions registered Achtung: it is as yet unknown whether auto extensions registered
from one JNIEnv (thread) can be safely called from another. from one JNIEnv (thread) can be safely called from another.
Design note: this family of methods is synchronized in order to
help avoid a small race condition where an in-progress
sqlite3_reset_auto_extension() or sqlite3_cancel_auto_extension()
could cause sqlite3_open() to fail with SQLITE_BUSY.
*/ */
public static native int sqlite3_auto_extension(@NotNull AutoExtension callback); public static synchronized native int sqlite3_auto_extension(@NotNull AutoExtension callback);
public static int sqlite3_bind_blob( public static int sqlite3_bind_blob(
@NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data @NotNull sqlite3_stmt stmt, int ndx, @Nullable byte[] data
@@ -296,7 +297,7 @@ public final class SQLite3Jni {
effects, if auto extensions are currently running. (The JNI-level effects, if auto extensions are currently running. (The JNI-level
list of extensions cannot be manipulated while it is being traversed.) list of extensions cannot be manipulated while it is being traversed.)
*/ */
public static native boolean sqlite3_cancel_auto_extension( public static synchronized native boolean sqlite3_cancel_auto_extension(
@NotNull AutoExtension ax @NotNull AutoExtension ax
); );
@@ -313,11 +314,11 @@ public final class SQLite3Jni {
); );
public static native int sqlite3_close( public static native int sqlite3_close(
@NotNull sqlite3 db @Nullable sqlite3 db
); );
public static native int sqlite3_close_v2( public static native int sqlite3_close_v2(
@NotNull sqlite3 db @Nullable sqlite3 db
); );
public static native byte[] sqlite3_column_blob( public static native byte[] sqlite3_column_blob(
@@ -593,19 +594,16 @@ public final class SQLite3Jni {
Recall that even if opening fails, the output pointer might be Recall that even if opening fails, the output pointer might be
non-null. Any error message about the failure will be in that non-null. Any error message about the failure will be in that
object and it is up to the caller to sqlite3_close() that object and it is up to the caller to sqlite3_close() that
db handle. db handle. Passing a null to sqlite3_close() is legal.
Pedantic note: though any number of Java-level sqlite3 objects Design note: this method is synchronized in order to help
may refer to/wrap a single C-level (sqlite3*), the JNI internals alleviate a race condition involving auto-extensions.
take a reference to the object which is passed to sqlite3_open()
or sqlite3_open_v2() so that they have a predictible object to
pass to, e.g., the sqlite3_collation_needed() callback.
*/ */
public static native int sqlite3_open( public static synchronized native int sqlite3_open(
@Nullable String filename, @NotNull OutputPointer.sqlite3 ppDb @Nullable String filename, @NotNull OutputPointer.sqlite3 ppDb
); );
public static native int sqlite3_open_v2( public static synchronized native int sqlite3_open_v2(
@Nullable String filename, @NotNull OutputPointer.sqlite3 ppDb, @Nullable String filename, @NotNull OutputPointer.sqlite3 ppDb,
int flags, @Nullable String zVfs int flags, @Nullable String zVfs
); );
@@ -729,7 +727,7 @@ public final class SQLite3Jni {
extensions are currently running. (The JNI-level list of extensions are currently running. (The JNI-level list of
extensions cannot be manipulated while it is being traversed.) extensions cannot be manipulated while it is being traversed.)
*/ */
public static native void sqlite3_reset_auto_extension(); public static synchronized native void sqlite3_reset_auto_extension();
public static native void sqlite3_result_double( public static native void sqlite3_result_double(
@NotNull sqlite3_context cx, double v @NotNull sqlite3_context cx, double v

View File

@@ -1,5 +1,5 @@
C Add\ssome\sdocs\sand\smetrics\sfor\sthe\snew\smutex\sinternals. C Add\sa\smutex\sfor\sauto-extensions,\stied\sin\sto\sthe\sopen()\sprocess\ssince\sthat's\sthe\sroute\sinto\sauto-extensions.
D 2023-08-13T10:28:35.456 D 2023-08-13T12:40:27.217
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -234,7 +234,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3
F ext/jni/GNUmakefile a9e11b92e620058558cbc1a2d49f8ec53c78d6a989b9db0b7d0b649b9f174881 F ext/jni/GNUmakefile a9e11b92e620058558cbc1a2d49f8ec53c78d6a989b9db0b7d0b649b9f174881
F ext/jni/README.md 7a614a2fa6c561205f7a53fd8626cf93a7b5711ff454fc1814517f796df398eb F ext/jni/README.md 7a614a2fa6c561205f7a53fd8626cf93a7b5711ff454fc1814517f796df398eb
F ext/jni/jar-dist.make f90a553203a57934bf275bed86479485135a52f48ac5c1cfe6499ae07b0b35a4 F ext/jni/jar-dist.make f90a553203a57934bf275bed86479485135a52f48ac5c1cfe6499ae07b0b35a4
F ext/jni/src/c/sqlite3-jni.c 44c1da6d1ae9d8ea2af16dd5c1d17224a655c9c94135892f81571b2481896431 F ext/jni/src/c/sqlite3-jni.c 4f6f8f2dec309a6b117a6e8f460078b5f6f6b65a17c530ae2f5907b6425d714c
F ext/jni/src/c/sqlite3-jni.h f10d2f38720687c70ecdd5e44f6e8db98efee2caa05fc86b2d9e0c76e6cc0a18 F ext/jni/src/c/sqlite3-jni.h f10d2f38720687c70ecdd5e44f6e8db98efee2caa05fc86b2d9e0c76e6cc0a18
F ext/jni/src/org/sqlite/jni/Authorizer.java 1308988f7f40579ea0e4deeaec3c6be971630566bd021c31367fe3f5140db892 F ext/jni/src/org/sqlite/jni/Authorizer.java 1308988f7f40579ea0e4deeaec3c6be971630566bd021c31367fe3f5140db892
F ext/jni/src/org/sqlite/jni/AutoExtension.java 18e83f6f463e306df60b2dceb65247d32af1f78af4bbbae9155411a8c6cdb093 F ext/jni/src/org/sqlite/jni/AutoExtension.java 18e83f6f463e306df60b2dceb65247d32af1f78af4bbbae9155411a8c6cdb093
@@ -254,7 +254,7 @@ F ext/jni/src/org/sqlite/jni/ProgressHandler.java 6f62053a828a572de809828b1ee495
F ext/jni/src/org/sqlite/jni/ResultCode.java ba701f20213a5f259e94cfbfdd36eb7ac7ce7797f2c6c7fca2004ff12ce20f86 F ext/jni/src/org/sqlite/jni/ResultCode.java ba701f20213a5f259e94cfbfdd36eb7ac7ce7797f2c6c7fca2004ff12ce20f86
F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564 F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564
F ext/jni/src/org/sqlite/jni/SQLFunction.java 09ce81c1c637e31c3a830d4c859cce95d65f5e02ff45f8bd1985b3479381bc46 F ext/jni/src/org/sqlite/jni/SQLFunction.java 09ce81c1c637e31c3a830d4c859cce95d65f5e02ff45f8bd1985b3479381bc46
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 7933fabc267dbfdccb784563d8c404f90275fe9418e8cd6c43c584bc9c57f70f F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 5eeba0b1a00fb34bc93fe60186f6032fcf4d568fc5868d70029883d3d07cc306
F ext/jni/src/org/sqlite/jni/Tester1.java fc2ec1f1be58474112b9df8284f0157b64872107f446154c3d0bf1742b924d2b F ext/jni/src/org/sqlite/jni/Tester1.java fc2ec1f1be58474112b9df8284f0157b64872107f446154c3d0bf1742b924d2b
F ext/jni/src/org/sqlite/jni/TesterFts5.java 59e22dd24af033ea8827d36225a2f3297908fb6af8818ead8850c6c6847557b1 F ext/jni/src/org/sqlite/jni/TesterFts5.java 59e22dd24af033ea8827d36225a2f3297908fb6af8818ead8850c6c6847557b1
F ext/jni/src/org/sqlite/jni/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d F ext/jni/src/org/sqlite/jni/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d
@@ -2091,8 +2091,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P c64e6a52ac79164be37fe643a4a39bd187af198a379410def8b8419f7c2224d4 P 33d1780b43182d2574adbc1928707af825c485c99762738e58bc6d7c6c52ac6a
R cd02d0fb58628c824a2d7de7efc47b02 R 6a1ce79c2368c04d74cde070b44b6572
U stephan U stephan
Z 6ab46f9c79559c9df9412a6d1bef3261 Z d637a436f204decfbfbf40fa44769c67
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@@ -1 +1 @@
33d1780b43182d2574adbc1928707af825c485c99762738e58bc6d7c6c52ac6a 8da97e0db4eeacf91aa6fd909fd7cb73b050d194dfc7739a502b55f7eca6d7b1