From 45fe10d02b067af9fb26d3215419f00aa9e24444 Mon Sep 17 00:00:00 2001 From: stephan Date: Sun, 30 Jul 2023 10:47:38 +0000 Subject: [PATCH] Internal JNI refacoring to support the pending sqlite3_collation_needed() callback. Correct a bug in the linked-list handling of PerDbStateJni which triggered an assert(). FossilOrigin-Name: 7ac6614e69b03304d09745619ed83f12c7eb775aaf4a636a79289b01642ddd14 --- ext/jni/src/c/sqlite3-jni.c | 179 +++++++++++++++++++++--------------- manifest | 12 +-- manifest.uuid | 2 +- 3 files changed, 113 insertions(+), 80 deletions(-) diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index 66384ef673..1ad16daac0 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -366,7 +366,8 @@ typedef struct PerDbStateJni PerDbStateJni; struct PerDbStateJni { JNIEnv *env; sqlite3 * pDb; - jobject jDb /* the object which was passed to sqlite3_open(_v2)() */; + jobject jDb /* a global ref of the object which was passed to + sqlite3_open(_v2)() */; PerDbStateJni * pNext; PerDbStateJni * pPrev; JniHookState trace; @@ -644,22 +645,29 @@ static void * getNativePointer(JNIEnv * env, jobject pObj, const char *zClassNam /** Extracts the new PerDbStateJni instance from the free-list, or allocates one if needed, associats it with pDb, and returns. - Returns NULL on OOM. + Returns NULL on OOM. pDb MUST be associated with jDb via + setNativePointer(). */ -static PerDbStateJni * PerDbStateJni_alloc(JNIEnv *env, sqlite3 *pDb){ +static PerDbStateJni * PerDbStateJni_alloc(JNIEnv *env, sqlite3 *pDb, jobject jDb){ PerDbStateJni * rv; assert( pDb ); if(S3Global.perDb.aFree){ rv = S3Global.perDb.aFree; + //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)); S3Global.perDb.aFree = rv->pNext; + assert(rv->pNext != rv); + assert(rv->pPrev != rv); + assert(rv->pPrev ? (rv->pPrev!=rv->pNext) : 1); if(rv->pNext){ assert(rv->pNext->pPrev == rv); - assert(rv->pNext == rv->pNext->pPrev); + assert(rv->pPrev ? (rv->pNext == rv->pPrev->pNext) : 1); rv->pNext->pPrev = 0; rv->pNext = 0; } }else{ rv = s3jni_malloc(env, sizeof(PerDbStateJni)); + //MARKER(("state@%p for db allocating for db@%p from heap\n", rv, pDb)); if(rv){ memset(rv, 0, sizeof(PerDbStateJni)); } @@ -671,6 +679,7 @@ static PerDbStateJni * PerDbStateJni_alloc(JNIEnv *env, sqlite3 *pDb){ assert(!rv->pNext->pPrev); rv->pNext->pPrev = rv; } + rv->jDb = REF_G(jDb); rv->pDb = pDb; rv->env = env; } @@ -685,6 +694,10 @@ static void PerDbStateJni_set_aside(PerDbStateJni * const s){ if(s){ JNIEnv * const env = s->env; assert(s->pDb && "Else this object is already in the free-list."); + //MARKER(("state@%p for db@%p setting aside\n", s, s->pDb)); + assert(s->pPrev != s); + assert(s->pNext != s); + assert(s->pPrev ? (s->pPrev!=s->pNext) : 1); if(s->pNext) s->pNext->pPrev = s->pPrev; if(s->pPrev) s->pPrev->pNext = s->pNext; else if(S3Global.perDb.aUsed == s){ @@ -699,7 +712,10 @@ static void PerDbStateJni_set_aside(PerDbStateJni * const s){ BusyHandlerJni_clear(&s->busyHandler); memset(s, 0, sizeof(PerDbStateJni)); s->pNext = S3Global.perDb.aFree; + if(s->pNext) s->pNext->pPrev = s; S3Global.perDb.aFree = s; + //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)); } } @@ -720,14 +736,24 @@ static void PerDbStateJni_dump(PerDbStateJni *s){ true then a new instance will be allocated if no mapping currently exists, else NULL is returned if no mapping is found. + The 3rd and 4th args should only be non-0 for + sqlite3_open(_v2)(). For all other cases, they must be 0, in which + case the db handle will be fished out of the jDb object and NULL is + returned if jDb does not have any associated PerDbStateJni. */ FIXME_THREADING -static PerDbStateJni * PerDbStateJni_for_db(JNIEnv *env, sqlite3 *pDb, int allocIfNeeded){ +static PerDbStateJni * PerDbStateJni_for_db(JNIEnv *env, jobject jDb, sqlite3 *pDb, int allocIfNeeded){ PerDbStateJni * s = S3Global.perDb.aUsed; - for( ; s; s = s->pNext){ + assert(allocIfNeeded ? !!pDb : 1); + if(!allocIfNeeded && !pDb){ + pDb = PtrGet_sqlite3_value(jDb); + } + for( ; pDb && s; s = s->pNext){ if(s->pDb == pDb) return s; } - if(allocIfNeeded) s = PerDbStateJni_alloc(env, pDb); + if(allocIfNeeded){ + s = PerDbStateJni_alloc(env, pDb, jDb); + } return s; } @@ -736,19 +762,19 @@ static PerDbStateJni * PerDbStateJni_for_db(JNIEnv *env, sqlite3 *pDb, int alloc */ FIXME_THREADING static void PerDbStateJni_free_all(void){ - PerDbStateJni * pS = S3Global.perDb.aUsed; + PerDbStateJni * ps = S3Global.perDb.aUsed; PerDbStateJni * pSNext = 0; - for( ; pS; pS = pSNext ){ - pSNext = pS->pNext; - PerDbStateJni_set_aside(pS); + for( ; ps; ps = pSNext ){ + pSNext = ps->pNext; + PerDbStateJni_set_aside(ps); assert(pSNext ? !pSNext->pPrev : 1); } assert( 0==S3Global.perDb.aUsed ); - pS = S3Global.perDb.aFree; + ps = S3Global.perDb.aFree; S3Global.perDb.aFree = 0; pSNext = 0; - for( ; pS; pS = pSNext ){ - pSNext = pS->pNext; + for( ; ps; ps = pSNext ){ + pSNext = ps->pNext; s3jni_free(pSNext); } } @@ -1358,59 +1384,59 @@ JDECL(jint,1bind_1zeroblob64)(JENV_JSELF, jobject jpStmt, } static int s3jni_busy_handler(void* pState, int n){ - PerDbStateJni * const pS = (PerDbStateJni *)pState; + PerDbStateJni * const ps = (PerDbStateJni *)pState; int rc = 0; - if( pS->busyHandler.jObj ){ - JNIEnv * const env = pS->env; - rc = (*env)->CallIntMethod(env, pS->busyHandler.jObj, - pS->busyHandler.jmidxCallback, (jint)n); + if( ps->busyHandler.jObj ){ + JNIEnv * const env = ps->env; + rc = (*env)->CallIntMethod(env, ps->busyHandler.jObj, + ps->busyHandler.jmidxCallback, (jint)n); IFTHREW_CLEAR; } return rc; } JDECL(jint,1busy_1handler)(JENV_JSELF, jobject jDb, jobject jBusy){ - sqlite3 * const pDb = PtrGet_sqlite3(jDb); - PerDbStateJni * const pS = PerDbStateJni_for_db(env, pDb, 1); + PerDbStateJni * const ps = PerDbStateJni_for_db(env, jDb, 0, 0); int rc; - if(!pS) return (jint)SQLITE_NOMEM; + if(!ps) return (jint)SQLITE_NOMEM; if(jBusy){ - if(pS->busyHandler.jObj && - (*env)->IsSameObject(env, pS->busyHandler.jObj, jBusy)){ + if(ps->busyHandler.jObj && + (*env)->IsSameObject(env, ps->busyHandler.jObj, jBusy)){ /* Same object - this is a no-op. */ return 0; } - rc = BusyHandlerJni_init(env, &pS->busyHandler, jBusy); + rc = BusyHandlerJni_init(env, &ps->busyHandler, jBusy); if(rc){ - assert(!pS->busyHandler.jObj); + assert(!ps->busyHandler.jObj); return (jint)rc; } - assert(pS->busyHandler.jObj && pS->busyHandler.klazz); - assert( (*env)->IsSameObject(env, pS->busyHandler.jObj, jBusy) ); + assert(ps->busyHandler.jObj && ps->busyHandler.klazz); + assert( (*env)->IsSameObject(env, ps->busyHandler.jObj, jBusy) ); }else{ - BusyHandlerJni_clear(&pS->busyHandler); + BusyHandlerJni_clear(&ps->busyHandler); } return jBusy - ? sqlite3_busy_handler(pDb, s3jni_busy_handler, pS) - : sqlite3_busy_handler(pDb, 0, 0); + ? sqlite3_busy_handler(ps->pDb, s3jni_busy_handler, ps) + : sqlite3_busy_handler(ps->pDb, 0, 0); } JDECL(jint,1busy_1timeout)(JENV_JSELF, jobject jDb, jint ms){ - sqlite3* const pDb = PtrGet_sqlite3(jDb); - PerDbStateJni * const pS = PerDbStateJni_for_db(env, pDb, 0); - if( pS && pS->busyHandler.jObj ){ - BusyHandlerJni_clear(&pS->busyHandler); + PerDbStateJni * const ps = PerDbStateJni_for_db(env, jDb, 0, 0); + if( ps ){ + if( ps->busyHandler.jObj ){ + BusyHandlerJni_clear(&ps->busyHandler); + } + return sqlite3_busy_timeout(ps->pDb, (int)ms); } - return sqlite3_busy_timeout(pDb, (int)ms); + return SQLITE_MISUSE; } /** Wrapper for sqlite3_close(_v2)(). */ static jint s3jni_close_db(JNIEnv *env, jobject jDb, int version){ - sqlite3 * pDb; int rc = 0; - PerDbStateJni * pS = 0; + PerDbStateJni * ps = 0; assert(version == 1 || version == 2); if(0){ PerDbStateJni * s = S3Global.perDb.aUsed; @@ -1418,12 +1444,11 @@ static jint s3jni_close_db(JNIEnv *env, jobject jDb, int version){ PerDbStateJni_dump(s); } } - pDb = PtrGet_sqlite3(jDb); - if(!pDb) return rc; - pS = PerDbStateJni_for_db(env, pDb, 0); - rc = 1==version ? (jint)sqlite3_close(pDb) : (jint)sqlite3_close_v2(pDb); - if(pS) PerDbStateJni_set_aside(pS) - /* MUST come after close() because of pS->trace. */; + ps = PerDbStateJni_for_db(env, jDb, 0, 0); + if(!ps) return rc; + rc = 1==version ? (jint)sqlite3_close(ps->pDb) : (jint)sqlite3_close_v2(ps->pDb); + if(ps) PerDbStateJni_set_aside(ps) + /* MUST come after close() because of ps->trace. */; setNativePointer(env, jDb, 0, ClassNames.sqlite3); return (jint)rc; } @@ -1536,14 +1561,13 @@ static void s3jni_rollback_hook_impl(void *pP){ static jobject s3jni_commit_rollback_hook(int isCommit, JNIEnv *env,jobject jDb, jobject jHook){ - sqlite3 * const pDb = PtrGet_sqlite3(jDb); - PerDbStateJni * const ps = PerDbStateJni_for_db(env, pDb, 1); + PerDbStateJni * const ps = PerDbStateJni_for_db(env, jDb, 0, 0); jclass klazz; jobject pOld = 0; jmethodID xCallback; JniHookState * const pHook = isCommit ? &ps->commitHook : &ps->rollbackHook; if(!ps){ - s3jni_db_error(pDb, SQLITE_NOMEM, 0); + s3jni_db_error(ps->pDb, SQLITE_NOMEM, 0); return 0; } pOld = pHook->jObj; @@ -1558,8 +1582,8 @@ static jobject s3jni_commit_rollback_hook(int isCommit, JNIEnv *env,jobject jDb, pOld = tmp; } memset(pHook, 0, sizeof(JniHookState)); - if( isCommit ) sqlite3_commit_hook(pDb, 0, 0); - else sqlite3_rollback_hook(pDb, 0, 0); + if( isCommit ) sqlite3_commit_hook(ps->pDb, 0, 0); + else sqlite3_rollback_hook(ps->pDb, 0, 0); return pOld; } klazz = (*env)->GetObjectClass(env, jHook); @@ -1569,14 +1593,14 @@ static jobject s3jni_commit_rollback_hook(int isCommit, JNIEnv *env,jobject jDb, IFTHREW { EXCEPTION_REPORT; EXCEPTION_CLEAR; - s3jni_db_error(pDb, SQLITE_ERROR, + s3jni_db_error(ps->pDb, SQLITE_ERROR, "Cannot not find matching callback on " "hook object."); }else{ pHook->midCallback = xCallback; pHook->jObj = REF_G(jHook); - if( isCommit ) sqlite3_commit_hook(pDb, s3jni_commit_hook_impl, ps); - else sqlite3_rollback_hook(pDb, s3jni_rollback_hook_impl, ps); + if( isCommit ) sqlite3_commit_hook(ps->pDb, s3jni_commit_hook_impl, ps); + else sqlite3_rollback_hook(ps->pDb, s3jni_rollback_hook_impl, ps); if(pOld){ jobject tmp = REF_L(pOld); UNREF_G(pOld); @@ -1729,27 +1753,39 @@ JDECL(jlong,1last_1insert_1rowid)(JENV_JSELF, jobject jpDb){ return (jlong)sqlite3_last_insert_rowid(PtrGet_sqlite3(jpDb)); } +static int s3jni_open_post(JNIEnv *env, sqlite3 **ppDb, jobject jDb, int theRc){ + if(1 && *ppDb){ + PerDbStateJni * const s = PerDbStateJni_for_db(env, jDb, *ppDb, 1); + if(!s && 0==theRc){ + sqlite3_close(*ppDb); + *ppDb = 0; + theRc = SQLITE_NOMEM; + } + } + setNativePointer(env, jDb, *ppDb, ClassNames.sqlite3); + return theRc; +} -JDECL(jint,1open)(JENV_JSELF, jstring strName, jobject ppOut){ +JDECL(jint,1open)(JENV_JSELF, jstring strName, jobject jOut){ sqlite3 * pOut = 0; const char *zName = strName ? JSTR_TOC(strName) : 0; int nrc = sqlite3_open(zName, &pOut); //MARKER(("env=%p, *env=%p\n", env, *env)); - setNativePointer(env, ppOut, pOut, ClassNames.sqlite3); + nrc = s3jni_open_post(env, &pOut, jOut, nrc); assert(nrc==0 ? pOut!=0 : 1); JSTR_RELEASE(strName, zName); return (jint)nrc; } JDECL(jint,1open_1v2)(JENV_JSELF, jstring strName, - jobject ppOut, jint flags, jstring strVfs){ + jobject jOut, jint flags, jstring strVfs){ sqlite3 * pOut = 0; const char *zName = strName ? JSTR_TOC(strName) : 0; const char *zVfs = strVfs ? JSTR_TOC(strVfs) : 0; int nrc = sqlite3_open_v2(zName, &pOut, (int)flags, zVfs); /*MARKER(("zName=%s, zVfs=%s, pOut=%p, flags=%d, nrc=%d\n", zName, zVfs, pOut, (int)flags, nrc));*/ - setNativePointer(env, ppOut, pOut, ClassNames.sqlite3); + nrc = s3jni_open_post(env, &pOut, jOut, nrc); assert(nrc==0 ? pOut!=0 : 1); JSTR_RELEASE(strName, zName); JSTR_RELEASE(strVfs, zVfs); @@ -1820,8 +1856,7 @@ static int s3jni_progress_handler_impl(void *pP){ } JDECL(void,1progress_1handler)(JENV_JSELF,jobject jDb, jint n, jobject jProgress){ - sqlite3 * const pDb = PtrGet_sqlite3(jDb); - PerDbStateJni * ps = PerDbStateJni_for_db(env, pDb, 1); + PerDbStateJni * ps = PerDbStateJni_for_db(env, jDb, 0, 0); jclass klazz; jmethodID xCallback; if( n<1 || !jProgress ){ @@ -1829,25 +1864,25 @@ JDECL(void,1progress_1handler)(JENV_JSELF,jobject jDb, jint n, jobject jProgress UNREF_G(ps->progress.jObj); memset(&ps->progress, 0, sizeof(ps->progress)); } - sqlite3_progress_handler(pDb, 0, 0, 0); + sqlite3_progress_handler(ps->pDb, 0, 0, 0); return; } if(!ps){ - s3jni_db_error(pDb, SQLITE_NOMEM, 0); + s3jni_db_error(ps->pDb, SQLITE_NOMEM, 0); return; } klazz = (*env)->GetObjectClass(env, jProgress); xCallback = (*env)->GetMethodID(env, klazz, "xCallback", "()I"); IFTHREW { EXCEPTION_CLEAR; - s3jni_db_error(pDb, SQLITE_ERROR, + s3jni_db_error(ps->pDb, SQLITE_ERROR, "Cannot not find matching xCallback() on " "ProgressHandler object."); }else{ UNREF_G(ps->progress.jObj); ps->progress.midCallback = xCallback; ps->progress.jObj = REF_G(jProgress); - sqlite3_progress_handler(pDb, (int)n, s3jni_progress_handler_impl, ps); + sqlite3_progress_handler(ps->pDb, (int)n, s3jni_progress_handler_impl, ps); } } @@ -2081,15 +2116,14 @@ static int s3jni_trace_impl(unsigned traceflag, void *pC, void *pP, void *pX){ } JDECL(jint,1trace_1v2)(JENV_JSELF,jobject jDb, jint traceMask, jobject jTracer){ - sqlite3 * const pDb = PtrGet_sqlite3(jDb); - PerDbStateJni * const ps = PerDbStateJni_for_db(env, pDb, 1); + PerDbStateJni * const ps = PerDbStateJni_for_db(env, jDb, 0, 0); jclass klazz; if( !traceMask || !jTracer ){ if(ps){ UNREF_G(ps->trace.jObj); memset(&ps->trace, 0, sizeof(ps->trace)); } - return (jint)sqlite3_trace_v2(pDb, 0, 0, 0); + return (jint)sqlite3_trace_v2(ps->pDb, 0, 0, 0); } if(!ps) return SQLITE_NOMEM; klazz = (*env)->GetObjectClass(env, jTracer); @@ -2097,11 +2131,11 @@ JDECL(jint,1trace_1v2)(JENV_JSELF,jobject jDb, jint traceMask, jobject jTracer){ "(IJLjava/lang/Object;)I"); IFTHREW { EXCEPTION_CLEAR; - return s3jni_db_error(pDb, SQLITE_ERROR, + return s3jni_db_error(ps->pDb, SQLITE_ERROR, "Cannot not find matching xCallback() on Tracer object."); } ps->trace.jObj = REF_G(jTracer); - return sqlite3_trace_v2(pDb, (unsigned)traceMask, s3jni_trace_impl, ps); + return sqlite3_trace_v2(ps->pDb, (unsigned)traceMask, s3jni_trace_impl, ps); } static void s3jni_update_hook_impl(void * pState, int opId, const char *zDb, @@ -2133,14 +2167,13 @@ static void s3jni_update_hook_impl(void * pState, int opId, const char *zDb, JDECL(jobject,1update_1hook)(JENV_JSELF, jobject jDb, jobject jHook){ - sqlite3 * const pDb = PtrGet_sqlite3(jDb); - PerDbStateJni * const ps = PerDbStateJni_for_db(env, pDb, 1); + PerDbStateJni * const ps = PerDbStateJni_for_db(env, jDb, 0, 0); jclass klazz; jobject pOld = 0; jmethodID xCallback; JniHookState * const pHook = &ps->updateHook; if(!ps){ - s3jni_db_error(pDb, SQLITE_NOMEM, 0); + s3jni_db_error(ps->pDb, SQLITE_NOMEM, 0); return 0; } pOld = pHook->jObj; @@ -2155,7 +2188,7 @@ JDECL(jobject,1update_1hook)(JENV_JSELF, jobject jDb, jobject jHook){ pOld = tmp; } memset(pHook, 0, sizeof(JniHookState)); - sqlite3_update_hook(pDb, 0, 0); + sqlite3_update_hook(ps->pDb, 0, 0); return pOld; } klazz = (*env)->GetObjectClass(env, jHook); @@ -2163,13 +2196,13 @@ JDECL(jobject,1update_1hook)(JENV_JSELF, jobject jDb, jobject jHook){ "(ILjava/lang/String;Ljava/lang/String;J)V"); IFTHREW { EXCEPTION_CLEAR; - s3jni_db_error(pDb, SQLITE_ERROR, + s3jni_db_error(ps->pDb, SQLITE_ERROR, "Cannot not find matching callback on " "update hook object."); }else{ pHook->midCallback = xCallback; pHook->jObj = REF_G(jHook); - sqlite3_update_hook(pDb, s3jni_update_hook_impl, ps); + sqlite3_update_hook(ps->pDb, s3jni_update_hook_impl, ps); if(pOld){ jobject tmp = REF_L(pOld); UNREF_G(pOld); diff --git a/manifest b/manifest index 131b57da31..4542011eac 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Incremental\scheckin\sto\sminimize\sthe\sdiff\swhile\snarrowing\sin\son\san\sassertion\scaused\sby\srefactoring. -D 2023-07-30T09:45:54.025 +C Internal\sJNI\srefacoring\sto\ssupport\sthe\spending\ssqlite3_collation_needed()\scallback.\sCorrect\sa\sbug\sin\sthe\slinked-list\shandling\sof\sPerDbStateJni\swhich\striggered\san\sassert(). +D 2023-07-30T10:47:38.755 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -232,7 +232,7 @@ F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282 F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8 F ext/jni/GNUmakefile 56a014dbff9516774d895ec1ae9df0ed442765b556f79a0fc0b5bc438217200d F ext/jni/README.md c0e6e80935e7761acead89b69c87765b23a6bcb2858c321c3d05681fd338292a -F ext/jni/src/c/sqlite3-jni.c 5b5631520dd2e3ae6890bcbbee2aad3d7b5c404e96ae826b661e1105d2d2a69d +F ext/jni/src/c/sqlite3-jni.c 57db39bd2443435764777a1e43e2f8e356b8c411ee2649ad08df4b32087cbe80 F ext/jni/src/c/sqlite3-jni.h 85345dd3c970b539f1de4e6ad59c245fa6e80ca775a498ab1ed3d67f8615ce34 F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c F ext/jni/src/org/sqlite/jni/Collation.java 8dffbb00938007ad0967b2ab424d3c908413af1bbd3d212b9c9899910f1218d1 @@ -2071,8 +2071,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 5e592ed2dfc89225fff3a1c76509adc799a238282413984e0c4b32af18525d18 -R a4ee8dd84c4c810bd2a0b503fc8278d5 +P 2d7a91b1396d87852f1153ab7af7385514a9537cb64ba3bbd0faba2d28704214 +R 5bff367529a1829789141e745a6b193a U stephan -Z f4150e59d6c4033aef1bd32347c40f57 +Z a4b019fdb819701e83942a71127183e7 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index be036f7c53..b867e2523a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2d7a91b1396d87852f1153ab7af7385514a9537cb64ba3bbd0faba2d28704214 \ No newline at end of file +7ac6614e69b03304d09745619ed83f12c7eb775aaf4a636a79289b01642ddd14 \ No newline at end of file