1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-30 19:03:16 +03:00

Re-frame the incongruous SQLite3Jni.uncacheThread() API as sqlite3_java_uncache_thread().

FossilOrigin-Name: 7232b033954fae40df3db43e489e0e5a703c03308f500a1ae36fd9d707632d7f
This commit is contained in:
stephan
2023-08-24 22:28:44 +00:00
parent 70dcc2822d
commit 3401736694
6 changed files with 86 additions and 68 deletions

View File

@ -547,48 +547,49 @@ static void s3jni_incr( volatile unsigned int * const p ){
#endif #endif
/* Helpers for working with specific mutexes. */ /* Helpers for working with specific mutexes. */
#define S3JniMutex_Env_assertLocked \ #define S3JniMutex_Env_assertLocked \
assert( 0 != SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" ) assert( 0 != SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
#define S3JniMutex_Env_assertLocker \ #define S3JniMutex_Env_assertLocker \
assert( (env) == SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" ) assert( (env) == SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
#define S3JniMutex_Env_assertNotLocker \ #define S3JniMutex_Env_assertNotLocker \
assert( (env) != SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" ) assert( (env) != SJG.envCache.locker && "Misuse of S3JniGlobal.envCache.mutex" )
#define S3JniMutex_Env_enter \ #define S3JniMutex_Env_enter \
S3JniMutex_Env_assertNotLocker; \ S3JniMutex_Env_assertNotLocker; \
/*MARKER(("Entering ENV mutex@%p %s.\n", env));*/ \ /*MARKER(("Entering ENV mutex@%p %s.\n", env));*/ \
sqlite3_mutex_enter( SJG.envCache.mutex ); \ sqlite3_mutex_enter( SJG.envCache.mutex ); \
++SJG.metrics.nMutexEnv; \ ++SJG.metrics.nMutexEnv; \
SJG.envCache.locker = env SJG.envCache.locker = env
#define S3JniMutex_Env_leave \ #define S3JniMutex_Env_leave \
/*MARKER(("Leaving ENV mutex @%p %s.\n", env));*/ \ /*MARKER(("Leaving ENV mutex @%p %s.\n", env));*/ \
S3JniMutex_Env_assertLocker; \ S3JniMutex_Env_assertLocker; \
SJG.envCache.locker = 0; \ SJG.envCache.locker = 0; \
sqlite3_mutex_leave( SJG.envCache.mutex ) sqlite3_mutex_leave( SJG.envCache.mutex )
#define S3JniMutex_Ext_enter \ #define S3JniMutex_Ext_enter \
/*MARKER(("Entering autoExt mutex@%p %s.\n", env));*/ \ /*MARKER(("Entering autoExt mutex@%p %s.\n", env));*/ \
sqlite3_mutex_enter( SJG.autoExt.mutex ); \ sqlite3_mutex_enter( SJG.autoExt.mutex ); \
++SJG.metrics.nMutexAutoExt ++SJG.metrics.nMutexAutoExt
#define S3JniMutex_Ext_leave \ #define S3JniMutex_Ext_leave \
/*MARKER(("Leaving autoExt mutex@%p %s.\n", env));*/ \ /*MARKER(("Leaving autoExt mutex@%p %s.\n", env));*/ \
sqlite3_mutex_leave( SJG.autoExt.mutex ) sqlite3_mutex_leave( SJG.autoExt.mutex )
#define S3JniMutex_Nph_enter \ #define S3JniMutex_Nph_enter \
S3JniMutex_Env_assertNotLocker; \ S3JniMutex_Env_assertNotLocker; \
/*MARKER(("Entering NPH mutex@%p %s.\n", env));*/ \ /*MARKER(("Entering NPH mutex@%p %s.\n", env));*/ \
sqlite3_mutex_enter( SJG.envCache.mutex ); \ sqlite3_mutex_enter( SJG.envCache.mutex ); \
++SJG.metrics.nMutexEnv2; \ ++SJG.metrics.nMutexEnv2; \
SJG.envCache.locker = env SJG.envCache.locker = env
#define S3JniMutex_Nph_leave \ #define S3JniMutex_Nph_leave \
/*MARKER(("Leaving NPH mutex @%p %s.\n", env));*/ \ /*MARKER(("Leaving NPH mutex @%p %s.\n", env));*/ \
S3JniMutex_Env_assertLocker; \ S3JniMutex_Env_assertLocker; \
SJG.envCache.locker = 0; \ SJG.envCache.locker = 0; \
sqlite3_mutex_leave( SJG.envCache.mutex ) sqlite3_mutex_leave( SJG.envCache.mutex )
#define S3JniMutex_Pdb_enter \ #define S3JniMutex_S3JniDb_enter \
/*MARKER(("Entering PerDb mutex@%p %s.\n", env));*/ \
sqlite3_mutex_enter( SJG.perDb.mutex ); \ sqlite3_mutex_enter( SJG.perDb.mutex ); \
assert( 0==SJG.perDb.locker ); \
++SJG.metrics.nMutexPerDb; \ ++SJG.metrics.nMutexPerDb; \
SJG.perDb.locker = env; SJG.perDb.locker = env;
#define S3JniMutex_Pdb_leave \ #define S3JniMutex_S3JniDb_leave \
/*MARKER(("Leaving PerDb mutex@%p %s.\n", env));*/ \ /*MARKER(("Leaving PerDb mutex@%p %s.\n", env));*/ \
assert( env == SJG.perDb.locker ); \
SJG.perDb.locker = 0; \ SJG.perDb.locker = 0; \
sqlite3_mutex_leave( SJG.perDb.mutex ) sqlite3_mutex_leave( SJG.perDb.mutex )
@ -890,7 +891,7 @@ static void s3jni_call_xDestroy(JNIEnv * const env, jobject jObj){
** references. ** references.
*/ */
static void S3JniHook_unref(JNIEnv * const env, S3JniHook * const s, int doXDestroy){ static void S3JniHook_unref(JNIEnv * const env, S3JniHook * const s, int doXDestroy){
if(doXDestroy && s->jObj){ if( doXDestroy && s->jObj ){
s3jni_call_xDestroy(env, s->jObj); s3jni_call_xDestroy(env, s->jObj);
} }
UNREF_G(s->jObj); UNREF_G(s->jObj);
@ -900,9 +901,9 @@ static void S3JniHook_unref(JNIEnv * const env, S3JniHook * const s, int doXDest
/* /*
** Clears s's state and moves it to the free-list. ** Clears s's state and moves it to the free-list.
*/ */
static void S3JniDb_set_aside(JNIEnv * env, S3JniDb * const s){ static void S3JniDb_set_aside_unlocked(JNIEnv * env, S3JniDb * const s){
if(s){ if( s ){
S3JniMutex_Pdb_enter; assert( S3JniGlobal.perDb.locker == env );
assert(s->pPrev != s); assert(s->pPrev != s);
assert(s->pNext != s); assert(s->pNext != s);
assert(s->pPrev ? (s->pPrev!=s->pNext) : 1); assert(s->pPrev ? (s->pPrev!=s->pNext) : 1);
@ -932,7 +933,13 @@ static void S3JniDb_set_aside(JNIEnv * env, S3JniDb * const s){
s->pNext = SJG.perDb.aFree; s->pNext = SJG.perDb.aFree;
if(s->pNext) s->pNext->pPrev = s; if(s->pNext) s->pNext->pPrev = s;
SJG.perDb.aFree = s; SJG.perDb.aFree = s;
S3JniMutex_Pdb_leave; }
}
static void S3JniDb_set_aside(JNIEnv * env, S3JniDb * const s){
if( s ){
S3JniMutex_S3JniDb_enter;
S3JniDb_set_aside_unlocked(env, s);
S3JniMutex_S3JniDb_leave;
} }
} }
@ -1064,7 +1071,7 @@ static void * NativePointerHolder_get(JNIEnv * env, jobject pObj, S3NphRef const
static S3JniDb * S3JniDb_alloc(JNIEnv * const env, sqlite3 *pDb, static S3JniDb * S3JniDb_alloc(JNIEnv * const env, sqlite3 *pDb,
jobject jDb){ jobject jDb){
S3JniDb * rv; S3JniDb * rv;
S3JniMutex_Pdb_enter; S3JniMutex_S3JniDb_enter;
if( SJG.perDb.aFree ){ if( SJG.perDb.aFree ){
rv = SJG.perDb.aFree; rv = SJG.perDb.aFree;
SJG.perDb.aFree = rv->pNext; SJG.perDb.aFree = rv->pNext;
@ -1095,7 +1102,7 @@ static S3JniDb * S3JniDb_alloc(JNIEnv * const env, sqlite3 *pDb,
rv->jDb = REF_G(jDb); rv->jDb = REF_G(jDb);
rv->pDb = pDb; rv->pDb = pDb;
} }
S3JniMutex_Pdb_leave; S3JniMutex_S3JniDb_leave;
return rv; return rv;
} }
@ -1113,7 +1120,7 @@ static S3JniDb * S3JniDb_alloc(JNIEnv * const env, sqlite3 *pDb,
static S3JniDb * S3JniDb_for_db(JNIEnv * const env, jobject jDb, sqlite3 *pDb){ static S3JniDb * S3JniDb_for_db(JNIEnv * const env, jobject jDb, sqlite3 *pDb){
S3JniDb * s = 0; S3JniDb * s = 0;
if( jDb || pDb ){ if( jDb || pDb ){
S3JniMutex_Pdb_enter; S3JniMutex_S3JniDb_enter;
s = SJG.perDb.aUsed; s = SJG.perDb.aUsed;
if( !pDb ){ if( !pDb ){
assert( jDb ); assert( jDb );
@ -1124,7 +1131,7 @@ static S3JniDb * S3JniDb_for_db(JNIEnv * const env, jobject jDb, sqlite3 *pDb){
break; break;
} }
} }
S3JniMutex_Pdb_leave; S3JniMutex_S3JniDb_leave;
} }
return s; return s;
} }
@ -2713,6 +2720,21 @@ S3JniApi(sqlite3_is_interrupted(),jboolean,1is_1interrupted)(
return rc ? JNI_TRUE : JNI_FALSE; return rc ? JNI_TRUE : JNI_FALSE;
} }
/*
** Uncaches the current JNIEnv from the S3JniGlobal state, clearing any
** resources owned by that cache entry and making that slot available
** for re-use. It is important that the Java-side decl of this
** function be declared as synchronous.
*/
JniDecl(jboolean,1java_1uncache_1thread)(JniArgsEnvClass){
int rc;
S3JniMutex_Env_enter;
rc = S3JniGlobal_env_uncache(env);
S3JniMutex_Env_leave;
return rc ? JNI_TRUE : JNI_FALSE;
}
S3JniApi(sqlite3_last_insert_rowid(),jlong,1last_1insert_1rowid)( S3JniApi(sqlite3_last_insert_rowid(),jlong,1last_1insert_1rowid)(
JniArgsEnvClass, jobject jpDb JniArgsEnvClass, jobject jpDb
){ ){
@ -3546,8 +3568,19 @@ S3JniApi(sqlite3_shutdown(),jint,1shutdown)(
S3JniGlobal_env_uncache( SJG.envCache.aHead->env ); S3JniGlobal_env_uncache( SJG.envCache.aHead->env );
} }
S3JniMutex_Env_leave; S3JniMutex_Env_leave;
/* Do not clear S3JniGlobal.jvm: it's legal to call #if 0
sqlite3_initialize() again to restart the lib. */ /*
** Is this a good idea? We will get rid of the perDb list once
** sqlite3 gets a per-db client state, at which point we won't have
** a central list of databases to close.
*/
S3JniMutex_S3JniDb_enter;
while( SJG.perDb.pHead ){
s3jni_close_db(env, SJG.perDb.pHead->jDb, 2);
}
S3JniMutex_S3JniDb_leave;
#endif
/* Do not clear S3JniGlobal.jvm: it's legal to restart the lib. */
return sqlite3_shutdown(); return sqlite3_shutdown();
} }
@ -4615,22 +4648,6 @@ Java_org_sqlite_jni_tester_SQLTester_installCustomExtensions(JniArgsEnvClass){
// End of SQLTester bindings. Start of lower-level bits. // End of SQLTester bindings. Start of lower-level bits.
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
/*
** Uncaches the current JNIEnv from the S3JniGlobal state, clearing any
** resources owned by that cache entry and making that slot available
** for re-use. It is important that the Java-side decl of this
** function be declared as synchronous.
*/
JNIEXPORT jboolean JNICALL
Java_org_sqlite_jni_SQLite3Jni_uncacheJniEnv(JniArgsEnvClass){
int rc;
S3JniMutex_Env_enter;
rc = S3JniGlobal_env_uncache(env);
S3JniMutex_Env_leave;
return rc ? JNI_TRUE : JNI_FALSE;
}
/* /*
** Called during static init of the SQLite3Jni class to sync certain ** Called during static init of the SQLite3Jni class to sync certain
** compile-time constants to Java-space. ** compile-time constants to Java-space.

View File

@ -765,10 +765,10 @@ JNIEXPORT void JNICALL Java_org_sqlite_jni_SQLite3Jni_init
/* /*
* Class: org_sqlite_jni_SQLite3Jni * Class: org_sqlite_jni_SQLite3Jni
* Method: uncacheJniEnv * Method: sqlite3_java_uncache_thread
* Signature: ()Z * Signature: ()Z
*/ */
JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_SQLite3Jni_uncacheJniEnv JNIEXPORT jboolean JNICALL Java_org_sqlite_jni_SQLite3Jni_sqlite3_1java_1uncache_1thread
(JNIEnv *, jclass); (JNIEnv *, jclass);
/* /*

View File

@ -121,10 +121,9 @@ public final class SQLite3Jni {
/** /**
Each thread which uses the SQLite3 JNI APIs should call Each thread which uses the SQLite3 JNI APIs should call
uncacheJniEnv() when it is done with the library - either right sqlite3_jni_uncache_thread() when it is done with the library -
before it terminates or when it is finished using the SQLite API. either right before it terminates or when it finishes using the
This will clean up any cached per-JNIEnv info. Calling into the SQLite API. This will clean up any cached per-thread info.
library will re-initialize the cache on demand.
<p>This process does not close any databases or finalize <p>This process does not close any databases or finalize
any prepared statements because their ownership does not depend on any prepared statements because their ownership does not depend on
@ -133,10 +132,9 @@ public final class SQLite3Jni {
all databases before calling this function. all databases before calling this function.
<p>Calling this from the main application thread is not strictly <p>Calling this from the main application thread is not strictly
required but is "polite." Additional threads must call this required. Additional threads must call this before ending or they
before ending or they will leak cache entries in the C heap, will leak cache entries in the C heap, which in turn may keep
which in turn may keep numerous Java-side global references numerous Java-side global references active.
active.
<p>This routine returns false without side effects if the current <p>This routine returns false without side effects if the current
JNIEnv is not cached, else returns true, but this information is JNIEnv is not cached, else returns true, but this information is
@ -144,7 +142,7 @@ public final class SQLite3Jni {
which client-level code should use to make any informed which client-level code should use to make any informed
decisions. decisions.
*/ */
public static synchronized native boolean uncacheJniEnv(); public static native boolean sqlite3_java_uncache_thread();
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// Maintenance reminder: please keep the sqlite3_.... functions // Maintenance reminder: please keep the sqlite3_.... functions
@ -1154,9 +1152,12 @@ public final class SQLite3Jni {
); );
/** /**
Cleans up all per-JNIEnv and per-db state managed by the library, Cleans up all stale per-thread state managed by the library, as
as well as any registered auto-extensions, then calls the well as any registered auto-extensions, then calls the C-native
C-native sqlite3_shutdown(). sqlite3_shutdown(). Calling this while database handles or
prepared statements are still active will leak resources. Trying
to use those objects after this routine is called invoked
undefined behavior.
*/ */
public static synchronized native int sqlite3_shutdown(); public static synchronized native int sqlite3_shutdown();

View File

@ -1421,8 +1421,8 @@ public class Tester1 implements Runnable {
listErrors.add(e); listErrors.add(e);
} }
}finally{ }finally{
affirm( SQLite3Jni.uncacheJniEnv() ); affirm( sqlite3_java_uncache_thread() );
affirm( !SQLite3Jni.uncacheJniEnv() ); affirm( !sqlite3_java_uncache_thread() );
} }
} }

View File

@ -1,5 +1,5 @@
C Update\ssome\soutdated\sJNI\sdocs\sand\saccount\sfor\sa\sfunction\srenamed\searlier\sthis\sevening. C Re-frame\sthe\sincongruous\sSQLite3Jni.uncacheThread()\sAPI\sas\ssqlite3_java_uncache_thread().
D 2023-08-24T21:45:30.722 D 2023-08-24T22:28:44.239
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@ -236,8 +236,8 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3
F ext/jni/GNUmakefile 6aeafa0ebcf0f0d834c814ae8b450b54135ea11a2a7868f90b6286ec1bf6020f F ext/jni/GNUmakefile 6aeafa0ebcf0f0d834c814ae8b450b54135ea11a2a7868f90b6286ec1bf6020f
F ext/jni/README.md 9d3caa2e038bfe5e8356a9e8ff66f93ca0647ac278339eeea296f10017f5cf35 F ext/jni/README.md 9d3caa2e038bfe5e8356a9e8ff66f93ca0647ac278339eeea296f10017f5cf35
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
F ext/jni/src/c/sqlite3-jni.c c15bd15c895ec698a669c7058cb19e8bfccdcab88dc6345357f698fbfe9544aa F ext/jni/src/c/sqlite3-jni.c e4bdcd17e8f8e825f206e1c6ab5adf7f507d70b64b0f795c0cde141077fb68b2
F ext/jni/src/c/sqlite3-jni.h 7e9f36434b919cd8b6aa66c61e3910e9f112e252f52d1ac8a9811c52710aefcb F ext/jni/src/c/sqlite3-jni.h 91c2eeee22d3594e6652d51edcce0cd94d258a768802fcfac13a78f900127b72
F ext/jni/src/org/sqlite/jni/Authorizer.java 1308988f7f40579ea0e4deeaec3c6be971630566bd021c31367fe3f5140db892 F ext/jni/src/org/sqlite/jni/Authorizer.java 1308988f7f40579ea0e4deeaec3c6be971630566bd021c31367fe3f5140db892
F ext/jni/src/org/sqlite/jni/AutoExtension.java bcc1849b2fccbe5e2d7ac9e9ac7f8d05a6d7088a8fedbaad90e39569745a61e6 F ext/jni/src/org/sqlite/jni/AutoExtension.java bcc1849b2fccbe5e2d7ac9e9ac7f8d05a6d7088a8fedbaad90e39569745a61e6
F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c
@ -258,8 +258,8 @@ F ext/jni/src/org/sqlite/jni/ResultCode.java ba701f20213a5f259e94cfbfdd36eb7ac7c
F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564 F ext/jni/src/org/sqlite/jni/RollbackHook.java b04c8abcc6ade44a8a57129e33765793f69df0ba909e49ba18d73f4268d92564
F ext/jni/src/org/sqlite/jni/SQLFunction.java 4d6291fa14fcca1a040609378f9f00a193145d79c3abbda98ba32c340904cbeb F ext/jni/src/org/sqlite/jni/SQLFunction.java 4d6291fa14fcca1a040609378f9f00a193145d79c3abbda98ba32c340904cbeb
F ext/jni/src/org/sqlite/jni/SQLLog.java c60610b35208416940822e834d61f08fbbe5d6e06b374b541b49e41fd56c9798 F ext/jni/src/org/sqlite/jni/SQLLog.java c60610b35208416940822e834d61f08fbbe5d6e06b374b541b49e41fd56c9798
F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 1e791b79e96cc98a37659ea6f578ce595e1a38fb89b05e3560aa28462b283f6d F ext/jni/src/org/sqlite/jni/SQLite3Jni.java 5fddc34787b26a494dc9843ea2530cd319dc7a6bd369fd4e86dc713f20640fa6
F ext/jni/src/org/sqlite/jni/Tester1.java 239eb0133547d4a23317a6dd5bc456172cfb1f2547fd15ba8408871c2776a721 F ext/jni/src/org/sqlite/jni/Tester1.java e9b82c561ec8771b3e4ea537ebd7c16dd096928b6b8221967a4726104c7c6cb2
F ext/jni/src/org/sqlite/jni/TesterFts5.java 6f135c60e24c89e8eecb9fe61dde0f3bb2906de668ca6c9186bcf34bdaf94629 F ext/jni/src/org/sqlite/jni/TesterFts5.java 6f135c60e24c89e8eecb9fe61dde0f3bb2906de668ca6c9186bcf34bdaf94629
F ext/jni/src/org/sqlite/jni/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d F ext/jni/src/org/sqlite/jni/Tracer.java a5cece9f947b0af27669b8baec300b6dd7ff859c3e6a6e4a1bd8b50f9714775d
F ext/jni/src/org/sqlite/jni/UpdateHook.java e58645a1727f8a9bbe72dc072ec5b40d9f9362cb0aa24acfe93f49ff56a9016d F ext/jni/src/org/sqlite/jni/UpdateHook.java e58645a1727f8a9bbe72dc072ec5b40d9f9362cb0aa24acfe93f49ff56a9016d
@ -2096,8 +2096,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P e8308f0c6ec2d8999c8a2502fb130cb3501ba326f23f71f2cd8d452debae79b5 P 3f684ef5018116f4be46a07779451c8983ac87a5db182477f71ee7bf28287a04
R 3d26ad0e6ed454d9e8adb86ee7670851 R ce1f562cc06444ed73ad1cad9371c48a
U stephan U stephan
Z 11f2caacf45a97bd14e07afe2fb5856c Z fbdf5ee5d7ecf00150898b00dcd91489
# Remove this line to create a well-formed Fossil manifest. # Remove this line to create a well-formed Fossil manifest.

View File

@ -1 +1 @@
3f684ef5018116f4be46a07779451c8983ac87a5db182477f71ee7bf28287a04 7232b033954fae40df3db43e489e0e5a703c03308f500a1ae36fd9d707632d7f