diff --git a/ant/build-core.xml b/ant/build-core.xml
index 47d9c682e5..64dd2f7e3c 100644
--- a/ant/build-core.xml
+++ b/ant/build-core.xml
@@ -647,6 +647,8 @@
+
+
+
+ LogAllThreads
+ lucee.runtime.functions.system.LogAllThreads
+ system,log,debugging,threads,performance,analysis
+
+ Creates detailed thread stack trace logs in JSONL format for performance analysis and debugging.
+ This function captures stack traces from all running threads at specified intervals for a given duration.
+ It executes asynchronously, returning immediately after starting the logging process, making it ideal
+ for analyzing specific code segments by initiating logging just before the target code execution.
+
+ The output format is JSONL (JSON Lines), where each line represents a separate JSON object containing:
+ - Timestamp offset in milliseconds from 1/1/1970 00:00:00 UTC (Unix 0)
+ - Complete stack trace of each thread's current location
+
+ This data can be used for:
+ - Performance bottleneck identification
+ - Thread behavior analysis
+ - Deadlock detection
+ - Resource usage patterns
+
+
+
+ path
+ string
+ true
+
+ Full file path where the log will be written. The file should have a '.jsonl' extension
+ for proper identification as a JSON Lines format file. The function will create the file
+ if it doesn't exist, or append to it if it does.
+
+ Example: "/var/log/lucee/thread_analysis.jsonl"
+
+
+
+
+ interval
+ number
+ false
+ 0
+
+ The time interval (in milliseconds) between stack trace captures. Lower values provide
+ more detailed analysis but generate larger log files and may impact performance.
+
+ Recommended ranges:
+ - 1-10ms: Very detailed analysis, higher overhead
+ - 10-100ms: Balanced detail and performance
+ - 100ms+: Lower detail, minimal performance impact
+
+
+
+
+ duration
+ number
+ false
+ 10000
+
+ Total duration (in milliseconds) for which the function will collect thread data.
+ After this period, logging automatically stops.
+
+ Common durations:
+ - 1000-5000ms: Quick snapshots
+ - 10000ms: Standard analysis period
+ - 30000ms+: Extended analysis for complex operations
+
+
+
void
diff --git a/core/src/main/java/resource/setting/sysprop-envvar.json b/core/src/main/java/resource/setting/sysprop-envvar.json
index 25ba8c6a70..fe31d2867f 100644
--- a/core/src/main/java/resource/setting/sysprop-envvar.json
+++ b/core/src/main/java/resource/setting/sysprop-envvar.json
@@ -378,6 +378,8 @@
"sysprop": "lucee.dump.threads",
"envvar": "LUCEE_DUMP_THREADS",
"desc": "Used for debugging, when enabled, it will dump out running threads to the console via the background controller thread"
+ },
+ {
"sysprop": "lucee.scope.local.capacity",
"envvar": "LUCEE_SCOPE_LOCAL_CAPACITY",
"desc": "Sets the initial capacity (size) for the local scope hashmap"
@@ -386,5 +388,15 @@
"sysprop": "lucee.scope.arguments.capacity",
"envvar": "LUCEE_SCOPE_ARGUMENTS_CAPACITY",
"desc": "Sets the initial capacity (size) for the arguments scope hashmap"
+ },
+ {
+ "sysprop": "lucee.cache.variableKeys",
+ "envvar": "LUCEE_CACHE_VARIABLEKEYS",
+ "desc": "Sets the max number of variable names (keys) to cache"
+ },
+ {
+ "sysprop": "lucee.threads.maxDefault",
+ "envvar": "LUCEE_THREADS_MAXDEFAULT",
+ "desc": "Sets the default max number of parallel threads, default 20"
}
]
\ No newline at end of file
diff --git a/loader/build.xml b/loader/build.xml
index a2eec916d3..4ac0aafc4f 100644
--- a/loader/build.xml
+++ b/loader/build.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/loader/pom.xml b/loader/pom.xml
index 1fa6f416ff..0edcc434f8 100644
--- a/loader/pom.xml
+++ b/loader/pom.xml
@@ -3,7 +3,7 @@
org.lucee
lucee
- 7.0.0.85-SNAPSHOT
+ 7.0.0.86-SNAPSHOT
jar
Lucee Loader Build
diff --git a/loader/src/main/java/lucee/loader/engine/CFMLEngineFactory.java b/loader/src/main/java/lucee/loader/engine/CFMLEngineFactory.java
index 06f0a96de1..91f3c0bd33 100755
--- a/loader/src/main/java/lucee/loader/engine/CFMLEngineFactory.java
+++ b/loader/src/main/java/lucee/loader/engine/CFMLEngineFactory.java
@@ -290,8 +290,6 @@ public void shutdownFelix() throws BundleException {
BundleCollection bc = singelton.getBundleCollection();
if (bc == null || bc.felix == null) return;
-
- // BundleLoader.removeBundles(bc, false);
BundleUtil.stop(felix, false);
}
@@ -744,12 +742,12 @@ public Felix getFelix(final File cacheRootDir, Map config) throw
// Enables or disables bundle cache locking, which is used to prevent concurrent access to the
// bundle cache.
- extend(config, "felix.cache.locking", "false", false);
+ extend(config, "felix.cache.locking", null, false);
extend(config, "org.osgi.framework.executionenvironment", null, false);
extend(config, "org.osgi.framework.storage", null, false);
- extend(config, "org.osgi.framework.storage.clean", "none", false);
+ extend(config, "org.osgi.framework.storage.clean", Constants.FRAMEWORK_STORAGE_CLEAN_ONFIRSTINIT, false);
extend(config, Constants.FRAMEWORK_BUNDLE_PARENT, Constants.FRAMEWORK_BUNDLE_PARENT_FRAMEWORK, false);
- // felix.cache.bufsize
+
boolean isNew = false;
// felix.cache.rootdir
if (Util.isEmpty((String) config.get("felix.cache.rootdir"))) {
@@ -764,7 +762,7 @@ public Felix getFelix(final File cacheRootDir, Map config) throw
extend(config, Constants.FRAMEWORK_SYSTEMPACKAGES, null, true);
extend(config, Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, null, true);
extend(config, "felix.cache.filelimit", null, false);
- extend(config, "felix.cache.bufsize", "65536", false); // 64kb default is 8kb
+ extend(config, "felix.cache.bufsize", null, false);
extend(config, "felix.bootdelegation.implicit", null, false);
extend(config, "felix.systembundle.activators", null, false);
extend(config, "org.osgi.framework.startlevel.beginning", null, false);
@@ -789,12 +787,14 @@ public Felix getFelix(final File cacheRootDir, Map config) throw
}
}
- /*
- * final StringBuilder sb = new StringBuilder("Loading felix with config:"); final
- * Iterator> it = config.entrySet().iterator(); Entry e; while
- * (it.hasNext()) { e = it.next();
- * sb.append("\n- ").append(e.getKey()).append(':').append(e.getValue()); } System.err.println(sb);
- */
+ final StringBuilder sb = new StringBuilder("Loading felix with config:");
+ final Iterator> it = config.entrySet().iterator();
+ Entry e;
+ while (it.hasNext()) {
+ e = it.next();
+ sb.append("\n- ").append(e.getKey()).append(':').append(e.getValue());
+ }
+ // log(Logger.LOG_INFO, sb.toString());
felix = new Felix(config);
try {
@@ -804,7 +804,9 @@ public Felix getFelix(final File cacheRootDir, Map config) throw
// this could be cause by an invalid felix cache, so we simply delete it and try again
if (!isNew && "Error creating bundle cache.".equals(be.getMessage())) {
Util.deleteContent(cacheRootDir, null);
+
}
+
}
return felix;
diff --git a/loader/src/main/java/lucee/loader/util/Util.java b/loader/src/main/java/lucee/loader/util/Util.java
index 701ca08982..18cba37a94 100755
--- a/loader/src/main/java/lucee/loader/util/Util.java
+++ b/loader/src/main/java/lucee/loader/util/Util.java
@@ -58,6 +58,7 @@ public class Util {
static {
UTF8 = Charset.forName("UTF-8");
}
+
private static final int QUALIFIER_APPENDIX_SNAPSHOT = 1;
private static final int QUALIFIER_APPENDIX_BETA = 2;
private static final int QUALIFIER_APPENDIX_RC = 3;
@@ -392,7 +393,6 @@ public static void write(File file, String string, Charset charset, boolean appe
if (charset == null) {
charset = UTF8;
}
-
Writer writer = null;
try {
writer = getWriter(file, charset, append);
@@ -623,27 +623,6 @@ private static Throwable unwrap(Throwable t) {
return t;
}
- public static String getSystemPropOrEnvVar(String name, String defaultValue) {
- // env
- String value = System.getenv(name);
- if (!isEmpty(value)) return value;
-
- // prop
- value = System.getProperty(name);
- if (!isEmpty(value)) return value;
-
- // env 2
- name = convertSystemPropToEnvVar(name);
- value = System.getenv(name);
- if (!isEmpty(value)) return value;
-
- return defaultValue;
- }
-
- private static String convertSystemPropToEnvVar(String name) {
- return name.replace('.', '_').toUpperCase();
- }
-
public static void sleep(int time) {
try {
Thread.sleep(time);
diff --git a/test/functions/BitOr.cfc b/test/functions/BitOr.cfc
index ba7d28eb8c..f0979ecd2a 100644
--- a/test/functions/BitOr.cfc
+++ b/test/functions/BitOr.cfc
@@ -44,7 +44,7 @@ component extends="org.lucee.cfml.test.LuceeTestCase"{
application action="update" preciseMath=true;
expect( BitOr(2147483647, 1) ).toBe(2147483647);
application action="update" preciseMath=false;
- expect( BitOr(2147483647, 1) ).toBe(2147483648);
+ expect( BitOr(2147483647, 1) ).toBe(2147483647);
});
it("should return the non-zero value when one number is zero", function() {
diff --git a/test/functions/BitSHLN.cfc b/test/functions/BitSHLN.cfc
index 0c2c507fb5..1242c47325 100644
--- a/test/functions/BitSHLN.cfc
+++ b/test/functions/BitSHLN.cfc
@@ -35,7 +35,7 @@ component extends="org.lucee.cfml.test.LuceeTestCase"{
application action="update" preciseMath=true;
assertEquals("4294967294", toString(BitSHLN(2147483647, 1))); // 2147483647 << 1 = 0 (overflow)
application action="update" preciseMath=false;
- assertEquals("4294967296", toString(BitSHLN(2147483647, 1))); // 2147483647 << 1 = 0 (overflow)
+ assertEquals("4294967294", toString(BitSHLN(2147483647, 1))); // 2147483647 << 1 = 0 (overflow)
});
it(title="Checking BitSHLN() function with negative shift", body = function(currentSpec) {
diff --git a/test/functions/BitSHRN.cfc b/test/functions/BitSHRN.cfc
index d637dc384e..e9568fbe63 100644
--- a/test/functions/BitSHRN.cfc
+++ b/test/functions/BitSHRN.cfc
@@ -35,7 +35,7 @@ component extends="org.lucee.cfml.test.LuceeTestCase"{
application action="update" preciseMath=true;
assertEquals("2147483647", BitSHRN(4294967295, 1)); // Large number shifted right
application action="update" preciseMath=false;
- assertEquals("2147483648", BitSHRN(4294967295, 1)); // Large number shifted right
+ assertEquals("2147483647", BitSHRN(4294967295, 1)); // Large number shifted right
});
it(title="Checking BitSHRN() function with negative numbers", body = function(currentSpec) {
diff --git a/test/tickets/LDEV5173.cfc b/test/tickets/LDEV5173.cfc
new file mode 100644
index 0000000000..d53bcc6332
--- /dev/null
+++ b/test/tickets/LDEV5173.cfc
@@ -0,0 +1,24 @@
+component extends = "org.lucee.cfml.test.LuceeTestCase" skip="true" {
+ function run( testResults, testBox ){
+ describe( "Test for LDEV-5173", function() {
+ beforeEach( function(){
+ variables.startingTZ=getTimeZone();
+ setTimeZone("IST");
+ });
+ afterEach( function(){
+ setTimeZone(variables.startingTZ?:"UTC");
+ });
+ it( title="round trip DateTimeFormat/ParseDateTime with format 'epoch'", body=function( currentSpec ) {
+ var date = DateTimeFormat( datetime="2024/12/11 16:19:54", mask="epoch" );
+ expect(toString(parseDateTime(date=date, format="epoch"))).toBe("{ts '2024-12-11 16:19:54'}");
+ expect( parseDateTime( date=date, format="epoch" ) ).toBe( date );
+ });
+
+ it( title="round trip DateTimeFormat/ParseDateTime with format 'epochms'", body=function( currentSpec ) {
+ var date = DateTimeFormat( datetime="2024/12/11 16:19:54", mask="epochms" );
+ expect(toString(parseDateTime(date=date, format="epochms"))).toBe("{ts '2024-12-11 16:19:54'}");
+ expect( parseDateTime( date=date, format="epochms" ) ).toBe( date );
+ });
+ } );
+ }
+}
diff --git a/test/tickets/LDEV5198.cfc b/test/tickets/LDEV5198.cfc
new file mode 100644
index 0000000000..dd44b3183b
--- /dev/null
+++ b/test/tickets/LDEV5198.cfc
@@ -0,0 +1,32 @@
+component extends = "org.lucee.cfml.test.LuceeTestCase" {
+
+ function beforeAll(){
+ variables.preciseMath = getApplicationSettings().preciseMath;
+ };
+
+ function afterAll(){
+ application action="update" preciseMath=variables.preciseMath;
+ };
+
+ function run( testResults, testBox ){
+ describe( "LDEV-5198 regression", function(){
+
+ it( "bit preciseMath=false", function(){
+ application action="update" preciseMath=false;
+ var t= 197;
+ var num = 9103313;
+ expect ( bitSHLN( t, 24) ).toBe( 3305111552 );
+ expect ( bitOr( num, 3305111552) ).toBe( 3314214865 ); // returns 3314214912
+ });
+
+ it( "bit preciseMath=true", function(){
+ application action="update" preciseMath=true;
+ var t= 197;
+ var num = 9103313;
+ expect ( bitSHLN( t, 24) ).toBe( 3305111552 );
+ expect ( bitOr( num, 3305111552) ).toBe( 3314214865 ); // returns 3314214912
+ });
+ } );
+ }
+
+}