mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-05 15:55:57 +03:00
Recycle per-UDF JNI state.
FossilOrigin-Name: cf406528eb86d8d0d55a468b2c4ec32a11a4947f45c4bbabdde8742ae199ce1f
This commit is contained in:
@@ -426,6 +426,33 @@ struct S3JniAutoExtension {
|
|||||||
jmethodID midFunc /* xEntryPoint() callback */;
|
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)
|
#if !defined(SQLITE_JNI_OMIT_METRICS) && !defined(SQLITE_JNI_ENABLE_METRICS)
|
||||||
# ifdef SQLITE_DEBUG
|
# ifdef SQLITE_DEBUG
|
||||||
# define SQLITE_JNI_ENABLE_METRICS
|
# define SQLITE_JNI_ENABLE_METRICS
|
||||||
@@ -464,10 +491,11 @@ struct S3JniGlobalType {
|
|||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
JavaVM * jvm;
|
JavaVM * jvm;
|
||||||
|
/* Global mutex. */
|
||||||
sqlite3_mutex * mutex;
|
sqlite3_mutex * mutex;
|
||||||
/*
|
/*
|
||||||
** Cache of Java refs and method IDs for NativePointerHolder
|
** Cache of Java refs and method IDs for NativePointerHolder
|
||||||
** subclasses. Initialized on demand.
|
** subclasses and OutputPointer.T types.
|
||||||
*/
|
*/
|
||||||
S3JniNphClass nph[S3Jni_NphCache_size];
|
S3JniNphClass nph[S3Jni_NphCache_size];
|
||||||
/*
|
/*
|
||||||
@@ -494,6 +522,10 @@ struct S3JniGlobalType {
|
|||||||
always have this set to the current JNIEnv
|
always have this set to the current JNIEnv
|
||||||
object. Used only for sanity checking. */;
|
object. Used only for sanity checking. */;
|
||||||
} perDb;
|
} 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
|
** Refs to global classes and methods. Obtained during static init
|
||||||
** and never released.
|
** and never released.
|
||||||
@@ -553,9 +585,13 @@ struct S3JniGlobalType {
|
|||||||
volatile unsigned nMutexPerDb /* number of times perDb.mutex was entered */;
|
volatile unsigned nMutexPerDb /* number of times perDb.mutex was entered */;
|
||||||
volatile unsigned nMutexAutoExt /* number of times autoExt.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 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 nDestroy /* xDestroy() calls across all types */;
|
||||||
volatile unsigned nPdbAlloc /* Number of S3JniDb alloced. */;
|
volatile unsigned nPdbAlloc /* Number of S3JniDb alloced. */;
|
||||||
volatile unsigned nPdbRecycled /* Number of S3JniDb reused. */;
|
volatile unsigned nPdbRecycled /* Number of S3JniDb reused. */;
|
||||||
|
volatile unsigned nUdfAlloc /* Number of S3JniUdf alloced. */;
|
||||||
|
volatile unsigned nUdfRecycled /* Number of S3JniUdf reused. */;
|
||||||
struct {
|
struct {
|
||||||
/* Number of calls for each type of UDF callback. */
|
/* Number of calls for each type of UDF callback. */
|
||||||
volatile unsigned nFunc;
|
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);
|
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_xFunc_f)(sqlite3_context*,int,sqlite3_value**);
|
||||||
typedef void (*udf_xStep_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_xFinal_f)(sqlite3_context*);
|
||||||
/*typedef void (*udf_xValue_f)(sqlite3_context*);*/
|
/*typedef void (*udf_xValue_f)(sqlite3_context*);*/
|
||||||
/*typedef void (*udf_xInverse_f)(sqlite3_context*,int,sqlite3_value**);*/
|
/*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){
|
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 ){
|
if( s ){
|
||||||
const char * zFSI = /* signature for xFunc, xStep, xInverse */
|
const char * zFSI = /* signature for xFunc, xStep, xInverse */
|
||||||
"(Lorg/sqlite/jni/sqlite3_context;[Lorg/sqlite/jni/sqlite3_value;)V";
|
"(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";
|
"(Lorg/sqlite/jni/sqlite3_context;)V";
|
||||||
jclass const klazz = (*env)->GetObjectClass(env, jObj);
|
jclass const klazz = (*env)->GetObjectClass(env, jObj);
|
||||||
|
|
||||||
memset(s, 0, sizeof(S3JniUdf));
|
memset(s, 0, sizeof(*s));
|
||||||
s->jObj = S3JniRefGlobal(jObj);
|
s->jObj = S3JniRefGlobal(jObj);
|
||||||
#define FGET(FuncName,FuncType,Field) \
|
#define FGET(FuncName,FuncType,Field) \
|
||||||
s->Field = (*env)->GetMethodID(env, klazz, FuncName, FuncType); \
|
s->Field = (*env)->GetMethodID(env, klazz, FuncName, FuncType); \
|
||||||
if( !s->Field ) (*env)->ExceptionClear(env)
|
if( !s->Field ) (*env)->ExceptionClear(env)
|
||||||
FGET("xFunc", zFSI, jmidxFunc);
|
FGET("xFunc", zFSI, jmidxFunc);
|
||||||
@@ -1607,20 +1631,24 @@ static S3JniUdf * S3JniUdf_alloc(JNIEnv * const env, jobject jObj){
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void S3JniUdf_free(S3JniUdf * s){
|
static void S3JniUdf_free(S3JniUdf * s){
|
||||||
S3JniDeclLocal_env;
|
S3JniDeclLocal_env;
|
||||||
if( env ){
|
//MARKER(("UDF cleanup: %s\n", s->zFuncName));
|
||||||
//MARKER(("UDF cleanup: %s\n", s->zFuncName));
|
s3jni_call_xDestroy(env, s->jObj);
|
||||||
s3jni_call_xDestroy(env, s->jObj);
|
S3JniUnrefGlobal(s->jObj);
|
||||||
S3JniUnrefGlobal(s->jObj);
|
|
||||||
}
|
|
||||||
sqlite3_free(s->zFuncName);
|
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){
|
static void S3JniUdf_finalizer(void * s){
|
||||||
//MARKER(("UDF finalizer @ %p\n", 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);
|
s = S3JniUdf_alloc(env, jFunctor);
|
||||||
if( !s ) return SQLITE_NOMEM;
|
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,
|
rc = s3jni_db_error(pDb, SQLITE_MISUSE,
|
||||||
"Cannot unambiguously determine function type.");
|
"Cannot unambiguously determine function type.");
|
||||||
S3JniUdf_free(s);
|
S3JniUdf_free(s);
|
||||||
@@ -4001,20 +4030,25 @@ JniDecl(void,1jni_1internal_1details)(JniArgsEnvClass){
|
|||||||
SJG.metrics.envCacheMisses,
|
SJG.metrics.envCacheMisses,
|
||||||
SJG.metrics.envCacheHits);
|
SJG.metrics.envCacheHits);
|
||||||
printf("Mutex entry:"
|
printf("Mutex entry:"
|
||||||
"\n\tglobal %u"
|
"\n\tglobal = %u"
|
||||||
"\n\tenv %u"
|
"\n\tenv = %u"
|
||||||
"\n\tnph inits %u"
|
"\n\tnph inits = %u"
|
||||||
"\n\tperDb %u"
|
"\n\tperDb = %u"
|
||||||
"\n\tautoExt %u list accesses"
|
"\n\tautoExt list = %u"
|
||||||
"\n\tmetrics %u\n",
|
"\n\tS3JniUdf free-list = %u"
|
||||||
|
"\n\tmetrics = %u\n",
|
||||||
SJG.metrics.nMutexGlobal, SJG.metrics.nMutexEnv,
|
SJG.metrics.nMutexGlobal, SJG.metrics.nMutexEnv,
|
||||||
SJG.metrics.nMutexEnv2, SJG.metrics.nMutexPerDb,
|
SJG.metrics.nMutexEnv2, SJG.metrics.nMutexPerDb,
|
||||||
SJG.metrics.nMutexAutoExt,
|
SJG.metrics.nMutexAutoExt, SJG.metrics.nMutexUdf,
|
||||||
SJG.metrics.nMetrics);
|
SJG.metrics.nMetrics);
|
||||||
printf("S3JniDb: %u alloced (*%u = %u bytes), %u recycled\n",
|
printf("S3JniDb: %u alloced (*%u = %u bytes), %u recycled\n",
|
||||||
SJG.metrics.nPdbAlloc, (unsigned) sizeof(S3JniDb),
|
SJG.metrics.nPdbAlloc, (unsigned) sizeof(S3JniDb),
|
||||||
(unsigned)(SJG.metrics.nPdbAlloc * sizeof(S3JniDb)),
|
(unsigned)(SJG.metrics.nPdbAlloc * sizeof(S3JniDb)),
|
||||||
SJG.metrics.nPdbRecycled);
|
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:");
|
puts("Java-side UDF calls:");
|
||||||
#define UDF(T) printf("\t%-8s = %u\n", "x" #T, SJG.metrics.udf.n##T)
|
#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);
|
UDF(Func); UDF(Step); UDF(Final); UDF(Value); UDF(Inverse);
|
||||||
|
12
manifest
12
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Code\sconsolidation\scleanups.
|
C Recycle\sper-UDF\sJNI\sstate.
|
||||||
D 2023-08-26T14:55:44.725
|
D 2023-08-26T16:29:48.809
|
||||||
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,7 +236,7 @@ F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a3
|
|||||||
F ext/jni/GNUmakefile d9244b5addf58868343a74a94faa71f829e7f40c163486d053f4b4bbea173703
|
F ext/jni/GNUmakefile d9244b5addf58868343a74a94faa71f829e7f40c163486d053f4b4bbea173703
|
||||||
F ext/jni/README.md 1332b1fa27918bd5d9ca2d0d4f3ac3a6ab86b9e3699dc5bfe32904a027f3d2a9
|
F ext/jni/README.md 1332b1fa27918bd5d9ca2d0d4f3ac3a6ab86b9e3699dc5bfe32904a027f3d2a9
|
||||||
F ext/jni/jar-dist.make 030aaa4ae71dd86e4ec5e7c1e6cd86f9dfa47c4592c070d2e35157e42498e1fa
|
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/c/sqlite3-jni.h 2745c4abd0933a4e8cc48989fffbad3936b4eaada64cce9ce11453dcd30e4184
|
||||||
F ext/jni/src/org/sqlite/jni/AggregateFunction.java e0aac6ccae05702f8ee779820570866a2760aaa57a73135c57c8d3580bef52d5
|
F ext/jni/src/org/sqlite/jni/AggregateFunction.java e0aac6ccae05702f8ee779820570866a2760aaa57a73135c57c8d3580bef52d5
|
||||||
F ext/jni/src/org/sqlite/jni/AuthorizerCallback.java c374bb76409cce7a0bdba94877706b59ac6127fa5d9e6af3e8058c99ce99c030
|
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.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 cc3153ed341f59262485c3541a8879c4e86520c8a10f4ce819344a88099e7d0e
|
P d6b5ecd28740c2c5d21797fce9fe137c8a83f702f22901720cc6e8b1b42af001
|
||||||
R 2f6845a9eeb7c9c5a2de49d358b42470
|
R b3a9fb323c6b84f48b5856006714684b
|
||||||
U stephan
|
U stephan
|
||||||
Z 1a214861a65c5eead4ace1eeab3dd83d
|
Z 9c33a91e895e4fc7c7f885475275408f
|
||||||
# Remove this line to create a well-formed Fossil manifest.
|
# Remove this line to create a well-formed Fossil manifest.
|
||||||
|
@@ -1 +1 @@
|
|||||||
d6b5ecd28740c2c5d21797fce9fe137c8a83f702f22901720cc6e8b1b42af001
|
cf406528eb86d8d0d55a468b2c4ec32a11a4947f45c4bbabdde8742ae199ce1f
|
Reference in New Issue
Block a user