# define SQLITE_TEMP_STORE 2
#endif
#ifndef SQLITE_THREADSAFE
-# define SQLITE_THREADSAFE 0
+# define SQLITE_THREADSAFE 1
#endif
/**********************************************************************/
/** Helpers for extracting pointers from jobjects, noting that the
corresponding Java interfaces have already done the type-checking.
*/
-#define PtrGet_sqlite3(OBJ) NativePointerHolder_get(env,OBJ,S3JniClassNames.sqlite3)
-#define PtrGet_sqlite3_stmt(OBJ) NativePointerHolder_get(env,OBJ,S3JniClassNames.sqlite3_stmt)
-#define PtrGet_sqlite3_value(OBJ) NativePointerHolder_get(env,OBJ,S3JniClassNames.sqlite3_value)
-#define PtrGet_sqlite3_context(OBJ) NativePointerHolder_get(env,OBJ,S3JniClassNames.sqlite3_context)
+#define PtrGet_sqlite3(OBJ) NativePointerHolder_get(env,OBJ,&S3NphRefs.sqlite3)
+#define PtrGet_sqlite3_stmt(OBJ) NativePointerHolder_get(env,OBJ,&S3NphRefs.sqlite3_stmt)
+#define PtrGet_sqlite3_value(OBJ) NativePointerHolder_get(env,OBJ,&S3NphRefs.sqlite3_value)
+#define PtrGet_sqlite3_context(OBJ) NativePointerHolder_get(env,OBJ,&S3NphRefs.sqlite3_context)
/* Helpers for Java value reference management. */
static inline jobject new_global_ref(JNIEnv * const env, jobject const v){
return v ? (*env)->NewGlobalRef(env, v) : NULL;
#define UNREF_L(VAR) delete_local_ref(env,(VAR))
/**
- Constant string class names used as keys for S3JniGlobal_nph_cache(),
-S3Jni
- and
- friends.
+ Keys for use with S3JniGlobal_nph_cache().
+*/
+typedef struct S3NphRef S3NphRef;
+struct S3NphRef {
+ const int index /* index into S3JniEnv->nph[] */;
+ const char * const zName /* Full Java name of the class */;
+};
+
+/**
+ Keys for each concrete NativePointerHolder subclass.
*/
static const struct {
- const char * const sqlite3;
- const char * const sqlite3_stmt;
- const char * const sqlite3_context;
- const char * const sqlite3_value;
- const char * const OutputPointer_Int32;
- const char * const OutputPointer_Int64;
- const char * const OutputPointer_String;
- const char * const OutputPointer_ByteArray;
- const char * const OutputPointer_sqlite3;
- const char * const OutputPointer_sqlite3_stmt;
+ const S3NphRef sqlite3;
+ const S3NphRef sqlite3_stmt;
+ const S3NphRef sqlite3_context;
+ const S3NphRef sqlite3_value;
+ const S3NphRef OutputPointer_Int32;
+ const S3NphRef OutputPointer_Int64;
+ const S3NphRef OutputPointer_String;
+ const S3NphRef OutputPointer_ByteArray;
+ const S3NphRef OutputPointer_sqlite3;
+ const S3NphRef OutputPointer_sqlite3_stmt;
#ifdef SQLITE_ENABLE_FTS5
- const char * const Fts5Context;
- const char * const Fts5ExtensionApi;
- const char * const fts5_api;
- const char * const fts5_tokenizer;
- const char * const Fts5Tokenizer;
+ const S3NphRef Fts5Context;
+ const S3NphRef Fts5ExtensionApi;
+ const S3NphRef fts5_api;
+ const S3NphRef fts5_tokenizer;
+ const S3NphRef Fts5Tokenizer;
#endif
-} S3JniClassNames = {
- "org/sqlite/jni/sqlite3",
- "org/sqlite/jni/sqlite3_stmt",
- "org/sqlite/jni/sqlite3_context",
- "org/sqlite/jni/sqlite3_value",
- "org/sqlite/jni/OutputPointer$Int32",
- "org/sqlite/jni/OutputPointer$Int64",
- "org/sqlite/jni/OutputPointer$String",
- "org/sqlite/jni/OutputPointer$ByteArray",
- "org/sqlite/jni/OutputPointer$sqlite3",
- "org/sqlite/jni/OutputPointer$sqlite3_stmt",
+} S3NphRefs = {
+#define NREF(INDEX, NAME) { INDEX, "org/sqlite/jni/" NAME }
+ NREF(0, "sqlite3"),
+ NREF(1, "sqlite3_stmt"),
+ NREF(2, "sqlite3_context"),
+ NREF(3, "sqlite3_value"),
+ NREF(4, "OutputPointer$Int32"),
+ NREF(5, "OutputPointer$Int64"),
+ NREF(6, "OutputPointer$String"),
+ NREF(7, "OutputPointer$ByteArray"),
+ NREF(8, "OutputPointer$sqlite3"),
+ NREF(9, "OutputPointer$sqlite3_stmt"),
#ifdef SQLITE_ENABLE_FTS5
- "org/sqlite/jni/Fts5Context",
- "org/sqlite/jni/Fts5ExtensionApi",
- "org/sqlite/jni/fts5_api",
- "org/sqlite/jni/fts5_tokenizer",
- "org/sqlite/jni/Fts5Tokenizer"
+ NREF(10, "Fts5Context"),
+ NREF(11, "Fts5ExtensionApi"),
+ NREF(12, "fts5_api"),
+ NREF(13, "fts5_tokenizer"),
+ NREF(14, "Fts5Tokenizer")
#endif
+#undef NREF
};
/** Create a trivial JNI wrapper for (int CName(void)). */
(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 S3JniClassNames
- object. The S3JniClassNames entries are the keys for this particular
+ to be exactly the number of entries in the S3NphRefs object. The
+ index field of those entries are the keys for this particular
cache.
*/
- NphCache_SIZE = sizeof(S3JniClassNames) / sizeof(char const *)
+ NphCache_SIZE = sizeof(S3NphRefs) / sizeof(S3NphRef)
};
/**
Cache entry for NativePointerHolder subclasses and OutputPointer
types.
*/
-typedef struct S3JniNphCache S3JniNphCache;
-struct S3JniNphCache {
- const char * zClassName /* "full/class/Name". Must be a static
- string pointer from the S3JniClassNames
- struct. */;
+typedef struct S3JniNphClass S3JniNphClass;
+struct S3JniNphClass {
+ const S3NphRef * pRef /* Entry from S3NphRefs. */;
jclass klazz /* global ref to the concrete
NativePointerHolder subclass represented by
zClassName */;
/**
Cache of Java refs/IDs for NativePointerHolder subclasses.
*/
- S3JniNphCache nph[NphCache_SIZE];
+ S3JniNphClass nph[NphCache_SIZE];
};
-static void S3JniNphCache_clear(JNIEnv * const env, S3JniNphCache * const p){
+static void S3JniNphClass_clear(JNIEnv * const env, S3JniNphClass * const p){
UNREF_G(p->klazz);
- memset(p, 0, sizeof(S3JniNphCache));
+ memset(p, 0, sizeof(S3JniNphClass));
}
/*
current JNIEnv object. */;
} perDb;
struct {
- unsigned nphCacheHits;
- unsigned nphCacheMisses;
unsigned envCacheHits;
unsigned envCacheMisses;
unsigned nMutexEnv /* number of times envCache.mutex was entered */;
condition in which two open() calls could set pdbOpening.
*/
S3JniDb * pdbOpening;
- sqlite3_mutex * mutex /* mutex for aUsed and aFree */;
+ sqlite3_mutex * mutex /* mutex for manipulation/traversal of pHead */;
void const * locker /* Mutex is locked on this object's behalf */;
} autoExt;
} S3JniGlobal;
assert( (env) == S3JniGlobal.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
#define MUTEX_ASSERT_NOTLOCKER_ENV \
assert( (env) != S3JniGlobal.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
-#define MUTEX_ENTER_ENV \
+#define MUTEX_ENV_ENTER \
/*MARKER(("Entering ENV mutex@%p %s.\n", env, __func__));*/ \
MUTEX_ASSERT_NOTLOCKER_ENV; \
sqlite3_mutex_enter( S3JniGlobal.envCache.mutex ); \
++S3JniGlobal.metrics.nMutexEnv; \
S3JniGlobal.envCache.locker = env
-#define MUTEX_LEAVE_ENV \
+#define MUTEX_ENV_LEAVE \
/*MARKER(("Leaving ENV mutex @%p %s.\n", env, __func__));*/ \
MUTEX_ASSERT_LOCKER_ENV; \
S3JniGlobal.envCache.locker = 0; \
sqlite3_mutex_leave( S3JniGlobal.envCache.mutex )
#define MUTEX_ASSERT_LOCKED_PDB \
assert( 0 != S3JniGlobal.perDb.locker && "Misuse of S3JniGlobal.perDb.mutex" )
-#define MUTEX_ENTER_PDB \
+#define MUTEX_PDB_ENTER \
/*MARKER(("Entering PerDb mutex@%p %s.\n", env, __func__));*/ \
sqlite3_mutex_enter( S3JniGlobal.perDb.mutex ); \
++S3JniGlobal.metrics.nMutexPerDb; \
S3JniGlobal.perDb.locker = env;
-#define MUTEX_LEAVE_PDB \
+#define MUTEX_PDB_LEAVE \
/*MARKER(("Leaving PerDb mutex@%p %s.\n", env, __func__));*/ \
S3JniGlobal.perDb.locker = 0; \
sqlite3_mutex_leave( S3JniGlobal.perDb.mutex )
-#define MUTEX_ENTER_EXT \
+#define MUTEX_ENV_EXT \
/*MARKER(("Entering autoExt mutex@%p %s.\n", env, __func__));*/ \
sqlite3_mutex_enter( S3JniGlobal.autoExt.mutex ); \
++S3JniGlobal.metrics.nMutexAutoExt
if( sqlite3_mutex_try( S3JniGlobal.autoExt.mutex ) ){ FAIL_EXPR; } \
S3JniGlobal.autoExt.locker = env; \
++S3JniGlobal.metrics.nMutexAutoExt
-#define MUTEX_LEAVE_EXT \
+#define MUTEX_EXT_LEAVE \
/*MARKER(("Leaving PerDb mutex@%p %s.\n", env, __func__));*/ \
S3JniGlobal.autoExt.locker = 0; \
sqlite3_mutex_leave( S3JniGlobal.autoExt.mutex )
*/
static S3JniEnv * S3JniGlobal_env_cache(JNIEnv * const env){
struct S3JniEnv * row;
- MUTEX_ENTER_ENV;
+ MUTEX_ENV_ENTER;
row = S3JniGlobal.envCache.aHead;
for( ; row; row = row->pNext ){
if( row->env == env ){
++S3JniGlobal.metrics.envCacheHits;
- MUTEX_LEAVE_ENV;
+ MUTEX_ENV_LEAVE;
return row;
}
}
REF_G((*env)->GetStaticObjectField(env, klazzSC, fUtf8));
EXCEPTION_IS_FATAL("Error getting reference to StandardCharsets.UTF_8.");
}
- MUTEX_LEAVE_ENV;
+ MUTEX_ENV_LEAVE;
return row;
}
static void S3JniDb_free_for_env(JNIEnv *env){
S3JniDb * ps;
S3JniDb * pNext = 0;
- MUTEX_ENTER_PDB;
+ MUTEX_PDB_ENTER;
ps = S3JniGlobal.perDb.aUsed;
for( ; ps; ps = pNext ){
pNext = ps->pNext;
if(ps->env == env){
S3JniDb * const pPrev = ps->pPrev;
S3JniDb_set_aside(ps);
- assert(pPrev ? pPrev->pNext!=ps : 1);
- pNext = pPrev;
+ assert(pPrev ? pPrev->pNext==pNext : 1);
+ assert( ps == S3JniGlobal.perDb.aFree );
}
}
- MUTEX_LEAVE_PDB;
+ MUTEX_PDB_LEAVE;
}
/**
UNREF_G(row->jPhraseIter.klazz);
#endif
for( i = 0; i < NphCache_SIZE; ++i ){
- S3JniNphCache_clear(env, &row->nph[i]);
+ S3JniNphClass_clear(env, &row->nph[i]);
}
memset(row, 0, sizeof(S3JniEnv));
row->pNext = S3JniGlobal.envCache.aFree;
/**
Searches the NativePointerHolder cache for the given combination.
- If it finds one, it returns it as-is. If it doesn't AND the cache
- has a free slot, it populates that slot with (env, zClassName,
- klazz) and returns it. If the cache is full with no match it
- returns NULL.
+ If it finds one, it returns it as-is. If it doesn't, it populates a
+ cache slot's klazz member and returns the cache slot.
It is up to the caller to populate the other members of the returned
object if needed.
This simple cache catches >99% of searches in the current
(2023-07-31) tests.
*/
-static S3JniNphCache * S3JniGlobal_nph_cache(JNIEnv * const env, const char *zClassName){
+static S3JniNphClass * S3JniGlobal_nph_cache(JNIEnv * const env, S3NphRef const* pRef){
/**
According to:
guards the fetching of envRow.
*/
struct S3JniEnv * const envRow = S3JniGlobal_env_cache(env);
- S3JniNphCache * freeSlot = 0;
- S3JniNphCache * pCache = 0;
- int i;
+ S3JniNphClass * pCache;
assert(envRow);
- for( i = 0; i < NphCache_SIZE; ++i ){
- pCache = &envRow->nph[i];
- if(zClassName == pCache->zClassName){
- ++S3JniGlobal.metrics.nphCacheHits;
-#define DUMP_NPH_CACHES 0
-#if DUMP_NPH_CACHES
- MARKER(("Cache hit #%u %s klazz@%p nativePointer field@%p, ctor@%p\n",
- S3JniGlobal.metrics.nphCacheHits, zClassName, pCache->klazz, pCache->fidValue,
- pCache->midCtor));
-#endif
- assert(pCache->klazz);
- return pCache;
- }else if(!freeSlot && !pCache->zClassName){
- freeSlot = pCache;
- }
- }
- if(freeSlot){
- freeSlot->zClassName = zClassName;
- freeSlot->klazz = (*env)->FindClass(env, zClassName);
+ pCache = &envRow->nph[pRef->index];
+ if( !pCache->pRef ){
+ pCache->pRef = pRef;
+ pCache->klazz = (*env)->FindClass(env, pRef->zName);
EXCEPTION_IS_FATAL("FindClass() unexpectedly threw");
- freeSlot->klazz = REF_G(freeSlot->klazz);
- ++S3JniGlobal.metrics.nphCacheMisses;
-#if DUMP_NPH_CACHES
- static unsigned int cacheMisses = 0;
- MARKER(("Cache miss #%u %s klazz@%p nativePointer field@%p, ctor@%p\n",
- S3JniGlobal.metrics.nphCacheMisses, zClassName, freeSlot->klazz,
- freeSlot->fidValue, freeSlot->midCtor));
-#endif
-#undef DUMP_NPH_CACHES
- }else{
- (*env)->FatalError(env, "MAINTENANCE REQUIRED: NphCache_SIZE is too low.");
+ pCache->klazz = REF_G(pCache->klazz);
}
- return freeSlot;
+ return pCache;
}
/**
as a cache key.
*/
static void NativePointerHolder_set(JNIEnv * env, jobject ppOut, const void * p,
- const char *zClassName){
+ S3NphRef const* pRef){
jfieldID setter = 0;
- S3JniNphCache * const pCache = S3JniGlobal_nph_cache(env, zClassName);
+ S3JniNphClass * const pCache = S3JniGlobal_nph_cache(env, pRef);
if(pCache && pCache->klazz && pCache->fidValue){
- assert(zClassName == pCache->zClassName);
setter = pCache->fidValue;
assert(setter);
}else{
if(pCache){
assert(pCache->klazz);
assert(!pCache->fidValue);
- assert(zClassName == pCache->zClassName);
pCache->fidValue = setter;
}
}
zClassName must be a static string so we can use its address as a
cache key.
*/
-static void * NativePointerHolder_get(JNIEnv * env, jobject pObj, const char *zClassName){
+static void * NativePointerHolder_get(JNIEnv * env, jobject pObj, S3NphRef const* pRef){
if( pObj ){
jfieldID getter = 0;
void * rv = 0;
- S3JniNphCache * const pCache = S3JniGlobal_nph_cache(env, zClassName);
+ S3JniNphClass * const pCache = S3JniGlobal_nph_cache(env, pRef);
if(pCache && pCache->fidValue){
getter = pCache->fidValue;
}else{
getter = NativePointerHolder_getField(env, klazz);
if(pCache){
assert(pCache->klazz);
- assert(zClassName == pCache->zClassName);
pCache->fidValue = getter;
}
}
static S3JniDb * S3JniDb_alloc(JNIEnv * const env, sqlite3 *pDb,
jobject jDb){
S3JniDb * rv;
- MUTEX_ASSERT_LOCKED_PDB;
+ MUTEX_PDB_ENTER;
if(S3JniGlobal.perDb.aFree){
rv = S3JniGlobal.perDb.aFree;
//MARKER(("state@%p for db allocating for db@%p from free-list\n", rv, pDb));
rv->pDb = pDb;
rv->env = env;
}
+ MUTEX_PDB_LEAVE;
return rv;
}
static S3JniDb * S3JniDb_for_db(JNIEnv * const env, jobject jDb, sqlite3 *pDb){
S3JniDb * s = 0;
if(jDb || pDb){
- MUTEX_ENTER_PDB;
+ MUTEX_PDB_ENTER;
s = S3JniGlobal.perDb.aUsed;
if(!pDb){
assert( jDb );
break;
}
}
- MUTEX_LEAVE_PDB;
+ MUTEX_PDB_LEAVE;
}
return s;
}
jfieldID member;
void * pAgg;
int rc = 0;
- S3JniNphCache * const pCache =
- S3JniGlobal_nph_cache(env, S3JniClassNames.sqlite3_context);
+ S3JniNphClass * const pCache =
+ S3JniGlobal_nph_cache(env, &S3NphRefs.sqlite3_context);
if(pCache && pCache->klazz && pCache->fidSetAgg){
member = pCache->fidSetAgg;
assert(member);
/**
Common init for OutputPointer_set_Int32() and friends. zClassName must be a
- pointer from S3JniClassNames. jOut must be an instance of that
+ pointer from S3NphRefs. jOut must be an instance of that
class. Fetches the jfieldID for jOut's [value] property, which must
be of the type represented by the JNI type signature zTypeSig, and
stores it in pFieldId. Fails fatally if the property is not found,
this routine with the same zClassName but different zTypeSig: it
will misbehave.
*/
-static void setupOutputPointer(JNIEnv * const env, const char *zClassName,
+static void setupOutputPointer(JNIEnv * const env, S3NphRef const * pRef,
const char * const zTypeSig,
jobject const jOut, jfieldID * const pFieldId){
jfieldID setter = 0;
- S3JniNphCache * const pCache =
- S3JniGlobal_nph_cache(env, zClassName);
+ S3JniNphClass * const pCache = S3JniGlobal_nph_cache(env, pRef);
if(pCache && pCache->klazz && pCache->fidValue){
setter = pCache->fidValue;
}else{
to v. */
static void OutputPointer_set_Int32(JNIEnv * const env, jobject const jOut, int v){
jfieldID setter = 0;
- setupOutputPointer(env, S3JniClassNames.OutputPointer_Int32, "I", jOut, &setter);
+ setupOutputPointer(env, &S3NphRefs.OutputPointer_Int32, "I", jOut, &setter);
(*env)->SetIntField(env, jOut, setter, (jint)v);
EXCEPTION_IS_FATAL("Cannot set OutputPointer.Int32.value");
}
to v. */
static void OutputPointer_set_Int64(JNIEnv * const env, jobject const jOut, jlong v){
jfieldID setter = 0;
- setupOutputPointer(env, S3JniClassNames.OutputPointer_Int64, "J", jOut, &setter);
+ setupOutputPointer(env, &S3NphRefs.OutputPointer_Int64, "J", jOut, &setter);
(*env)->SetLongField(env, jOut, setter, v);
EXCEPTION_IS_FATAL("Cannot set OutputPointer.Int64.value");
}
static void OutputPointer_set_sqlite3(JNIEnv * const env, jobject const jOut,
jobject jDb){
jfieldID setter = 0;
- setupOutputPointer(env, S3JniClassNames.OutputPointer_sqlite3,
+ setupOutputPointer(env, &S3NphRefs.OutputPointer_sqlite3,
"Lorg/sqlite/jni/sqlite3;", jOut, &setter);
(*env)->SetObjectField(env, jOut, setter, jDb);
EXCEPTION_IS_FATAL("Cannot set OutputPointer.sqlite3.value");
static void OutputPointer_set_sqlite3_stmt(JNIEnv * const env, jobject const jOut,
jobject jStmt){
jfieldID setter = 0;
- setupOutputPointer(env, S3JniClassNames.OutputPointer_sqlite3_stmt,
+ setupOutputPointer(env, &S3NphRefs.OutputPointer_sqlite3_stmt,
"Lorg/sqlite/jni/sqlite3_stmt;", jOut, &setter);
(*env)->SetObjectField(env, jOut, setter, jStmt);
EXCEPTION_IS_FATAL("Cannot set OutputPointer.sqlite3_stmt.value");
static void OutputPointer_set_ByteArray(JNIEnv * const env, jobject const jOut,
jbyteArray const v){
jfieldID setter = 0;
- setupOutputPointer(env, S3JniClassNames.OutputPointer_ByteArray, "[B",
+ setupOutputPointer(env, &S3NphRefs.OutputPointer_ByteArray, "[B",
jOut, &setter);
(*env)->SetObjectField(env, jOut, setter, v);
EXCEPTION_IS_FATAL("Cannot set OutputPointer.ByteArray.value");
static void OutputPointer_set_String(JNIEnv * const env, jobject const jOut,
jstring const v){
jfieldID setter = 0;
- setupOutputPointer(env, S3JniClassNames.OutputPointer_String,
+ setupOutputPointer(env, &S3NphRefs.OutputPointer_String,
"Ljava/lang/String;", jOut, &setter);
(*env)->SetObjectField(env, jOut, setter, v);
EXCEPTION_IS_FATAL("Cannot set OutputPointer.String.value");
if Java fails to allocate, but the JNI docs are not entirely clear
on that detail.
- Always use a static string pointer from S3JniClassNames for the 2nd
+ Always use an static pointer from the S3NphRefs struct for the 2nd
argument so that we can use its address as a cache key.
*/
-static jobject new_NativePointerHolder_object(JNIEnv * const env, const char *zClassName,
+static jobject new_NativePointerHolder_object(JNIEnv * const env, S3NphRef const * pRef,
const void * pNative){
jobject rv = 0;
jclass klazz = 0;
jmethodID ctor = 0;
- S3JniNphCache * const pCache =
- S3JniGlobal_nph_cache(env, zClassName);
- if(pCache && pCache->midCtor){
+ S3JniNphClass * const pCache = S3JniGlobal_nph_cache(env, pRef);
+ if(pCache->midCtor){
assert( pCache->klazz );
klazz = pCache->klazz;
ctor = pCache->midCtor;
}else{
klazz = pCache
? pCache->klazz
- : (*env)->FindClass(env, zClassName);
+ : (*env)->FindClass(env, pRef->zName);
ctor = klazz ? (*env)->GetMethodID(env, klazz, "<init>", "()V") : 0;
EXCEPTION_IS_FATAL("Cannot find constructor for class.");
if(pCache){
- assert(zClassName == pCache->zClassName);
assert(pCache->klazz);
assert(!pCache->midCtor);
pCache->midCtor = ctor;
assert(ctor);
rv = (*env)->NewObject(env, klazz, ctor);
EXCEPTION_IS_FATAL("No-arg constructor threw.");
- if(rv) NativePointerHolder_set(env, rv, pNative, zClassName);
+ if(rv) NativePointerHolder_set(env, rv, pNative, pRef);
return rv;
}
static inline jobject new_sqlite3_wrapper(JNIEnv * const env, sqlite3 *sv){
- return new_NativePointerHolder_object(env, S3JniClassNames.sqlite3, sv);
+ return new_NativePointerHolder_object(env, &S3NphRefs.sqlite3, sv);
}
static inline jobject new_sqlite3_context_wrapper(JNIEnv * const env, sqlite3_context *sv){
- return new_NativePointerHolder_object(env, S3JniClassNames.sqlite3_context, sv);
+ return new_NativePointerHolder_object(env, &S3NphRefs.sqlite3_context, sv);
}
static inline jobject new_sqlite3_stmt_wrapper(JNIEnv * const env, sqlite3_stmt *sv){
- return new_NativePointerHolder_object(env, S3JniClassNames.sqlite3_stmt, sv);
+ return new_NativePointerHolder_object(env, &S3NphRefs.sqlite3_stmt, sv);
}
static inline jobject new_sqlite3_value_wrapper(JNIEnv * const env, sqlite3_value *sv){
- return new_NativePointerHolder_object(env, S3JniClassNames.sqlite3_value, sv);
+ return new_NativePointerHolder_object(env, &S3NphRefs.sqlite3_value, sv);
}
enum UDFType {
assert( !ps->pDb /* it's still being opened */ );
ps->pDb = pDb;
assert( ps->jDb );
- NativePointerHolder_set(env, ps->jDb, pDb, S3JniClassNames.sqlite3);
+ NativePointerHolder_set(env, ps->jDb, pDb, &S3NphRefs.sqlite3);
for( ; pAX; pAX = pAX->pNext ){
rc = (*env)->CallIntMethod(env, pAX->jObj, pAX->midFunc, ps->jDb);
IFTHREW {
S3JniAutoExtension * ax;
if( !jAutoExt ) return SQLITE_MISUSE;
- MUTEX_ENTER_EXT;
+ MUTEX_ENV_EXT;
if( 0==once && ++once ){
sqlite3_auto_extension( (void(*)(void))s3jni_run_java_auto_extensions );
}
}
}
ax = S3JniAutoExtension_alloc(env, jAutoExt);
- MUTEX_LEAVE_EXT;
+ MUTEX_EXT_LEAVE;
return ax ? 0 : SQLITE_NOMEM;
}
JDECL(jboolean,1cancel_1auto_1extension)(JENV_CSELF, jobject jAutoExt){
S3JniAutoExtension * ax;
jboolean rc = JNI_FALSE;
- MUTEX_ENTER_EXT;
+ MUTEX_ENV_EXT;
for( ax = S3JniGlobal.autoExt.pHead; ax; ax = ax->pNext ){
if( (*env)->IsSameObject(env, ax->jObj, jAutoExt) ){
S3JniAutoExtension_free(env, ax);
break;
}
}
- MUTEX_LEAVE_EXT;
+ MUTEX_EXT_LEAVE;
return rc;
}
ps = S3JniDb_for_db(env, jDb, 0);
if(ps){
rc = 1==version ? (jint)sqlite3_close(ps->pDb) : (jint)sqlite3_close_v2(ps->pDb);
- MUTEX_ENTER_PDB;
+ MUTEX_PDB_ENTER;
S3JniDb_set_aside(ps)
/* MUST come after close() because of ps->trace. */;
- MUTEX_LEAVE_PDB;
- NativePointerHolder_set(env, jDb, 0, S3JniClassNames.sqlite3);
+ MUTEX_PDB_LEAVE;
+ NativePointerHolder_set(env, jDb, 0, &S3NphRefs.sqlite3);
}
return (jint)rc;
}
sqlite3_stmt * const pStmt = PtrGet_sqlite3_stmt(jpStmt);
if( pStmt ){
rc = sqlite3_finalize(pStmt);
- NativePointerHolder_set(env, jpStmt, 0, S3JniClassNames.sqlite3_stmt);
+ NativePointerHolder_set(env, jpStmt, 0, &S3NphRefs.sqlite3_stmt);
}
return rc;
}
is infinitely easier to track down from client code. Note that
we rely on the Java methods for open() and auto-extension
handling to be synchronized so that this BUSY cannot be
- triggered by a race condition with those functions. */;
+ triggered by a race condition with the auto-ext functions. */;
*jc = S3JniGlobal_env_cache(env);
if(!*jc){
rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM;
goto end;
}
- MUTEX_ENTER_PDB;
*ps = S3JniDb_alloc(env, 0, *jDb);
- MUTEX_LEAVE_PDB;
if(*ps){
S3JniGlobal.autoExt.pdbOpening = *ps;
S3JniGlobal.autoExt.locker = *ps;
}
//MARKER(("pre-open ps@%p\n", *ps));
end:
- /* Remain in autoExt.mutex until s3jni_open_post(). */
if(rc){
- MUTEX_LEAVE_EXT;
+ MUTEX_EXT_LEAVE;
+ /* Else remain in autoExt.mutex until s3jni_open_post(). */
}
return rc;
}
assert(ps->jDb);
if( 0==ps->pDb ){
ps->pDb = *ppDb;
- NativePointerHolder_set(env, ps->jDb, *ppDb, S3JniClassNames.sqlite3);
+ NativePointerHolder_set(env, ps->jDb, *ppDb, &S3NphRefs.sqlite3);
}else{
assert( ps->pDb == *ppDb /* set up via s3jni_run_java_auto_extensions() */);
}
}else{
- MUTEX_ENTER_PDB;
+ MUTEX_PDB_ENTER;
S3JniDb_set_aside(ps);
- MUTEX_LEAVE_PDB;
+ MUTEX_PDB_LEAVE;
ps = 0;
}
OutputPointer_set_sqlite3(env, jOut, ps ? ps->jDb : 0);
- MUTEX_LEAVE_EXT;
+ MUTEX_EXT_LEAVE /* locked in s3jni_open_pre() */;
return theRc;
}
OutputPointer_set_Int32(env, outTail, (int)(zTail ? (zTail - (const char *)pBuf) : 0));
}
if( pStmt ){
- NativePointerHolder_set(env, jStmt, pStmt, S3JniClassNames.sqlite3_stmt);
+ NativePointerHolder_set(env, jStmt, pStmt, &S3NphRefs.sqlite3_stmt);
}else{
/* Happens for comments and whitespace */
UNREF_L(jStmt);
}
JDECL(void,1reset_1auto_1extension)(JENV_CSELF){
- MUTEX_ENTER_EXT;
+ MUTEX_ENV_EXT;
while( S3JniGlobal.autoExt.pHead ){
S3JniAutoExtension_free(env, S3JniGlobal.autoExt.pHead);
}
- MUTEX_LEAVE_EXT;
+ MUTEX_EXT_LEAVE;
}
/* sqlite3_result_text/blob() and friends. */
}
JDECL(jint,1shutdown)(JENV_CSELF){
- MUTEX_ENTER_ENV;
+ MUTEX_ENV_ENTER;
while( S3JniGlobal.envCache.aHead ){
S3JniGlobal_env_uncache( S3JniGlobal.envCache.aHead->env );
}
- MUTEX_LEAVE_ENV;
+ MUTEX_ENV_LEAVE;
/* Do not clear S3JniGlobal.jvm: it's legal to call
sqlite3_initialize() again to restart the lib. */
return sqlite3_shutdown();
SO(S3JniEnv);
SO(S3JniHook);
SO(S3JniDb);
- SO(S3JniClassNames);
+ SO(S3NphRefs);
printf("\t(^^^ %u NativePointerHolder subclasses)\n",
- (unsigned)(sizeof(S3JniClassNames) / sizeof(const char *)));
+ (unsigned)NphCache_SIZE);
SO(S3JniGlobal);
SO(S3JniAutoExtension);
SO(S3JniUdf);
printf("Cache info:\n");
- printf("\tNativePointerHolder cache: %u misses, %u hits\n",
- S3JniGlobal.metrics.nphCacheMisses,
- S3JniGlobal.metrics.nphCacheHits);
printf("\tJNIEnv cache %u misses, %u hits\n",
S3JniGlobal.metrics.envCacheMisses,
S3JniGlobal.metrics.envCacheHits);
JNIEXPORT ReturnType JNICALL \
JFuncNameFtsTok(Suffix)
-#define PtrGet_fts5_api(OBJ) NativePointerHolder_get(env,OBJ,S3JniClassNames.fts5_api)
-#define PtrGet_fts5_tokenizer(OBJ) NativePointerHolder_get(env,OBJ,S3JniClassNames.fts5_tokenizer)
-#define PtrGet_Fts5Context(OBJ) NativePointerHolder_get(env,OBJ,S3JniClassNames.Fts5Context)
-#define PtrGet_Fts5Tokenizer(OBJ) NativePointerHolder_get(env,OBJ,S3JniClassNames.Fts5Tokenizer)
+#define PtrGet_fts5_api(OBJ) NativePointerHolder_get(env,OBJ,&S3NphRefs.fts5_api)
+#define PtrGet_fts5_tokenizer(OBJ) NativePointerHolder_get(env,OBJ,&S3NphRefs.fts5_tokenizer)
+#define PtrGet_Fts5Context(OBJ) NativePointerHolder_get(env,OBJ,&S3NphRefs.Fts5Context)
+#define PtrGet_Fts5Tokenizer(OBJ) NativePointerHolder_get(env,OBJ,&S3NphRefs.Fts5Tokenizer)
#define Fts5ExtDecl Fts5ExtensionApi const * const fext = s3jni_ftsext()
/**
}
static inline jobject new_Fts5Context_wrapper(JNIEnv * const env, Fts5Context *sv){
- return new_NativePointerHolder_object(env, S3JniClassNames.Fts5Context, sv);
+ return new_NativePointerHolder_object(env, &S3NphRefs.Fts5Context, sv);
}
static inline jobject new_fts5_api_wrapper(JNIEnv * const env, fts5_api *sv){
- return new_NativePointerHolder_object(env, S3JniClassNames.fts5_api, sv);
+ return new_NativePointerHolder_object(env, &S3NphRefs.fts5_api, sv);
}
/**
static jobject s3jni_getFts5ExensionApi(JNIEnv * const env){
S3JniEnv * const row = S3JniGlobal_env_cache(env);
if( !row->jFtsExt ){
- row->jFtsExt = new_NativePointerHolder_object(env, S3JniClassNames.Fts5ExtensionApi,
+ row->jFtsExt = new_NativePointerHolder_object(env, &S3NphRefs.Fts5ExtensionApi,
s3jni_ftsext());
if(row->jFtsExt) row->jFtsExt = REF_G(row->jFtsExt);
}
/**
Proxy for Fts5ExtensionApi.xTokenize() and fts5_tokenizer.xTokenize()
*/
-static jint s3jni_fts5_xTokenize(JENV_OSELF, const char *zClassName,
+static jint s3jni_fts5_xTokenize(JENV_OSELF, S3NphRef const *pRef,
jint tokFlags, jobject jFcx,
jbyteArray jbaText, jobject jCallback){
Fts5ExtDecl;
s.tok.jba = REF_L(jbaText);
s.tok.zPrev = (const char *)pText;
s.tok.nPrev = (int)nText;
- if( zClassName == S3JniClassNames.Fts5ExtensionApi ){
+ if( pRef == &S3NphRefs.Fts5ExtensionApi ){
rc = fext->xTokenize(PtrGet_Fts5Context(jFcx),
(const char *)pText, (int)nText,
&s, s3jni_xTokenize_xToken);
- }else if( zClassName == S3JniClassNames.fts5_tokenizer ){
+ }else if( pRef == &S3NphRefs.fts5_tokenizer ){
fts5_tokenizer * const pTok = PtrGet_fts5_tokenizer(jSelf);
rc = pTok->xTokenize(PtrGet_Fts5Tokenizer(jFcx), &s, tokFlags,
(const char *)pText, (int)nText,
JDECLFtsXA(jint,xTokenize)(JENV_OSELF,jobject jFcx, jbyteArray jbaText,
jobject jCallback){
- return s3jni_fts5_xTokenize(env, jSelf, S3JniClassNames.Fts5ExtensionApi,
+ return s3jni_fts5_xTokenize(env, jSelf, &S3NphRefs.Fts5ExtensionApi,
0, jFcx, jbaText, jCallback);
}
JDECLFtsTok(jint,xTokenize)(JENV_OSELF,jobject jFcx, jint tokFlags,
jbyteArray jbaText, jobject jCallback){
- return s3jni_fts5_xTokenize(env, jSelf, S3JniClassNames.Fts5Tokenizer,
+ return s3jni_fts5_xTokenize(env, jSelf, &S3NphRefs.Fts5Tokenizer,
tokFlags, jFcx, jbaText, jCallback);
}
JNIEXPORT jboolean JNICALL
Java_org_sqlite_jni_SQLite3Jni_uncacheJniEnv(JENV_CSELF){
int rc;
- MUTEX_ENTER_ENV;
+ MUTEX_ENV_ENTER;
rc = S3JniGlobal_env_uncache(env);
- MUTEX_LEAVE_ENV;
+ MUTEX_ENV_LEAVE;
return rc ? JNI_TRUE : JNI_FALSE;
}