1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-30 19:03:16 +03:00

JNI internal cleanups and docs.

FossilOrigin-Name: b7b26bfb4f86e0b8aaabab258ccb0713737ffd4ecd3156d6a83a4f9a1d25edf6
This commit is contained in:
stephan
2023-08-26 11:57:34 +00:00
parent d9cf47e377
commit 3ff458d61e
4 changed files with 119 additions and 82 deletions

View File

@ -233,8 +233,8 @@ static inline void s3jni_unref_local(JNIEnv * const env, jobject const v){
#define S3JniUnrefGlobal(VAR) s3jni_unref_global(env, (VAR))
#define S3JniUnrefLocal(VAR) s3jni_unref_local(env, (VAR))
/**
Keys for use with S3JniGlobal_nph_cache().
/*
** Key type for use with S3JniGlobal_nph_cache().
*/
typedef struct S3NphRef S3NphRef;
struct S3NphRef {
@ -242,10 +242,11 @@ struct S3NphRef {
const char * const zName /* Full Java name of the class */;
};
/**
Keys for each concrete NativePointerHolder subclass. These are to
be used with S3JniGlobal_nph_cache() and friends. These are
initialized on-demand by S3JniGlobal_nph_cache().
/*
** Cache keys for each concrete NativePointerHolder subclass and
** OutputPointer type. The members are to be used with
** S3JniGlobal_nph_cache() and friends, and each one's member->index
** corresponds to its index in the S3JniGlobal.nph[] array.
*/
static const struct {
const S3NphRef sqlite3;
@ -289,21 +290,14 @@ static const struct {
#undef NREF
};
/* Helpers for jstring and jbyteArray. */
#define s3jni_jstring_to_mutf8(ARG) (*env)->GetStringUTFChars(env, ARG, NULL)
#define s3jni_mutf8_release(ARG,VAR) if( VAR ) (*env)->ReleaseStringUTFChars(env, ARG, VAR)
#define s3jni_jbytearray_bytes(ARG) (*env)->GetByteArrayElements(env,ARG, NULL)
#define s3jni_jbytearray_release(ARG,VAR) if( VAR ) (*env)->ReleaseByteArrayElements(env, ARG, VAR, JNI_ABORT)
enum {
/*
** Size of the NativePointerHolder cache. Need enough space for
** (only) the library's NativePointerHolder types, a fixed count
** known at build-time. If we add more than this a fatal error will
** be triggered with a reminder to increase this. This value needs
** to be exactly the number of entries in the S3NphRefs object. The
** index field of those entries are the keys for this particular
** cache.
** (only) the library's NativePointerHolder and OutputPointer types,
** a fixed count known at build-time. This value needs to be
** exactly the number of S3NphRef entries in the S3NphRefs
** object. The index field of those entries are the keys for this
** particular cache.
*/
S3Jni_NphCache_size = sizeof(S3NphRefs) / sizeof(S3NphRef)
};
@ -316,13 +310,13 @@ typedef struct S3JniNphClass S3JniNphClass;
struct S3JniNphClass {
volatile const S3NphRef * pRef /* Entry from S3NphRefs. */;
jclass klazz /* global ref to the concrete
** NativePointerHolder subclass represented by
** zClassName */;
** NativePointerHolder subclass
** represented by zClassName */;
volatile jmethodID midCtor /* klazz's no-arg constructor. Used by
** new_NativePointerHolder_object(). */;
volatile jfieldID fidValue /* NativePointerHolder.nativePointer or
** OutputPointer.T.value */;
volatile jfieldID fidAggCtx /* sqlite3_context::aggregateContext. Used only
volatile jfieldID fidAggCtx /* sqlite3_context.aggregateContext, used only
** by the sqlite3_context binding. */;
};
@ -337,7 +331,7 @@ struct S3JniHook{
/* We lookup the jObj.xDestroy() method as-needed for contexts which
** have custom finalizers. */
};
#ifndef SQLITE_ENABLE_PREUPDATE_HOOK
#if !defined(SQLITE_ENABLE_PREUPDATE_HOOK) || defined(SQLITE_ENABLE_SQLLOG)
static const S3JniHook S3JniHook_empty = {0,0};
#endif
@ -459,6 +453,7 @@ struct S3JniGlobalType {
**
*/
JavaVM * jvm;
sqlite3_mutex * mutex;
/*
** Cache of Java refs and method IDs for NativePointerHolder
** subclasses. Initialized on demand.
@ -546,6 +541,7 @@ struct S3JniGlobalType {
a S3JniNphClass operation. */;
volatile unsigned nMutexPerDb /* number of times perDb.mutex was entered */;
volatile unsigned nMutexAutoExt /* number of times autoExt.mutex was entered */;
volatile unsigned nMutexGlobal /* number of times global mutex was entered. */;
volatile unsigned nDestroy /* xDestroy() calls across all types */;
volatile unsigned nPdbAlloc /* Number of S3JniDb alloced. */;
volatile unsigned nPdbRecycled /* Number of S3JniDb reused. */;
@ -601,6 +597,7 @@ static void s3jni_incr( volatile unsigned int * const p ){
S3JniMutex_Env_assertLocker; \
SJG.envCache.locker = 0; \
sqlite3_mutex_leave( SJG.envCache.mutex )
#define S3JniMutex_Ext_enter \
/*MARKER(("Entering autoExt mutex@%p %s.\n", env));*/ \
sqlite3_mutex_enter( SJG.autoExt.mutex ); \
@ -612,6 +609,15 @@ static void s3jni_incr( volatile unsigned int * const p ){
sqlite3_mutex_leave( SJG.autoExt.mutex )
#define S3JniMutex_Ext_assertLocker \
assert( env == SJG.autoExt.locker )
#define S3JniMutex_Global_enter \
/*MARKER(("Entering GLOBAL mutex@%p %s.\n", env));*/ \
sqlite3_mutex_enter( SJG.mutex ); \
s3jni_incr(&SJG.metrics.nMutexGlobal);
#define S3JniMutex_Global_leave \
/*MARKER(("Leaving GLOBAL mutex @%p %s.\n", env));*/ \
sqlite3_mutex_leave( SJG.mutex )
#define S3JniMutex_Nph_enter \
S3JniMutex_Env_assertNotLocker; \
/*MARKER(("Entering NPH mutex@%p %s.\n", env));*/ \
@ -623,6 +629,7 @@ static void s3jni_incr( volatile unsigned int * const p ){
S3JniMutex_Env_assertLocker; \
SJG.envCache.locker = 0; \
sqlite3_mutex_leave( SJG.envCache.mutex )
#define S3JniMutex_S3JniDb_enter \
sqlite3_mutex_enter( SJG.perDb.mutex ); \
assert( 0==SJG.perDb.locker ); \
@ -633,6 +640,7 @@ static void s3jni_incr( volatile unsigned int * const p ){
assert( env == SJG.perDb.locker ); \
SJG.perDb.locker = 0; \
sqlite3_mutex_leave( SJG.perDb.mutex )
#else /* SQLITE_THREADSAFE==0 */
#define S3JniMutex_Env_assertLocked
#define S3JniMutex_Env_assertLocker
@ -642,17 +650,29 @@ static void s3jni_incr( volatile unsigned int * const p ){
#define S3JniMutex_Ext_assertLocker
#define S3JniMutex_Ext_enter
#define S3JniMutex_Ext_leave
#define S3JniMutex_Global_enter
#define S3JniMutex_Global_leave
#define S3JniMutex_Nph_enter
#define S3JniMutex_Nph_leave
#define S3JniMutex_S3JniDb_enter
#define S3JniMutex_S3JniDb_leave
#endif
#define s3jni_oom_check(VAR) if( !(VAR) ) s3jni_oom(env)
/* Helpers for jstring and jbyteArray. */
#define s3jni_jstring_to_mutf8(ARG) (*env)->GetStringUTFChars(env, ARG, NULL)
#define s3jni_mutf8_release(ARG,VAR) if( VAR ) (*env)->ReleaseStringUTFChars(env, ARG, VAR)
#define s3jni_jbytearray_bytes(ARG) (*env)->GetByteArrayElements(env,ARG, NULL)
#define s3jni_jbytearray_release(ARG,VAR) if( VAR ) (*env)->ReleaseByteArrayElements(env, ARG, VAR, JNI_ABORT)
/* Fail fatally with an OOM message. */
static inline void s3jni_oom(JNIEnv * const env){
(*env)->FatalError(env, "Out of memory.") /* does not return */;
}
/* Fail fatally if !VAR. */
#define s3jni_oom_check(VAR) if( !(VAR) ) s3jni_oom(env)
/*
** sqlite3_malloc() proxy which fails fatally on OOM. This should
** only be used for routines which manage global state and have no
@ -969,7 +989,7 @@ static void S3JniHook_unref(JNIEnv * const env, S3JniHook * const s, int doXDest
** has to haves its own Java reference, but it need only be
** call-local.
*/
static void S3JniHook_copy( JNIEnv * const env, S3JniHook const * const src,
static void S3JniHook_localdup( JNIEnv * const env, S3JniHook const * const src,
S3JniHook * const dest ){
S3JniMutex_S3JniDb_enter;
*dest = *src;
@ -1402,7 +1422,7 @@ static int CollationState_xCompare(void *pArg, int nLhs, const void *lhs,
jint rc = 0;
S3JniHook hook;
S3JniHook_copy(env, &ps->hooks.collation, &hook );
S3JniHook_localdup(env, &ps->hooks.collation, &hook );
if( hook.jObj ){
jbyteArray jbaLhs = (*env)->NewByteArray(env, (jint)nLhs);
jbyteArray jbaRhs = jbaLhs ? (*env)->NewByteArray(env, (jint)nRhs) : NULL;
@ -2092,7 +2112,7 @@ static int s3jni_busy_handler(void* pState, int n){
S3JniDeclLocal_env;
S3JniHook hook;
S3JniHook_copy(env, &ps->hooks.busyHandler, &hook );
S3JniHook_localdup(env, &ps->hooks.busyHandler, &hook );
if( hook.jObj ){
rc = (*env)->CallIntMethod(env, hook.jObj,
hook.midCallback, (jint)n);
@ -2230,7 +2250,7 @@ static void s3jni_collation_needed_impl16(void *pState, sqlite3 *pDb,
S3JniDeclLocal_env;
S3JniHook hook;
S3JniHook_copy(env, &ps->hooks.collationNeeded, &hook );
S3JniHook_localdup(env, &ps->hooks.collationNeeded, &hook );
if( hook.jObj ){
unsigned int const nName = s3jni_utf16_strlen(z16Name);
jstring jName = (*env)->NewString(env, (jchar const *)z16Name, nName);
@ -2354,7 +2374,7 @@ static int s3jni_commit_rollback_hook_impl(int isCommit,
int rc = 0;
S3JniHook hook;
S3JniHook_copy( env,
S3JniHook_localdup( env,
isCommit ? &ps->hooks.commit : &ps->hooks.rollback,
&hook);
if( hook.jObj ){
@ -2472,9 +2492,12 @@ static void s3jni_config_sqllog(void *ignored, sqlite3 *pDb, const char *z, int
jstring jArg1 = 0;
S3JniDeclLocal_env;
S3JniDb * const ps = S3JniDb_for_db(env, 0, pDb);
S3JniHook * const hook = &SJG.hooks.sqllog;
S3JniHook hook = S3JniHook_empty;
if( !ps || !hook->jObj ) return;
if( ps ){
S3JniHook_localdup(env, &SJG.hooks.sqllog, &hook);
}
if( !hook.jObj ) return;
jArg0 = S3JniRefLocal(ps->jDb);
switch( op ){
case 0: /* db opened */
@ -2487,11 +2510,12 @@ static void s3jni_config_sqllog(void *ignored, sqlite3 *pDb, const char *z, int
(*env)->FatalError(env, "Unhandled 4th arg to SQLITE_CONFIG_SQLLOG.");
break;
}
(*env)->CallVoidMethod(env, hook->jObj, hook->midCallback, jArg0, jArg1, op);
(*env)->CallVoidMethod(env, hook.jObj, hook.midCallback, jArg0, jArg1, op);
S3JniIfThrew{
S3JniExceptionWarnCallbackThrew("SQLITE_CONFIG_SQLLOG callback");
S3JniExceptionClear;
}
S3JniUnrefLocal(hook.jObj);
S3JniUnrefLocal(jArg0);
S3JniUnrefLocal(jArg1);
}
@ -2502,41 +2526,40 @@ void sqlite3_init_sqllog(void){
#endif
S3JniApi(sqlite3_config() /* for SQLLOG */,
jint,1config__Lorg_sqlite_jni_SQLLog_2)(JniArgsEnvClass, jobject jLog){
jint, 1config__Lorg_sqlite_jni_ConfigSqllogCallback_2)(
JniArgsEnvClass, jobject jLog
){
#ifndef SQLITE_ENABLE_SQLLOG
return SQLITE_MISUSE;
#else
S3JniHook tmpHook;
S3JniHook * const hook = &tmpHook;
S3JniHook * const hookOld = & SJG.hooks.sqllog;
jclass klazz;
S3JniHook * const pHook = &SJG.hooks.sqllog;
int rc = 0;
S3JniMutex_Global_enter;
if( !jLog ){
S3JniHook_unref(env, hookOld, 0);
return 0;
}
if( hookOld->jObj && (*env)->IsSameObject(env, jLog, hookOld->jObj) ){
return 0;
}
klazz = (*env)->GetObjectClass(env, jLog);
hook->midCallback = (*env)->GetMethodID(env, klazz, "call",
S3JniHook_unref(env, pHook, 0);
}else if( pHook->jObj && (*env)->IsSameObject(env, jLog, pHook->jObj) ){
/* No-op */
}else {
jclass const klazz = (*env)->GetObjectClass(env, jLog);
jmethodID const midCallback = (*env)->GetMethodID(env, klazz, "call",
"(Lorg/sqlite/jni/sqlite3;"
"Ljava/lang/String;"
"I)V");
S3JniUnrefLocal(klazz);
if( !hook->midCallback ){
S3JniExceptionWarnIgnore;
S3JniHook_unref(env, hook, 0);
return SQLITE_ERROR;
}
hook->jObj = S3JniRefGlobal(jLog);
if( midCallback ){
rc = sqlite3_config( SQLITE_CONFIG_SQLLOG, s3jni_config_sqllog, 0 );
if( rc ){
S3JniHook_unref(env, hook, 0);
}else{
S3JniHook_unref(env, hookOld, 0);
*hookOld = *hook;
if( 0==rc ){
S3JniHook_unref(env, pHook, 0);
pHook->midCallback = midCallback;
pHook->jObj = S3JniRefGlobal(jLog);
}
}else{
S3JniExceptionWarnIgnore;
rc = SQLITE_ERROR;
}
}
S3JniMutex_Global_leave;
return rc;
#endif
}
@ -3080,7 +3103,7 @@ static void s3jni_updatepre_hook_impl(void * pState, sqlite3 *pDb, int opId,
const int isPre = 0!=pDb;
S3JniHook hook;
S3JniHook_copy(env, isPre ?
S3JniHook_localdup(env, isPre ?
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
&ps->hooks.preUpdate
#else
@ -3274,7 +3297,7 @@ static int s3jni_progress_handler_impl(void *pP){
S3JniDeclLocal_env;
S3JniHook hook;
S3JniHook_copy( env, &ps->hooks.progress, &hook );
S3JniHook_localdup( env, &ps->hooks.progress, &hook );
if( hook.jObj ){
rc = (int)(*env)->CallIntMethod(env, hook.jObj, hook.midCallback);
S3JniIfThrew{
@ -3569,7 +3592,7 @@ int s3jni_xAuth(void* pState, int op,const char*z0, const char*z1,
S3JniHook hook;
int rc = 0;
S3JniHook_copy(env, &ps->hooks.auth, &hook );
S3JniHook_localdup(env, &ps->hooks.auth, &hook );
if( hook.jObj ){
jstring const s0 = z0 ? s3jni_utf8_to_jstring(env, z0, -1) : 0;
jstring const s1 = z1 ? s3jni_utf8_to_jstring(env, z1, -1) : 0;
@ -3759,7 +3782,7 @@ static int s3jni_trace_impl(unsigned traceflag, void *pC, void *pP, void *pX){
int rc = 0;
S3JniHook hook;
S3JniHook_copy( env, &ps->hooks.trace, &hook );
S3JniHook_localdup( env, &ps->hooks.trace, &hook );
if( !hook.jObj ){
return 0;
}
@ -3973,13 +3996,15 @@ JniDecl(void,1jni_1internal_1details)(JniArgsEnvClass){
SJG.metrics.envCacheMisses,
SJG.metrics.envCacheHits);
printf("Mutex entry:"
"\n\tglobal %u"
"\n\tenv %u"
"\n\tnph inits %u"
"\n\tperDb %u"
"\n\tautoExt %u list accesses"
"\n\tmetrics %u\n",
SJG.metrics.nMutexEnv, SJG.metrics.nMutexEnv2,
SJG.metrics.nMutexPerDb, SJG.metrics.nMutexAutoExt,
SJG.metrics.nMutexGlobal, SJG.metrics.nMutexEnv,
SJG.metrics.nMutexEnv2, SJG.metrics.nMutexPerDb,
SJG.metrics.nMutexAutoExt,
SJG.metrics.nMetrics);
printf("S3JniDb: %u alloced (*%u = %u bytes), %u recycled\n",
SJG.metrics.nPdbAlloc, (unsigned) sizeof(S3JniDb),
@ -4906,6 +4931,8 @@ Java_org_sqlite_jni_SQLite3Jni_init(JniArgsEnvClass){
S3JniUnrefLocal(klazz);
#endif
SJG.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
s3jni_oom_check( SJG.mutex );
SJG.envCache.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
s3jni_oom_check( SJG.envCache.mutex );
SJG.perDb.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);

View File

@ -494,6 +494,11 @@ public final class SQLite3Jni {
<p>Others may be added in the future. It returns SQLITE_MISUSE if
given an argument it does not handle.
<p>Note that sqlite3_config() is not threadsafe with regards to
the rest of the library. This must not be called when any other
library APIs are being called.
*/
public static native int sqlite3_config(int op);
@ -504,8 +509,13 @@ public final class SQLite3Jni {
logger. If installation of a logger fails, any previous logger is
retained.
If not built with SQLITE_ENABLE_SQLLOG defined, this returns
<p>If not built with SQLITE_ENABLE_SQLLOG defined, this returns
SQLITE_MISUSE.
<p>Note that sqlite3_config() is not threadsafe with regards to
the rest of the library. This must not be called when any other
library APIs are being called.
*/
public static native int sqlite3_config( @Nullable ConfigSqllogCallback logger );

View File

@ -1,5 +1,5 @@
C Remove\sthe\sJava\sBusyHandler.xDestroy()\smethod\s-\sit\sshould\snot\shave\shad\sone.\sEliminate\sthe\slast\sof\sthe\spotentially-significant\sMUTF-8\scases.
D 2023-08-26T10:51:19.217
C JNI\sinternal\scleanups\sand\sdocs.
D 2023-08-26T11:57:34.208
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -236,7 +236,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3
F ext/jni/GNUmakefile b28f8b304ef97db8250857cb463aea1b329bfcb584a2902d4c1a490a831e2c9d
F ext/jni/README.md 1332b1fa27918bd5d9ca2d0d4f3ac3a6ab86b9e3699dc5bfe32904a027f3d2a9
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
F ext/jni/src/c/sqlite3-jni.c 86a9f9182e8c0b1f058196ac4017f3290b948bcfbea1bc55198bdd0ad10a2ea1
F ext/jni/src/c/sqlite3-jni.c e914d5ec2d7a80a2735d777b4309c1bb0adc721be63abed0b9927a3880008f9b
F ext/jni/src/c/sqlite3-jni.h 2745c4abd0933a4e8cc48989fffbad3936b4eaada64cce9ce11453dcd30e4184
F ext/jni/src/org/sqlite/jni/AggregateFunction.java e0aac6ccae05702f8ee779820570866a2760aaa57a73135c57c8d3580bef52d5
F ext/jni/src/org/sqlite/jni/AuthorizerCallback.java c374bb76409cce7a0bdba94877706b59ac6127fa5d9e6af3e8058c99ce99c030
@ -262,7 +262,7 @@ F ext/jni/src/org/sqlite/jni/ResultCode.java ba701f20213a5f259e94cfbfdd36eb7ac7c
F ext/jni/src/org/sqlite/jni/RollbackHookCallback.java be7f7a26d1102fb514d835e11198d51302af8053d97188bfb2e34c2133208568
F ext/jni/src/org/sqlite/jni/SQLFunction.java d060f302b2cc4cf7a4f5a6b2d36458a2e6fc9648374b5d09c36a43665af41207
F ext/jni/src/org/sqlite/jni/SQLite3CallbackProxy.java 13c4ea6f35871261eba63fa4117715515e0beecbdebfb879ec5b1f340ed36904
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java cb3040fcfe35199bb10b4bca2cc541ca383563f85c9b460412c3bd15f413ae23
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 4be23360d93011d80676bebb1f21f7da0fc4ab637a6d138c8c35bbb2f764b19d
F ext/jni/src/org/sqlite/jni/ScalarFunction.java 21301a947e49f0dd9c682dfe2cc8a6518226c837253dd791cd512f847eeca52c
F ext/jni/src/org/sqlite/jni/Tester1.java 2921142fff8cd5a09d1cee30853457926dc63e647df9a687265bb4e678bc9570
F ext/jni/src/org/sqlite/jni/TesterFts5.java 6f135c60e24c89e8eecb9fe61dde0f3bb2906de668ca6c9186bcf34bdaf94629
@ -2103,8 +2103,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P f2af7bbf493fe28d92fc9c77425f8bb9d48c02af9a5eabceb0365c705651e114
R 0a5c5021d2a5ccca7e44db0ac1e86f8f
P c852f1ebbde273c3d28fe5aff0bf73cfc06b41dd371a94d7520536dc7a1dbcc1
R e2cc30a4c5c5fdac12de199e721e1eae
U stephan
Z 3f70be94b4b4f3d48d8c6e932937aea1
Z afcbdc6516d9f37dfcef349abedaeb15
# Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
c852f1ebbde273c3d28fe5aff0bf73cfc06b41dd371a94d7520536dc7a1dbcc1
b7b26bfb4f86e0b8aaabab258ccb0713737ffd4ecd3156d6a83a4f9a1d25edf6