From: stephan Date: Sat, 26 Aug 2023 16:29:48 +0000 (+0000) Subject: Recycle per-UDF JNI state. X-Git-Tag: version-3.44.0~280 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fec793dd8aeecbd3e84f1edfd0012f04e7fdee53;p=thirdparty%2Fsqlite.git Recycle per-UDF JNI state. FossilOrigin-Name: cf406528eb86d8d0d55a468b2c4ec32a11a4947f45c4bbabdde8742ae199ce1f --- diff --git a/ext/jni/src/c/sqlite3-jni.c b/ext/jni/src/c/sqlite3-jni.c index 6badc3be31..980da3d9f2 100644 --- a/ext/jni/src/c/sqlite3-jni.c +++ b/ext/jni/src/c/sqlite3-jni.c @@ -426,6 +426,33 @@ struct S3JniAutoExtension { jmethodID midFunc /* xEntryPoint() callback */; }; +/* +** Type IDs for SQL function categories. +*/ +enum UDFType { + UDF_UNKNOWN_TYPE = 0/*for error propagation*/, + UDF_SCALAR, + UDF_AGGREGATE, + UDF_WINDOW +}; + +/** + State for binding Java-side UDFs. +*/ +typedef struct S3JniUdf S3JniUdf; +struct S3JniUdf { + jobject jObj /* SQLFunction instance */; + char * zFuncName /* Only for error reporting and debug logging */; + enum UDFType type; + /** Method IDs for the various UDF methods. */ + jmethodID jmidxFunc /* Java ID of xFunc method */; + jmethodID jmidxStep /* Java ID of xStep method */; + jmethodID jmidxFinal /* Java ID of xFinal method */; + jmethodID jmidxValue /* Java ID of xValue method */; + jmethodID jmidxInverse /* Java ID of xInverse method */; + S3JniUdf * pNext /* Next entry in free-list. */; +}; + #if !defined(SQLITE_JNI_OMIT_METRICS) && !defined(SQLITE_JNI_ENABLE_METRICS) # ifdef SQLITE_DEBUG # define SQLITE_JNI_ENABLE_METRICS @@ -464,10 +491,11 @@ struct S3JniGlobalType { ** */ JavaVM * jvm; + /* Global mutex. */ sqlite3_mutex * mutex; /* ** Cache of Java refs and method IDs for NativePointerHolder - ** subclasses. Initialized on demand. + ** subclasses and OutputPointer.T types. */ S3JniNphClass nph[S3Jni_NphCache_size]; /* @@ -494,6 +522,10 @@ struct S3JniGlobalType { always have this set to the current JNIEnv object. Used only for sanity checking. */; } perDb; + struct { + S3JniUdf * aFree /* Head of the free-item list. Guarded by global + mutex. */; + } udf; /* ** Refs to global classes and methods. Obtained during static init ** and never released. @@ -553,9 +585,13 @@ struct S3JniGlobalType { 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 nMutexUdf /* number of times global mutex was entered + for UDFs. */; volatile unsigned nDestroy /* xDestroy() calls across all types */; volatile unsigned nPdbAlloc /* Number of S3JniDb alloced. */; volatile unsigned nPdbRecycled /* Number of S3JniDb reused. */; + volatile unsigned nUdfAlloc /* Number of S3JniUdf alloced. */; + volatile unsigned nUdfRecycled /* Number of S3JniUdf reused. */; struct { /* Number of calls for each type of UDF callback. */ volatile unsigned nFunc; @@ -1544,40 +1580,28 @@ static inline jobject new_sqlite3_value_wrapper(JNIEnv * const env, sqlite3_valu return new_NativePointerHolder_object(env, &S3NphRefs.sqlite3_value, sv); } -/* -** Type IDs for SQL function categories. -*/ -enum UDFType { - UDF_SCALAR = 1, - UDF_AGGREGATE, - UDF_WINDOW, - UDF_UNKNOWN_TYPE/*for error propagation*/ -}; - typedef void (*udf_xFunc_f)(sqlite3_context*,int,sqlite3_value**); typedef void (*udf_xStep_f)(sqlite3_context*,int,sqlite3_value**); typedef void (*udf_xFinal_f)(sqlite3_context*); /*typedef void (*udf_xValue_f)(sqlite3_context*);*/ /*typedef void (*udf_xInverse_f)(sqlite3_context*,int,sqlite3_value**);*/ -/** - State for binding Java-side UDFs. -*/ -typedef struct S3JniUdf S3JniUdf; -struct S3JniUdf { - jobject jObj /* SQLFunction instance */; - char * zFuncName /* Only for error reporting and debug logging */; - enum UDFType type; - /** Method IDs for the various UDF methods. */ - jmethodID jmidxFunc; - jmethodID jmidxStep; - jmethodID jmidxFinal; - jmethodID jmidxValue; - jmethodID jmidxInverse; -}; - static S3JniUdf * S3JniUdf_alloc(JNIEnv * const env, jobject jObj){ - S3JniUdf * const s = sqlite3_malloc(sizeof(S3JniUdf)); + S3JniUdf * s = 0; + + S3JniMutex_Global_enter; + s3jni_incr(&SJG.metrics.nMutexUdf); + if( SJG.udf.aFree ){ + s = SJG.udf.aFree; + SJG.udf.aFree = s->pNext; + s->pNext = 0; + s3jni_incr(&SJG.metrics.nUdfRecycled); + } + S3JniMutex_Global_leave; + if( !s ){ + s = sqlite3_malloc(sizeof(*s)); + s3jni_incr(&SJG.metrics.nUdfAlloc); + } if( s ){ const char * zFSI = /* signature for xFunc, xStep, xInverse */ "(Lorg/sqlite/jni/sqlite3_context;[Lorg/sqlite/jni/sqlite3_value;)V"; @@ -1585,9 +1609,9 @@ static S3JniUdf * S3JniUdf_alloc(JNIEnv * const env, jobject jObj){ "(Lorg/sqlite/jni/sqlite3_context;)V"; jclass const klazz = (*env)->GetObjectClass(env, jObj); - memset(s, 0, sizeof(S3JniUdf)); + memset(s, 0, sizeof(*s)); s->jObj = S3JniRefGlobal(jObj); -#define FGET(FuncName,FuncType,Field) \ +#define FGET(FuncName,FuncType,Field) \ s->Field = (*env)->GetMethodID(env, klazz, FuncName, FuncType); \ if( !s->Field ) (*env)->ExceptionClear(env) FGET("xFunc", zFSI, jmidxFunc); @@ -1607,20 +1631,24 @@ static S3JniUdf * S3JniUdf_alloc(JNIEnv * const env, jobject jObj){ return s; } + static void S3JniUdf_free(S3JniUdf * s){ S3JniDeclLocal_env; - if( env ){ - //MARKER(("UDF cleanup: %s\n", s->zFuncName)); - s3jni_call_xDestroy(env, s->jObj); - S3JniUnrefGlobal(s->jObj); - } + //MARKER(("UDF cleanup: %s\n", s->zFuncName)); + s3jni_call_xDestroy(env, s->jObj); + S3JniUnrefGlobal(s->jObj); sqlite3_free(s->zFuncName); - sqlite3_free(s); + assert( !s->pNext ); + memset(s, 0, sizeof(*s)); + S3JniMutex_Global_enter; + s->pNext = S3JniGlobal.udf.aFree; + S3JniGlobal.udf.aFree = s; + S3JniMutex_Global_leave; } static void S3JniUdf_finalizer(void * s){ //MARKER(("UDF finalizer @ %p\n", s)); - if( s ) S3JniUdf_free((S3JniUdf*)s); + S3JniUdf_free((S3JniUdf*)s); } /** @@ -2630,7 +2658,8 @@ S3JniApi(sqlite3_create_function() sqlite3_create_function_v2() sqlite3_create_w } s = S3JniUdf_alloc(env, jFunctor); if( !s ) return SQLITE_NOMEM; - else if( UDF_UNKNOWN_TYPE==s->type ){ + + if( UDF_UNKNOWN_TYPE==s->type ){ rc = s3jni_db_error(pDb, SQLITE_MISUSE, "Cannot unambiguously determine function type."); S3JniUdf_free(s); @@ -4001,20 +4030,25 @@ 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", + "\n\tglobal = %u" + "\n\tenv = %u" + "\n\tnph inits = %u" + "\n\tperDb = %u" + "\n\tautoExt list = %u" + "\n\tS3JniUdf free-list = %u" + "\n\tmetrics = %u\n", SJG.metrics.nMutexGlobal, SJG.metrics.nMutexEnv, SJG.metrics.nMutexEnv2, SJG.metrics.nMutexPerDb, - SJG.metrics.nMutexAutoExt, + SJG.metrics.nMutexAutoExt, SJG.metrics.nMutexUdf, SJG.metrics.nMetrics); printf("S3JniDb: %u alloced (*%u = %u bytes), %u recycled\n", SJG.metrics.nPdbAlloc, (unsigned) sizeof(S3JniDb), (unsigned)(SJG.metrics.nPdbAlloc * sizeof(S3JniDb)), SJG.metrics.nPdbRecycled); + printf("S3JniUdf: %u alloced (*%u = %u bytes), %u recycled\n", + SJG.metrics.nUdfAlloc, (unsigned) sizeof(S3JniUdf), + (unsigned)(SJG.metrics.nUdfAlloc * sizeof(S3JniUdf)), + SJG.metrics.nUdfRecycled); puts("Java-side UDF calls:"); #define UDF(T) printf("\t%-8s = %u\n", "x" #T, SJG.metrics.udf.n##T) UDF(Func); UDF(Step); UDF(Final); UDF(Value); UDF(Inverse); diff --git a/manifest b/manifest index 64d0d4a6b5..7e8b84cc87 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Code\sconsolidation\scleanups. -D 2023-08-26T14:55:44.725 +C Recycle\sper-UDF\sJNI\sstate. +D 2023-08-26T16:29:48.809 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 d9244b5addf58868343a74a94faa71f829e7f40c163486d053f4b4bbea173703 F ext/jni/README.md 1332b1fa27918bd5d9ca2d0d4f3ac3a6ab86b9e3699dc5bfe32904a027f3d2a9 F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa -F ext/jni/src/c/sqlite3-jni.c 3003be176ac3326ba29f79679c7351593065e0e3ecf83b8f84345aea57ab4d21 +F ext/jni/src/c/sqlite3-jni.c ac4020f987abc0f3970119d279d26b74de8fb9b1b49da4046dd3e74a40f9a819 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 @@ -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 cc3153ed341f59262485c3541a8879c4e86520c8a10f4ce819344a88099e7d0e -R 2f6845a9eeb7c9c5a2de49d358b42470 +P d6b5ecd28740c2c5d21797fce9fe137c8a83f702f22901720cc6e8b1b42af001 +R b3a9fb323c6b84f48b5856006714684b U stephan -Z 1a214861a65c5eead4ace1eeab3dd83d +Z 9c33a91e895e4fc7c7f885475275408f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 4d43f5d182..f3a58cea1e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d6b5ecd28740c2c5d21797fce9fe137c8a83f702f22901720cc6e8b1b42af001 \ No newline at end of file +cf406528eb86d8d0d55a468b2c4ec32a11a4947f45c4bbabdde8742ae199ce1f \ No newline at end of file