@@ -205,15 +205,41 @@ measure_endpoint() {
205205 local end=$( date +%s%3N)
206206 local time=$(( end - start))
207207 local http_code=$( echo " $response " | tail -n1)
208-
209- # Handle curl failure (connection timeout, etc)
210- if [ -z " $http_code " ] || [ " $http_code " == " 000" ]; then
208+ local response_body=$( echo " $response " | head -n-1)
209+
210+ # Validate timing (protect against clock skew/adjustment)
211+ if [ " $time " -lt 0 ]; then
212+ # Clock went backward during operation
213+ local negative_time=$time # Preserve negative value for logging
214+
215+ # Check if HTTP request actually succeeded before treating as error
216+ if [ -z " $http_code " ] || [ " $http_code " == " 000" ]; then
217+ # No HTTP code at all - actual timeout/failure
218+ http_code=" 000"
219+ echo -e " ${YELLOW} [CLOCK SKEW DETECTED]${NC} $endpoint " >&2
220+ echo -e " Start: ${start} ms, End: ${end} ms, Calculated: ${negative_time} ms (NEGATIVE!)" >&2
221+ echo -e " HTTP Code: ${RED}${http_code} (NO RESPONSE)${NC} " >&2
222+ echo -e " ${RED} Result: Actual timeout/connection failure${NC} " >&2
223+ time=0
224+ else
225+ # HTTP succeeded but timing is invalid - use 0ms as placeholder
226+ echo -e " ${YELLOW} [CLOCK SKEW DETECTED]${NC} $endpoint " >&2
227+ echo -e " Start: ${start} ms, End: ${end} ms, Calculated: ${negative_time} ms (NEGATIVE!)" >&2
228+ echo -e " HTTP Code: ${GREEN}${http_code} (SUCCESS)${NC} " >&2
229+ echo -e " ${GREEN} Result: Operation succeeded, timing unmeasurable${NC} " >&2
230+ echo " 0|$http_code |clock_skew"
231+ return
232+ fi
233+ fi
234+
235+ # Handle curl failure (connection timeout, etc) - only if we have no HTTP code
236+ if [ -z " $http_code " ]; then
211237 http_code=" 000"
212238 # Log to stderr to avoid polluting the return value
213239 echo " [WARN] Endpoint $endpoint timed out or connection failed" >&2
214240 fi
215-
216- echo " $time |$http_code |$( echo " $response " | head -n-1 ) "
241+
242+ echo " $time |$http_code |$response_body "
217243}
218244
219245# Clear cache
@@ -228,8 +254,8 @@ clear_cache() {
228254 while [ $attempt -le $max_attempts ]; do
229255 curl -s -X POST " ${API_BASE} /api/cache/clear" > /dev/null 2>&1
230256
231- # Sanity check: Verify cache is actually empty
232- local stats=$( get_cache_stats )
257+ # Sanity check: Verify cache is actually empty (use fast version - no need to wait for full sync)
258+ local stats=$( get_cache_stats_fast )
233259 cache_length=$( echo " $stats " | jq -r ' .length' 2> /dev/null || echo " unknown" )
234260
235261 if [ " $cache_length " = " 0" ]; then
@@ -352,11 +378,16 @@ warmup_system() {
352378 clear_cache
353379}
354380
355- # Get cache stats
381+ # Get cache stats (fast version - may not be synced across workers)
382+ get_cache_stats_fast () {
383+ curl -s " ${API_BASE} /api/cache/stats" 2> /dev/null
384+ }
385+
386+ # Get cache stats (with sync wait for accurate cross-worker aggregation)
356387get_cache_stats () {
357- log_info " Waiting for cache stats to sync across all PM2 workers (8 seconds. HOLD!)..."
388+ log_info " Waiting for cache stats to sync across all PM2 workers (8 seconds. HOLD!)..." >&2
358389 sleep 8
359- curl -s " ${API_BASE} /api/cache/stats?details=true " 2> /dev/null
390+ curl -s " ${API_BASE} /api/cache/stats" 2> /dev/null
360391}
361392
362393# Helper: Create a test object and track it for cleanup
@@ -570,10 +601,11 @@ run_write_performance_test() {
570601 local num_tests=${5:- 100}
571602
572603 log_info " Running $num_tests $endpoint_name operations..." >&2
573-
604+
574605 declare -a times=()
575606 local total_time=0
576607 local failed_count=0
608+ local clock_skew_count=0
577609
578610 # For create endpoint, collect IDs directly into global array
579611 local collect_ids=0
@@ -590,10 +622,14 @@ run_write_performance_test() {
590622 # Only include successful operations with valid positive timing
591623 if [ " $time " = " -1" ] || [ -z " $time " ] || [ " $time " -lt 0 ]; then
592624 failed_count=$(( failed_count + 1 ))
625+ elif [ " $response_body " = " clock_skew" ]; then
626+ # Clock skew with successful HTTP code - count as success but note it
627+ clock_skew_count=$(( clock_skew_count + 1 ))
628+ # Don't add to times array (0ms is not meaningful) or total_time
593629 else
594630 times+=($time )
595631 total_time=$(( total_time + time))
596-
632+
597633 # Store created ID directly to global array for cleanup
598634 if [ $collect_ids -eq 1 ] && [ -n " $response_body " ]; then
599635 local obj_id=$( echo " $response_body " | grep -o ' "@id":"[^"]*"' | head -1 | cut -d' "' -f4)
@@ -609,34 +645,51 @@ run_write_performance_test() {
609645 fi
610646 done
611647 echo " " >&2
612-
648+
613649 local successful=$(( num_tests - failed_count))
614-
650+ local measurable=$(( ${# times[@]} ))
651+
615652 if [ $successful -eq 0 ]; then
616653 log_warning " All $endpoint_name operations failed!" >&2
617654 echo " 0|0|0|0"
618655 return 1
619656 fi
620-
621- # Calculate statistics
622- local avg_time=$(( total_time / successful))
623-
624- # Calculate median
625- IFS=$' \n ' sorted=($( sort -n <<< " ${times[*]}" ) )
626- unset IFS
627- local median_idx=$(( successful / 2 ))
628- local median_time=${sorted[$median_idx]}
629-
630- # Calculate min/max
631- local min_time=${sorted[0]}
632- local max_time=${sorted[$((successful - 1))]}
633-
657+
658+ # Calculate statistics only from operations with valid timing
659+ local avg_time=0
660+ local median_time=0
661+ local min_time=0
662+ local max_time=0
663+
664+ if [ $measurable -gt 0 ]; then
665+ avg_time=$(( total_time / measurable))
666+
667+ # Calculate median
668+ IFS=$' \n ' sorted=($( sort -n <<< " ${times[*]}" ) )
669+ unset IFS
670+ local median_idx=$(( measurable / 2 ))
671+ median_time=${sorted[$median_idx]}
672+
673+ # Calculate min/max
674+ min_time=${sorted[0]}
675+ max_time=${sorted[$((measurable - 1))]}
676+ fi
677+
634678 log_success " $successful /$num_tests successful" >&2
635- echo " Average: ${avg_time} ms, Median: ${median_time} ms, Min: ${min_time} ms, Max: ${max_time} ms" >&2
636-
679+
680+ if [ $measurable -gt 0 ]; then
681+ echo " Average: ${avg_time} ms, Median: ${median_time} ms, Min: ${min_time} ms, Max: ${max_time} ms" >&2
682+ else
683+ echo " (timing data unavailable - all operations affected by clock skew)" >&2
684+ fi
685+
637686 if [ $failed_count -gt 0 ]; then
638687 log_warning " Failed operations: $failed_count " >&2
639688 fi
689+
690+ if [ $clock_skew_count -gt 0 ]; then
691+ log_warning " Clock skew detections (timing unmeasurable but HTTP succeeded): $clock_skew_count " >&2
692+ fi
640693
641694 # Write stats to temp file (so they persist when function is called directly, not in subshell)
642695 echo " $avg_time |$median_time |$min_time |$max_time " > /tmp/rerum_write_stats
@@ -1147,20 +1200,20 @@ test_create_endpoint_full() {
11471200 local full_median=$( cat /tmp/rerum_write_stats 2> /dev/null | cut -d' |' -f2)
11481201
11491202 ENDPOINT_WARM_TIMES[" create" ]=$full_avg
1150-
1151- if [ " $full_avg " != " 0" ]; then
1152- local empty_avg=${ENDPOINT_COLD_TIMES["create"]}
1203+
1204+ local empty_avg=${ENDPOINT_COLD_TIMES["create"]:- 0}
1205+
1206+ if [ " $empty_avg " -eq 0 ] || [ -z " $empty_avg " ]; then
1207+ log_warning " Cannot calculate overhead - baseline test had no successful operations"
1208+ else
11531209 local overhead=$(( full_avg - empty_avg))
11541210 local overhead_pct=$(( overhead * 100 / empty_avg))
11551211
11561212 # WORST-CASE TEST: Measure O(n) scanning overhead
1157- log_overhead $overhead " O(n) invalidation scan overhead: ${overhead} ms (${overhead_pct} %) [Empty: ${empty_avg} ms → Full: ${full_avg} ms]"
11581213 if [ $overhead -lt 0 ]; then
1159- log_info " ℹ️ Negative values indicate DB variance between runs, not cache efficiency"
1160- elif [ $overhead -le 5 ]; then
1161- log_info " ✅ O(n) scanning overhead is negligible (${overhead} ms to scan ${CACHE_FILL_SIZE} entries)"
1214+ log_overhead 0 " Overhead: 0ms (0%) [Empty: ${empty_avg} ms → Full: ${full_avg} ms] (negligible - within statistical variance)"
11621215 else
1163- log_info " ⚠️ O(n) scanning adds ${overhead } ms overhead (scanning ${CACHE_FILL_SIZE} entries with no matches) "
1216+ log_overhead $overhead " Overhead: ${overhead} ms ( ${overhead_pct} %) [Empty: ${empty_avg } ms → Full: ${full_avg} ms] "
11641217 fi
11651218 fi
11661219}
@@ -1222,24 +1275,31 @@ test_update_endpoint_empty() {
12221275 if [ $empty_success -eq 0 ]; then
12231276 log_failure " Update endpoint failed (all requests failed)"
12241277 ENDPOINT_STATUS[" update" ]=" ❌ Failed"
1225- return
1226- elif [ $empty_failures -gt 0 ]; then
1227- log_warning " $empty_success /$NUM_ITERATIONS successful"
1228- log_warning " Update endpoint had partial failures: $empty_failures /$NUM_ITERATIONS failed"
1229- ENDPOINT_STATUS[" update" ]=" ⚠️ Partial Failures ($empty_failures /$NUM_ITERATIONS )"
1278+ ENDPOINT_COLD_TIMES[" update" ]=0
12301279 return
12311280 fi
1232-
1233- log_success " $empty_success /$NUM_ITERATIONS successful"
1234-
1281+
1282+ # Calculate average and median even with partial failures
12351283 local empty_avg=$(( empty_total / empty_success))
12361284 IFS=$' \n ' sorted_empty=($( sort -n <<< " ${empty_times[*]}" ) )
12371285 unset IFS
12381286 local empty_median=${sorted_empty[$((empty_success / 2))]}
1239-
1287+
12401288 ENDPOINT_COLD_TIMES[" update" ]=$empty_avg
1241- log_success " Update endpoint functional"
1242- ENDPOINT_STATUS[" update" ]=" ✅ Functional"
1289+
1290+ if [ $empty_failures -eq 0 ]; then
1291+ log_success " $empty_success /$NUM_ITERATIONS successful"
1292+ log_success " Update endpoint functional"
1293+ ENDPOINT_STATUS[" update" ]=" ✅ Functional"
1294+ elif [ $empty_failures -le 1 ]; then
1295+ log_success " $empty_success /$NUM_ITERATIONS successful"
1296+ log_warning " Update endpoint functional (${empty_failures} /${NUM_ITERATIONS} transient failures)"
1297+ ENDPOINT_STATUS[" update" ]=" ✅ Functional (${empty_failures} /${NUM_ITERATIONS} transient failures)"
1298+ else
1299+ log_warning " $empty_success /$NUM_ITERATIONS successful"
1300+ log_warning " Update endpoint had partial failures: $empty_failures /$NUM_ITERATIONS failed"
1301+ ENDPOINT_STATUS[" update" ]=" ⚠️ Partial Failures ($empty_failures /$NUM_ITERATIONS )"
1302+ fi
12431303}
12441304
12451305# Update endpoint - full cache version
@@ -1312,18 +1372,21 @@ test_update_endpoint_full() {
13121372 local full_median=${sorted_full[$((full_success / 2))]}
13131373
13141374 ENDPOINT_WARM_TIMES[" update" ]=$full_avg
1315-
1316- local empty_avg=${ENDPOINT_COLD_TIMES["update"]}
1317- local overhead=$(( full_avg - empty_avg))
1318- local overhead_pct=$(( overhead * 100 / empty_avg))
13191375
1320- log_overhead $overhead " O(n) scan overhead: ${overhead} ms (${overhead_pct} %) [Empty: ${empty_avg} ms → Full: ${full_avg} ms]"
1321- if [ $overhead -lt 0 ]; then
1322- log_info " ℹ️ Negative = DB variance, not cache"
1323- elif [ $overhead -le 5 ]; then
1324- log_info " ✅ Negligible O(n) overhead"
1376+ local empty_avg=${ENDPOINT_COLD_TIMES["update"]:- 0}
1377+
1378+ if [ " $empty_avg " -eq 0 ] || [ -z " $empty_avg " ]; then
1379+ log_warning " Cannot calculate overhead - baseline test had no successful operations"
13251380 else
1326- log_info " ⚠️ ${overhead} ms to scan ${CACHE_FILL_SIZE} entries"
1381+ local overhead=$(( full_avg - empty_avg))
1382+ local overhead_pct=$(( overhead * 100 / empty_avg))
1383+
1384+ # Display clamped value (0 or positive) but store actual value for report
1385+ if [ $overhead -lt 0 ]; then
1386+ log_overhead 0 " Overhead: 0ms (0%) [Empty: ${empty_avg} ms → Full: ${full_avg} ms] (negligible - within statistical variance)"
1387+ else
1388+ log_overhead $overhead " Overhead: ${overhead} ms (${overhead_pct} %) [Empty: ${empty_avg} ms → Full: ${full_avg} ms]"
1389+ fi
13271390 fi
13281391}
13291392
@@ -1390,12 +1453,20 @@ test_patch_endpoint_full() {
13901453 [ $success -eq 0 ] && return
13911454 local avg=$(( total / success))
13921455 ENDPOINT_WARM_TIMES[" patch" ]=$avg
1393- local empty=${ENDPOINT_COLD_TIMES["patch"]}
1394- local overhead=$(( avg - empty))
1395- local overhead_pct=$(( overhead * 100 / empty))
1456+ local empty=${ENDPOINT_COLD_TIMES["patch"]:- 0}
13961457
1397- log_overhead $overhead " O(n) scan: ${overhead} ms (${overhead_pct} %) [Empty: ${empty} ms → Full: ${avg} ms]"
1398- [ $overhead -lt 0 ] && log_info " ℹ️ DB variance" || [ $overhead -le 5 ] && log_info " ✅ Negligible" || log_info " ⚠️ ${overhead} ms overhead"
1458+ if [ " $empty " -eq 0 ] || [ -z " $empty " ]; then
1459+ log_warning " Cannot calculate overhead - baseline test had no successful operations"
1460+ else
1461+ local overhead=$(( avg - empty))
1462+ local overhead_pct=$(( overhead * 100 / empty))
1463+
1464+ if [ $overhead -lt 0 ]; then
1465+ log_overhead 0 " Overhead: 0ms (0%) [Empty: ${empty} ms → Full: ${avg} ms] (negligible - within statistical variance)"
1466+ else
1467+ log_overhead $overhead " Overhead: ${overhead} ms (${overhead_pct} %) [Empty: ${empty} ms → Full: ${avg} ms]"
1468+ fi
1469+ fi
13991470}
14001471
14011472test_set_endpoint_empty () {
@@ -1447,12 +1518,21 @@ test_set_endpoint_full() {
14471518 echo " " >&2
14481519 [ $success -eq 0 ] && return
14491520 ENDPOINT_WARM_TIMES[" set" ]=$(( total / success))
1450- local overhead=$(( ENDPOINT_WARM_TIMES["set"] - ENDPOINT_COLD_TIMES["set"]))
1451- local empty=${ENDPOINT_COLD_TIMES["set"]}
1521+ local empty=${ENDPOINT_COLD_TIMES["set"]:- 0}
14521522 local full=${ENDPOINT_WARM_TIMES["set"]}
14531523
1454- log_overhead $overhead " O(n): ${overhead} ms [Empty: ${empty} ms → Full: ${full} ms]"
1455- [ $overhead -lt 0 ] && log_info " ℹ️ DB variance" || [ $overhead -le 5 ] && log_info " ✅ Negligible" || log_info " ⚠️ ${overhead} ms"
1524+ if [ " $empty " -eq 0 ] || [ -z " $empty " ]; then
1525+ log_warning " Cannot calculate overhead - baseline test had no successful operations"
1526+ else
1527+ local overhead=$(( full - empty))
1528+ local overhead_pct=$(( overhead * 100 / empty))
1529+
1530+ if [ $overhead -lt 0 ]; then
1531+ log_overhead 0 " Overhead: 0ms (0%) [Empty: ${empty} ms → Full: ${full} ms] (negligible - within statistical variance)"
1532+ else
1533+ log_overhead $overhead " Overhead: ${overhead} ms (${overhead_pct} %) [Empty: ${empty} ms → Full: ${full} ms]"
1534+ fi
1535+ fi
14561536}
14571537
14581538test_unset_endpoint_empty () {
@@ -1509,9 +1589,9 @@ test_unset_endpoint_full() {
15091589 local overhead=$(( ENDPOINT_WARM_TIMES["unset"] - ENDPOINT_COLD_TIMES["unset"]))
15101590 local empty=${ENDPOINT_COLD_TIMES["unset"]}
15111591 local full=${ENDPOINT_WARM_TIMES["unset"]}
1592+ local overhead_pct=$(( overhead * 100 / empty))
15121593
1513- log_overhead $overhead " O(n): ${overhead} ms [${empty} ms → ${full} ms]"
1514- [ $overhead -lt 0 ] && log_info " ℹ️ DB variance" || [ $overhead -le 5 ] && log_info " ✅ Negligible" || log_info " ⚠️ ${overhead} ms"
1594+ log_overhead $overhead " Overhead: ${overhead} ms (${overhead_pct} %) [Empty: ${empty} ms → Full: ${full} ms]"
15151595}
15161596
15171597test_overwrite_endpoint_empty () {
@@ -1566,9 +1646,9 @@ test_overwrite_endpoint_full() {
15661646 local overhead=$(( ENDPOINT_WARM_TIMES["overwrite"] - ENDPOINT_COLD_TIMES["overwrite"]))
15671647 local empty=${ENDPOINT_COLD_TIMES["overwrite"]}
15681648 local full=${ENDPOINT_WARM_TIMES["overwrite"]}
1649+ local overhead_pct=$(( overhead * 100 / empty))
15691650
1570- log_overhead $overhead " O(n): ${overhead} ms [${empty} ms → ${full} ms]"
1571- [ $overhead -lt 0 ] && log_info " ℹ️ DB variance" || [ $overhead -le 5 ] && log_info " ✅ Negligible" || log_info " ⚠️ ${overhead} ms"
1651+ log_overhead $overhead " Overhead: ${overhead} ms (${overhead_pct} %) [Empty: ${empty} ms → Full: ${full} ms]"
15721652}
15731653
15741654test_delete_endpoint_empty () {
@@ -1643,9 +1723,9 @@ test_delete_endpoint_full() {
16431723 local overhead=$(( ENDPOINT_WARM_TIMES["delete"] - ENDPOINT_COLD_TIMES["delete"]))
16441724 local empty=${ENDPOINT_COLD_TIMES["delete"]}
16451725 local full=${ENDPOINT_WARM_TIMES["delete"]}
1726+ local overhead_pct=$(( overhead * 100 / empty))
16461727
1647- log_overhead $overhead " O(n): ${overhead} ms [${empty} ms → ${full} ms] (deleted: $success )"
1648- [ $overhead -lt 0 ] && log_info " ℹ️ DB variance" || [ $overhead -le 5 ] && log_info " ✅ Negligible" || log_info " ⚠️ ${overhead} ms"
1728+ log_overhead $overhead " Overhead: ${overhead} ms (${overhead_pct} %) [Empty: ${empty} ms → Full: ${full} ms] (deleted: $success )"
16491729}
16501730
16511731# ###############################################################################
0 commit comments