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

Others may be added in the future. It returns SQLITE_MISUSE if given an argument it does not handle. + +

Note that sqlite3_config() is not threadsafe with regards to + the rest of the library. This must not be called when any other + library APIs are being called. + */ public static native int sqlite3_config(int op); @@ -504,8 +509,13 @@ public final class SQLite3Jni { logger. If installation of a logger fails, any previous logger is retained. - If not built with SQLITE_ENABLE_SQLLOG defined, this returns +

If not built with SQLITE_ENABLE_SQLLOG defined, this returns SQLITE_MISUSE. + +

Note that sqlite3_config() is not threadsafe with regards to + the rest of the library. This must not be called when any other + library APIs are being called. + */ public static native int sqlite3_config( @Nullable ConfigSqllogCallback logger ); diff --git a/manifest b/manifest index db9eb67524..cd32317d2a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sthe\sJava\sBusyHandler.xDestroy()\smethod\s-\sit\sshould\snot\shave\shad\sone.\sEliminate\sthe\slast\sof\sthe\spotentially-significant\sMUTF-8\scases. -D 2023-08-26T10:51:19.217 +C JNI\sinternal\scleanups\sand\sdocs. +D 2023-08-26T11:57:34.208 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -236,7 +236,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3 F ext/jni/GNUmakefile b28f8b304ef97db8250857cb463aea1b329bfcb584a2902d4c1a490a831e2c9d F ext/jni/README.md 1332b1fa27918bd5d9ca2d0d4f3ac3a6ab86b9e3699dc5bfe32904a027f3d2a9 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa -F ext/jni/src/c/sqlite3-jni.c 86a9f9182e8c0b1f058196ac4017f3290b948bcfbea1bc55198bdd0ad10a2ea1 +F ext/jni/src/c/sqlite3-jni.c e914d5ec2d7a80a2735d777b4309c1bb0adc721be63abed0b9927a3880008f9b F ext/jni/src/c/sqlite3-jni.h 2745c4abd0933a4e8cc48989fffbad3936b4eaada64cce9ce11453dcd30e4184 F ext/jni/src/org/sqlite/jni/AggregateFunction.java e0aac6ccae05702f8ee779820570866a2760aaa57a73135c57c8d3580bef52d5 F ext/jni/src/org/sqlite/jni/AuthorizerCallback.java c374bb76409cce7a0bdba94877706b59ac6127fa5d9e6af3e8058c99ce99c030 @@ -262,7 +262,7 @@ F ext/jni/src/org/sqlite/jni/ResultCode.java ba701f20213a5f259e94cfbfdd36eb7ac7c F ext/jni/src/org/sqlite/jni/RollbackHookCallback.java be7f7a26d1102fb514d835e11198d51302af8053d97188bfb2e34c2133208568 F ext/jni/src/org/sqlite/jni/SQLFunction.java d060f302b2cc4cf7a4f5a6b2d36458a2e6fc9648374b5d09c36a43665af41207 F ext/jni/src/org/sqlite/jni/SQLite3CallbackProxy.java 13c4ea6f35871261eba63fa4117715515e0beecbdebfb879ec5b1f340ed36904 -F ext/jni/src/org/sqlite/jni/SQLite3Jni.java cb3040fcfe35199bb10b4bca2cc541ca383563f85c9b460412c3bd15f413ae23 +F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 4be23360d93011d80676bebb1f21f7da0fc4ab637a6d138c8c35bbb2f764b19d F ext/jni/src/org/sqlite/jni/ScalarFunction.java 21301a947e49f0dd9c682dfe2cc8a6518226c837253dd791cd512f847eeca52c F ext/jni/src/org/sqlite/jni/Tester1.java 2921142fff8cd5a09d1cee30853457926dc63e647df9a687265bb4e678bc9570 F ext/jni/src/org/sqlite/jni/TesterFts5.java 6f135c60e24c89e8eecb9fe61dde0f3bb2906de668ca6c9186bcf34bdaf94629 @@ -2103,8 +2103,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P f2af7bbf493fe28d92fc9c77425f8bb9d48c02af9a5eabceb0365c705651e114 -R 0a5c5021d2a5ccca7e44db0ac1e86f8f +P c852f1ebbde273c3d28fe5aff0bf73cfc06b41dd371a94d7520536dc7a1dbcc1 +R e2cc30a4c5c5fdac12de199e721e1eae U stephan -Z 3f70be94b4b4f3d48d8c6e932937aea1 +Z afcbdc6516d9f37dfcef349abedaeb15 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 8ec48b7eeb..d29f07c1cc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c852f1ebbde273c3d28fe5aff0bf73cfc06b41dd371a94d7520536dc7a1dbcc1 \ No newline at end of file +b7b26bfb4f86e0b8aaabab258ccb0713737ffd4ecd3156d6a83a4f9a1d25edf6 \ No newline at end of file