Move most of the per-JNIEnv global Java class refs into the global state, saving a bit of per-thread overhead.
FossilOrigin-Name: 7342bf578790e1a87c128a7c1c7745fe2e7c442890370feb160d406597d4d8ec
This commit is contained in:
parent
484f9bed4e
commit
0a102087d8
@ -386,15 +386,16 @@ typedef struct S3JniDb S3JniDb;
|
|||||||
struct S3JniDb {
|
struct S3JniDb {
|
||||||
JNIEnv *env /* The associated JNIEnv handle */;
|
JNIEnv *env /* The associated JNIEnv handle */;
|
||||||
sqlite3 *pDb /* The associated db handle */;
|
sqlite3 *pDb /* The associated db handle */;
|
||||||
jobject jDb /* A global ref of the object which was passed to
|
jobject jDb /* A global ref of the output object which gets
|
||||||
sqlite3_open(_v2)(). We need this in order to have
|
returned from sqlite3_open(_v2)(). We need this in
|
||||||
an object to pass to sqlite3_collation_needed()'s
|
order to have an object to pass to routines like
|
||||||
callback, or else we have to dynamically create one
|
sqlite3_collation_needed()'s callback, or else we
|
||||||
for that purpose, which would be fine except that
|
have to dynamically create one for that purpose,
|
||||||
it would be a different instance (and maybe even a
|
which would be fine except that it would be a
|
||||||
different class) than the one the user may expect
|
different instance (and maybe even a different
|
||||||
to receive. */;
|
class) than the one the user may expect to
|
||||||
char * zMainDbName /* Holds any string allocated on behave of
|
receive. */;
|
||||||
|
char * zMainDbName /* Holds the string allocated on behalf of
|
||||||
SQLITE_DBCONFIG_MAINDBNAME. */;
|
SQLITE_DBCONFIG_MAINDBNAME. */;
|
||||||
S3JniHook busyHandler;
|
S3JniHook busyHandler;
|
||||||
S3JniHook collation;
|
S3JniHook collation;
|
||||||
@ -413,77 +414,48 @@ struct S3JniDb {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Cache for per-JNIEnv data.
|
** Cache for per-JNIEnv (i.e. per-thread) data.
|
||||||
**
|
|
||||||
** Potential TODO: move the jclass entries to global space because,
|
|
||||||
** per https://developer.android.com/training/articles/perf-jni:
|
|
||||||
**
|
|
||||||
** > once you have a valid jclass global reference you can use it from
|
|
||||||
** any attached thread.
|
|
||||||
**
|
|
||||||
** Whereas we cache new refs for each thread.
|
|
||||||
*/
|
*/
|
||||||
typedef struct S3JniEnv S3JniEnv;
|
typedef struct S3JniEnv S3JniEnv;
|
||||||
struct S3JniEnv {
|
struct S3JniEnv {
|
||||||
JNIEnv *env /* env in which this cache entry was created */;
|
JNIEnv *env /* env in which this cache entry was created */;
|
||||||
//! The various refs to global classes might be cacheable a single
|
|
||||||
// time globally. Information online seems inconsistent on that
|
|
||||||
// point.
|
|
||||||
struct {
|
|
||||||
jclass cObj /* global ref to java.lang.Object */;
|
|
||||||
jclass cLong /* global ref to java.lang.Long */;
|
|
||||||
jclass cString /* global ref to java.lang.String */;
|
|
||||||
jobject oCharsetUtf8 /* global ref to StandardCharset.UTF_8 */;
|
|
||||||
jmethodID ctorLong1 /* the Long(long) constructor */;
|
|
||||||
jmethodID ctorStringBA /* the String(byte[],Charset) constructor */;
|
|
||||||
jmethodID stringGetBytes /* the String.getBytes(Charset) method */;
|
|
||||||
} g /* refs to global Java state */;
|
|
||||||
/*
|
/*
|
||||||
** pdbOpening is used to coordinate the Java/DB connection of a
|
** pdbOpening is used to coordinate the Java/DB connection of a
|
||||||
** being-open()'d db in the face of auto-extensions. "The problem"
|
** being-open()'d db in the face of auto-extensions. "The problem"
|
||||||
** is that auto-extensions run before we can bind the C db to its
|
** is that auto-extensions run before we can bind the C db to its
|
||||||
** Java representation, but auto-extensions require that binding. We
|
** Java representation, but auto-extensions require that binding. We
|
||||||
** handle this as follows:
|
** handle this as follows:
|
||||||
**
|
**
|
||||||
** - In the JNI side of sqlite3_open(), allocate the Java side of
|
** - In the JNI side of sqlite3_open(), allocate the Java side of
|
||||||
** that connection and set pdbOpening to point to that
|
** that connection and set pdbOpening to point to that
|
||||||
** object. Note that it's per-thread, and we remain in that
|
** object. Note that it's per-thread, and we remain in that
|
||||||
** thread until after the auto-extensions are run.
|
** thread until after the auto-extensions are run, so we don't
|
||||||
**
|
** need to mutex-lock this.
|
||||||
** - Call sqlite3_open(), which triggers the auto-extension
|
**
|
||||||
** handler. That handler uses pdbOpening to connect the native
|
** - Call sqlite3_open(), which triggers the auto-extension
|
||||||
** db handle which it receives with pdbOpening.
|
** handler. That handler uses pdbOpening to connect the native
|
||||||
**
|
** db handle which it receives with pdbOpening.
|
||||||
** - When sqlite3_open() returns, check whether pdbOpening->pDb is
|
**
|
||||||
** NULL. If it isn't, auto-extension handling set it up. If it
|
** - When sqlite3_open() returns, check whether pdbOpening->pDb is
|
||||||
** is, complete the Java/C binding unless sqlite3_open() returns
|
** NULL. If it isn't, auto-extension handling set it up. If it
|
||||||
** a NULL db, in which case free pdbOpening.
|
** is, complete the Java/C binding unless sqlite3_open() returns
|
||||||
|
** a NULL db, in which case free pdbOpening.
|
||||||
*/
|
*/
|
||||||
S3JniDb * pdbOpening;
|
S3JniDb * pdbOpening;
|
||||||
#ifdef SQLITE_ENABLE_FTS5
|
|
||||||
jobject jFtsExt /* Global ref to Java singleton for the
|
|
||||||
Fts5ExtensionApi instance. */;
|
|
||||||
struct {
|
|
||||||
jclass klazz /* Global ref to the Fts5Phrase iter class */;
|
|
||||||
jfieldID fidA /* Fts5Phrase::a member */;
|
|
||||||
jfieldID fidB /* Fts5Phrase::b member */;
|
|
||||||
} jPhraseIter;
|
|
||||||
#endif
|
|
||||||
S3JniEnv * pPrev /* Previous entry in the linked list */;
|
S3JniEnv * pPrev /* Previous entry in the linked list */;
|
||||||
S3JniEnv * pNext /* Next entry in the linked list */;
|
S3JniEnv * pNext /* Next entry in the linked list */;
|
||||||
/*
|
/*
|
||||||
** Cache of Java refs/IDs for NativePointerHolder subclasses.
|
** Cache of Java refs/IDs for NativePointerHolder subclasses. We
|
||||||
|
** "could" move this into S3JniGLobal but doing so would require
|
||||||
|
** adding a mutex for this state in several places. It might be a
|
||||||
|
** win, though, as it would eliminate many locks of of the
|
||||||
|
** S3JniGlobal.envCache.mutex.
|
||||||
*/
|
*/
|
||||||
S3JniNphClass nph[NphCache_SIZE];
|
S3JniNphClass nph[NphCache_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Whether auto extensions are feasible here is currently unknown due
|
** State for proxying sqlite3_auto_extension() in Java.
|
||||||
** to...
|
|
||||||
**
|
|
||||||
** JNIEnv/threading issues. A db instance is mapped to a specific
|
|
||||||
** JNIEnv object but auto extensions may be added from any thread. In
|
|
||||||
** such contexts, which JNIEnv do we use for the JNI APIs?
|
|
||||||
*/
|
*/
|
||||||
typedef struct S3JniAutoExtension S3JniAutoExtension;
|
typedef struct S3JniAutoExtension S3JniAutoExtension;
|
||||||
struct S3JniAutoExtension {
|
struct S3JniAutoExtension {
|
||||||
@ -494,7 +466,8 @@ struct S3JniAutoExtension {
|
|||||||
/*
|
/*
|
||||||
** Global state, e.g. caches and metrics.
|
** Global state, e.g. caches and metrics.
|
||||||
*/
|
*/
|
||||||
static struct {
|
typedef struct S3JniGlobalType S3JniGlobalType;
|
||||||
|
struct S3JniGlobalType {
|
||||||
/*
|
/*
|
||||||
** According to: https://developer.ibm.com/articles/j-jni/
|
** According to: https://developer.ibm.com/articles/j-jni/
|
||||||
**
|
**
|
||||||
@ -523,6 +496,30 @@ static struct {
|
|||||||
always have this set to the current JNIEnv
|
always have this set to the current JNIEnv
|
||||||
object. Used only for sanity checking. */;
|
object. Used only for sanity checking. */;
|
||||||
} perDb;
|
} perDb;
|
||||||
|
/*
|
||||||
|
** Refs to global classes and methods. Obtained during static init
|
||||||
|
** and never released.
|
||||||
|
*/
|
||||||
|
struct {
|
||||||
|
jclass cObj /* global ref to java.lang.Object */;
|
||||||
|
jclass cLong /* global ref to java.lang.Long */;
|
||||||
|
jclass cString /* global ref to java.lang.String */;
|
||||||
|
jobject oCharsetUtf8 /* global ref to StandardCharset.UTF_8 */;
|
||||||
|
jmethodID ctorLong1 /* the Long(long) constructor */;
|
||||||
|
jmethodID ctorStringBA /* the String(byte[],Charset) constructor */;
|
||||||
|
jmethodID stringGetBytes /* the String.getBytes(Charset) method */;
|
||||||
|
} g /* refs to global Java state */;
|
||||||
|
#ifdef SQLITE_ENABLE_FTS5
|
||||||
|
struct {
|
||||||
|
volatile jobject jFtsExt /* Global ref to Java singleton for the
|
||||||
|
Fts5ExtensionApi instance. */;
|
||||||
|
struct {
|
||||||
|
volatile jclass klazz /* Global ref to the Fts5Phrase iter class */;
|
||||||
|
jfieldID fidA /* Fts5Phrase::a member */;
|
||||||
|
jfieldID fidB /* Fts5Phrase::b member */;
|
||||||
|
} jPhraseIter;
|
||||||
|
} fts5;
|
||||||
|
#endif
|
||||||
/* Internal metrics. */
|
/* Internal metrics. */
|
||||||
struct {
|
struct {
|
||||||
volatile unsigned envCacheHits;
|
volatile unsigned envCacheHits;
|
||||||
@ -552,41 +549,43 @@ static struct {
|
|||||||
int nExt /* number of active entries in pExt. */;
|
int nExt /* number of active entries in pExt. */;
|
||||||
sqlite3_mutex * mutex /* mutex for manipulation/traversal of pExt */;
|
sqlite3_mutex * mutex /* mutex for manipulation/traversal of pExt */;
|
||||||
} autoExt;
|
} autoExt;
|
||||||
} S3JniGlobal;
|
};
|
||||||
|
static S3JniGlobalType S3JniGlobal = {};
|
||||||
|
#define SJG S3JniGlobal
|
||||||
|
|
||||||
#define MUTEX_ASSERT_LOCKER_ENV \
|
#define MUTEX_ASSERT_LOCKER_ENV \
|
||||||
assert( (env) == S3JniGlobal.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
|
assert( (env) == SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
|
||||||
#define MUTEX_ASSERT_NOTLOCKER_ENV \
|
#define MUTEX_ASSERT_NOTLOCKER_ENV \
|
||||||
assert( (env) != S3JniGlobal.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
|
assert( (env) != SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
|
||||||
#define MUTEX_ENV_ENTER \
|
#define MUTEX_ENV_ENTER \
|
||||||
MUTEX_ASSERT_NOTLOCKER_ENV; \
|
MUTEX_ASSERT_NOTLOCKER_ENV; \
|
||||||
sqlite3_mutex_enter( S3JniGlobal.envCache.mutex ); \
|
/*MARKER(("Entering ENV mutex@%p %s.\n", env, __func__));*/ \
|
||||||
/*MARKER(("Entered ENV mutex@%p %s.\n", env, __func__));*/ \
|
sqlite3_mutex_enter( SJG.envCache.mutex ); \
|
||||||
++S3JniGlobal.metrics.nMutexEnv; \
|
++SJG.metrics.nMutexEnv; \
|
||||||
S3JniGlobal.envCache.locker = env
|
SJG.envCache.locker = env
|
||||||
#define MUTEX_ENV_LEAVE \
|
#define MUTEX_ENV_LEAVE \
|
||||||
/*MARKER(("Leaving ENV mutex @%p %s.\n", env, __func__));*/ \
|
/*MARKER(("Leaving ENV mutex @%p %s.\n", env, __func__));*/ \
|
||||||
MUTEX_ASSERT_LOCKER_ENV; \
|
MUTEX_ASSERT_LOCKER_ENV; \
|
||||||
S3JniGlobal.envCache.locker = 0; \
|
SJG.envCache.locker = 0; \
|
||||||
sqlite3_mutex_leave( S3JniGlobal.envCache.mutex )
|
sqlite3_mutex_leave( SJG.envCache.mutex )
|
||||||
#define MUTEX_ASSERT_LOCKED_PDB \
|
#define MUTEX_ASSERT_LOCKED_PDB \
|
||||||
assert( 0 != S3JniGlobal.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" )
|
assert( 0 != SJG.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" )
|
||||||
#define MUTEX_PDB_ENTER \
|
#define MUTEX_PDB_ENTER \
|
||||||
/*MARKER(("Entering PerDb mutex@%p %s.\n", env, __func__));*/ \
|
/*MARKER(("Entering PerDb mutex@%p %s.\n", env, __func__));*/ \
|
||||||
sqlite3_mutex_enter( S3JniGlobal.perDb.mutex ); \
|
sqlite3_mutex_enter( SJG.perDb.mutex ); \
|
||||||
++S3JniGlobal.metrics.nMutexPerDb; \
|
++SJG.metrics.nMutexPerDb; \
|
||||||
S3JniGlobal.perDb.locker = env;
|
SJG.perDb.locker = env;
|
||||||
#define MUTEX_PDB_LEAVE \
|
#define MUTEX_PDB_LEAVE \
|
||||||
/*MARKER(("Leaving PerDb mutex@%p %s.\n", env, __func__));*/ \
|
/*MARKER(("Leaving PerDb mutex@%p %s.\n", env, __func__));*/ \
|
||||||
S3JniGlobal.perDb.locker = 0; \
|
SJG.perDb.locker = 0; \
|
||||||
sqlite3_mutex_leave( S3JniGlobal.perDb.mutex )
|
sqlite3_mutex_leave( SJG.perDb.mutex )
|
||||||
#define MUTEX_EXT_ENTER \
|
#define MUTEX_EXT_ENTER \
|
||||||
/*MARKER(("Entering autoExt mutex@%p %s.\n", env, __func__));*/ \
|
/*MARKER(("Entering autoExt mutex@%p %s.\n", env, __func__));*/ \
|
||||||
sqlite3_mutex_enter( S3JniGlobal.autoExt.mutex ); \
|
sqlite3_mutex_enter( SJG.autoExt.mutex ); \
|
||||||
++S3JniGlobal.metrics.nMutexAutoExt
|
++SJG.metrics.nMutexAutoExt
|
||||||
#define MUTEX_EXT_LEAVE \
|
#define MUTEX_EXT_LEAVE \
|
||||||
/*MARKER(("Leaving autoExt mutex@%p %s.\n", env, __func__));*/ \
|
/*MARKER(("Leaving autoExt mutex@%p %s.\n", env, __func__));*/ \
|
||||||
sqlite3_mutex_leave( S3JniGlobal.autoExt.mutex )
|
sqlite3_mutex_leave( SJG.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){
|
||||||
@ -614,64 +613,29 @@ static void * s3jni_malloc(JNIEnv * const env, size_t n){
|
|||||||
static S3JniEnv * S3JniGlobal_env_cache(JNIEnv * const env){
|
static S3JniEnv * S3JniGlobal_env_cache(JNIEnv * const env){
|
||||||
struct S3JniEnv * row;
|
struct S3JniEnv * row;
|
||||||
MUTEX_ENV_ENTER;
|
MUTEX_ENV_ENTER;
|
||||||
row = S3JniGlobal.envCache.aHead;
|
row = SJG.envCache.aHead;
|
||||||
for( ; row; row = row->pNext ){
|
for( ; row; row = row->pNext ){
|
||||||
if( row->env == env ){
|
if( row->env == env ){
|
||||||
++S3JniGlobal.metrics.envCacheHits;
|
++SJG.metrics.envCacheHits;
|
||||||
MUTEX_ENV_LEAVE;
|
MUTEX_ENV_LEAVE;
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++S3JniGlobal.metrics.envCacheMisses;
|
++SJG.metrics.envCacheMisses;
|
||||||
row = S3JniGlobal.envCache.aFree;
|
row = SJG.envCache.aFree;
|
||||||
if( row ){
|
if( row ){
|
||||||
assert(!row->pPrev);
|
assert(!row->pPrev);
|
||||||
S3JniGlobal.envCache.aFree = row->pNext;
|
SJG.envCache.aFree = row->pNext;
|
||||||
if( row->pNext ) row->pNext->pPrev = 0;
|
if( row->pNext ) row->pNext->pPrev = 0;
|
||||||
}else{
|
}else{
|
||||||
row = s3jni_malloc(env, sizeof(S3JniEnv));
|
row = s3jni_malloc(env, sizeof(S3JniEnv));
|
||||||
}
|
}
|
||||||
memset(row, 0, sizeof(*row));
|
memset(row, 0, sizeof(*row));
|
||||||
row->pNext = S3JniGlobal.envCache.aHead;
|
row->pNext = SJG.envCache.aHead;
|
||||||
if(row->pNext) row->pNext->pPrev = row;
|
if(row->pNext) row->pNext->pPrev = row;
|
||||||
S3JniGlobal.envCache.aHead = row;
|
SJG.envCache.aHead = row;
|
||||||
row->env = env;
|
row->env = env;
|
||||||
|
|
||||||
//MARKER(("Initalizing cache for JNIEnv@%p\n", env));
|
|
||||||
|
|
||||||
/* Grab references to various global classes and objects... */
|
|
||||||
row->g.cObj = REF_G((*env)->FindClass(env,"java/lang/Object"));
|
|
||||||
EXCEPTION_IS_FATAL("Error getting reference to Object class.");
|
|
||||||
|
|
||||||
row->g.cLong = REF_G((*env)->FindClass(env,"java/lang/Long"));
|
|
||||||
EXCEPTION_IS_FATAL("Error getting reference to Long class.");
|
|
||||||
row->g.ctorLong1 = (*env)->GetMethodID(env, row->g.cLong,
|
|
||||||
"<init>", "(J)V");
|
|
||||||
EXCEPTION_IS_FATAL("Error getting reference to Long constructor.");
|
|
||||||
|
|
||||||
row->g.cString = REF_G((*env)->FindClass(env,"java/lang/String"));
|
|
||||||
EXCEPTION_IS_FATAL("Error getting reference to String class.");
|
|
||||||
row->g.ctorStringBA =
|
|
||||||
(*env)->GetMethodID(env, row->g.cString,
|
|
||||||
"<init>", "([BLjava/nio/charset/Charset;)V");
|
|
||||||
EXCEPTION_IS_FATAL("Error getting reference to String(byte[],Charset) ctor.");
|
|
||||||
row->g.stringGetBytes =
|
|
||||||
(*env)->GetMethodID(env, row->g.cString,
|
|
||||||
"getBytes", "(Ljava/nio/charset/Charset;)[B");
|
|
||||||
EXCEPTION_IS_FATAL("Error getting reference to String.getBytes(Charset).");
|
|
||||||
|
|
||||||
{ /* StandardCharsets.UTF_8 */
|
|
||||||
jfieldID fUtf8;
|
|
||||||
jclass const klazzSC =
|
|
||||||
(*env)->FindClass(env,"java/nio/charset/StandardCharsets");
|
|
||||||
EXCEPTION_IS_FATAL("Error getting reference to StndardCharsets class.");
|
|
||||||
fUtf8 = (*env)->GetStaticFieldID(env, klazzSC, "UTF_8",
|
|
||||||
"Ljava/nio/charset/Charset;");
|
|
||||||
EXCEPTION_IS_FATAL("Error getting StandardCharsets.UTF_8 field.");
|
|
||||||
row->g.oCharsetUtf8 =
|
|
||||||
REF_G((*env)->GetStaticObjectField(env, klazzSC, fUtf8));
|
|
||||||
EXCEPTION_IS_FATAL("Error getting reference to StandardCharsets.UTF_8.");
|
|
||||||
}
|
|
||||||
MUTEX_ENV_LEAVE;
|
MUTEX_ENV_LEAVE;
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
@ -740,8 +704,8 @@ static jstring s3jni_utf8_to_jstring(S3JniEnv * const jc,
|
|||||||
if( n<0 ) n = sqlite3Strlen30(z);
|
if( n<0 ) n = sqlite3Strlen30(z);
|
||||||
jba = s3jni_new_jbyteArray(env, (unsigned const char *)z, (jsize)n);
|
jba = s3jni_new_jbyteArray(env, (unsigned const char *)z, (jsize)n);
|
||||||
if( jba ){
|
if( jba ){
|
||||||
rv = (*env)->NewObject(env, jc->g.cString, jc->g.ctorStringBA,
|
rv = (*env)->NewObject(env, SJG.g.cString, SJG.g.ctorStringBA,
|
||||||
jba, jc->g.oCharsetUtf8);
|
jba, SJG.g.oCharsetUtf8);
|
||||||
UNREF_L(jba);
|
UNREF_L(jba);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -771,8 +735,8 @@ static char * s3jni_jstring_to_utf8(S3JniEnv * const jc,
|
|||||||
char *rv;
|
char *rv;
|
||||||
|
|
||||||
if(!jstr) return 0;
|
if(!jstr) return 0;
|
||||||
jba = (*env)->CallObjectMethod(env, jstr, jc->g.stringGetBytes,
|
jba = (*env)->CallObjectMethod(env, jstr, SJG.g.stringGetBytes,
|
||||||
jc->g.oCharsetUtf8);
|
SJG.g.oCharsetUtf8);
|
||||||
if( (*env)->ExceptionCheck(env) || !jba
|
if( (*env)->ExceptionCheck(env) || !jba
|
||||||
/* order of these checks is significant for -Xlint:jni */ ) {
|
/* order of these checks is significant for -Xlint:jni */ ) {
|
||||||
EXCEPTION_REPORT;
|
EXCEPTION_REPORT;
|
||||||
@ -885,7 +849,7 @@ static void s3jni_call_xDestroy(JNIEnv * const env, jobject jObj, jclass klazz){
|
|||||||
method = (*env)->GetMethodID(env, klazz, "xDestroy", "()V");
|
method = (*env)->GetMethodID(env, klazz, "xDestroy", "()V");
|
||||||
//MARKER(("jObj=%p, klazz=%p, method=%p\n", jObj, klazz, method));
|
//MARKER(("jObj=%p, klazz=%p, method=%p\n", jObj, klazz, method));
|
||||||
if(method){
|
if(method){
|
||||||
++S3JniGlobal.metrics.nDestroy;
|
++SJG.metrics.nDestroy;
|
||||||
(*env)->CallVoidMethod(env, jObj, method);
|
(*env)->CallVoidMethod(env, jObj, method);
|
||||||
IFTHREW{
|
IFTHREW{
|
||||||
EXCEPTION_WARN_CALLBACK_THREW("xDestroy() callback");
|
EXCEPTION_WARN_CALLBACK_THREW("xDestroy() callback");
|
||||||
@ -926,9 +890,9 @@ static void S3JniDb_set_aside(S3JniDb * const s){
|
|||||||
assert(s->pPrev ? (s->pPrev!=s->pNext) : 1);
|
assert(s->pPrev ? (s->pPrev!=s->pNext) : 1);
|
||||||
if(s->pNext) s->pNext->pPrev = s->pPrev;
|
if(s->pNext) s->pNext->pPrev = s->pPrev;
|
||||||
if(s->pPrev) s->pPrev->pNext = s->pNext;
|
if(s->pPrev) s->pPrev->pNext = s->pNext;
|
||||||
else if(S3JniGlobal.perDb.aUsed == s){
|
else if(SJG.perDb.aUsed == s){
|
||||||
assert(!s->pPrev);
|
assert(!s->pPrev);
|
||||||
S3JniGlobal.perDb.aUsed = s->pNext;
|
SJG.perDb.aUsed = s->pNext;
|
||||||
}
|
}
|
||||||
sqlite3_free( s->zMainDbName );
|
sqlite3_free( s->zMainDbName );
|
||||||
#define UNHOOK(MEMBER,XDESTROY) S3JniHook_unref(env, &s->MEMBER, XDESTROY)
|
#define UNHOOK(MEMBER,XDESTROY) S3JniHook_unref(env, &s->MEMBER, XDESTROY)
|
||||||
@ -943,13 +907,10 @@ static void S3JniDb_set_aside(S3JniDb * const s){
|
|||||||
UNHOOK(busyHandler, 1);
|
UNHOOK(busyHandler, 1);
|
||||||
#undef UNHOOK
|
#undef UNHOOK
|
||||||
UNREF_G(s->jDb);
|
UNREF_G(s->jDb);
|
||||||
#ifdef SQLITE_ENABLE_FTS5
|
|
||||||
UNREF_G(s->jFtsApi);
|
|
||||||
#endif
|
|
||||||
memset(s, 0, sizeof(S3JniDb));
|
memset(s, 0, sizeof(S3JniDb));
|
||||||
s->pNext = S3JniGlobal.perDb.aFree;
|
s->pNext = SJG.perDb.aFree;
|
||||||
if(s->pNext) s->pNext->pPrev = s;
|
if(s->pNext) s->pNext->pPrev = s;
|
||||||
S3JniGlobal.perDb.aFree = s;
|
SJG.perDb.aFree = s;
|
||||||
//MARKER(("%p->pPrev@%p, pNext@%p\n", s, s->pPrev, s->pNext));
|
//MARKER(("%p->pPrev@%p, pNext@%p\n", s, s->pPrev, s->pNext));
|
||||||
//if(s->pNext) MARKER(("next: %p->pPrev@%p\n", s->pNext, s->pNext->pPrev));
|
//if(s->pNext) MARKER(("next: %p->pPrev@%p\n", s->pNext, s->pNext->pPrev));
|
||||||
}
|
}
|
||||||
@ -963,7 +924,7 @@ static void S3JniDb_free_for_env(JNIEnv *env){
|
|||||||
S3JniDb * ps;
|
S3JniDb * ps;
|
||||||
S3JniDb * pNext = 0;
|
S3JniDb * pNext = 0;
|
||||||
MUTEX_PDB_ENTER;
|
MUTEX_PDB_ENTER;
|
||||||
ps = S3JniGlobal.perDb.aUsed;
|
ps = SJG.perDb.aUsed;
|
||||||
for( ; ps; ps = pNext ){
|
for( ; ps; ps = pNext ){
|
||||||
pNext = ps->pNext;
|
pNext = ps->pNext;
|
||||||
if(ps->env == env){
|
if(ps->env == env){
|
||||||
@ -972,7 +933,7 @@ static void S3JniDb_free_for_env(JNIEnv *env){
|
|||||||
#endif
|
#endif
|
||||||
S3JniDb_set_aside(ps);
|
S3JniDb_set_aside(ps);
|
||||||
assert( pPrev ? pPrev->pNext==pNext : 1 );
|
assert( pPrev ? pPrev->pNext==pNext : 1 );
|
||||||
assert( ps == S3JniGlobal.perDb.aFree );
|
assert( ps == SJG.perDb.aFree );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MUTEX_PDB_LEAVE;
|
MUTEX_PDB_LEAVE;
|
||||||
@ -990,7 +951,7 @@ static int S3JniGlobal_env_uncache(JNIEnv * const env){
|
|||||||
struct S3JniEnv * row;
|
struct S3JniEnv * row;
|
||||||
int i;
|
int i;
|
||||||
MUTEX_ASSERT_LOCKER_ENV;
|
MUTEX_ASSERT_LOCKER_ENV;
|
||||||
row = S3JniGlobal.envCache.aHead;
|
row = SJG.envCache.aHead;
|
||||||
for( ; row; row = row->pNext ){
|
for( ; row; row = row->pNext ){
|
||||||
if( row->env == env ){
|
if( row->env == env ){
|
||||||
break;
|
break;
|
||||||
@ -1002,26 +963,18 @@ static int S3JniGlobal_env_uncache(JNIEnv * const env){
|
|||||||
//MARKER(("Uncaching JNIEnv@%p\n", env));
|
//MARKER(("Uncaching JNIEnv@%p\n", env));
|
||||||
if( row->pNext ) row->pNext->pPrev = row->pPrev;
|
if( row->pNext ) row->pNext->pPrev = row->pPrev;
|
||||||
if( row->pPrev ) row->pPrev->pNext = row->pNext;
|
if( row->pPrev ) row->pPrev->pNext = row->pNext;
|
||||||
if( S3JniGlobal.envCache.aHead == row ){
|
if( SJG.envCache.aHead == row ){
|
||||||
assert( !row->pPrev );
|
assert( !row->pPrev );
|
||||||
S3JniGlobal.envCache.aHead = row->pNext;
|
SJG.envCache.aHead = row->pNext;
|
||||||
}
|
}
|
||||||
S3JniDb_free_for_env(env);
|
S3JniDb_free_for_env(env);
|
||||||
UNREF_G(row->g.cObj);
|
|
||||||
UNREF_G(row->g.cLong);
|
|
||||||
UNREF_G(row->g.cString);
|
|
||||||
UNREF_G(row->g.oCharsetUtf8);
|
|
||||||
#ifdef SQLITE_ENABLE_FTS5
|
|
||||||
UNREF_G(row->jFtsExt);
|
|
||||||
UNREF_G(row->jPhraseIter.klazz);
|
|
||||||
#endif
|
|
||||||
for( i = 0; i < NphCache_SIZE; ++i ){
|
for( i = 0; i < NphCache_SIZE; ++i ){
|
||||||
S3JniNphClass_clear(env, &row->nph[i]);
|
S3JniNphClass_clear(env, &row->nph[i]);
|
||||||
}
|
}
|
||||||
memset(row, 0, sizeof(S3JniEnv));
|
memset(row, 0, sizeof(S3JniEnv));
|
||||||
row->pNext = S3JniGlobal.envCache.aFree;
|
row->pNext = SJG.envCache.aFree;
|
||||||
if( row->pNext ) row->pNext->pPrev = row;
|
if( row->pNext ) row->pNext->pPrev = row;
|
||||||
S3JniGlobal.envCache.aFree = row;
|
SJG.envCache.aFree = row;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1136,11 +1089,11 @@ static S3JniDb * S3JniDb_alloc(JNIEnv * const env, sqlite3 *pDb,
|
|||||||
jobject jDb){
|
jobject jDb){
|
||||||
S3JniDb * rv;
|
S3JniDb * rv;
|
||||||
MUTEX_PDB_ENTER;
|
MUTEX_PDB_ENTER;
|
||||||
if(S3JniGlobal.perDb.aFree){
|
if(SJG.perDb.aFree){
|
||||||
rv = S3JniGlobal.perDb.aFree;
|
rv = SJG.perDb.aFree;
|
||||||
//MARKER(("state@%p for db allocating for db@%p from free-list\n", rv, pDb));
|
//MARKER(("state@%p for db allocating for db@%p from free-list\n", rv, pDb));
|
||||||
//MARKER(("%p->pPrev@%p, pNext@%p\n", rv, rv->pPrev, rv->pNext));
|
//MARKER(("%p->pPrev@%p, pNext@%p\n", rv, rv->pPrev, rv->pNext));
|
||||||
S3JniGlobal.perDb.aFree = rv->pNext;
|
SJG.perDb.aFree = rv->pNext;
|
||||||
assert(rv->pNext != rv);
|
assert(rv->pNext != rv);
|
||||||
assert(rv->pPrev != rv);
|
assert(rv->pPrev != rv);
|
||||||
assert(rv->pPrev ? (rv->pPrev!=rv->pNext) : 1);
|
assert(rv->pPrev ? (rv->pPrev!=rv->pNext) : 1);
|
||||||
@ -1158,8 +1111,8 @@ static S3JniDb * S3JniDb_alloc(JNIEnv * const env, sqlite3 *pDb,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(rv){
|
if(rv){
|
||||||
rv->pNext = S3JniGlobal.perDb.aUsed;
|
rv->pNext = SJG.perDb.aUsed;
|
||||||
S3JniGlobal.perDb.aUsed = rv;
|
SJG.perDb.aUsed = rv;
|
||||||
if(rv->pNext){
|
if(rv->pNext){
|
||||||
assert(!rv->pNext->pPrev);
|
assert(!rv->pNext->pPrev);
|
||||||
rv->pNext->pPrev = rv;
|
rv->pNext->pPrev = rv;
|
||||||
@ -1200,7 +1153,7 @@ static S3JniDb * S3JniDb_for_db(JNIEnv * const env, jobject jDb, sqlite3 *pDb){
|
|||||||
S3JniDb * s = 0;
|
S3JniDb * s = 0;
|
||||||
if(jDb || pDb){
|
if(jDb || pDb){
|
||||||
MUTEX_PDB_ENTER;
|
MUTEX_PDB_ENTER;
|
||||||
s = S3JniGlobal.perDb.aUsed;
|
s = SJG.perDb.aUsed;
|
||||||
if(!pDb){
|
if(!pDb){
|
||||||
assert( jDb );
|
assert( jDb );
|
||||||
pDb = PtrGet_sqlite3(jDb);
|
pDb = PtrGet_sqlite3(jDb);
|
||||||
@ -1556,6 +1509,7 @@ static jobject new_NativePointerHolder_object(JNIEnv * const env, S3NphRef const
|
|||||||
assert(ctor);
|
assert(ctor);
|
||||||
rv = (*env)->NewObject(env, klazz, ctor);
|
rv = (*env)->NewObject(env, klazz, ctor);
|
||||||
EXCEPTION_IS_FATAL("No-arg constructor threw.");
|
EXCEPTION_IS_FATAL("No-arg constructor threw.");
|
||||||
|
OOM_CHECK(rv);
|
||||||
if(rv) NativePointerHolder_set(env, rv, pNative, pRef);
|
if(rv) NativePointerHolder_set(env, rv, pNative, pRef);
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -1680,7 +1634,7 @@ static int udf_args(JNIEnv *env,
|
|||||||
*jArgv = 0;
|
*jArgv = 0;
|
||||||
if(!jcx) goto error_oom;
|
if(!jcx) goto error_oom;
|
||||||
ja = (*env)->NewObjectArray(env, argc,
|
ja = (*env)->NewObjectArray(env, argc,
|
||||||
S3JniGlobal_env_cache(env)->g.cObj,
|
SJG.g.cObj,
|
||||||
NULL);
|
NULL);
|
||||||
if(!ja) goto error_oom;
|
if(!ja) goto error_oom;
|
||||||
for(i = 0; i < argc; ++i){
|
for(i = 0; i < argc; ++i){
|
||||||
@ -1779,29 +1733,29 @@ static int udf_xFV(sqlite3_context* cx, S3JniUdf * s,
|
|||||||
static void udf_xFunc(sqlite3_context* cx, int argc,
|
static void udf_xFunc(sqlite3_context* cx, int argc,
|
||||||
sqlite3_value** argv){
|
sqlite3_value** argv){
|
||||||
S3JniUdf * const s = (S3JniUdf*)sqlite3_user_data(cx);
|
S3JniUdf * const s = (S3JniUdf*)sqlite3_user_data(cx);
|
||||||
++S3JniGlobal.metrics.udf.nFunc;
|
++SJG.metrics.udf.nFunc;
|
||||||
udf_xFSI(cx, argc, argv, s, s->jmidxFunc, "xFunc");
|
udf_xFSI(cx, argc, argv, s, s->jmidxFunc, "xFunc");
|
||||||
}
|
}
|
||||||
static void udf_xStep(sqlite3_context* cx, int argc,
|
static void udf_xStep(sqlite3_context* cx, int argc,
|
||||||
sqlite3_value** argv){
|
sqlite3_value** argv){
|
||||||
S3JniUdf * const s = (S3JniUdf*)sqlite3_user_data(cx);
|
S3JniUdf * const s = (S3JniUdf*)sqlite3_user_data(cx);
|
||||||
++S3JniGlobal.metrics.udf.nStep;
|
++SJG.metrics.udf.nStep;
|
||||||
udf_xFSI(cx, argc, argv, s, s->jmidxStep, "xStep");
|
udf_xFSI(cx, argc, argv, s, s->jmidxStep, "xStep");
|
||||||
}
|
}
|
||||||
static void udf_xFinal(sqlite3_context* cx){
|
static void udf_xFinal(sqlite3_context* cx){
|
||||||
S3JniUdf * const s = (S3JniUdf*)sqlite3_user_data(cx);
|
S3JniUdf * const s = (S3JniUdf*)sqlite3_user_data(cx);
|
||||||
++S3JniGlobal.metrics.udf.nFinal;
|
++SJG.metrics.udf.nFinal;
|
||||||
udf_xFV(cx, s, s->jmidxFinal, "xFinal");
|
udf_xFV(cx, s, s->jmidxFinal, "xFinal");
|
||||||
}
|
}
|
||||||
static void udf_xValue(sqlite3_context* cx){
|
static void udf_xValue(sqlite3_context* cx){
|
||||||
S3JniUdf * const s = (S3JniUdf*)sqlite3_user_data(cx);
|
S3JniUdf * const s = (S3JniUdf*)sqlite3_user_data(cx);
|
||||||
++S3JniGlobal.metrics.udf.nValue;
|
++SJG.metrics.udf.nValue;
|
||||||
udf_xFV(cx, s, s->jmidxValue, "xValue");
|
udf_xFV(cx, s, s->jmidxValue, "xValue");
|
||||||
}
|
}
|
||||||
static void udf_xInverse(sqlite3_context* cx, int argc,
|
static void udf_xInverse(sqlite3_context* cx, int argc,
|
||||||
sqlite3_value** argv){
|
sqlite3_value** argv){
|
||||||
S3JniUdf * const s = (S3JniUdf*)sqlite3_user_data(cx);
|
S3JniUdf * const s = (S3JniUdf*)sqlite3_user_data(cx);
|
||||||
++S3JniGlobal.metrics.udf.nInverse;
|
++SJG.metrics.udf.nInverse;
|
||||||
udf_xFSI(cx, argc, argv, s, s->jmidxInverse, "xInverse");
|
udf_xFSI(cx, argc, argv, s, s->jmidxInverse, "xInverse");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1845,7 +1799,7 @@ WRAP_INT_SVALUE(1value_1type, sqlite3_value_type)
|
|||||||
|
|
||||||
static JNIEnv * s3jni_get_env(void){
|
static JNIEnv * s3jni_get_env(void){
|
||||||
JNIEnv * env = 0;
|
JNIEnv * env = 0;
|
||||||
if( (*S3JniGlobal.jvm)->GetEnv(S3JniGlobal.jvm, (void **)&env,
|
if( (*SJG.jvm)->GetEnv(SJG.jvm, (void **)&env,
|
||||||
JNI_VERSION_1_8) ){
|
JNI_VERSION_1_8) ){
|
||||||
fprintf(stderr, "Fatal error: cannot get current JNIEnv.\n");
|
fprintf(stderr, "Fatal error: cannot get current JNIEnv.\n");
|
||||||
abort();
|
abort();
|
||||||
@ -1861,7 +1815,7 @@ static int s3jni_run_java_auto_extensions(sqlite3 *pDb, const char **pzErr,
|
|||||||
JNIEnv * env = 0;
|
JNIEnv * env = 0;
|
||||||
S3JniDb * ps;
|
S3JniDb * ps;
|
||||||
S3JniEnv * jc;
|
S3JniEnv * jc;
|
||||||
if( 0==S3JniGlobal.autoExt.nExt ) return 0;
|
if( 0==SJG.autoExt.nExt ) return 0;
|
||||||
env = s3jni_get_env();
|
env = s3jni_get_env();
|
||||||
jc = S3JniGlobal_env_cache(env);
|
jc = S3JniGlobal_env_cache(env);
|
||||||
ps = jc->pdbOpening;
|
ps = jc->pdbOpening;
|
||||||
@ -1875,11 +1829,11 @@ static int s3jni_run_java_auto_extensions(sqlite3 *pDb, const char **pzErr,
|
|||||||
for( i = 0; go && 0==rc; ++i ){
|
for( i = 0; go && 0==rc; ++i ){
|
||||||
S3JniAutoExtension const * ax;
|
S3JniAutoExtension const * ax;
|
||||||
MUTEX_EXT_ENTER;
|
MUTEX_EXT_ENTER;
|
||||||
if( i >= S3JniGlobal.autoExt.nExt ){
|
if( i >= SJG.autoExt.nExt ){
|
||||||
ax = 0;
|
ax = 0;
|
||||||
go = 0;
|
go = 0;
|
||||||
}else{
|
}else{
|
||||||
ax = &S3JniGlobal.autoExt.pExt[i];
|
ax = &SJG.autoExt.pExt[i];
|
||||||
}
|
}
|
||||||
MUTEX_EXT_LEAVE;
|
MUTEX_EXT_LEAVE;
|
||||||
if( ax && ax->jObj ){
|
if( ax && ax->jObj ){
|
||||||
@ -1907,30 +1861,30 @@ JDECL(jint,1auto_1extension)(JENV_CSELF, jobject jAutoExt){
|
|||||||
|
|
||||||
if( !jAutoExt ) return SQLITE_MISUSE;
|
if( !jAutoExt ) return SQLITE_MISUSE;
|
||||||
MUTEX_EXT_ENTER;
|
MUTEX_EXT_ENTER;
|
||||||
for( i = 0; i < S3JniGlobal.autoExt.nExt; ++i ){
|
for( i = 0; i < SJG.autoExt.nExt; ++i ){
|
||||||
/* Look for match or first empty slot. */
|
/* Look for match or first empty slot. */
|
||||||
ax = &S3JniGlobal.autoExt.pExt[i];
|
ax = &SJG.autoExt.pExt[i];
|
||||||
if( ax->jObj && (*env)->IsSameObject(env, ax->jObj, jAutoExt) ){
|
if( ax->jObj && (*env)->IsSameObject(env, ax->jObj, jAutoExt) ){
|
||||||
MUTEX_EXT_LEAVE;
|
MUTEX_EXT_LEAVE;
|
||||||
return 0 /* this as a no-op. */;
|
return 0 /* this as a no-op. */;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(i == S3JniGlobal.autoExt.nExt ){
|
if(i == SJG.autoExt.nExt ){
|
||||||
assert( S3JniGlobal.autoExt.nExt <= S3JniGlobal.autoExt.nAlloc );
|
assert( SJG.autoExt.nExt <= SJG.autoExt.nAlloc );
|
||||||
if( S3JniGlobal.autoExt.nExt == S3JniGlobal.autoExt.nAlloc ){
|
if( SJG.autoExt.nExt == SJG.autoExt.nAlloc ){
|
||||||
unsigned n = 1 + S3JniGlobal.autoExt.nAlloc;
|
unsigned n = 1 + SJG.autoExt.nAlloc;
|
||||||
S3JniAutoExtension * const aNew =
|
S3JniAutoExtension * const aNew =
|
||||||
sqlite3_realloc( S3JniGlobal.autoExt.pExt,
|
sqlite3_realloc( SJG.autoExt.pExt,
|
||||||
n * sizeof(S3JniAutoExtension) );
|
n * sizeof(S3JniAutoExtension) );
|
||||||
if( !aNew ){
|
if( !aNew ){
|
||||||
rc = SQLITE_NOMEM;
|
rc = SQLITE_NOMEM;
|
||||||
}else{
|
}else{
|
||||||
S3JniGlobal.autoExt.pExt = aNew;
|
SJG.autoExt.pExt = aNew;
|
||||||
++S3JniGlobal.autoExt.nAlloc;
|
++SJG.autoExt.nAlloc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( 0==rc ){
|
if( 0==rc ){
|
||||||
ax = &S3JniGlobal.autoExt.pExt[S3JniGlobal.autoExt.nExt];
|
ax = &SJG.autoExt.pExt[SJG.autoExt.nExt];
|
||||||
rc = S3JniAutoExtension_init(env, ax, jAutoExt);
|
rc = S3JniAutoExtension_init(env, ax, jAutoExt);
|
||||||
assert( rc ? 0==ax->jObj : 0!=ax->jObj );
|
assert( rc ? 0==ax->jObj : 0!=ax->jObj );
|
||||||
}
|
}
|
||||||
@ -1944,7 +1898,7 @@ JDECL(jint,1auto_1extension)(JENV_CSELF, jobject jAutoExt){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( 0==rc ){
|
if( 0==rc ){
|
||||||
++S3JniGlobal.autoExt.nExt;
|
++SJG.autoExt.nExt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MUTEX_EXT_LEAVE;
|
MUTEX_EXT_LEAVE;
|
||||||
@ -2079,16 +2033,16 @@ JDECL(jboolean,1cancel_1auto_1extension)(JENV_CSELF, jobject jAutoExt){
|
|||||||
int i;
|
int i;
|
||||||
MUTEX_EXT_ENTER;
|
MUTEX_EXT_ENTER;
|
||||||
/* This algo mirrors the one in the core. */
|
/* This algo mirrors the one in the core. */
|
||||||
for( i = S3JniGlobal.autoExt.nExt-1; i >= 0; --i ){
|
for( i = SJG.autoExt.nExt-1; i >= 0; --i ){
|
||||||
ax = &S3JniGlobal.autoExt.pExt[i];
|
ax = &SJG.autoExt.pExt[i];
|
||||||
if( ax->jObj && (*env)->IsSameObject(env, ax->jObj, jAutoExt) ){
|
if( ax->jObj && (*env)->IsSameObject(env, ax->jObj, jAutoExt) ){
|
||||||
S3JniAutoExtension_clear(env, ax);
|
S3JniAutoExtension_clear(env, ax);
|
||||||
/* Move final entry into this slot. */
|
/* Move final entry into this slot. */
|
||||||
--S3JniGlobal.autoExt.nExt;
|
--SJG.autoExt.nExt;
|
||||||
*ax = S3JniGlobal.autoExt.pExt[S3JniGlobal.autoExt.nExt];
|
*ax = SJG.autoExt.pExt[SJG.autoExt.nExt];
|
||||||
memset(&S3JniGlobal.autoExt.pExt[S3JniGlobal.autoExt.nExt], 0,
|
memset(&SJG.autoExt.pExt[SJG.autoExt.nExt], 0,
|
||||||
sizeof(S3JniAutoExtension));
|
sizeof(S3JniAutoExtension));
|
||||||
assert(! S3JniGlobal.autoExt.pExt[S3JniGlobal.autoExt.nExt].jObj );
|
assert(! SJG.autoExt.pExt[SJG.autoExt.nExt].jObj );
|
||||||
rc = JNI_TRUE;
|
rc = JNI_TRUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2874,10 +2828,10 @@ JDECL(jint,1reset)(JENV_CSELF, jobject jpStmt){
|
|||||||
static void s3jni_reset_auto_extension(JNIEnv *env){
|
static void s3jni_reset_auto_extension(JNIEnv *env){
|
||||||
int i;
|
int i;
|
||||||
MUTEX_EXT_ENTER;
|
MUTEX_EXT_ENTER;
|
||||||
for( i = 0; i < S3JniGlobal.autoExt.nExt; ++i ){
|
for( i = 0; i < SJG.autoExt.nExt; ++i ){
|
||||||
S3JniAutoExtension_clear( env, &S3JniGlobal.autoExt.pExt[i] );
|
S3JniAutoExtension_clear( env, &SJG.autoExt.pExt[i] );
|
||||||
}
|
}
|
||||||
S3JniGlobal.autoExt.nExt = 0;
|
SJG.autoExt.nExt = 0;
|
||||||
MUTEX_EXT_LEAVE;
|
MUTEX_EXT_LEAVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3189,8 +3143,8 @@ JDECL(jint,1strlike)(JENV_CSELF, jbyteArray baG, jbyteArray baT, jint escChar){
|
|||||||
JDECL(jint,1shutdown)(JENV_CSELF){
|
JDECL(jint,1shutdown)(JENV_CSELF){
|
||||||
s3jni_reset_auto_extension(env);
|
s3jni_reset_auto_extension(env);
|
||||||
MUTEX_ENV_ENTER;
|
MUTEX_ENV_ENTER;
|
||||||
while( S3JniGlobal.envCache.aHead ){
|
while( SJG.envCache.aHead ){
|
||||||
S3JniGlobal_env_uncache( S3JniGlobal.envCache.aHead->env );
|
S3JniGlobal_env_uncache( SJG.envCache.aHead->env );
|
||||||
}
|
}
|
||||||
MUTEX_ENV_LEAVE;
|
MUTEX_ENV_LEAVE;
|
||||||
/* Do not clear S3JniGlobal.jvm: it's legal to call
|
/* Do not clear S3JniGlobal.jvm: it's legal to call
|
||||||
@ -3237,7 +3191,7 @@ static int s3jni_trace_impl(unsigned traceflag, void *pC, void *pP, void *pX){
|
|||||||
createStmt = 1;
|
createStmt = 1;
|
||||||
break;
|
break;
|
||||||
case SQLITE_TRACE_PROFILE:
|
case SQLITE_TRACE_PROFILE:
|
||||||
jX = (*env)->NewObject(env, jc->g.cLong, jc->g.ctorLong1,
|
jX = (*env)->NewObject(env, SJG.g.cLong, SJG.g.ctorLong1,
|
||||||
(jlong)*((sqlite3_int64*)pX));
|
(jlong)*((sqlite3_int64*)pX));
|
||||||
// hmm. ^^^ (*pX) really is zero.
|
// hmm. ^^^ (*pX) really is zero.
|
||||||
// MARKER(("profile time = %llu\n", *((sqlite3_int64*)pX)));
|
// MARKER(("profile time = %llu\n", *((sqlite3_int64*)pX)));
|
||||||
@ -3471,6 +3425,8 @@ JDECL(void,1do_1something_1for_1developer)(JENV_CSELF){
|
|||||||
puts("sizeofs:");
|
puts("sizeofs:");
|
||||||
#define SO(T) printf("\tsizeof(" #T ") = %u\n", (unsigned)sizeof(T))
|
#define SO(T) printf("\tsizeof(" #T ") = %u\n", (unsigned)sizeof(T))
|
||||||
SO(void*);
|
SO(void*);
|
||||||
|
SO(jmethodID);
|
||||||
|
SO(jfieldID);
|
||||||
SO(S3JniEnv);
|
SO(S3JniEnv);
|
||||||
SO(S3JniHook);
|
SO(S3JniHook);
|
||||||
SO(S3JniDb);
|
SO(S3JniDb);
|
||||||
@ -3482,18 +3438,18 @@ JDECL(void,1do_1something_1for_1developer)(JENV_CSELF){
|
|||||||
SO(S3JniUdf);
|
SO(S3JniUdf);
|
||||||
printf("Cache info:\n");
|
printf("Cache info:\n");
|
||||||
printf("\tJNIEnv cache %u misses, %u hits\n",
|
printf("\tJNIEnv cache %u misses, %u hits\n",
|
||||||
S3JniGlobal.metrics.envCacheMisses,
|
SJG.metrics.envCacheMisses,
|
||||||
S3JniGlobal.metrics.envCacheHits);
|
SJG.metrics.envCacheHits);
|
||||||
printf("Mutex entry:\n\t%u env\n\t%u perDb\n\t%u autoExt\n",
|
printf("Mutex entry:\n\t%u env\n\t%u perDb\n\t%u autoExt\n",
|
||||||
S3JniGlobal.metrics.nMutexEnv,
|
SJG.metrics.nMutexEnv,
|
||||||
S3JniGlobal.metrics.nMutexPerDb,
|
SJG.metrics.nMutexPerDb,
|
||||||
S3JniGlobal.metrics.nMutexAutoExt);
|
SJG.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, SJG.metrics.udf.n##T)
|
||||||
UDF(Func); UDF(Step); UDF(Final); UDF(Value); UDF(Inverse);
|
UDF(Func); UDF(Step); UDF(Final); UDF(Value); UDF(Inverse);
|
||||||
#undef UDF
|
#undef UDF
|
||||||
printf("xDestroy calls across all callback types: %u\n",
|
printf("xDestroy calls across all callback types: %u\n",
|
||||||
S3JniGlobal.metrics.nDestroy);
|
SJG.metrics.nDestroy);
|
||||||
#undef SO
|
#undef SO
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3598,13 +3554,20 @@ static inline jobject new_fts5_api_wrapper(JNIEnv * const env, fts5_api *sv){
|
|||||||
instance, or NULL on OOM.
|
instance, or NULL on OOM.
|
||||||
*/
|
*/
|
||||||
static jobject s3jni_getFts5ExensionApi(JNIEnv * const env){
|
static jobject s3jni_getFts5ExensionApi(JNIEnv * const env){
|
||||||
S3JniEnv * const row = S3JniGlobal_env_cache(env);
|
if( !SJG.fts5.jFtsExt ){
|
||||||
if( !row->jFtsExt ){
|
jobject pNPH = new_NativePointerHolder_object(
|
||||||
row->jFtsExt = new_NativePointerHolder_object(env, &S3NphRefs.Fts5ExtensionApi,
|
env, &S3NphRefs.Fts5ExtensionApi, s3jni_ftsext()
|
||||||
s3jni_ftsext());
|
);
|
||||||
if(row->jFtsExt) row->jFtsExt = REF_G(row->jFtsExt);
|
MUTEX_ENV_ENTER;
|
||||||
|
if( pNPH ){
|
||||||
|
if( !SJG.fts5.jFtsExt ){
|
||||||
|
SJG.fts5.jFtsExt = REF_G(pNPH);
|
||||||
|
}
|
||||||
|
UNREF_L(pNPH);
|
||||||
|
}
|
||||||
|
MUTEX_ENV_LEAVE;
|
||||||
}
|
}
|
||||||
return row->jFtsExt;
|
return SJG.fts5.jFtsExt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3820,41 +3783,28 @@ JDECLFtsXA(jint,xPhraseCount)(JENV_OSELF,jobject jCtx){
|
|||||||
return (jint)fext->xPhraseCount(PtrGet_Fts5Context(jCtx));
|
return (jint)fext->xPhraseCount(PtrGet_Fts5Context(jCtx));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
Initializes jc->jPhraseIter if it needed it.
|
|
||||||
*/
|
|
||||||
static void s3jni_phraseIter_init(JNIEnv *const env, S3JniEnv * const jc,
|
|
||||||
jobject jIter){
|
|
||||||
if(!jc->jPhraseIter.klazz){
|
|
||||||
jclass klazz = (*env)->GetObjectClass(env, jIter);
|
|
||||||
jc->jPhraseIter.klazz = REF_G(klazz);
|
|
||||||
jc->jPhraseIter.fidA = (*env)->GetFieldID(env, klazz, "a", "J");
|
|
||||||
EXCEPTION_IS_FATAL("Cannot get Fts5PhraseIter.a field.");
|
|
||||||
jc->jPhraseIter.fidB = (*env)->GetFieldID(env, klazz, "a", "J");
|
|
||||||
EXCEPTION_IS_FATAL("Cannot get Fts5PhraseIter.b field.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy the 'a' and 'b' fields from pSrc to Fts5PhraseIter object jIter. */
|
/* Copy the 'a' and 'b' fields from pSrc to Fts5PhraseIter object jIter. */
|
||||||
static void s3jni_phraseIter_NToJ(JNIEnv *const env, S3JniEnv const * const jc,
|
static void s3jni_phraseIter_NToJ(JNIEnv *const env,
|
||||||
Fts5PhraseIter const * const pSrc,
|
Fts5PhraseIter const * const pSrc,
|
||||||
jobject jIter){
|
jobject jIter){
|
||||||
assert(jc->jPhraseIter.klazz);
|
S3JniGlobalType * const g = &S3JniGlobal;
|
||||||
(*env)->SetLongField(env, jIter, jc->jPhraseIter.fidA, (jlong)pSrc->a);
|
assert(g->fts5.jPhraseIter.klazz);
|
||||||
|
(*env)->SetLongField(env, jIter, g->fts5.jPhraseIter.fidA, (jlong)pSrc->a);
|
||||||
EXCEPTION_IS_FATAL("Cannot set Fts5PhraseIter.a field.");
|
EXCEPTION_IS_FATAL("Cannot set Fts5PhraseIter.a field.");
|
||||||
(*env)->SetLongField(env, jIter, jc->jPhraseIter.fidB, (jlong)pSrc->b);
|
(*env)->SetLongField(env, jIter, g->fts5.jPhraseIter.fidB, (jlong)pSrc->b);
|
||||||
EXCEPTION_IS_FATAL("Cannot set Fts5PhraseIter.b field.");
|
EXCEPTION_IS_FATAL("Cannot set Fts5PhraseIter.b field.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy the 'a' and 'b' fields from Fts5PhraseIter object jIter to pDest. */
|
/* Copy the 'a' and 'b' fields from Fts5PhraseIter object jIter to pDest. */
|
||||||
static void s3jni_phraseIter_JToN(JNIEnv *const env, S3JniEnv const * const jc,
|
static void s3jni_phraseIter_JToN(JNIEnv *const env, jobject jIter,
|
||||||
jobject jIter, Fts5PhraseIter * const pDest){
|
Fts5PhraseIter * const pDest){
|
||||||
assert(jc->jPhraseIter.klazz);
|
S3JniGlobalType * const g = &S3JniGlobal;
|
||||||
|
assert(g->fts5.jPhraseIter.klazz);
|
||||||
pDest->a =
|
pDest->a =
|
||||||
(const unsigned char *)(*env)->GetLongField(env, jIter, jc->jPhraseIter.fidA);
|
(const unsigned char *)(*env)->GetLongField(env, jIter, g->fts5.jPhraseIter.fidA);
|
||||||
EXCEPTION_IS_FATAL("Cannot get Fts5PhraseIter.a field.");
|
EXCEPTION_IS_FATAL("Cannot get Fts5PhraseIter.a field.");
|
||||||
pDest->b =
|
pDest->b =
|
||||||
(const unsigned char *)(*env)->GetLongField(env, jIter, jc->jPhraseIter.fidB);
|
(const unsigned char *)(*env)->GetLongField(env, jIter, g->fts5.jPhraseIter.fidB);
|
||||||
EXCEPTION_IS_FATAL("Cannot get Fts5PhraseIter.b field.");
|
EXCEPTION_IS_FATAL("Cannot get Fts5PhraseIter.b field.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3862,16 +3812,14 @@ JDECLFtsXA(jint,xPhraseFirst)(JENV_OSELF,jobject jCtx, jint iPhrase,
|
|||||||
jobject jIter, jobject jOutCol,
|
jobject jIter, jobject jOutCol,
|
||||||
jobject jOutOff){
|
jobject jOutOff){
|
||||||
Fts5ExtDecl;
|
Fts5ExtDecl;
|
||||||
S3JniEnv * const jc = S3JniGlobal_env_cache(env);
|
|
||||||
Fts5PhraseIter iter;
|
Fts5PhraseIter iter;
|
||||||
int rc, iCol = 0, iOff = 0;
|
int rc, iCol = 0, iOff = 0;
|
||||||
s3jni_phraseIter_init(env, jc, jIter);
|
|
||||||
rc = fext->xPhraseFirst(PtrGet_Fts5Context(jCtx), (int)iPhrase,
|
rc = fext->xPhraseFirst(PtrGet_Fts5Context(jCtx), (int)iPhrase,
|
||||||
&iter, &iCol, &iOff);
|
&iter, &iCol, &iOff);
|
||||||
if( 0==rc ){
|
if( 0==rc ){
|
||||||
OutputPointer_set_Int32(env, jOutCol, iCol);
|
OutputPointer_set_Int32(env, jOutCol, iCol);
|
||||||
OutputPointer_set_Int32(env, jOutOff, iOff);
|
OutputPointer_set_Int32(env, jOutOff, iOff);
|
||||||
s3jni_phraseIter_NToJ(env, jc, &iter, jIter);
|
s3jni_phraseIter_NToJ(env, &iter, jIter);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -3879,15 +3827,13 @@ JDECLFtsXA(jint,xPhraseFirst)(JENV_OSELF,jobject jCtx, jint iPhrase,
|
|||||||
JDECLFtsXA(jint,xPhraseFirstColumn)(JENV_OSELF,jobject jCtx, jint iPhrase,
|
JDECLFtsXA(jint,xPhraseFirstColumn)(JENV_OSELF,jobject jCtx, jint iPhrase,
|
||||||
jobject jIter, jobject jOutCol){
|
jobject jIter, jobject jOutCol){
|
||||||
Fts5ExtDecl;
|
Fts5ExtDecl;
|
||||||
S3JniEnv * const jc = S3JniGlobal_env_cache(env);
|
|
||||||
Fts5PhraseIter iter;
|
Fts5PhraseIter iter;
|
||||||
int rc, iCol = 0;
|
int rc, iCol = 0;
|
||||||
s3jni_phraseIter_init(env, jc, jIter);
|
|
||||||
rc = fext->xPhraseFirstColumn(PtrGet_Fts5Context(jCtx), (int)iPhrase,
|
rc = fext->xPhraseFirstColumn(PtrGet_Fts5Context(jCtx), (int)iPhrase,
|
||||||
&iter, &iCol);
|
&iter, &iCol);
|
||||||
if( 0==rc ){
|
if( 0==rc ){
|
||||||
OutputPointer_set_Int32(env, jOutCol, iCol);
|
OutputPointer_set_Int32(env, jOutCol, iCol);
|
||||||
s3jni_phraseIter_NToJ(env, jc, &iter, jIter);
|
s3jni_phraseIter_NToJ(env, &iter, jIter);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -3895,29 +3841,26 @@ JDECLFtsXA(jint,xPhraseFirstColumn)(JENV_OSELF,jobject jCtx, jint iPhrase,
|
|||||||
JDECLFtsXA(void,xPhraseNext)(JENV_OSELF,jobject jCtx, jobject jIter,
|
JDECLFtsXA(void,xPhraseNext)(JENV_OSELF,jobject jCtx, jobject jIter,
|
||||||
jobject jOutCol, jobject jOutOff){
|
jobject jOutCol, jobject jOutOff){
|
||||||
Fts5ExtDecl;
|
Fts5ExtDecl;
|
||||||
S3JniEnv * const jc = S3JniGlobal_env_cache(env);
|
|
||||||
Fts5PhraseIter iter;
|
Fts5PhraseIter iter;
|
||||||
int iCol = 0, iOff = 0;
|
int iCol = 0, iOff = 0;
|
||||||
if(!jc->jPhraseIter.klazz) return /*SQLITE_MISUSE*/;
|
if(!SJG.fts5.jPhraseIter.klazz) return /*SQLITE_MISUSE*/;
|
||||||
s3jni_phraseIter_JToN(env, jc, jIter, &iter);
|
s3jni_phraseIter_JToN(env, jIter, &iter);
|
||||||
fext->xPhraseNext(PtrGet_Fts5Context(jCtx),
|
fext->xPhraseNext(PtrGet_Fts5Context(jCtx), &iter, &iCol, &iOff);
|
||||||
&iter, &iCol, &iOff);
|
|
||||||
OutputPointer_set_Int32(env, jOutCol, iCol);
|
OutputPointer_set_Int32(env, jOutCol, iCol);
|
||||||
OutputPointer_set_Int32(env, jOutOff, iOff);
|
OutputPointer_set_Int32(env, jOutOff, iOff);
|
||||||
s3jni_phraseIter_NToJ(env, jc, &iter, jIter);
|
s3jni_phraseIter_NToJ(env, &iter, jIter);
|
||||||
}
|
}
|
||||||
|
|
||||||
JDECLFtsXA(void,xPhraseNextColumn)(JENV_OSELF,jobject jCtx, jobject jIter,
|
JDECLFtsXA(void,xPhraseNextColumn)(JENV_OSELF,jobject jCtx, jobject jIter,
|
||||||
jobject jOutCol){
|
jobject jOutCol){
|
||||||
Fts5ExtDecl;
|
Fts5ExtDecl;
|
||||||
S3JniEnv * const jc = S3JniGlobal_env_cache(env);
|
|
||||||
Fts5PhraseIter iter;
|
Fts5PhraseIter iter;
|
||||||
int iCol = 0;
|
int iCol = 0;
|
||||||
if(!jc->jPhraseIter.klazz) return /*SQLITE_MISUSE*/;
|
if(!SJG.fts5.jPhraseIter.klazz) return /*SQLITE_MISUSE*/;
|
||||||
s3jni_phraseIter_JToN(env, jc, jIter, &iter);
|
s3jni_phraseIter_JToN(env, jIter, &iter);
|
||||||
fext->xPhraseNextColumn(PtrGet_Fts5Context(jCtx), &iter, &iCol);
|
fext->xPhraseNextColumn(PtrGet_Fts5Context(jCtx), &iter, &iCol);
|
||||||
OutputPointer_set_Int32(env, jOutCol, iCol);
|
OutputPointer_set_Int32(env, jOutCol, iCol);
|
||||||
s3jni_phraseIter_NToJ(env, jc, &iter, jIter);
|
s3jni_phraseIter_NToJ(env, &iter, jIter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3952,7 +3895,7 @@ static int s3jni_xQueryPhrase(const Fts5ExtensionApi *xapi,
|
|||||||
struct s3jni_xQueryPhraseState const * s = pData;
|
struct s3jni_xQueryPhraseState const * s = pData;
|
||||||
JNIEnv * const env = s->env;
|
JNIEnv * const env = s->env;
|
||||||
int rc = (int)(*env)->CallIntMethod(env, s->jCallback, s->midCallback,
|
int rc = (int)(*env)->CallIntMethod(env, s->jCallback, s->midCallback,
|
||||||
s->jc->jFtsExt, s->jFcx);
|
SJG.fts5.jFtsExt, s->jFcx);
|
||||||
IFTHREW{
|
IFTHREW{
|
||||||
EXCEPTION_WARN_CALLBACK_THREW("xQueryPhrase callback");
|
EXCEPTION_WARN_CALLBACK_THREW("xQueryPhrase callback");
|
||||||
EXCEPTION_CLEAR;
|
EXCEPTION_CLEAR;
|
||||||
@ -4391,6 +4334,7 @@ Java_org_sqlite_jni_SQLite3Jni_init(JENV_CSELF){
|
|||||||
{0,0}
|
{0,0}
|
||||||
};
|
};
|
||||||
jfieldID fieldId;
|
jfieldID fieldId;
|
||||||
|
jclass klazz;
|
||||||
const ConfigFlagEntry * pConfFlag;
|
const ConfigFlagEntry * pConfFlag;
|
||||||
|
|
||||||
if( 0==sqlite3_threadsafe() ){
|
if( 0==sqlite3_threadsafe() ){
|
||||||
@ -4398,26 +4342,70 @@ Java_org_sqlite_jni_SQLite3Jni_init(JENV_CSELF){
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
memset(&S3JniGlobal, 0, sizeof(S3JniGlobal));
|
memset(&S3JniGlobal, 0, sizeof(S3JniGlobal));
|
||||||
if( (*env)->GetJavaVM(env, &S3JniGlobal.jvm) ){
|
if( (*env)->GetJavaVM(env, &SJG.jvm) ){
|
||||||
(*env)->FatalError(env, "GetJavaVM() failure shouldn't be possible.");
|
(*env)->FatalError(env, "GetJavaVM() failure shouldn't be possible.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
S3JniGlobal.envCache.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
|
||||||
OOM_CHECK( S3JniGlobal.envCache.mutex );
|
/* Grab references to various global classes and objects... */
|
||||||
S3JniGlobal.perDb.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
SJG.g.cObj = REF_G((*env)->FindClass(env,"java/lang/Object"));
|
||||||
OOM_CHECK( S3JniGlobal.perDb.mutex );
|
EXCEPTION_IS_FATAL("Error getting reference to Object class.");
|
||||||
S3JniGlobal.autoExt.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
|
||||||
OOM_CHECK( S3JniGlobal.autoExt.mutex );
|
SJG.g.cLong = REF_G((*env)->FindClass(env,"java/lang/Long"));
|
||||||
|
EXCEPTION_IS_FATAL("Error getting reference to Long class.");
|
||||||
|
SJG.g.ctorLong1 = (*env)->GetMethodID(env, SJG.g.cLong,
|
||||||
|
"<init>", "(J)V");
|
||||||
|
EXCEPTION_IS_FATAL("Error getting reference to Long constructor.");
|
||||||
|
|
||||||
|
SJG.g.cString = REF_G((*env)->FindClass(env,"java/lang/String"));
|
||||||
|
EXCEPTION_IS_FATAL("Error getting reference to String class.");
|
||||||
|
SJG.g.ctorStringBA =
|
||||||
|
(*env)->GetMethodID(env, SJG.g.cString,
|
||||||
|
"<init>", "([BLjava/nio/charset/Charset;)V");
|
||||||
|
EXCEPTION_IS_FATAL("Error getting reference to String(byte[],Charset) ctor.");
|
||||||
|
SJG.g.stringGetBytes =
|
||||||
|
(*env)->GetMethodID(env, SJG.g.cString,
|
||||||
|
"getBytes", "(Ljava/nio/charset/Charset;)[B");
|
||||||
|
EXCEPTION_IS_FATAL("Error getting reference to String.getBytes(Charset).");
|
||||||
|
|
||||||
|
{ /* StandardCharsets.UTF_8 */
|
||||||
|
jfieldID fUtf8;
|
||||||
|
jclass const klazzSC =
|
||||||
|
(*env)->FindClass(env,"java/nio/charset/StandardCharsets");
|
||||||
|
EXCEPTION_IS_FATAL("Error getting reference to StndardCharsets class.");
|
||||||
|
fUtf8 = (*env)->GetStaticFieldID(env, klazzSC, "UTF_8",
|
||||||
|
"Ljava/nio/charset/Charset;");
|
||||||
|
EXCEPTION_IS_FATAL("Error getting StandardCharsets.UTF_8 field.");
|
||||||
|
SJG.g.oCharsetUtf8 =
|
||||||
|
REF_G((*env)->GetStaticObjectField(env, klazzSC, fUtf8));
|
||||||
|
EXCEPTION_IS_FATAL("Error getting reference to StandardCharsets.UTF_8.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SQLITE_ENABLE_FTS5
|
||||||
|
klazz = (*env)->FindClass(env, "org/sqlite/jni/Fts5PhraseIter");
|
||||||
|
EXCEPTION_IS_FATAL("Error getting reference to org.sqlite.jni.Fts5PhraseIter.");
|
||||||
|
SJG.fts5.jPhraseIter.klazz = REF_G(klazz);
|
||||||
|
SJG.fts5.jPhraseIter.fidA = (*env)->GetFieldID(env, klazz, "a", "J");
|
||||||
|
EXCEPTION_IS_FATAL("Cannot get Fts5PhraseIter.a field.");
|
||||||
|
SJG.fts5.jPhraseIter.fidB = (*env)->GetFieldID(env, klazz, "a", "J");
|
||||||
|
EXCEPTION_IS_FATAL("Cannot get Fts5PhraseIter.b field.");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SJG.envCache.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
||||||
|
OOM_CHECK( SJG.envCache.mutex );
|
||||||
|
SJG.perDb.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
||||||
|
OOM_CHECK( SJG.perDb.mutex );
|
||||||
|
SJG.autoExt.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);
|
||||||
|
OOM_CHECK( SJG.autoExt.mutex );
|
||||||
#if 0
|
#if 0
|
||||||
/* Just for sanity checking... */
|
/* Just for sanity checking... */
|
||||||
(void)S3JniGlobal_env_cache(env);
|
(void)S3JniGlobal_env_cache(env);
|
||||||
if( !S3JniGlobal.envCache.aHead ){
|
if( !SJG.envCache.aHead ){
|
||||||
(*env)->FatalError(env, "Could not allocate JNIEnv-specific cache.");
|
(*env)->FatalError(env, "Could not allocate JNIEnv-specific cache.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert( 1 == S3JniGlobal.metrics.envCacheMisses );
|
assert( 1 == SJG.metrics.envCacheMisses );
|
||||||
assert( env == S3JniGlobal.envCache.aHead->env );
|
assert( env == SJG.envCache.aHead->env );
|
||||||
assert( 0 != S3JniGlobal.envCache.aHead->g.cObj );
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for( pConfFlag = &aLimits[0]; pConfFlag->zName; ++pConfFlag ){
|
for( pConfFlag = &aLimits[0]; pConfFlag->zName; ++pConfFlag ){
|
||||||
|
12
manifest
12
manifest
@ -1,5 +1,5 @@
|
|||||||
C Minor\sJNI\scleanups.
|
C Move\smost\sof\sthe\sper-JNIEnv\sglobal\sJava\sclass\srefs\sinto\sthe\sglobal\sstate,\ssaving\sa\sbit\sof\sper-thread\soverhead.
|
||||||
D 2023-08-21T23:45:19.079
|
D 2023-08-22T11:34:34.096
|
||||||
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
|
||||||
@ -235,7 +235,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3
|
|||||||
F ext/jni/GNUmakefile 4849b0ac41c3a92777aebf0ec3d51c2be7c78d3ea9b91ece03ade6f9fa13d99a
|
F ext/jni/GNUmakefile 4849b0ac41c3a92777aebf0ec3d51c2be7c78d3ea9b91ece03ade6f9fa13d99a
|
||||||
F ext/jni/README.md 975b35173debbbf3a4ab7166e14d2ffa2bacff9b6850414f09cc919805e81ba4
|
F ext/jni/README.md 975b35173debbbf3a4ab7166e14d2ffa2bacff9b6850414f09cc919805e81ba4
|
||||||
F ext/jni/jar-dist.make 9a03d10dbb5a74c724bfec4b76fd9e4c9865cbbc858d731cb48f38ac897d73a3
|
F ext/jni/jar-dist.make 9a03d10dbb5a74c724bfec4b76fd9e4c9865cbbc858d731cb48f38ac897d73a3
|
||||||
F ext/jni/src/c/sqlite3-jni.c 77ff2a7d608737aef5734d60881cd167d4b5916bcca8669067aa13afd641ba6e
|
F ext/jni/src/c/sqlite3-jni.c 96252788a8eea13e8da997103c05b8c1d2c878eb2c5a71a123baeb2bd5e91027
|
||||||
F ext/jni/src/c/sqlite3-jni.h 8b0ab1a3f0f92b75d4ff50db4a88b66a137cfb561268eb15bb3993ed174dbb74
|
F ext/jni/src/c/sqlite3-jni.h 8b0ab1a3f0f92b75d4ff50db4a88b66a137cfb561268eb15bb3993ed174dbb74
|
||||||
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
|
||||||
@ -2092,8 +2092,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 0a84131008a2e7886dac64a3545dea634811f6eac2b90885ec9c61ed1e6544c3
|
P b88910aaaaaaa0936974379bb3eb8a5a3a634395b14e67cc9030f8a520f471f1
|
||||||
R e61cca732e3141bc7655ea7dcc403579
|
R 76968b303e9bd6c480af577a480bf905
|
||||||
U stephan
|
U stephan
|
||||||
Z 1c9a32335d26ec39640641e263699a74
|
Z edf907aa4738f3b50b53a088953efc54
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
@ -1 +1 @@
|
|||||||
b88910aaaaaaa0936974379bb3eb8a5a3a634395b14e67cc9030f8a520f471f1
|
7342bf578790e1a87c128a7c1c7745fe2e7c442890370feb160d406597d4d8ec
|
Loading…
Reference in New Issue
Block a user