]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
More work on the JNI-specific mutexes. Rework the NativePointerHolder cache lookup...
authorstephan <stephan@noemail.net>
Mon, 14 Aug 2023 13:27:40 +0000 (13:27 +0000)
committerstephan <stephan@noemail.net>
Mon, 14 Aug 2023 13:27:40 +0000 (13:27 +0000)
FossilOrigin-Name: c84ded0e59aea4861d72b53b4b40cf580747c0f6ca58c334a996f1a825276cb5

ext/jni/src/c/sqlite3-jni.c
ext/jni/src/org/sqlite/jni/SQLite3Jni.java
manifest
manifest.uuid

index 129a601210957855d8cf03669231a3a15439c478..d33329575d8ccb5f52191e6621edd2c76b0fa195 100644 (file)
 # 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;
@@ -209,47 +209,55 @@ static inline void delete_local_ref(JNIEnv * const env, jobject const v){
 #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)). */
@@ -321,22 +329,20 @@ enum {
      (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 */;
@@ -388,12 +394,12 @@ struct S3JniEnv {
   /**
      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));
 }
 
 /*
@@ -507,8 +513,6 @@ static struct {
                              current JNIEnv object. */;
   } perDb;
   struct {
-    unsigned nphCacheHits;
-    unsigned nphCacheMisses;
     unsigned envCacheHits;
     unsigned envCacheMisses;
     unsigned nMutexEnv       /* number of times envCache.mutex was entered */;
@@ -556,7 +560,7 @@ static struct {
        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;
@@ -565,29 +569,29 @@ static struct {
   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
@@ -596,7 +600,7 @@ static struct {
   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 )
@@ -626,12 +630,12 @@ static void * s3jni_malloc(JNIEnv * const env, size_t n){
 */
 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;
     }
   }
@@ -684,7 +688,7 @@ static S3JniEnv * S3JniGlobal_env_cache(JNIEnv * const env){
       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;
 }
 
@@ -975,18 +979,18 @@ static void S3JniDb_set_aside(S3JniDb * const s){
 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;
 }
 
 /**
@@ -1026,7 +1030,7 @@ static int S3JniGlobal_env_uncache(JNIEnv * const env){
   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;
@@ -1037,10 +1041,8 @@ static int S3JniGlobal_env_uncache(JNIEnv * const env){
 
 /**
    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.
@@ -1051,7 +1053,7 @@ static int S3JniGlobal_env_uncache(JNIEnv * const env){
    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:
 
@@ -1072,43 +1074,16 @@ static S3JniNphCache * S3JniGlobal_nph_cache(JNIEnv * const env, const char *zCl
      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;
 }
 
 /**
@@ -1127,11 +1102,10 @@ static jfieldID NativePointerHolder_getField(JNIEnv * const env, jclass klazz){
    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{
@@ -1141,7 +1115,6 @@ static void NativePointerHolder_set(JNIEnv * env, jobject ppOut, const void * p,
     if(pCache){
       assert(pCache->klazz);
       assert(!pCache->fidValue);
-      assert(zClassName == pCache->zClassName);
       pCache->fidValue = setter;
     }
   }
@@ -1154,11 +1127,11 @@ static void NativePointerHolder_set(JNIEnv * env, jobject ppOut, const void * p,
    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{
@@ -1167,7 +1140,6 @@ static void * NativePointerHolder_get(JNIEnv * env, jobject pObj, const char *zC
       getter = NativePointerHolder_getField(env, klazz);
       if(pCache){
         assert(pCache->klazz);
-        assert(zClassName == pCache->zClassName);
         pCache->fidValue = getter;
       }
     }
@@ -1188,7 +1160,7 @@ static void * NativePointerHolder_get(JNIEnv * env, jobject pObj, const char *zC
 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));
@@ -1221,6 +1193,7 @@ static S3JniDb * S3JniDb_alloc(JNIEnv * const env, sqlite3 *pDb,
     rv->pDb = pDb;
     rv->env = env;
   }
+  MUTEX_PDB_LEAVE;
   return rv;
 }
 
@@ -1251,7 +1224,7 @@ static void S3JniDb_dump(S3JniDb *s){
 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 );
@@ -1262,7 +1235,7 @@ static S3JniDb * S3JniDb_for_db(JNIEnv * const env, jobject jDb, sqlite3 *pDb){
         break;
       }
     }
-    MUTEX_LEAVE_PDB;
+    MUTEX_PDB_LEAVE;
   }
   return s;
 }
@@ -1341,8 +1314,8 @@ static int udf_setAggregateContext(JNIEnv * env, jobject jCx,
   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);
@@ -1375,7 +1348,7 @@ static int udf_setAggregateContext(JNIEnv * env, jobject jCx,
 
 /**
    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,
@@ -1385,12 +1358,11 @@ static int udf_setAggregateContext(JNIEnv * env, jobject jCx,
    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{
@@ -1410,7 +1382,7 @@ static void setupOutputPointer(JNIEnv * const env, const char *zClassName,
    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");
 }
@@ -1419,7 +1391,7 @@ static void OutputPointer_set_Int32(JNIEnv * const env, jobject const jOut, int
    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");
 }
@@ -1427,7 +1399,7 @@ static void OutputPointer_set_Int64(JNIEnv * const env, jobject const jOut, jlon
 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");
@@ -1436,7 +1408,7 @@ static void OutputPointer_set_sqlite3(JNIEnv * const env, jobject const jOut,
 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");
@@ -1449,7 +1421,7 @@ static void OutputPointer_set_sqlite3_stmt(JNIEnv * const env, jobject const jOu
 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");
@@ -1461,7 +1433,7 @@ static void OutputPointer_set_ByteArray(JNIEnv * const env, jobject const jOut,
 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");
@@ -1587,28 +1559,26 @@ static void ResultJavaVal_finalizer(void *v){
    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;
@@ -1618,21 +1588,21 @@ static jobject new_NativePointerHolder_object(JNIEnv * const env, const char *zC
   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 {
@@ -1938,7 +1908,7 @@ static int s3jni_run_java_auto_extensions(sqlite3 *pDb, const char **pzErr,
   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 {
@@ -1964,7 +1934,7 @@ JDECL(jint,1auto_1extension)(JENV_OSELF, jobject jAutoExt){
   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 );
   }
@@ -1975,7 +1945,7 @@ JDECL(jint,1auto_1extension)(JENV_OSELF, jobject jAutoExt){
     }
   }
   ax = S3JniAutoExtension_alloc(env, jAutoExt);
-  MUTEX_LEAVE_EXT;
+  MUTEX_EXT_LEAVE;
   return ax ? 0 : SQLITE_NOMEM;
 }
 
@@ -2117,7 +2087,7 @@ FIXME_THREADING(autoExt)
 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);
@@ -2125,7 +2095,7 @@ JDECL(jboolean,1cancel_1auto_1extension)(JENV_CSELF, jobject jAutoExt){
       break;
     }
   }
-  MUTEX_LEAVE_EXT;
+  MUTEX_EXT_LEAVE;
   return rc;
 }
 
@@ -2140,11 +2110,11 @@ static jint s3jni_close_db(JNIEnv * const env, jobject jDb, int version){
   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;
 }
@@ -2647,7 +2617,7 @@ JDECL(jint,1finalize)(JENV_CSELF, jobject jpStmt){
   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;
 }
@@ -2683,7 +2653,7 @@ static int s3jni_open_pre(JNIEnv * const env, S3JniEnv **jc,
        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;
@@ -2701,9 +2671,7 @@ static int s3jni_open_pre(JNIEnv * const env, S3JniEnv **jc,
     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;
@@ -2712,9 +2680,9 @@ static int s3jni_open_pre(JNIEnv * const env, S3JniEnv **jc,
   }
   //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;
 }
@@ -2739,18 +2707,18 @@ static int s3jni_open_post(JNIEnv * const env, S3JniDb * ps,
     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;
 }
 
@@ -2848,7 +2816,7 @@ end:
       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);
@@ -2937,11 +2905,11 @@ JDECL(jint,1reset)(JENV_CSELF, jobject jpStmt){
 }
 
 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. */
@@ -3244,11 +3212,11 @@ JDECL(jint,1strlike)(JENV_CSELF, jbyteArray baG, jbyteArray baT, jint escChar){
 }
 
 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();
@@ -3539,16 +3507,13 @@ JDECL(void,1do_1something_1for_1developer)(JENV_CSELF){
   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);
@@ -3588,10 +3553,10 @@ JDECL(void,1do_1something_1for_1developer)(JENV_CSELF){
   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()
 
 /**
@@ -3655,10 +3620,10 @@ static inline Fts5ExtensionApi const * s3jni_ftsext(void){
 }
 
 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);
 }
 
 /**
@@ -3668,7 +3633,7 @@ static inline jobject new_fts5_api_wrapper(JNIEnv * const env, 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);
   }
@@ -4113,7 +4078,7 @@ static int s3jni_xTokenize_xToken(void *p, int tFlags, const char* z,
 /**
    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;
@@ -4140,11 +4105,11 @@ static jint s3jni_fts5_xTokenize(JENV_OSELF, const char *zClassName,
   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,
@@ -4162,13 +4127,13 @@ static jint s3jni_fts5_xTokenize(JENV_OSELF, const char *zClassName,
 
 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);
 }
 
@@ -4396,9 +4361,9 @@ Java_org_sqlite_jni_tester_SQLTester_installCustomExtensions(JENV_CSELF){
 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;
 }
 
index dbd2e4bae7015127f830a0300f5100a7310e5db7..073a79835f5963bc2705e271f54280c1361008af 100644 (file)
@@ -178,8 +178,9 @@ public final class SQLite3Jni {
        not have access to the sqlite3_api object which native
        auto-extensions do.
 
-     - If an auto-extension opens a db, opening will fail with SQLITE_BUSY.
-       The alternative would be endless recursion into the auto-extension.
+     - If an auto-extension opens a db from the same thread, opening
+       will fail with SQLITE_BUSY.  The alternative would be endless
+       recursion into the auto-extension.
 
      - The list of auto-extensions must not be manipulated from within
        an auto-extension. Auto extensions can neither be added,
index 8673db6eeb169e50e9f75eba2c1b3887821fa818..8cb273b6f58b1d30dca78e119a86b5f035c59032 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C JNI-internal\sdocs\sand\sremoval\sof\sobsolete\scode.
-D 2023-08-14T08:28:46.677
+C More\swork\son\sthe\sJNI-specific\smutexes.\sRework\sthe\sNativePointerHolder\scache\slookup\sto\sbe\sslightly\ssimpler\sand\sO(1)\sinstead\sof\sO(N).
+D 2023-08-14T13:27:40.885
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -234,7 +234,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3
 F ext/jni/GNUmakefile a9e11b92e620058558cbc1a2d49f8ec53c78d6a989b9db0b7d0b649b9f174881
 F ext/jni/README.md 7a614a2fa6c561205f7a53fd8626cf93a7b5711ff454fc1814517f796df398eb
 F ext/jni/jar-dist.make f90a553203a57934bf275bed86479485135a52f48ac5c1cfe6499ae07b0b35a4
-F ext/jni/src/c/sqlite3-jni.c 1bc1cbaf075065793f83cf5bfba631216ced48d7beae0768ebd838e923e7e590
+F ext/jni/src/c/sqlite3-jni.c 0ca77c27d05b677191f105bc6f8570c916b78991a809d44566c60cfc16b50612
 F ext/jni/src/c/sqlite3-jni.h f10d2f38720687c70ecdd5e44f6e8db98efee2caa05fc86b2d9e0c76e6cc0a18
 F ext/jni/src/org/sqlite/jni/Authorizer.java 1308988f7f40579ea0e4deeaec3c6be971630566bd021c31367fe3f5140db892
 F ext/jni/src/org/sqlite/jni/AutoExtension.java 18e83f6f463e306df60b2dceb65247d32af1f78af4bbbae9155411a8c6cdb093
@@ -254,7 +254,7 @@ F ext/jni/src/org/sqlite/jni/ProgressHandler.java 6f62053a828a572de809828b1ee495
 F ext/jni/src/org/sqlite/jni/ResultCode.java ba701f20213a5f259e94cfbfdd36eb7ac7ce7797f2c6c7fca2004ff12ce20f86
 F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564
 F ext/jni/src/org/sqlite/jni/SQLFunction.java 09ce81c1c637e31c3a830d4c859cce95d65f5e02ff45f8bd1985b3479381bc46
-F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 5eeba0b1a00fb34bc93fe60186f6032fcf4d568fc5868d70029883d3d07cc306
+F ext/jni/src/org/sqlite/jni/SQLite3Jni.java cd0627b5317435f9a6c72247915f9e32d6e8c225fd6f0db2c66b4a7f0b4e5601
 F ext/jni/src/org/sqlite/jni/Tester1.java 368e836d943d9e882d2a217d0f582ed4141d164f174bebc50715acd57549a09b
 F ext/jni/src/org/sqlite/jni/TesterFts5.java 59e22dd24af033ea8827d36225a2f3297908fb6af8818ead8850c6c6847557b1
 F ext/jni/src/org/sqlite/jni/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d
@@ -2091,8 +2091,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 911e4fc5aaf9478214095a65f74af3ebca883922c36cf7a8d911116c42cf9de8
-R c6d49900ed87c14449d9c08a36536c71
+P b62d93258b6a661f3a9b61468b3b641c14faf2d2196f78aca95fe14de43c9444
+R 640b629cd539e67d64418aa6a08729eb
 U stephan
-Z 09908deaf1ed6a1fae2d9bef97861a7c
+Z db03beab64a32e82d4161306677f6282
 # Remove this line to create a well-formed Fossil manifest.
index 7a0d99b2d33f5fa463ee7afbd2adcb7252664d28..0f159ac8d90747398f588302820ae9ceadc2be72 100644 (file)
@@ -1 +1 @@
-b62d93258b6a661f3a9b61468b3b641c14faf2d2196f78aca95fe14de43c9444
\ No newline at end of file
+c84ded0e59aea4861d72b53b4b40cf580747c0f6ca58c334a996f1a825276cb5
\ No newline at end of file