Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d2ca79dfd | ||
|
|
22c943d495 | ||
|
|
7e3d9b6825 | ||
|
|
547d22d09f | ||
|
|
ce9ae5a488 |
+16
-4
@@ -92,8 +92,20 @@ RUN cd c_utils_lib && \
|
||||
RUN cd nostr_core_lib && \
|
||||
chmod +x build.sh && \
|
||||
sed -i 's/CFLAGS="-Wall -Wextra -std=c99 -fPIC -O2"/CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 -Wall -Wextra -std=c99 -fPIC -O2"/' build.sh && \
|
||||
if [ "$(uname -m)" = "aarch64" ] && ! command -v aarch64-linux-gnu-gcc >/dev/null 2>&1; then \
|
||||
ln -sf /usr/bin/gcc /usr/local/bin/aarch64-linux-gnu-gcc; \
|
||||
fi && \
|
||||
rm -f *.o *.a 2>/dev/null || true && \
|
||||
./build.sh --nips=1,6,13,17,19,44,59
|
||||
./build.sh --nips=1,6,13,17,19,44,59 && \
|
||||
if [ -f libnostr_core_arm64.a ]; then \
|
||||
cp libnostr_core_arm64.a libnostr_core.a; \
|
||||
elif [ -f libnostr_core_x64.a ]; then \
|
||||
cp libnostr_core_x64.a libnostr_core.a; \
|
||||
else \
|
||||
echo "ERROR: No supported nostr_core static library produced"; \
|
||||
ls -la *.a 2>/dev/null || true; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
# Copy c-relay source files LAST (only this layer rebuilds on source changes)
|
||||
COPY src/ /build/src/
|
||||
@@ -103,9 +115,9 @@ COPY Makefile /build/Makefile
|
||||
# Disable fortification to avoid __*_chk symbols that don't exist in MUSL
|
||||
# Use conditional compilation flags based on DEBUG_BUILD argument
|
||||
RUN if [ "$DEBUG_BUILD" = "true" ]; then \
|
||||
CFLAGS="-g -O2 -DDEBUG"; \
|
||||
CFLAGS="-g -O2 -DDEBUG -fno-omit-frame-pointer"; \
|
||||
STRIP_CMD="echo 'Keeping debug symbols'"; \
|
||||
echo "Building with DEBUG symbols enabled (optimized with -O2)"; \
|
||||
echo "Building with DEBUG symbols enabled (optimized with -O2, frame pointers kept for perf)"; \
|
||||
else \
|
||||
CFLAGS="-O2"; \
|
||||
STRIP_CMD="strip /build/c_relay_static"; \
|
||||
@@ -121,7 +133,7 @@ RUN if [ "$DEBUG_BUILD" = "true" ]; then \
|
||||
src/db_ops.c src/thread_pool.c \
|
||||
-o /build/c_relay_static \
|
||||
c_utils_lib/libc_utils.a \
|
||||
nostr_core_lib/libnostr_core_x64.a \
|
||||
nostr_core_lib/libnostr_core.a \
|
||||
-lwebsockets -lssl -lcrypto -lsqlite3 -lsecp256k1 \
|
||||
-lcurl -lz -lpthread -lm -ldl && \
|
||||
eval "$STRIP_CMD"
|
||||
|
||||
@@ -92,63 +92,20 @@ x86: $(BUILD_DIR) src/main.h src/sql_schema.h $(MAIN_SRC) $(NOSTR_CORE_LIB) $(C_
|
||||
$(CC) $(CFLAGS) $(INCLUDES) $(MAIN_SRC) -o $(BUILD_DIR)/c_relay_x86 $(NOSTR_CORE_LIB) $(C_UTILS_LIB) $(LIBS)
|
||||
@echo "Build complete: $(BUILD_DIR)/c_relay_x86"
|
||||
|
||||
arm64: $(BUILD_DIR) src/main.h src/sql_schema.h $(MAIN_SRC) $(NOSTR_CORE_LIB) $(C_UTILS_LIB)
|
||||
@echo "Cross-compiling C-Relay for ARM64..."
|
||||
@if ! command -v aarch64-linux-gnu-gcc >/dev/null 2>&1; then \
|
||||
echo "ERROR: ARM64 cross-compiler not found."; \
|
||||
echo "Install with: make install-cross-tools"; \
|
||||
echo "Or install manually: sudo apt install gcc-aarch64-linux-gnu"; \
|
||||
exit 1; \
|
||||
fi
|
||||
@echo "Checking for ARM64 development libraries..."
|
||||
@if ! dpkg -l | grep -q "libssl-dev:arm64\|libsqlite3-dev:arm64"; then \
|
||||
echo "ERROR: ARM64 libraries not found. Cross-compilation requires ARM64 versions of:"; \
|
||||
echo " - libssl-dev:arm64"; \
|
||||
echo " - libsqlite3-dev:arm64"; \
|
||||
echo " - libwebsockets-dev:arm64"; \
|
||||
echo " - libsecp256k1-dev:arm64"; \
|
||||
echo " - zlib1g-dev:arm64"; \
|
||||
echo " - libcurl4-openssl-dev:arm64"; \
|
||||
echo ""; \
|
||||
echo "Install ARM64 libraries with: make install-arm64-deps"; \
|
||||
echo "Or use Docker for cross-platform builds."; \
|
||||
exit 1; \
|
||||
fi
|
||||
@echo "Using aarch64-linux-gnu-gcc with ARM64 libraries..."
|
||||
PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig:/usr/share/pkgconfig \
|
||||
aarch64-linux-gnu-gcc $(CFLAGS) $(INCLUDES) $(MAIN_SRC) -o $(BUILD_DIR)/c_relay_arm64 $(NOSTR_CORE_LIB) $(C_UTILS_LIB) \
|
||||
-L/usr/lib/aarch64-linux-gnu $(LIBS)
|
||||
@echo "Build complete: $(BUILD_DIR)/c_relay_arm64"
|
||||
|
||||
# Install ARM64 cross-compilation dependencies
|
||||
install-arm64-deps:
|
||||
@echo "Installing ARM64 cross-compilation dependencies..."
|
||||
@echo "This requires adding ARM64 architecture and installing cross-libraries..."
|
||||
sudo dpkg --add-architecture arm64
|
||||
sudo apt update
|
||||
sudo apt install -y \
|
||||
gcc-aarch64-linux-gnu \
|
||||
libc6-dev-arm64-cross \
|
||||
libssl-dev:arm64 \
|
||||
libsqlite3-dev:arm64 \
|
||||
zlib1g-dev:arm64 \
|
||||
libcurl4-openssl-dev:arm64
|
||||
@echo "Note: libwebsockets-dev:arm64 and libsecp256k1-dev:arm64 may need manual building"
|
||||
|
||||
# Install cross-compilation tools
|
||||
install-cross-tools:
|
||||
@echo "Installing cross-compilation tools..."
|
||||
sudo apt update
|
||||
sudo apt install -y gcc-aarch64-linux-gnu libc6-dev-arm64-cross
|
||||
|
||||
# Check what architectures we can actually build
|
||||
# Check local build tooling used by static Docker builder
|
||||
check-toolchain:
|
||||
@echo "Checking available toolchains:"
|
||||
@echo "Native compiler: $(shell $(CC) --version | head -1)"
|
||||
@if command -v aarch64-linux-gnu-gcc >/dev/null 2>&1; then \
|
||||
echo "ARM64 cross-compiler: $(shell aarch64-linux-gnu-gcc --version | head -1)"; \
|
||||
@if command -v docker >/dev/null 2>&1; then \
|
||||
echo "Docker: $$(docker --version)"; \
|
||||
else \
|
||||
echo "ARM64 cross-compiler: NOT INSTALLED (install with 'make install-cross-tools')"; \
|
||||
echo "Docker: NOT INSTALLED"; \
|
||||
fi
|
||||
@if docker buildx version >/dev/null 2>&1; then \
|
||||
echo "Docker buildx: AVAILABLE"; \
|
||||
else \
|
||||
echo "Docker buildx: NOT AVAILABLE (required for cross-architecture static builds)"; \
|
||||
fi
|
||||
|
||||
# Run tests
|
||||
@@ -185,42 +142,41 @@ help:
|
||||
@echo "Targets:"
|
||||
@echo " all Build the relay for current architecture (default)"
|
||||
@echo " x86 Build specifically for x86_64"
|
||||
@echo " arm64 Build for ARM64 (requires cross-compilation setup)"
|
||||
@echo " static-musl-x86_64 Build static MUSL binary using Docker (host arch default)"
|
||||
@echo " static-musl-arm64 Build static MUSL ARM64 binary using Docker buildx"
|
||||
@echo " static-musl Build both static MUSL binaries"
|
||||
@echo " test Build and run tests"
|
||||
@echo " init-db Initialize the database"
|
||||
@echo " clean Clean build artifacts"
|
||||
@echo " clean-all Clean everything including dependencies"
|
||||
@echo " install-deps Install system dependencies"
|
||||
@echo " install-cross-tools Install basic ARM64 cross-compiler"
|
||||
@echo " install-arm64-deps Install ARM64 cross-compilation libraries"
|
||||
@echo " check-toolchain Check available compilers"
|
||||
@echo " check-toolchain Check available local tooling"
|
||||
@echo " help Show this help"
|
||||
@echo ""
|
||||
@echo "Usage:"
|
||||
@echo " make # Build the relay for current arch"
|
||||
@echo " make x86 # Build for x86_64"
|
||||
@echo " make arm64 # Build for ARM64 (fails if cross-compilation not set up)"
|
||||
@echo " make install-arm64-deps # Install full ARM64 cross-compilation setup"
|
||||
@echo " make check-toolchain # Check what compilers are available"
|
||||
@echo " make static-musl-x86_64 # Build static binary via ./build_static.sh"
|
||||
@echo " make static-musl-arm64 # Build ARM64 static binary via ./build_static.sh --arch arm64"
|
||||
@echo " make static-musl # Build both static binaries"
|
||||
@echo " make check-toolchain # Check docker/buildx availability"
|
||||
@echo " make test # Run tests"
|
||||
@echo " make init-db # Set up database"
|
||||
@echo " make force-version # Force regenerate main.h from git"
|
||||
|
||||
# Build fully static MUSL binaries using Docker
|
||||
static-musl-x86_64:
|
||||
@echo "Building fully static MUSL binary for x86_64..."
|
||||
docker buildx build --platform linux/amd64 -f examples/deployment/static-builder.Dockerfile -t c-relay-static-builder-x86_64 --load .
|
||||
docker run --rm -v $(PWD)/build:/output c-relay-static-builder-x86_64 sh -c "cp /c_relay_static_musl_x86_64 /output/"
|
||||
@echo "Static binary created: build/c_relay_static_musl_x86_64"
|
||||
@echo "Building fully static MUSL binary using host architecture default..."
|
||||
./build_static.sh
|
||||
@echo "Static binary created in build/ (host architecture naming)"
|
||||
|
||||
static-musl-arm64:
|
||||
@echo "Building fully static MUSL binary for ARM64..."
|
||||
docker buildx build --platform linux/arm64 -f examples/deployment/static-builder.Dockerfile -t c-relay-static-builder-arm64 --load .
|
||||
docker run --rm -v $(PWD)/build:/output c-relay-static-builder-arm64 sh -c "cp /c_relay_static_musl_x86_64 /output/c_relay_static_musl_arm64"
|
||||
@echo "Static binary created: build/c_relay_static_musl_arm64"
|
||||
./build_static.sh --arch arm64
|
||||
@echo "Static ARM64 binary created in build/"
|
||||
|
||||
static-musl: static-musl-x86_64 static-musl-arm64
|
||||
@echo "Built static MUSL binaries for both architectures"
|
||||
|
||||
.PHONY: static-musl-x86_64 static-musl-arm64 static-musl
|
||||
.PHONY: all x86 arm64 test init-db clean clean-all install-deps install-cross-tools install-arm64-deps check-toolchain help force-version
|
||||
.PHONY: all x86 test init-db clean clean-all install-deps check-toolchain help force-version
|
||||
+3
-2
@@ -449,7 +449,8 @@ async function setupAutomaticRelayConnection(showSections = false) {
|
||||
const relayInfo = await fetchRelayInfo(httpUrl);
|
||||
|
||||
const fetchedPubkey = relayInfo && relayInfo.pubkey ? relayInfo.pubkey : null;
|
||||
relayPubkey = fetchedPubkey || '4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa';
|
||||
// Fallback must match the actual running relay pubkey when NIP-11 doesn't expose pubkey.
|
||||
relayPubkey = fetchedPubkey || 'e9aa50decff01f2cec1ec2b2e0b34332cf9c92cafdac5a7cc0881a6d26b59854';
|
||||
|
||||
// Keep relay metadata (including version) even when pubkey is missing/fallback
|
||||
relayInfoData = {
|
||||
@@ -466,7 +467,7 @@ async function setupAutomaticRelayConnection(showSections = false) {
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('⚠️ Could not fetch relay info, using fallback pubkey:', error.message);
|
||||
relayPubkey = '4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa';
|
||||
relayPubkey = 'e9aa50decff01f2cec1ec2b2e0b34332cf9c92cafdac5a7cc0881a6d26b59854';
|
||||
}
|
||||
|
||||
// Set up subscription to receive admin API responses
|
||||
|
||||
+78
-3
@@ -11,8 +11,41 @@ DOCKERFILE="$SCRIPT_DIR/Dockerfile.alpine-musl"
|
||||
|
||||
# Parse command line arguments
|
||||
DEBUG_BUILD=false
|
||||
if [[ "$1" == "--debug" ]]; then
|
||||
DEBUG_BUILD=true
|
||||
TARGET_ARCH=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--debug)
|
||||
DEBUG_BUILD=true
|
||||
shift
|
||||
;;
|
||||
--arch)
|
||||
if [[ -z "$2" ]]; then
|
||||
echo "ERROR: --arch requires a value"
|
||||
echo "Usage: $0 [--debug] [--arch <arm64|armv7|x86_64>]"
|
||||
exit 1
|
||||
fi
|
||||
case "$2" in
|
||||
arm64|armv7|x86_64)
|
||||
TARGET_ARCH="$2"
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: Unsupported architecture '$2'"
|
||||
echo "Supported values: arm64, armv7, x86_64"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: Unknown argument '$1'"
|
||||
echo "Usage: $0 [--debug] [--arch <arm64|armv7|x86_64>]"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$DEBUG_BUILD" = true ]; then
|
||||
echo "=========================================="
|
||||
echo "C-Relay MUSL Static Binary Builder (DEBUG MODE)"
|
||||
echo "=========================================="
|
||||
@@ -24,6 +57,9 @@ fi
|
||||
echo "Project directory: $SCRIPT_DIR"
|
||||
echo "Build directory: $BUILD_DIR"
|
||||
echo "Debug build: $DEBUG_BUILD"
|
||||
if [[ -n "$TARGET_ARCH" ]]; then
|
||||
echo "Requested target architecture: $TARGET_ARCH"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Create build directory
|
||||
@@ -58,17 +94,43 @@ DOCKER_CMD="docker"
|
||||
echo "✓ Docker is available and running"
|
||||
echo ""
|
||||
|
||||
# Detect architecture
|
||||
# Detect host architecture
|
||||
ARCH=$(uname -m)
|
||||
case "$ARCH" in
|
||||
x86_64)
|
||||
HOST_ARCH="x86_64"
|
||||
;;
|
||||
aarch64|arm64)
|
||||
HOST_ARCH="arm64"
|
||||
;;
|
||||
armv7l|armv7)
|
||||
HOST_ARCH="armv7"
|
||||
;;
|
||||
*)
|
||||
HOST_ARCH="unknown"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Resolve target architecture
|
||||
if [[ -n "$TARGET_ARCH" ]]; then
|
||||
ARCH="$TARGET_ARCH"
|
||||
fi
|
||||
|
||||
case "$ARCH" in
|
||||
x86_64)
|
||||
PLATFORM="linux/amd64"
|
||||
OUTPUT_NAME="c_relay_static_x86_64"
|
||||
;;
|
||||
aarch64|arm64)
|
||||
ARCH="arm64"
|
||||
PLATFORM="linux/arm64"
|
||||
OUTPUT_NAME="c_relay_static_arm64"
|
||||
;;
|
||||
armv7l|armv7)
|
||||
ARCH="armv7"
|
||||
PLATFORM="linux/arm/v7"
|
||||
OUTPUT_NAME="c_relay_static_armv7"
|
||||
;;
|
||||
*)
|
||||
echo "WARNING: Unknown architecture: $ARCH"
|
||||
echo "Defaulting to linux/amd64"
|
||||
@@ -77,6 +139,19 @@ case "$ARCH" in
|
||||
;;
|
||||
esac
|
||||
|
||||
# When cross-building, ensure buildx exists and warn about QEMU/binfmt setup
|
||||
if [[ "$HOST_ARCH" != "unknown" && "$ARCH" != "$HOST_ARCH" ]]; then
|
||||
echo "NOTE: Cross-building from host '$HOST_ARCH' to target '$ARCH'."
|
||||
echo " Docker QEMU/binfmt support is required for this to work."
|
||||
if ! docker buildx version >/dev/null 2>&1; then
|
||||
echo "ERROR: docker buildx is required for cross-architecture builds but is not available."
|
||||
echo "Install/enable buildx and binfmt support, then retry."
|
||||
exit 1
|
||||
fi
|
||||
echo "✓ docker buildx is available for cross-architecture build"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Append _debug suffix to output name for debug builds so production binary is never overwritten
|
||||
if [ "$DEBUG_BUILD" = true ]; then
|
||||
OUTPUT_NAME="${OUTPUT_NAME}_debug"
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
# Agent Browser Testing Guide for C-Relay
|
||||
|
||||
This document explains how to use the `agent-browser` CLI tool to test the c-relay admin web UI from an AI agent context (no physical display required).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **agent-browser** installed globally: `npm install -g agent-browser`
|
||||
- Binary location: `/home/user/.nvm/versions/node/v24.14.1/bin/agent-browser`
|
||||
- The relay must be running locally (default port 8888)
|
||||
- Test keys configured in `.test_keys`
|
||||
|
||||
## Starting the Relay for Local Testing
|
||||
|
||||
```bash
|
||||
./make_and_restart_relay.sh -t
|
||||
```
|
||||
|
||||
This reads `.test_keys` and starts the relay with:
|
||||
- `ADMIN_PUBKEY` — the hex public key of the admin account
|
||||
- `ADMIN_PRIVKEY` — the hex secret key (used for browser login, not by the relay itself)
|
||||
- `SERVER_PRIVKEY` — the relay's own private key
|
||||
|
||||
## Key URLs
|
||||
|
||||
| URL | Purpose |
|
||||
|-----|---------|
|
||||
| `http://127.0.0.1:8888/api/index.html` | Admin web UI (the correct entry point) |
|
||||
| `http://127.0.0.1:8888/` | Returns 406 without NIP-11 Accept header — **do not use for browser testing** |
|
||||
| `http://127.0.0.1:8888/` with `Accept: application/nostr+json` | NIP-11 relay info JSON |
|
||||
|
||||
**Important:** The root URL `/` is a WebSocket/NIP-11 endpoint, not an HTML page. Always use `/api/index.html` for browser testing.
|
||||
|
||||
## Admin Login Credentials
|
||||
|
||||
The admin nsec for the current `.test_keys` configuration:
|
||||
|
||||
```
|
||||
nsec: nsec1zkn0hlt4jvcvn9yt5p7ea4m7f82pf3ph0gj3d4rlcz4s64x5z86satv9qm
|
||||
hex: 15a6fbfd759330c9948ba07d9ed77e49d414c4377a2516d47fc0ab0d54d411f5
|
||||
npub: npub1tlyzk6slzt8d989f4pn3synk98fea64ea3jmrdc7dtd0kw8uxlas9a9fwr
|
||||
hex pubkey: 5fc82b6a1f12ced29ca9a86718127629d39eeab9ec65b1b71e6adafb38fc37fb
|
||||
```
|
||||
|
||||
## Complete Login Flow with agent-browser
|
||||
|
||||
### Step 1: Open the admin UI
|
||||
|
||||
```bash
|
||||
agent-browser open http://127.0.0.1:8888/api/index.html
|
||||
agent-browser wait --load networkidle
|
||||
```
|
||||
|
||||
### Step 2: Take an interactive snapshot to see what is on screen
|
||||
|
||||
```bash
|
||||
agent-browser snapshot -i
|
||||
```
|
||||
|
||||
You will see a login modal with buttons like:
|
||||
- `"Browser Extension"` — skip this
|
||||
- `"Local Key"` — **use this one**
|
||||
- `"Seed Phrase"` — skip
|
||||
- `"Nostr Connect"` — skip
|
||||
- `"Read Only"` — skip
|
||||
|
||||
### Step 3: Click "Local Key"
|
||||
|
||||
```bash
|
||||
agent-browser click @e15
|
||||
```
|
||||
|
||||
(The ref number may vary — use the ref from the snapshot output for the "Local Key" button.)
|
||||
|
||||
After clicking, a text input appears asking for the secret key.
|
||||
|
||||
### Step 4: Enter the admin nsec
|
||||
|
||||
```bash
|
||||
agent-browser fill @e14 "nsec1zkn0hlt4jvcvn9yt5p7ea4m7f82pf3ph0gj3d4rlcz4s64x5z86satv9qm"
|
||||
```
|
||||
|
||||
(Use the ref from the snapshot for the textbox element.)
|
||||
|
||||
### Step 5: Click "Import Key"
|
||||
|
||||
```bash
|
||||
agent-browser snapshot -i
|
||||
```
|
||||
|
||||
Check the snapshot — the "Import Key" button should now be enabled. Click it:
|
||||
|
||||
```bash
|
||||
agent-browser click @e15
|
||||
```
|
||||
|
||||
### Step 6: Click "Continue" on the success screen
|
||||
|
||||
After import, a success screen appears with "Continue" button:
|
||||
|
||||
```bash
|
||||
agent-browser wait 800
|
||||
agent-browser snapshot -i
|
||||
agent-browser click @e19
|
||||
```
|
||||
|
||||
(Use the ref from the snapshot for the "Continue" button.)
|
||||
|
||||
### Step 7: Wait for admin UI to load
|
||||
|
||||
```bash
|
||||
agent-browser wait 5000
|
||||
agent-browser snapshot -i
|
||||
```
|
||||
|
||||
You should now see the admin dashboard with:
|
||||
- Statistics table (Database Size, Total Events, PID, etc.)
|
||||
- Navigation buttons (Statistics, Subscriptions, Configuration, Authorization, etc.)
|
||||
- Admin profile area showing "admin" label
|
||||
|
||||
## Navigating Admin Sections
|
||||
|
||||
After login, use the sidebar navigation buttons:
|
||||
|
||||
```bash
|
||||
# View configuration
|
||||
agent-browser click @e8 # Configuration button ref
|
||||
|
||||
# View authorization rules
|
||||
agent-browser click @e9 # Authorization button ref
|
||||
|
||||
# View statistics
|
||||
agent-browser click @e6 # Statistics button ref
|
||||
|
||||
# Always snapshot after navigation to see results
|
||||
agent-browser wait 2500
|
||||
agent-browser snapshot -i
|
||||
```
|
||||
|
||||
## Checking for Errors
|
||||
|
||||
```bash
|
||||
# View browser console logs
|
||||
agent-browser console
|
||||
|
||||
# View JavaScript errors
|
||||
agent-browser errors
|
||||
|
||||
# View relay server logs
|
||||
tail -n 100 relay.log
|
||||
```
|
||||
|
||||
## Chained Command Example (Full Login in One Shot)
|
||||
|
||||
```bash
|
||||
agent-browser open http://127.0.0.1:8888/api/index.html && \
|
||||
agent-browser wait --load networkidle && \
|
||||
agent-browser snapshot -i
|
||||
```
|
||||
|
||||
Then use refs from the snapshot to complete login steps.
|
||||
|
||||
## Tips for AI Agents
|
||||
|
||||
1. **Always use `/api/index.html`** — never the root URL
|
||||
2. **Use `snapshot -i`** after every action to see the current interactive elements and their refs
|
||||
3. **Refs change** between snapshots — always re-snapshot before clicking
|
||||
4. **Wait after clicks** — use `agent-browser wait 2000` (milliseconds) between actions that trigger async operations
|
||||
5. **The login flow has 3 screens**: method selection → key input → success confirmation
|
||||
6. **Console logs are cumulative** — they show all logs since page load, which is useful for debugging admin API responses
|
||||
7. **The relay log** at `relay.log` shows server-side processing of admin commands
|
||||
8. **Command chaining** with `&&` works — the browser daemon persists between commands
|
||||
|
||||
## Verifying Admin API is Working
|
||||
|
||||
After login, the statistics page should show populated data:
|
||||
- Database Size (e.g., "4 KB")
|
||||
- Process ID (the relay PID)
|
||||
- WebSocket Connections count
|
||||
- Memory Usage
|
||||
|
||||
If these show "-" or "Loading...", check:
|
||||
1. `relay.log` for errors
|
||||
2. `agent-browser console` for JavaScript errors
|
||||
3. `agent-browser errors` for page-level errors
|
||||
|
||||
## Closing the Browser
|
||||
|
||||
```bash
|
||||
agent-browser close --all
|
||||
```
|
||||
+81
-26
@@ -18,6 +18,8 @@ COMMIT_MESSAGE=""
|
||||
RELEASE_MODE=false
|
||||
VERSION_INCREMENT_TYPE="patch" # "patch", "minor", or "major"
|
||||
|
||||
VERSION_INCREMENT_EXPLICIT=false
|
||||
|
||||
show_usage() {
|
||||
echo "C-Relay Increment and Push Script"
|
||||
echo ""
|
||||
@@ -30,6 +32,7 @@ show_usage() {
|
||||
echo " $0 -m \"commit message\" Increment minor version"
|
||||
echo " $0 -M \"commit message\" Increment major version"
|
||||
echo " $0 -r \"commit message\" Create release with assets (no version increment)"
|
||||
echo " $0 -r -p \"commit message\" Create release with patch version increment"
|
||||
echo " $0 -r -m \"commit message\" Create release with minor version increment"
|
||||
echo " $0 -h Show this help message"
|
||||
echo ""
|
||||
@@ -45,6 +48,7 @@ show_usage() {
|
||||
echo " $0 -m \"Added new features\""
|
||||
echo " $0 -M \"Breaking API changes\""
|
||||
echo " $0 -r \"Release current version\""
|
||||
echo " $0 -r -p \"Release with patch increment\""
|
||||
echo " $0 -r -m \"Release with minor increment\""
|
||||
echo ""
|
||||
echo "VERSION INCREMENT MODES:"
|
||||
@@ -53,7 +57,7 @@ show_usage() {
|
||||
echo " -M, --major: Increment major version, zero minor+patch (v1.2.3 → v2.0.0)"
|
||||
echo ""
|
||||
echo "RELEASE MODE (-r flag):"
|
||||
echo " - Build static binary using build_static.sh"
|
||||
echo " - Build static binaries for x86_64 and ARM64 (Raspberry Pi) using build_static.sh"
|
||||
echo " - Create source tarball"
|
||||
echo " - Git add, commit, push, and create Gitea release with assets"
|
||||
echo " - Can be combined with version increment flags"
|
||||
@@ -72,14 +76,17 @@ while [[ $# -gt 0 ]]; do
|
||||
;;
|
||||
-p|--patch)
|
||||
VERSION_INCREMENT_TYPE="patch"
|
||||
VERSION_INCREMENT_EXPLICIT=true
|
||||
shift
|
||||
;;
|
||||
-m|--minor)
|
||||
VERSION_INCREMENT_TYPE="minor"
|
||||
VERSION_INCREMENT_EXPLICIT=true
|
||||
shift
|
||||
;;
|
||||
-M|--major)
|
||||
VERSION_INCREMENT_TYPE="major"
|
||||
VERSION_INCREMENT_EXPLICIT=true
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
@@ -306,9 +313,9 @@ git_commit_and_push_no_tag() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to build release binary
|
||||
# Function to build release binaries
|
||||
build_release_binary() {
|
||||
print_status "Building release binary..."
|
||||
print_status "Building release binaries..."
|
||||
|
||||
# Check if build_static.sh exists
|
||||
if [[ ! -f "build_static.sh" ]]; then
|
||||
@@ -316,14 +323,22 @@ build_release_binary() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Run the static build script
|
||||
# Build x86_64 first (required for success)
|
||||
if ./build_static.sh > /dev/null 2>&1; then
|
||||
print_success "Built static binary successfully"
|
||||
return 0
|
||||
print_success "Built x86_64 static binary successfully"
|
||||
else
|
||||
print_error "Failed to build static binary"
|
||||
print_error "Failed to build x86_64 static binary"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Build arm64 second (warning-only on failure)
|
||||
if ./build_static.sh --arch arm64 > /dev/null 2>&1; then
|
||||
print_success "Built ARM64 static binary successfully"
|
||||
else
|
||||
print_warning "Failed to build ARM64 static binary (continuing with release)"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to create source tarball
|
||||
@@ -353,8 +368,9 @@ create_source_tarball() {
|
||||
# Function to upload release assets to Gitea
|
||||
upload_release_assets() {
|
||||
local release_id="$1"
|
||||
local binary_path="$2"
|
||||
local binary_path_x86="$2"
|
||||
local tarball_path="$3"
|
||||
local binary_path_arm64="$4"
|
||||
|
||||
print_status "Uploading release assets..."
|
||||
|
||||
@@ -369,9 +385,9 @@ upload_release_assets() {
|
||||
local assets_url="$api_url/releases/$release_id/assets"
|
||||
print_status "Assets URL: $assets_url"
|
||||
|
||||
# Upload binary
|
||||
if [[ -f "$binary_path" ]]; then
|
||||
print_status "Uploading binary: $(basename "$binary_path")"
|
||||
# Upload x86_64 binary
|
||||
if [[ -f "$binary_path_x86" ]]; then
|
||||
print_status "Uploading binary: $(basename "$binary_path_x86")"
|
||||
|
||||
# Retry loop for eventual consistency
|
||||
local max_attempts=3
|
||||
@@ -380,11 +396,11 @@ upload_release_assets() {
|
||||
print_status "Upload attempt $attempt/$max_attempts"
|
||||
local binary_response=$(curl -fS -X POST "$assets_url" \
|
||||
-H "Authorization: token $token" \
|
||||
-F "attachment=@$binary_path;filename=$(basename "$binary_path")" \
|
||||
-F "name=$(basename "$binary_path")")
|
||||
-F "attachment=@$binary_path_x86;filename=$(basename "$binary_path_x86")" \
|
||||
-F "name=$(basename "$binary_path_x86")")
|
||||
|
||||
if echo "$binary_response" | grep -q '"id"'; then
|
||||
print_success "Uploaded binary successfully"
|
||||
print_success "Uploaded x86_64 binary successfully"
|
||||
break
|
||||
else
|
||||
print_warning "Upload attempt $attempt failed"
|
||||
@@ -392,7 +408,37 @@ upload_release_assets() {
|
||||
print_status "Retrying in 2 seconds..."
|
||||
sleep 2
|
||||
else
|
||||
print_error "Failed to upload binary after $max_attempts attempts"
|
||||
print_error "Failed to upload x86_64 binary after $max_attempts attempts"
|
||||
print_error "Response: $binary_response"
|
||||
fi
|
||||
fi
|
||||
((attempt++))
|
||||
done
|
||||
fi
|
||||
|
||||
# Upload ARM64 binary
|
||||
if [[ -f "$binary_path_arm64" ]]; then
|
||||
print_status "Uploading binary: $(basename "$binary_path_arm64")"
|
||||
|
||||
local max_attempts=3
|
||||
local attempt=1
|
||||
while [[ $attempt -le $max_attempts ]]; do
|
||||
print_status "Upload attempt $attempt/$max_attempts"
|
||||
local binary_response=$(curl -fS -X POST "$assets_url" \
|
||||
-H "Authorization: token $token" \
|
||||
-F "attachment=@$binary_path_arm64;filename=$(basename "$binary_path_arm64")" \
|
||||
-F "name=$(basename "$binary_path_arm64")")
|
||||
|
||||
if echo "$binary_response" | grep -q '"id"'; then
|
||||
print_success "Uploaded ARM64 binary successfully"
|
||||
break
|
||||
else
|
||||
print_warning "Upload attempt $attempt failed"
|
||||
if [[ $attempt -lt $max_attempts ]]; then
|
||||
print_status "Retrying in 2 seconds..."
|
||||
sleep 2
|
||||
else
|
||||
print_error "Failed to upload ARM64 binary after $max_attempts attempts"
|
||||
print_error "Response: $binary_response"
|
||||
fi
|
||||
fi
|
||||
@@ -482,7 +528,7 @@ main() {
|
||||
print_status "=== RELEASE MODE ==="
|
||||
|
||||
# Only increment version if explicitly requested (not just because of -r flag)
|
||||
if [[ "$VERSION_INCREMENT_TYPE" != "patch" ]]; then
|
||||
if [[ "$VERSION_INCREMENT_EXPLICIT" == true ]]; then
|
||||
increment_version "$VERSION_INCREMENT_TYPE"
|
||||
else
|
||||
# In release mode without version increment, get current version
|
||||
@@ -504,16 +550,25 @@ main() {
|
||||
git_commit_and_push_no_tag
|
||||
|
||||
# Build release binary
|
||||
local binary_path_x86=""
|
||||
local binary_path_arm64=""
|
||||
if build_release_binary; then
|
||||
local binary_path="build/c_relay_static_x86_64"
|
||||
else
|
||||
print_warning "Binary build failed, continuing with release creation"
|
||||
# Check if binary exists from previous build
|
||||
if [[ -f "build/c_relay_static_x86_64" ]]; then
|
||||
print_status "Using existing binary from previous build"
|
||||
binary_path="build/c_relay_static_x86_64"
|
||||
else
|
||||
binary_path=""
|
||||
binary_path_x86="build/c_relay_static_x86_64"
|
||||
fi
|
||||
if [[ -f "build/c_relay_static_arm64" ]]; then
|
||||
binary_path_arm64="build/c_relay_static_arm64"
|
||||
fi
|
||||
else
|
||||
print_warning "x86_64 binary build failed, continuing with release creation"
|
||||
# Check if binaries exist from previous build
|
||||
if [[ -f "build/c_relay_static_x86_64" ]]; then
|
||||
print_status "Using existing x86_64 binary from previous build"
|
||||
binary_path_x86="build/c_relay_static_x86_64"
|
||||
fi
|
||||
if [[ -f "build/c_relay_static_arm64" ]]; then
|
||||
print_status "Using existing ARM64 binary from previous build"
|
||||
binary_path_arm64="build/c_relay_static_arm64"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -531,8 +586,8 @@ main() {
|
||||
# Validate release_id is numeric
|
||||
if [[ "$release_id" =~ ^[0-9]+$ ]]; then
|
||||
# Upload assets if we have a release ID and assets
|
||||
if [[ -n "$release_id" && (-n "$binary_path" || -n "$tarball_path") ]]; then
|
||||
upload_release_assets "$release_id" "$binary_path" "$tarball_path"
|
||||
if [[ -n "$release_id" && (-n "$binary_path_x86" || -n "$binary_path_arm64" || -n "$tarball_path") ]]; then
|
||||
upload_release_assets "$release_id" "$binary_path_x86" "$tarball_path" "$binary_path_arm64"
|
||||
fi
|
||||
print_success "Release $NEW_VERSION completed successfully!"
|
||||
else
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
# Plan: Eliminate g_db from the Main Thread
|
||||
|
||||
## Problem Statement
|
||||
|
||||
All SQLite calls go through `db_ops.c`, but `db_active_connection()` falls back to `g_db` when `g_thread_db` is NULL. Since the main thread never sets `g_thread_db`, every `db_*` call from lws-main executes synchronous SQLite on the main thread. The thread pool workers have their own connections and work correctly — the problem is the **fallback path**.
|
||||
|
||||
Current perf data shows lws-main at **67.6% avg CPU**, dominated by SQLite symbols (`sqlite3BtreeTableMoveto`, `sqlite3VdbeExec`, `pcache1Fetch`).
|
||||
|
||||
## Goal
|
||||
|
||||
Remove `g_db` as a runtime connection used by the main thread. After this change:
|
||||
- The main thread has **no SQLite connection** and cannot execute synchronous queries
|
||||
- All DB work routes through thread pool workers (which have their own connections)
|
||||
- `g_db` is only used during startup/shutdown (before/after the event loop)
|
||||
- Any accidental `db_*` call from lws-main returns an error instead of silently blocking
|
||||
|
||||
## Architecture After Change
|
||||
|
||||
```
|
||||
lws-main thread:
|
||||
- WebSocket protocol handling
|
||||
- Message parsing/routing
|
||||
- Completion queue draining
|
||||
- NO SQLite access during event loop
|
||||
|
||||
db-read-0 thread:
|
||||
- REQ queries
|
||||
- COUNT queries
|
||||
- Config cache miss reads
|
||||
- Auth rule checks
|
||||
- Monitoring/stats queries
|
||||
|
||||
db-write thread:
|
||||
- EVENT inserts
|
||||
- Subscription logging
|
||||
- Config updates
|
||||
- Auth rule modifications
|
||||
|
||||
event-worker thread:
|
||||
- Signature validation
|
||||
- Duplicate check
|
||||
- Store via db-write
|
||||
```
|
||||
|
||||
## Categorized g_db Call Sites
|
||||
|
||||
### Category A: Startup-only — keep using g_db
|
||||
|
||||
These run before the event loop starts. They are fine.
|
||||
|
||||
| Function | File | Purpose |
|
||||
|----------|------|---------|
|
||||
| `db_init()` | db_ops.c:27 | Open database |
|
||||
| `db_exec_sql()` for PRAGMAs | main.c:854-882 | WAL, mmap, cache setup |
|
||||
| `db_table_exists()` | main.c:750 | Schema check |
|
||||
| `db_get_schema_version_dup()` | main.c:754 | Migration check |
|
||||
| `db_exec_sql()` for schema | main.c:842 | Create tables |
|
||||
| `populate_all_config_values_atomic()` | config.c:4290 | First-time config |
|
||||
| `populate_default_config_values()` | config.c:1657 | Default config |
|
||||
| `add_pubkeys_to_config_table()` | config.c:1778 | Pubkey storage |
|
||||
| `apply_cli_overrides_atomic()` | config.c:4211 | CLI overrides |
|
||||
| `db_store_relay_private_key_hex()` | config.c:495 | Key storage |
|
||||
| `db_populate_event_tags_from_existing()` | main.c:1156 | Tag migration |
|
||||
| `cleanup_all_subscriptions_on_startup()` | subscriptions.c:1092 | Orphan cleanup |
|
||||
|
||||
### Category B: Shutdown-only — keep using g_db
|
||||
|
||||
| Function | File | Purpose |
|
||||
|----------|------|---------|
|
||||
| `db_exec_sql()` WAL checkpoint | main.c:900 | Clean shutdown |
|
||||
| `db_close()` | main.c:904 | Close connection |
|
||||
|
||||
### Category C: Runtime hot path — must move off main thread
|
||||
|
||||
These are called during the event loop from lws-main context.
|
||||
|
||||
| Function | File | Called from | Fix strategy |
|
||||
|----------|------|------------|--------------|
|
||||
| `db_get_config_value_dup()` | db_ops.c:777 | config cache miss | Already cached with 5s TTL; pre-warm cache at startup so misses are rare |
|
||||
| `store_event()` for kind 14/1059 | main.c:983 | websockets.c sync path | Route through async event worker |
|
||||
| `store_event_post_actions()` | main.c | completion handler | Already runs on main; its DB calls need routing |
|
||||
| `db_log_subscription_created()` | db_ops.c:145 | subscriptions.c | Fire-and-forget via write queue |
|
||||
| `db_log_subscription_closed()` | db_ops.c:165 | subscriptions.c | Fire-and-forget via write queue |
|
||||
| `db_log_subscription_disconnected()` | db_ops.c:193 | subscriptions.c | Fire-and-forget via write queue |
|
||||
| `db_update_subscription_events_sent()` | db_ops.c:225 | subscriptions.c | Fire-and-forget via write queue |
|
||||
| `db_cleanup_orphaned_subscriptions()` | db_ops.c:244 | subscriptions.c | Move to startup only |
|
||||
| `generate_and_post_status_event()` | websockets.c:3408 | periodic timer | Submit to write worker |
|
||||
| `ip_ban_cleanup()` / `ip_ban_log_stats()` | websockets.c:3196 | periodic timer | Submit to write worker |
|
||||
| `db_get_total_event_count_ll()` | db_ops.c:589 | api.c monitoring | Submit to read worker |
|
||||
| `db_get_event_count_since()` | db_ops.c:606 | api.c monitoring | Submit to read worker |
|
||||
| `db_get_event_kind_distribution_rows()` | db_ops.c:625 | api.c monitoring | Submit to read worker |
|
||||
| `db_get_top_pubkeys_rows()` | db_ops.c:663 | api.c monitoring | Submit to read worker |
|
||||
| `db_get_subscription_details_rows()` | db_ops.c:697 | api.c monitoring | Submit to read worker |
|
||||
| `db_get_all_config_rows()` | db_ops.c:745 | api.c config query | Submit to read worker |
|
||||
| `db_execute_readonly_query_json()` | db_ops.c:442 | api.c SQL query | Submit to read worker |
|
||||
| `db_event_id_exists()` | db_ops.c:1041 | main.c event check | Already moved to event worker |
|
||||
| `db_retrieve_event_by_id()` | db_ops.c:1056 | main.c | Submit to read worker |
|
||||
| `db_get_event_pubkey()` | db_ops.c:262 | NIP-09 deletion | Submit to read worker |
|
||||
| `db_delete_event_by_id()` | db_ops.c:285 | NIP-09 deletion | Submit to write worker |
|
||||
| `db_delete_older_replaceable_events()` | db_ops.c:305 | store_event_core | Already on write worker |
|
||||
| `db_store_config_event()` | db_ops.c:888 | config.c | Submit to write worker |
|
||||
| `db_add_auth_rule()` | db_ops.c:1226 | config.c admin | Submit to write worker |
|
||||
| `db_remove_auth_rule()` | db_ops.c:1242 | config.c admin | Submit to write worker |
|
||||
| `db_delete_wot_whitelist_rules()` | db_ops.c:1258 | config.c WoT | Submit to write worker |
|
||||
| `db_count_wot_whitelist_rules()` | db_ops.c:1266 | config.c | Cache or read worker |
|
||||
| `db_store_event_tags_cjson()` | db_ops.c:1140 | main.c post-actions | Already on write worker path |
|
||||
| `db_get_config_row_count()` | db_ops.c:1121 | config.c diagnostics | Cache or read worker |
|
||||
| `db_set_config_value_full()` | db_ops.c:796 | config.c | Submit to write worker |
|
||||
| `db_update_config_value_only()` | db_ops.c:821 | config.c | Submit to write worker |
|
||||
| `db_upsert_config_value()` | db_ops.c:838 | api.c | Submit to write worker |
|
||||
| `db_exec_sql()` for transactions | config.c | admin events | Submit to write worker |
|
||||
| `db_count_with_sql()` | db_ops.c:415 | config.c admin | Submit to read worker |
|
||||
| `is_config_table_ready()` | config.c:4595 | config.c hybrid | Cache result at startup |
|
||||
| `generate_config_event_from_table()` | config.c:4933 | config.c | Cache or read worker |
|
||||
|
||||
### Category D: Auth rule checks — already use separate connections
|
||||
|
||||
These functions in `db_ops.c` open their own temporary read-only connections:
|
||||
|
||||
| Function | Line | Notes |
|
||||
|----------|------|-------|
|
||||
| `db_is_pubkey_blacklisted()` | 347 | Opens own connection |
|
||||
| `db_is_hash_blacklisted()` | 362 | Opens own connection |
|
||||
| `db_is_pubkey_whitelisted()` | 377 | Opens own connection |
|
||||
| `db_count_active_whitelist_rules()` | 392 | Opens own connection |
|
||||
|
||||
These are already safe — they don't use `g_db`. No change needed.
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### Phase 1: Pre-warm caches and eliminate cache-miss DB reads
|
||||
|
||||
1. Pre-warm the config cache at startup by loading all config values into the in-memory cache before the event loop starts
|
||||
2. Pre-warm the NIP-11 cache at startup
|
||||
3. Pre-warm the auth rules fast cache at startup
|
||||
4. This eliminates the most frequent cache-miss `db_get_config_value_dup()` calls
|
||||
|
||||
### Phase 2: Route subscription logging through write worker
|
||||
|
||||
1. Add a `THREAD_POOL_JOB_FIRE_AND_FORGET` job type to thread_pool
|
||||
2. Create async wrappers: `db_log_subscription_created_async()`, etc.
|
||||
3. These submit SQL to the write worker queue and return immediately
|
||||
4. No completion callback needed — fire and forget
|
||||
|
||||
### Phase 3: Route special-kind EVENT store through async worker
|
||||
|
||||
1. Remove the `event_is_async_eligible()` exclusion for kinds 14, 1059, 23456
|
||||
2. For kind 23456: process admin command in completion handler on main thread after store
|
||||
3. For kind 14/1059: process NIP-17 DM in completion handler after store
|
||||
|
||||
### Phase 4: Route periodic timer DB work through workers
|
||||
|
||||
1. `generate_and_post_status_event()` — submit event creation to write worker
|
||||
2. `ip_ban_cleanup()` / `ip_ban_log_stats()` — submit to write worker
|
||||
3. Monitoring queries — submit to read worker with completion callback
|
||||
|
||||
### Phase 5: Null out g_db before event loop
|
||||
|
||||
1. After startup is complete and thread pool is initialized, set `g_db = NULL`
|
||||
2. Change `db_active_connection()` to assert/warn if both `g_thread_db` and `g_db` are NULL
|
||||
3. Any accidental main-thread DB call will now fail loudly instead of silently blocking
|
||||
4. Restore `g_db` briefly for shutdown checkpoint
|
||||
|
||||
## Implementation Order
|
||||
|
||||
1. Phase 1 — lowest risk, immediate benefit from eliminating cache misses
|
||||
2. Phase 2 — straightforward fire-and-forget pattern
|
||||
3. Phase 3 — moderate complexity, needs careful completion handler design
|
||||
4. Phase 4 — moderate complexity, periodic tasks need async patterns
|
||||
5. Phase 5 — the final enforcement step, only safe after phases 1-4
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
- **Phase 1**: Very low risk — just pre-warming existing caches
|
||||
- **Phase 2**: Low risk — subscription logging is non-critical, fire-and-forget is safe
|
||||
- **Phase 3**: Medium risk — admin/DM event processing has complex state; needs careful testing
|
||||
- **Phase 4**: Medium risk — periodic tasks have side effects that need to complete
|
||||
- **Phase 5**: High risk if done prematurely — must verify ALL runtime paths are covered first
|
||||
|
||||
## Expected Impact
|
||||
|
||||
After all phases:
|
||||
- lws-main CPU should drop from ~67% to near 0% SQLite overhead
|
||||
- All SQLite work happens on db-read and db-write threads
|
||||
- Main thread only does WebSocket I/O, JSON parsing, and completion queue draining
|
||||
- Thread model becomes: lws-main = pure I/O, workers = all DB
|
||||
@@ -0,0 +1,204 @@
|
||||
# Remaining Implementation Plan — Zero SQLite on Main Thread + PG Fork Readiness
|
||||
|
||||
## Overview
|
||||
|
||||
This plan covers all remaining work to achieve two goals:
|
||||
1. **Zero direct SQLite calls on lws-main** during the event loop
|
||||
2. **Clean `db_ops` abstraction boundary** so the PG fork has no raw `sqlite3_*` calls outside `db_ops.c`
|
||||
|
||||
## Current State
|
||||
|
||||
### Completed (Fixes 1-5, 7 + Phases 1-3, 5)
|
||||
- Global config cache with 5s TTL
|
||||
- Dedup check moved to event worker
|
||||
- Async COUNT queries via thread pool
|
||||
- WoT auth rules cached per-session
|
||||
- Special-kind EVENT store through async worker
|
||||
- Subscription logging via fire-and-forget write queue
|
||||
- IP ban periodic save via write queue
|
||||
- g_db nulled before event loop
|
||||
|
||||
### Remaining
|
||||
- Fix 6: Reduce reader threads (trivial)
|
||||
- Fix 8: Move periodic tasks off main thread (partial — IP ban save done, monitoring/status not)
|
||||
- Fix 9: Cache NIP-11 response
|
||||
- Sync `store_event()` calls from admin/DM/NIP-09 paths
|
||||
- Raw `sqlite3_*` calls in `thread_pool.c` and `websockets.c`
|
||||
- COUNT query path in `websockets.c` still uses `json_each()` instead of `event_tags`
|
||||
|
||||
---
|
||||
|
||||
## Phase A: Move Remaining Periodic Tasks Off Main Thread
|
||||
|
||||
**Goal:** Eliminate the last regular SQLite calls from the lws-main event loop timer.
|
||||
|
||||
### A1: Move `generate_and_post_status_event()` to write worker
|
||||
|
||||
Currently called synchronously from the main event loop at `websockets.c:3455`.
|
||||
|
||||
**Changes:**
|
||||
- Add `THREAD_POOL_JOB_STATUS_POST` to `thread_pool.h` job type enum
|
||||
- Add executor in `thread_pool.c` that calls `generate_and_post_status_event()`
|
||||
- In `websockets.c` main loop, replace direct call with `thread_pool_submit_write()` job
|
||||
- The write worker has a DB connection, so `generate_stats_json()` → `store_event()` → `broadcast_event_to_subscriptions()` all work naturally
|
||||
- Note: `broadcast_event_to_subscriptions()` is thread-safe (uses its own mutex)
|
||||
|
||||
**Files:** `thread_pool.h`, `thread_pool.c`, `websockets.c`
|
||||
|
||||
### A2: Move monitoring queries to read/write worker
|
||||
|
||||
`monitoring_on_event_stored()` and `monitoring_on_subscription_change()` in `api.c` call `generate_event_driven_monitoring()` / `generate_subscription_driven_monitoring()` which do DB queries and then broadcast ephemeral events.
|
||||
|
||||
**Changes:**
|
||||
- Add `THREAD_POOL_JOB_MONITORING` job type
|
||||
- Submit monitoring generation as a read job (it mostly does SELECTs)
|
||||
- The completion broadcasts the ephemeral event via `lws_cancel_service()` + completion queue
|
||||
- Alternative simpler approach: since these are throttled (default 5s) and only fire when kind 24567 subscribers exist, they could run on the write worker as fire-and-forget
|
||||
|
||||
**Files:** `thread_pool.h`, `thread_pool.c`, `api.c`, `websockets.c`
|
||||
|
||||
### A3: Move `ip_ban_cleanup()` and `ip_ban_log_stats()` to write worker
|
||||
|
||||
Currently called from the 60-second periodic timer at `websockets.c:3479-3480`.
|
||||
|
||||
**Changes:**
|
||||
- Add `THREAD_POOL_JOB_IP_BAN_CLEANUP` job type (or reuse a generic callback job)
|
||||
- Submit as fire-and-forget write job from the periodic timer
|
||||
- `ip_ban_cleanup()` does in-memory cleanup + optional DB writes
|
||||
- `ip_ban_log_stats()` is purely logging, no DB
|
||||
|
||||
**Files:** `thread_pool.h`, `thread_pool.c`, `ip_ban.c`, `websockets.c`
|
||||
|
||||
---
|
||||
|
||||
## Phase B: Route Remaining Sync `store_event()` Calls Through Async Worker
|
||||
|
||||
**Goal:** Eliminate all synchronous `store_event()` calls from lws-main context.
|
||||
|
||||
### Current sync `store_event()` call sites on main thread
|
||||
|
||||
| Call site | File | Context | Frequency |
|
||||
|-----------|------|---------|-----------|
|
||||
| Kind 1059 gift wrap store | `websockets.c:1795,1803,1819` | NIP-17 DM processing | Low |
|
||||
| Kind 14 DM store | `websockets.c:1843` | NIP-17 DM processing | Low |
|
||||
| Regular event fallback | `websockets.c:1862,1876` | Non-async-eligible events | Low |
|
||||
| Kind 1059 (auth path) | `websockets.c:2594,2602,2618` | NIP-42 auth + DM | Low |
|
||||
| Kind 14 (auth path) | `websockets.c:2642` | NIP-42 auth + DM | Low |
|
||||
| Regular (auth path) | `websockets.c:2661,2675` | NIP-42 auth fallback | Low |
|
||||
| Admin response store | `config.c:2585` | Admin API response | Very low |
|
||||
| DM admin gift wrap | `dm_admin.c:389` | Admin DM response | Very low |
|
||||
| NIP-09 deletion store | `nip009.c:135` | Deletion events | Low |
|
||||
| Status event store | `api.c:595` | Periodic status post | Very low (handled by Phase A1) |
|
||||
| Admin response event | `api.c:908` | Admin API | Very low |
|
||||
| DM chat response | `api.c:1377` | Admin DM chat | Very low |
|
||||
| Relay-generated event | `api.c:2350` | Relay metadata | Very low |
|
||||
| DM stats response | `websockets.c:3648` | DM stats command | Very low |
|
||||
|
||||
### Strategy
|
||||
|
||||
Rather than converting each call site individually, create a **synchronous-to-async bridge**:
|
||||
|
||||
**Changes:**
|
||||
- Create `store_event_async(cJSON* event, store_event_callback_t cb, void* ctx)` that submits the event to the write worker
|
||||
- For call sites that need the result (e.g., to broadcast after store), use a completion callback
|
||||
- For fire-and-forget sites (admin responses, DM responses), use NULL callback
|
||||
- The existing `store_event()` wrapper becomes: submit to write worker + block on completion (for backward compat during transition)
|
||||
- Eventually, all callers migrate to the async version
|
||||
|
||||
**Alternative simpler approach:** Since these are all low-frequency paths, and the write worker already has a DB connection, we can submit them as generic write jobs with a callback that does the store + broadcast. The main thread just needs to hand off the event JSON.
|
||||
|
||||
**Files:** `main.c`, `websockets.c`, `api.c`, `config.c`, `dm_admin.c`, `nip009.c`, `thread_pool.h`, `thread_pool.c`
|
||||
|
||||
---
|
||||
|
||||
## Phase C: `db_ops` Abstraction Cleanup for PG Fork
|
||||
|
||||
**Goal:** Ensure all raw `sqlite3_*` calls are inside `db_ops.c` only. External code uses only `db_ops.h` functions.
|
||||
|
||||
### C1: Add `db_open_worker_connection()` / `db_close_worker_connection()` to `db_ops.h`
|
||||
|
||||
Currently, `thread_pool.c:208` and `websockets.c:537` call `sqlite3_open_v2()` directly.
|
||||
|
||||
**Changes:**
|
||||
- Add to `db_ops.h`:
|
||||
```c
|
||||
void* db_open_worker_connection(void); // Returns opaque connection handle
|
||||
void db_close_worker_connection(void* conn);
|
||||
```
|
||||
- Implementation in `db_ops.c`: opens a new SQLite connection with WAL + busy timeout
|
||||
- `thread_pool.c` worker init calls `db_open_worker_connection()` instead of raw `sqlite3_open_v2()`
|
||||
- `websockets.c` event-worker calls `db_open_worker_connection()` instead of raw `sqlite3_open_v2()`
|
||||
- Remove `#include <sqlite3.h>` from `thread_pool.c` and `websockets.c`
|
||||
|
||||
**Files:** `db_ops.h`, `db_ops.c`, `thread_pool.c`, `websockets.c`
|
||||
|
||||
### C2: Audit and remove remaining `sqlite3` includes outside `db_ops.c`
|
||||
|
||||
After C1, grep for any remaining `sqlite3` references outside `db_ops.c` and eliminate them.
|
||||
|
||||
**Files:** All `.c` files
|
||||
|
||||
### C3: Unify COUNT query tag path
|
||||
|
||||
The COUNT query builder in `websockets.c:3849` still uses `json_each(json(tags))` while the REQ query builder in `main.c:1604` uses the indexed `event_tags` table. Unify to use `event_tags` for consistency.
|
||||
|
||||
**Files:** `websockets.c`
|
||||
|
||||
---
|
||||
|
||||
## Phase D: Quick Wins
|
||||
|
||||
### D1: Fix 6 — Reduce reader threads from 4 to 1
|
||||
|
||||
Change default in `thread_pool_init()` or make configurable. With all reads going through the pool, a single reader is sufficient unless profiling shows otherwise.
|
||||
|
||||
**Files:** `thread_pool.c` or config default
|
||||
|
||||
### D2: Fix 9 — Cache NIP-11 response
|
||||
|
||||
Cache the serialized NIP-11 JSON string with a 60-second TTL. Invalidate on admin config change.
|
||||
|
||||
**Files:** `nip011.c`
|
||||
|
||||
---
|
||||
|
||||
## Implementation Order
|
||||
|
||||
| # | Task | Risk | Dependencies |
|
||||
|---|------|------|-------------|
|
||||
| 1 | A3: ip_ban_cleanup to write worker | Very Low | None |
|
||||
| 2 | A1: status post to write worker | Low | None |
|
||||
| 3 | A2: monitoring to worker | Low | None |
|
||||
| 4 | D1: reduce reader threads to 1 | Very Low | None |
|
||||
| 5 | D2: cache NIP-11 response | Very Low | None |
|
||||
| 6 | C1: db_open/close_worker_connection | Low | None |
|
||||
| 7 | C3: unify COUNT tag query path | Low | None |
|
||||
| 8 | C2: audit/remove sqlite3 includes | Very Low | C1 |
|
||||
| 9 | B: route sync store_event through async | Medium | A1 (status post already handled) |
|
||||
|
||||
## Expected Outcome
|
||||
|
||||
After all phases:
|
||||
- **lws-main has zero SQLite calls** during the event loop
|
||||
- **All `sqlite3_*` calls are inside `db_ops.c`** — clean abstraction boundary
|
||||
- **PG fork can replace `db_ops.c`** without touching any other file
|
||||
- Thread model is fully realized:
|
||||
- `lws-main` = WebSocket I/O + JSON parse + subscription match + completion drain
|
||||
- `event-worker` = signature verify + dedup + store submission
|
||||
- `db-read` = REQ queries + COUNT queries + monitoring reads
|
||||
- `db-write` = event INSERTs + subscription logging + periodic tasks + admin writes
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
CLIENT[Nostr Clients] --> LWS[lws-main<br/>Zero SQLite<br/>WS I/O + JSON + Sub Match]
|
||||
|
||||
LWS -->|EVENT| EW[event-worker<br/>Verify + Dedup]
|
||||
EW -->|store job| DW[db-write<br/>INSERT events<br/>Sub logging<br/>Periodic tasks<br/>Admin writes]
|
||||
EW -->|completion| LWS
|
||||
DW -->|completion| LWS
|
||||
|
||||
LWS -->|REQ/COUNT| DR[db-read<br/>SELECT queries<br/>Monitoring reads]
|
||||
DR -->|completion| LWS
|
||||
|
||||
LWS -->|OK/EVENT/EOSE/COUNT| CLIENT
|
||||
```
|
||||
@@ -0,0 +1,379 @@
|
||||
# Plan: Remove All SQLite from lws-main Thread
|
||||
|
||||
## Problem Statement
|
||||
|
||||
After implementing the 4 offload fixes (v2.1.4), `lws-main` still consumes **53.87% avg CPU** (down from 68.71%). Perf profiling shows **100% of the top symbols are SQLite** — B-tree traversal, page cache, VFS reads. The worker threads (`db-read`, `db-write`, `event-worker`) are nearly idle at 0.0–0.1%.
|
||||
|
||||
The goal is to eliminate all synchronous SQLite access from `lws-main` so it only does: JSON parsing, WebSocket I/O, subscription matching (in-memory), and message queuing.
|
||||
|
||||
## Thread Architecture Change
|
||||
|
||||
Reduce from 7 threads to 4:
|
||||
|
||||
```
|
||||
Current: lws-main, db-read-1, db-read-2, db-read-3, db-read-4, db-write, event-worker
|
||||
Proposed: lws-main, db-read, db-write, event-worker
|
||||
```
|
||||
|
||||
The 4 reader threads are overkill — they average 0.07–0.10% CPU each. A single `db-read` thread is sufficient for the current workload. This can be made configurable later if needed.
|
||||
|
||||
## Remaining SQLite Calls on lws-main
|
||||
|
||||
Every synchronous SQLite call that currently runs on `lws-main`:
|
||||
|
||||
### Hot Path — Per-Event (every incoming EVENT message)
|
||||
|
||||
| Call | Location | Frequency | Cost |
|
||||
|------|----------|-----------|------|
|
||||
| `event_id_exists_in_db()` | websockets.c:1324, 2134 | Every EVENT | ~10-50us per B-tree lookup |
|
||||
| `get_config_value("relay_pubkey")` | websockets.c:2050 | Every kind-14 EVENT | SQLite SELECT |
|
||||
| `get_config_value("admin_pubkey")` | websockets.c:2073 | Every kind-23456 EVENT | SQLite SELECT |
|
||||
|
||||
### Hot Path — Per-Connection (every new WebSocket connection)
|
||||
|
||||
| Call | Location | Frequency | Cost |
|
||||
|------|----------|-----------|------|
|
||||
| `get_config_bool("trust_proxy_headers")` | websockets.c:1071 | Every connection | SQLite SELECT |
|
||||
| `get_config_bool("nip42_auth_required_events")` | websockets.c:1134 | Every connection | SQLite SELECT |
|
||||
| `get_config_bool("nip42_auth_required_subscriptions")` | websockets.c:1135 | Every connection | SQLite SELECT |
|
||||
|
||||
### Hot Path — Per-REQ (every subscription request)
|
||||
|
||||
| Call | Location | Frequency | Cost |
|
||||
|------|----------|-----------|------|
|
||||
| `get_config_bool("expiration_enabled")` | main.c:1424 | Every REQ | SQLite SELECT |
|
||||
| `get_config_bool("expiration_filter")` | main.c:1425 | Every REQ | SQLite SELECT |
|
||||
| `check_database_auth_rules()` | websockets.c:1706 | Every REQ when WoT enabled | SQLite SELECT |
|
||||
|
||||
### Medium Path — Per-COUNT (NIP-45)
|
||||
|
||||
| Call | Location | Frequency | Cost |
|
||||
|------|----------|-----------|------|
|
||||
| `thread_pool_execute_count_sync()` | websockets.c:3689 | Every COUNT message | Blocks main thread waiting for db-read |
|
||||
|
||||
### Low Path — Periodic (every 60s or on timer)
|
||||
|
||||
| Call | Location | Frequency | Cost |
|
||||
|------|----------|-----------|------|
|
||||
| `refresh_hot_config_if_needed()` | websockets.c:228-247 | Every 5s | 8 SQLite SELECTs |
|
||||
| `generate_and_post_status_event()` | websockets.c:3213 | Every N hours | store_event + broadcast |
|
||||
| `ip_ban_cleanup/log_stats` | websockets.c:3004-3005 | Every 60s | SQLite reads/writes |
|
||||
|
||||
### Per-EVENT — Validator Path (called from event-worker AND sync path)
|
||||
|
||||
| Call | Location | Frequency | Cost |
|
||||
|------|----------|-----------|------|
|
||||
| `get_config_value("admin_pubkey")` | request_validator.c:308 | Every kind-23456 EVENT | SQLite SELECT |
|
||||
| `get_config_value("nip42_auth_enabled")` | request_validator.c:326 | Every EVENT | SQLite SELECT |
|
||||
| `get_config_bool("pow_enabled")` | request_validator.c:370 | Every EVENT | SQLite SELECT |
|
||||
| `get_config_int("pow_min_difficulty")` | request_validator.c:371 | Every EVENT | SQLite SELECT |
|
||||
| `get_config_int("pow_validation_flags")` | request_validator.c:372 | Every EVENT | SQLite SELECT |
|
||||
| `get_config_int("nip40_expiration_grace_period")` | request_validator.c:432 | Every EVENT with expiration | SQLite SELECT |
|
||||
| `get_config_value("auth_enabled")` | request_validator.c:212 | Every EVENT (reload_auth_config) | SQLite SELECT |
|
||||
| `get_config_value("auth_rules_enabled")` | request_validator.c:220 | Every EVENT (reload_auth_config) | SQLite SELECT |
|
||||
| `db_count_active_whitelist_rules()` | request_validator.c:536 | Every 5s (cached) | Opens separate SQLite connection |
|
||||
|
||||
**Note:** These run on the **event-worker** thread for async-eligible events, but on **lws-main** for special kinds (14, 1059, 23456) that go through the sync validation path. They also run on lws-main for the `nostr_validate_unified_request()` call in the sync fallback.
|
||||
|
||||
### Per-EVENT — NIP-13 PoW Validation
|
||||
|
||||
| Call | Location | Frequency | Cost |
|
||||
|------|----------|-----------|------|
|
||||
| `get_config_bool("pow_enabled")` | nip013.c:27 | Every EVENT | SQLite SELECT |
|
||||
| `get_config_int("pow_min_difficulty")` | nip013.c:28 | Every EVENT | SQLite SELECT |
|
||||
| `get_config_value("pow_mode")` | nip013.c:29 | Every EVENT | SQLite SELECT |
|
||||
|
||||
### Per-Broadcast — NIP-40 Expiration Check
|
||||
|
||||
| Call | Location | Frequency | Cost |
|
||||
|------|----------|-----------|------|
|
||||
| `get_config_bool("expiration_enabled")` | subscriptions.c:764 | Every broadcast | SQLite SELECT |
|
||||
| `get_config_bool("expiration_filter")` | subscriptions.c:765 | Every broadcast | SQLite SELECT |
|
||||
|
||||
### Per-NIP-11 Request (HTTP, not WebSocket)
|
||||
|
||||
| Call | Location | Frequency | Cost |
|
||||
|------|----------|-----------|------|
|
||||
| 15+ `get_config_value()` calls | nip011.c:96-110 | Every NIP-11 HTTP request | 15 SQLite SELECTs |
|
||||
| 10+ `get_config_int()`/`get_config_bool()` calls | nip011.c:113-123 | Every NIP-11 HTTP request | 10 SQLite SELECTs |
|
||||
|
||||
### Per-NIP-42 Auth Event
|
||||
|
||||
| Call | Location | Frequency | Cost |
|
||||
|------|----------|-----------|------|
|
||||
| `get_config_value("relay_url")` | nip042.c:99 | Every AUTH event | SQLite SELECT |
|
||||
| `get_config_int("relay_port")` | nip042.c:103 | Every AUTH event (fallback) | SQLite SELECT |
|
||||
|
||||
### Per-NIP-40 Expiration Check (EVENT submission)
|
||||
|
||||
| Call | Location | Frequency | Cost |
|
||||
|------|----------|-----------|------|
|
||||
| 5 `get_config_bool()`/`get_config_int()` calls | nip040.c:37-41 | Every EVENT with expiration tag | 5 SQLite SELECTs |
|
||||
|
||||
### Subscription Lifecycle (per sub create/close/disconnect)
|
||||
|
||||
| Call | Location | Frequency | Cost |
|
||||
|------|----------|-----------|------|
|
||||
| `db_log_subscription_created()` | subscriptions.c:1043 | Every REQ | SQLite INSERT |
|
||||
| `db_log_subscription_closed()` | subscriptions.c:1053 | Every CLOSE | SQLite INSERT + UPDATE |
|
||||
| `db_log_subscription_disconnected()` | subscriptions.c:1060 | Every disconnect | SQLite UPDATE + INSERT |
|
||||
| `db_update_subscription_events_sent()` | subscriptions.c:1088 | Every broadcast match | SQLite UPDATE |
|
||||
| `db_cleanup_orphaned_subscriptions()` | subscriptions.c:1100 | Startup only | SQLite DELETE |
|
||||
|
||||
### IP Ban System (per-connection and periodic)
|
||||
|
||||
| Call | Location | Frequency | Cost |
|
||||
|------|----------|-----------|------|
|
||||
| `get_config_value("idle_ban_whitelist")` | ip_ban.c:254 | Every ban check | SQLite SELECT |
|
||||
| `get_config_bool("auth_fail_ban_enabled")` | ip_ban.c:301, 343 | Every ban check + failure | SQLite SELECT |
|
||||
| `get_config_bool("idle_ban_enabled")` | ip_ban.c:307, 394 | Every ban check + idle failure | SQLite SELECT |
|
||||
| 6+ `get_config_int()` calls | ip_ban.c:345-399, 464-465 | Every failure recording | SQLite SELECTs |
|
||||
| `db_prepare()`/`db_step_stmt()` for ip_bans | ip_ban.c:141-238 | Load at startup + periodic save | SQLite reads/writes |
|
||||
|
||||
### Special Kind Sync Path (kinds 14, 1059, 23456)
|
||||
|
||||
| Call | Location | Frequency | Cost |
|
||||
|------|----------|-----------|------|
|
||||
| `store_event()` | websockets.c:1548-1629 | Every special-kind EVENT | Full sync store |
|
||||
| `process_admin_event_in_config()` | websockets.c:1468 | Every kind-23456 | Config DB writes |
|
||||
| `process_nip17_admin_message()` | websockets.c:1523 | Every kind-1059 when enabled | Decrypt + DB |
|
||||
| `process_dm_stats_command()` | websockets.c:3240 | Admin DM stats | Decrypt + query + encrypt |
|
||||
| `generate_stats_json()` | api.c:1167 (via dm_admin.c:805) | Admin stats command | Multiple SQLite queries |
|
||||
|
||||
### DM Admin Path (called from lws-main for kind 1059/14)
|
||||
|
||||
| Call | Location | Frequency | Cost |
|
||||
|------|----------|-----------|------|
|
||||
| `get_config_value("relay_pubkey")` | dm_admin.c:358, 451 | Every admin DM | SQLite SELECT |
|
||||
| `get_config_value("admin_pubkey")` | dm_admin.c:504 | Every admin DM | SQLite SELECT |
|
||||
| `get_config_int("nip59_timestamp_max_delay_sec")` | dm_admin.c:373 | Every admin DM | SQLite SELECT |
|
||||
| `get_config_int("wot_enabled")` | dm_admin.c:613, 640, 660 | WoT commands | SQLite SELECT |
|
||||
|
||||
### API/Monitoring (called from lws-main periodic timer)
|
||||
|
||||
| Call | Location | Frequency | Cost |
|
||||
|------|----------|-----------|------|
|
||||
| `generate_stats_json()` | api.c:1167 | Status post + admin stats | ~10 SQLite queries |
|
||||
| `query_time_based_statistics()` | api.c:102 | Monitoring events | SQLite queries |
|
||||
| `query_subscription_details()` | api.c:197 | Monitoring events | SQLite queries |
|
||||
| `get_config_value("relay_pubkey")` | api.c:419, 821, 1291 | Every monitoring event | SQLite SELECT |
|
||||
| `get_config_int("kind_1_status_posts_hours")` | api.c:547 | Status post check | SQLite SELECT |
|
||||
| `get_config_int("kind_24567_reporting_throttle_sec")` | api.c:60 | Monitoring throttle | SQLite SELECT |
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### Fix 1: Create Global Config Cache — Eliminate ALL get_config_* SQLite Calls
|
||||
|
||||
**Impact: Very High** — eliminates 50+ distinct `get_config_value/int/bool` call sites across 8 source files
|
||||
|
||||
The audit found `get_config_value/int/bool` calls in: `websockets.c`, `main.c`, `subscriptions.c`, `request_validator.c`, `nip011.c`, `nip013.c`, `nip040.c`, `nip042.c`, `ip_ban.c`, `dm_admin.c`, `api.c`, `config.c`. Every single one does a `SELECT value FROM config WHERE key=?` SQLite query.
|
||||
|
||||
**Approach:** Replace `get_config_value_from_table()` with an in-memory hash map that is loaded once at startup and refreshed periodically (every 5s) or on admin config change events.
|
||||
|
||||
**Changes:**
|
||||
|
||||
1. **New: `config_cache` in config.c** — A simple hash map or fixed array of key-value pairs loaded from the config table:
|
||||
```c
|
||||
typedef struct {
|
||||
char key[64];
|
||||
char value[512];
|
||||
} config_cache_entry_t;
|
||||
|
||||
static config_cache_entry_t g_config_cache[256];
|
||||
static int g_config_cache_count = 0;
|
||||
static time_t g_config_cache_last_refresh = 0;
|
||||
static pthread_mutex_t g_config_cache_mutex;
|
||||
#define CONFIG_CACHE_TTL_SEC 5
|
||||
```
|
||||
|
||||
2. **Modify `get_config_value_from_table()`** — Instead of querying SQLite, look up in the in-memory cache. If cache is stale, refresh from SQLite (but only once per TTL period, not per call).
|
||||
|
||||
3. **Add `config_cache_refresh()`** — Loads all rows from `SELECT key, value FROM config` into the hash map. Called:
|
||||
- Once at startup after config table is populated
|
||||
- Every 5 seconds from the existing `refresh_hot_config_if_needed()` timer
|
||||
- Immediately after `process_admin_event_in_config()` modifies config
|
||||
|
||||
4. **Thread safety:** The cache is read from lws-main and event-worker threads. Use a read-write lock or double-buffer pattern. Since config changes are rare, a simple mutex with short hold time is fine.
|
||||
|
||||
5. **Remove the existing `hot_config_cache_t`** in websockets.c — it becomes redundant since the global config cache serves the same purpose with broader coverage.
|
||||
|
||||
This single change eliminates SQLite calls from:
|
||||
- Per-connection: `trust_proxy_headers`, `nip42_auth_required_*` (websockets.c)
|
||||
- Per-REQ: `expiration_enabled`, `expiration_filter` (main.c)
|
||||
- Per-EVENT: `admin_pubkey`, `relay_pubkey`, `nip42_auth_enabled`, `pow_*` (request_validator.c, nip013.c)
|
||||
- Per-broadcast: `expiration_enabled`, `expiration_filter` (subscriptions.c)
|
||||
- Per-NIP-11: 25+ config values (nip011.c)
|
||||
- Per-NIP-42: `relay_url`, `relay_port` (nip042.c)
|
||||
- Per-NIP-40: 5 expiration config values (nip040.c)
|
||||
- Per-IP-ban: `idle_ban_*`, `auth_fail_*` config values (ip_ban.c)
|
||||
- Per-admin-DM: `relay_pubkey`, `admin_pubkey`, `wot_enabled` (dm_admin.c)
|
||||
- Per-monitoring: `relay_pubkey`, throttle values (api.c)
|
||||
|
||||
### Fix 2: Move Duplicate Check to Event Worker Thread
|
||||
|
||||
**Impact: High** — eliminates the most frequent per-EVENT SQLite call from lws-main
|
||||
|
||||
Currently `event_id_exists_in_db()` runs on lws-main before async submission. Move it into the `async_event_worker_main()` function, which already has its own SQLite connection.
|
||||
|
||||
**Changes:**
|
||||
- Remove `event_id_exists_in_db()` calls from both EVENT paths in websockets.c (lines 1324 and 2134)
|
||||
- Add the duplicate check at the start of `async_event_worker_main()` before `nostr_validate_unified_request()`
|
||||
- If duplicate found, set `completion->success = 1` and `completion->error_message = "duplicate: already have this event"` and skip crypto
|
||||
- The completion handler already sends OK responses, so this works seamlessly
|
||||
|
||||
**Trade-off:** Without the early dedup check on lws-main, duplicate events will be submitted to the event worker queue and consume a queue slot + thread wakeup before being detected. This is acceptable because:
|
||||
- The worker thread dedup check is still fast (B-tree index lookup)
|
||||
- It avoids the much larger cost of running SQLite on lws-main for every event
|
||||
- Queue depth is 4096, so even under heavy duplicate traffic this won't overflow
|
||||
|
||||
### Fix 3: Make COUNT Queries Async
|
||||
|
||||
**Impact: Medium** — eliminates blocking wait on lws-main for NIP-45 COUNT
|
||||
|
||||
Currently `handle_count_message()` calls `thread_pool_execute_count_sync()` which blocks lws-main waiting for the db-read worker. Convert to the same async pattern used for REQ queries.
|
||||
|
||||
**Changes:**
|
||||
- Create `count_async_state_t` similar to `req_async_state_t`
|
||||
- Create `count_async_completion_t` with count result
|
||||
- Add `submit_count_query_async()` that uses `thread_pool_submit_read()` with a callback
|
||||
- The callback pushes to a count completion queue
|
||||
- Add `process_count_async_completions()` to drain the queue on lws-main and send COUNT responses
|
||||
- Call it from the main event loop alongside `process_req_async_completions()`
|
||||
|
||||
### Fix 4: Cache Auth Rules Check Result
|
||||
|
||||
**Impact: Low-Medium** — eliminates per-REQ SQLite when WoT is enabled
|
||||
|
||||
`check_database_auth_rules()` at websockets.c:1706 runs a SQLite query for every REQ when `wot_enabled == 2`. Cache the result per-session.
|
||||
|
||||
**Changes:**
|
||||
- Add `wot_checked` and `wot_allowed` fields to `per_session_data`
|
||||
- On first REQ, call `check_database_auth_rules()` and cache the result
|
||||
- On subsequent REQs from the same session, use the cached value
|
||||
- Reset cache when auth state changes (e.g., after NIP-42 AUTH)
|
||||
|
||||
### Fix 5: Move Special-Kind EVENT Store to Event Worker
|
||||
|
||||
**Impact: Low** — special kinds are rare but currently do full sync store on lws-main
|
||||
|
||||
Kinds 14, 1059, and 23456 are currently excluded from async processing because they have special handling. However, the `store_event()` call within those paths still blocks lws-main.
|
||||
|
||||
**Changes:**
|
||||
- For kind 1059 and kind 14: after special processing completes, submit the store to the event worker instead of calling `store_event()` synchronously
|
||||
- For kind 23456: admin events are not stored (processed by admin API), so no change needed
|
||||
- This requires the special processing (decryption, admin check) to still happen on lws-main (it needs `pss` context), but the final DB write goes async
|
||||
|
||||
### Fix 6: Reduce Reader Threads from 4 to 1
|
||||
|
||||
**Impact: Resource savings** — 3 fewer threads, 3 fewer SQLite connections
|
||||
|
||||
**Changes:**
|
||||
- Change default `reader_threads` in `thread_pool_init()` from 4 to 1
|
||||
- Or make it configurable via config with default 1
|
||||
- The single `db-read` thread handles all REQ and COUNT queries sequentially
|
||||
- If future profiling shows the read thread becoming a bottleneck, increase back to 2+
|
||||
|
||||
### Fix 7: Move Subscription Logging Off Main Thread
|
||||
|
||||
**Impact: Medium** — eliminates per-REQ INSERT, per-CLOSE UPDATE, per-broadcast UPDATE
|
||||
|
||||
The subscription lifecycle functions in subscriptions.c do synchronous SQLite writes on lws-main:
|
||||
- `db_log_subscription_created()` — INSERT on every REQ
|
||||
- `db_log_subscription_closed()` — INSERT + UPDATE on every CLOSE
|
||||
- `db_log_subscription_disconnected()` — UPDATE + INSERT on every disconnect
|
||||
- `db_update_subscription_events_sent()` — UPDATE on every broadcast match
|
||||
|
||||
**Changes:**
|
||||
- Submit these as fire-and-forget write jobs to the db-write thread via `thread_pool_submit_write()`
|
||||
- Create a new job type `THREAD_POOL_JOB_SUBSCRIPTION_LOG` or simply use a generic callback job
|
||||
- The main thread doesn't need to wait for these to complete — they're purely observational logging
|
||||
|
||||
### Fix 8: Move Periodic Tasks Off Main Thread
|
||||
|
||||
**Impact: Low** — these run every 60s but can still cause latency spikes
|
||||
|
||||
- `generate_and_post_status_event()`: Submit as an async job to the event worker
|
||||
- `ip_ban_cleanup()`/`ip_ban_log_stats()`/`ip_ban_save()`: These do SQLite reads/writes. Move to a periodic job on the db-write thread
|
||||
- Config cache refresh (Fix 1) replaces the old `refresh_hot_config_if_needed()` SQLite queries
|
||||
|
||||
### Fix 9: Cache NIP-11 Response
|
||||
|
||||
**Impact: Low-Medium** — eliminates 25+ SQLite SELECTs per NIP-11 HTTP request
|
||||
|
||||
`generate_relay_info_json()` in nip011.c calls `get_config_value()` 15 times and `get_config_int()`/`get_config_bool()` 10 times. After Fix 1 (global config cache), these become in-memory lookups. But we can go further:
|
||||
|
||||
**Changes:**
|
||||
- Cache the serialized NIP-11 JSON response string with a TTL (e.g., 60 seconds)
|
||||
- On NIP-11 request, return the cached string directly without rebuilding
|
||||
- Invalidate on admin config change events
|
||||
|
||||
## Implementation Order
|
||||
|
||||
| # | Fix | Risk | Complexity |
|
||||
|---|-----|------|------------|
|
||||
| 1 | Global config cache (replaces all get_config_* SQLite) | Low | Medium |
|
||||
| 2 | Move dedup check to event worker | Low | Low |
|
||||
| 3 | Async COUNT queries | Low | Medium |
|
||||
| 4 | Cache WoT auth rules per-session | Very Low | Low |
|
||||
| 5 | Async store for special kinds | Medium | Medium |
|
||||
| 6 | Reduce reader threads to 1 | Very Low | Trivial |
|
||||
| 7 | Move subscription logging off main thread | Low | Low-Medium |
|
||||
| 8 | Move periodic tasks off main thread | Low | Medium |
|
||||
| 9 | Cache NIP-11 response | Very Low | Low |
|
||||
|
||||
## Expected Impact
|
||||
|
||||
After all 9 fixes, `lws-main` should have **zero direct SQLite calls**. Its work becomes:
|
||||
- JSON parse incoming messages (~fast)
|
||||
- In-memory subscription matching (~fast)
|
||||
- In-memory config lookups (~fast, hash map)
|
||||
- Message formatting and queuing (~fast)
|
||||
- `lws_service()` I/O (~fast)
|
||||
- Draining completion queues (~fast)
|
||||
|
||||
### Impact by fix
|
||||
|
||||
| Fix | SQLite calls eliminated | Frequency |
|
||||
|-----|------------------------|-----------|
|
||||
| Fix 1: Global config cache | ~50+ `get_config_*` call sites across 8 files | Per-event, per-connection, per-REQ, per-broadcast, per-NIP-11 |
|
||||
| Fix 2: Dedup to event worker | 2 `event_id_exists_in_db()` calls | Per-EVENT |
|
||||
| Fix 3: Async COUNT | 1 `thread_pool_execute_count_sync()` | Per-COUNT message |
|
||||
| Fix 4: WoT cache per-session | 1 `check_database_auth_rules()` | Per-REQ when WoT enabled |
|
||||
| Fix 5: Async special-kind store | ~6 `store_event()` calls | Per special-kind EVENT |
|
||||
| Fix 6: Reduce readers | N/A (resource savings) | N/A |
|
||||
| Fix 7: Async subscription logging | 4 `db_log_*`/`db_update_*` calls | Per-REQ, per-CLOSE, per-broadcast |
|
||||
| Fix 8: Async periodic tasks | `generate_stats_json()`, `ip_ban_*` | Every 60s |
|
||||
| Fix 9: Cache NIP-11 | 25+ config lookups per request | Per NIP-11 HTTP request |
|
||||
|
||||
Estimated main-thread CPU reduction: from **54% to ~5-10%** (mostly WebSocket I/O, subscription matching, and JSON parsing).
|
||||
|
||||
## Thread Model After Changes
|
||||
|
||||
```
|
||||
lws-main — WebSocket I/O, JSON parse, subscription match, message queue
|
||||
NO SQLite. Pure compute + I/O.
|
||||
|
||||
db-read — All SELECT queries: REQ results, COUNT results, config refresh,
|
||||
auth rule checks, event dedup checks via completion queue
|
||||
|
||||
db-write — All INSERT/UPDATE: event storage, tag inserts, IP ban persistence,
|
||||
status event generation
|
||||
|
||||
event-worker — EVENT validation: signature verification, then submits store to
|
||||
db-write via completion queue, results flow back to lws-main
|
||||
```
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
CLIENT[Nostr Clients] --> LWS[lws-main<br/>WebSocket I/O<br/>JSON parse<br/>Sub matching<br/>NO SQLite]
|
||||
|
||||
LWS -->|EVENT submit| EW[event-worker<br/>Sig verify<br/>Dedup check]
|
||||
EW -->|store job| DW[db-write<br/>INSERT events<br/>INSERT tags<br/>IP ban save]
|
||||
EW -->|completion| LWS
|
||||
DW -->|completion| LWS
|
||||
|
||||
LWS -->|REQ/COUNT submit| DR[db-read<br/>SELECT queries<br/>Config refresh<br/>Auth checks]
|
||||
DR -->|completion| LWS
|
||||
|
||||
LWS -->|OK/EVENT/EOSE| CLIENT
|
||||
```
|
||||
@@ -0,0 +1,107 @@
|
||||
# WAL Checkpoint Fix — db-write Thread CPU Plan
|
||||
|
||||
## Problem
|
||||
|
||||
Fresh profiling of the production server shows the `db-write` thread consuming **77% average CPU** (peaking at 100%) while `lws-main` sits at 0.3%.
|
||||
|
||||
The `perf` callgraph confirms 100% of the hot symbols are SQLite **B-tree read operations** running on the `db-write` thread:
|
||||
|
||||
| % CPU | Symbol | Role |
|
||||
|-------|--------|------|
|
||||
| 13.88 | `sqlite3BtreeTableMoveto` | B-tree seek |
|
||||
| 10.05 | `sqlite3VdbeExec` | VM execution |
|
||||
| 7.77 | `rep_movs_alternative` | kernel memcpy in pread |
|
||||
| 7.76 | `sqlite3GetVarint` | varint decode |
|
||||
| 6.66 | `pcache1Fetch` | page cache lookup |
|
||||
| 6.02 | `memcpy` | data copy |
|
||||
|
||||
These are **read-path** functions, not write-path. The `event-worker` thread accumulated only 3 CPU ticks over 5 minutes, meaning very few events are actually being stored.
|
||||
|
||||
## Root Cause
|
||||
|
||||
SQLite WAL auto-checkpoint. By default SQLite triggers a checkpoint every 1000 WAL pages. The checkpoint is executed by the **next writer** — which is always the `db-write` thread since all writes are funnelled through it.
|
||||
|
||||
A WAL checkpoint reads every dirty page from the WAL file and writes it back to the main database file. This involves B-tree traversals to locate pages, which explains the `BtreeTableMoveto` dominance.
|
||||
|
||||
The current `db_open_worker_connection` in `src/db_ops.c` sets `PRAGMA journal_mode=WAL` and `busy_timeout=5000` but does **not** configure `wal_autocheckpoint`. SQLite's default of 1000 pages applies.
|
||||
|
||||
In earlier profiling runs the same CPU burn appeared on `lws-main` at 55-67% — because that thread was doing the writes directly before the thread-pool refactoring. The work simply moved threads; the total cost is unchanged.
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### Step 1 — Disable auto-checkpoint on the write connection
|
||||
|
||||
In `db_open_worker_connection` add:
|
||||
|
||||
```c
|
||||
sqlite3_exec(db, "PRAGMA wal_autocheckpoint=0;", NULL, NULL, NULL);
|
||||
```
|
||||
|
||||
This prevents the write thread from ever running a checkpoint inline with normal writes.
|
||||
|
||||
### Step 2 — Add a periodic checkpoint job type to the thread pool
|
||||
|
||||
Add a new job type `THREAD_POOL_JOB_WAL_CHECKPOINT` to `thread_pool.h`.
|
||||
|
||||
The handler in `thread_pool.c` calls:
|
||||
|
||||
```c
|
||||
sqlite3_wal_checkpoint_v2(db, NULL, SQLITE_CHECKPOINT_PASSIVE, NULL, NULL);
|
||||
```
|
||||
|
||||
`PASSIVE` mode checkpoints only pages that are not currently being read, so it never blocks readers.
|
||||
|
||||
### Step 3 — Submit the checkpoint job on a timer
|
||||
|
||||
In the existing 60-second periodic timer in `websockets.c`, add a call to submit a WAL checkpoint job to the write queue:
|
||||
|
||||
```c
|
||||
thread_pool_submit_wal_checkpoint();
|
||||
```
|
||||
|
||||
This runs the checkpoint once per minute on the write thread, but as a **bounded, predictable** operation rather than being triggered unpredictably by every INSERT.
|
||||
|
||||
### Step 4 — Also disable auto-checkpoint on reader connections
|
||||
|
||||
In `db_open_worker_connection`, the same `wal_autocheckpoint=0` applies to reader connections too. Readers can also trigger checkpoints in SQLite; disabling it on all connections ensures only the explicit periodic job does checkpointing.
|
||||
|
||||
### Step 5 — Run a TRUNCATE checkpoint at shutdown
|
||||
|
||||
In `thread_pool_shutdown`, before closing the write connection, run:
|
||||
|
||||
```c
|
||||
sqlite3_wal_checkpoint_v2(db, NULL, SQLITE_CHECKPOINT_TRUNCATE, NULL, NULL);
|
||||
```
|
||||
|
||||
This ensures the WAL is fully flushed and truncated on clean shutdown, keeping the database file compact.
|
||||
|
||||
## Files Changed
|
||||
|
||||
| File | Change |
|
||||
|------|--------|
|
||||
| `src/db_ops.c` | Add `PRAGMA wal_autocheckpoint=0` in `db_open_worker_connection` |
|
||||
| `src/thread_pool.h` | Add `THREAD_POOL_JOB_WAL_CHECKPOINT` enum value |
|
||||
| `src/thread_pool.c` | Add `execute_wal_checkpoint_job` handler; add checkpoint-at-shutdown in `thread_pool_shutdown`; add `thread_pool_submit_wal_checkpoint` helper |
|
||||
| `src/websockets.c` | Call `thread_pool_submit_wal_checkpoint()` in the 60-second periodic timer |
|
||||
|
||||
## Expected Impact
|
||||
|
||||
- `db-write` CPU should drop from ~77% to near 0% when idle (no events to store)
|
||||
- Periodic checkpoint bursts of a few seconds every 60s instead of continuous burn
|
||||
- No change to data durability — WAL still protects against crashes; checkpoint just moves data from WAL to main DB file
|
||||
- Readers are unaffected — PASSIVE checkpoint never blocks them
|
||||
|
||||
## Risk
|
||||
|
||||
- If the relay crashes between checkpoints, the WAL file may be larger than before (up to 60s of accumulated writes). This is safe — SQLite replays the WAL on next open. The WAL file size is bounded by the write rate, which is low.
|
||||
- PASSIVE checkpoint may not checkpoint all pages if readers hold them. This is fine — the next checkpoint will catch up.
|
||||
|
||||
## Verification
|
||||
|
||||
After deploying, re-run the profiler:
|
||||
|
||||
```bash
|
||||
./deploy_lt_debug.sh && DURATION=300 INTERVAL=5 ./tests/thread_cpu_profile.sh
|
||||
```
|
||||
|
||||
Expected: `db-write` avg CPU drops below 5%.
|
||||
@@ -55,6 +55,14 @@ int generate_monitoring_event_for_type(const char* d_tag_value, cJSON* (*query_f
|
||||
// Forward declaration for CPU metrics query function
|
||||
cJSON* query_cpu_metrics(void);
|
||||
|
||||
static int api_open_temp_db_connection(void** out_db) {
|
||||
return db_open_worker_connection(db_get_database_path(), out_db);
|
||||
}
|
||||
|
||||
static void api_close_temp_db_connection(void* db) {
|
||||
db_close_worker_connection(db);
|
||||
}
|
||||
|
||||
// Monitoring system helper functions
|
||||
int get_monitoring_throttle_seconds(void) {
|
||||
return get_config_int("kind_24567_reporting_throttle_sec", 5);
|
||||
@@ -62,7 +70,8 @@ int get_monitoring_throttle_seconds(void) {
|
||||
|
||||
// Query event kind distribution from database
|
||||
cJSON* query_event_kind_distribution(void) {
|
||||
if (!db_is_available()) {
|
||||
void* temp_db = NULL;
|
||||
if (!db_is_available() && api_open_temp_db_connection(&temp_db) != 0) {
|
||||
DEBUG_ERROR("Database not available for monitoring query");
|
||||
return NULL;
|
||||
}
|
||||
@@ -95,12 +104,14 @@ cJSON* query_event_kind_distribution(void) {
|
||||
cJSON_AddNumberToObject(distribution, "total_events", total_events);
|
||||
cJSON_AddItemToObject(distribution, "kinds", kinds_array);
|
||||
|
||||
api_close_temp_db_connection(temp_db);
|
||||
return distribution;
|
||||
}
|
||||
|
||||
// Query time-based statistics from database
|
||||
cJSON* query_time_based_statistics(void) {
|
||||
if (!db_is_available()) {
|
||||
void* temp_db = NULL;
|
||||
if (!db_is_available() && api_open_temp_db_connection(&temp_db) != 0) {
|
||||
DEBUG_ERROR("Database not available for time stats query");
|
||||
return NULL;
|
||||
}
|
||||
@@ -146,12 +157,14 @@ cJSON* query_time_based_statistics(void) {
|
||||
cJSON_AddItemToObject(time_stats, "periods", periods_array);
|
||||
cJSON_AddNumberToObject(time_stats, "total_events", total_events);
|
||||
|
||||
api_close_temp_db_connection(temp_db);
|
||||
return time_stats;
|
||||
}
|
||||
|
||||
// Query top pubkeys by event count from database
|
||||
cJSON* query_top_pubkeys(void) {
|
||||
if (!db_is_available()) {
|
||||
void* temp_db = NULL;
|
||||
if (!db_is_available() && api_open_temp_db_connection(&temp_db) != 0) {
|
||||
DEBUG_ERROR("Database not available for top pubkeys query");
|
||||
return NULL;
|
||||
}
|
||||
@@ -163,6 +176,7 @@ cJSON* query_top_pubkeys(void) {
|
||||
cJSON* rows = db_get_top_pubkeys_rows(10);
|
||||
if (!rows) {
|
||||
cJSON_Delete(top_pubkeys);
|
||||
api_close_temp_db_connection(temp_db);
|
||||
DEBUG_ERROR("Failed to query top pubkeys rows");
|
||||
return NULL;
|
||||
}
|
||||
@@ -188,6 +202,7 @@ cJSON* query_top_pubkeys(void) {
|
||||
cJSON_AddItemToObject(top_pubkeys, "pubkeys", pubkeys_array);
|
||||
cJSON_AddNumberToObject(top_pubkeys, "total_events", total_events);
|
||||
|
||||
api_close_temp_db_connection(temp_db);
|
||||
return top_pubkeys;
|
||||
}
|
||||
|
||||
@@ -195,7 +210,8 @@ cJSON* query_top_pubkeys(void) {
|
||||
// Query detailed subscription information from database log (ADMIN ONLY)
|
||||
// Uses subscriptions table instead of in-memory iteration to avoid mutex contention
|
||||
cJSON* query_subscription_details(void) {
|
||||
if (!db_is_available()) {
|
||||
void* temp_db = NULL;
|
||||
if (!db_is_available() && api_open_temp_db_connection(&temp_db) != 0) {
|
||||
DEBUG_ERROR("Database not available for subscription details query");
|
||||
return NULL;
|
||||
}
|
||||
@@ -226,6 +242,7 @@ cJSON* query_subscription_details(void) {
|
||||
cJSON_Delete(subscriptions_data);
|
||||
cJSON_Delete(data);
|
||||
cJSON_Delete(subscriptions_array);
|
||||
api_close_temp_db_connection(temp_db);
|
||||
DEBUG_ERROR("Failed to query subscription details rows");
|
||||
return NULL;
|
||||
}
|
||||
@@ -278,9 +295,9 @@ cJSON* query_subscription_details(void) {
|
||||
// Parse wsi pointer from hex string
|
||||
struct lws* wsi = NULL;
|
||||
if (sscanf(wsi_pointer, "%p", (void**)&wsi) == 1 && wsi != NULL) {
|
||||
// Get per_session_data from wsi
|
||||
struct per_session_data* pss = (struct per_session_data*)lws_wsi_user(wsi);
|
||||
if (pss) {
|
||||
// Resolve live session data only if this wsi is still tracked.
|
||||
struct per_session_data* pss = NULL;
|
||||
if (websocket_get_live_pss(wsi, &pss) && pss) {
|
||||
db_queries = pss->db_queries_executed;
|
||||
db_rows = pss->db_rows_returned;
|
||||
|
||||
@@ -341,6 +358,7 @@ cJSON* query_subscription_details(void) {
|
||||
DEBUG_LOG("Total subscriptions found: %d", row_count);
|
||||
DEBUG_LOG("=== END SUBSCRIPTION_DETAILS QUERY DEBUG ===");
|
||||
|
||||
api_close_temp_db_connection(temp_db);
|
||||
return subscriptions_data;
|
||||
}
|
||||
|
||||
@@ -1165,7 +1183,8 @@ cJSON* query_cpu_metrics(void) {
|
||||
|
||||
// Generate stats JSON from database queries
|
||||
char* generate_stats_json(void) {
|
||||
if (!db_is_available()) {
|
||||
void* temp_db = NULL;
|
||||
if (!db_is_available() && api_open_temp_db_connection(&temp_db) != 0) {
|
||||
DEBUG_ERROR("Database not available for stats generation");
|
||||
return NULL;
|
||||
}
|
||||
@@ -1274,6 +1293,7 @@ char* generate_stats_json(void) {
|
||||
DEBUG_ERROR("Failed to generate stats JSON");
|
||||
}
|
||||
|
||||
api_close_temp_db_connection(temp_db);
|
||||
return json_string;
|
||||
}
|
||||
|
||||
|
||||
+259
-17
@@ -31,7 +31,6 @@
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <libwebsockets.h>
|
||||
|
||||
// External database connection (from main.c)
|
||||
|
||||
// External shutdown flag (from main.c)
|
||||
@@ -108,6 +107,17 @@ static cJSON* g_pending_config_event = NULL;
|
||||
// Temporary storage for relay private key during first-time setup
|
||||
static char g_temp_relay_privkey[65] = {0};
|
||||
|
||||
// Runtime cache for relay private key to support strict mode (g_db = NULL)
|
||||
static char g_cached_relay_privkey[65] = {0};
|
||||
|
||||
static int config_open_temp_db_connection(void** out_db) {
|
||||
return db_open_worker_connection(db_get_database_path(), out_db);
|
||||
}
|
||||
|
||||
static void config_close_temp_db_connection(void* db) {
|
||||
db_close_worker_connection(db);
|
||||
}
|
||||
|
||||
// ================================
|
||||
// UTILITY FUNCTIONS
|
||||
// ================================
|
||||
@@ -251,14 +261,21 @@ const char* get_config_value(const char* key) {
|
||||
if (!key) {
|
||||
return NULL;
|
||||
}
|
||||
return get_config_value_from_table(key);
|
||||
|
||||
const char* cached = get_config_value_from_table(key);
|
||||
if (!cached) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Public API returns an owned string; callers may free it.
|
||||
return cached;
|
||||
}
|
||||
|
||||
int get_config_int(const char* key, int default_value) {
|
||||
if (!key) {
|
||||
return default_value;
|
||||
}
|
||||
const char* value = get_config_value_from_table(key);
|
||||
const char* value = get_config_value(key);
|
||||
if (!value) {
|
||||
return default_value;
|
||||
}
|
||||
@@ -271,7 +288,7 @@ int get_config_bool(const char* key, int default_value) {
|
||||
if (!key) {
|
||||
return default_value;
|
||||
}
|
||||
const char* value = get_config_value_from_table(key);
|
||||
const char* value = get_config_value(key);
|
||||
if (!value) {
|
||||
return default_value;
|
||||
}
|
||||
@@ -405,6 +422,9 @@ void cleanup_configuration_system(void) {
|
||||
g_pending_config_event = NULL;
|
||||
}
|
||||
|
||||
// Clear cached sensitive material
|
||||
memset(g_cached_relay_privkey, 0, sizeof(g_cached_relay_privkey));
|
||||
|
||||
// Configuration system now uses direct database queries instead of cache
|
||||
// No cleanup needed for cache system
|
||||
}
|
||||
@@ -486,6 +506,10 @@ int store_relay_private_key(const char* relay_privkey_hex) {
|
||||
}
|
||||
|
||||
if (db_store_relay_private_key_hex(relay_privkey_hex) == 0) {
|
||||
// Keep an in-memory runtime copy for strict mode where g_db is NULL
|
||||
memset(g_cached_relay_privkey, 0, sizeof(g_cached_relay_privkey));
|
||||
strncpy(g_cached_relay_privkey, relay_privkey_hex, sizeof(g_cached_relay_privkey) - 1);
|
||||
g_cached_relay_privkey[sizeof(g_cached_relay_privkey) - 1] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -494,11 +518,16 @@ int store_relay_private_key(const char* relay_privkey_hex) {
|
||||
}
|
||||
|
||||
char* get_relay_private_key(void) {
|
||||
// Fast path for strict runtime mode where g_db may be NULL
|
||||
if (strlen(g_cached_relay_privkey) == 64) {
|
||||
return strdup(g_cached_relay_privkey);
|
||||
}
|
||||
|
||||
if (!db_is_available()) {
|
||||
DEBUG_ERROR("Database not available for relay private key retrieval");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
char* private_key = db_get_relay_private_key_hex_dup();
|
||||
if (!private_key || strlen(private_key) != 64) {
|
||||
if (private_key) {
|
||||
@@ -508,9 +537,35 @@ char* get_relay_private_key(void) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Prime runtime cache from DB for subsequent strict-mode operations
|
||||
memset(g_cached_relay_privkey, 0, sizeof(g_cached_relay_privkey));
|
||||
strncpy(g_cached_relay_privkey, private_key, sizeof(g_cached_relay_privkey) - 1);
|
||||
g_cached_relay_privkey[sizeof(g_cached_relay_privkey) - 1] = '\0';
|
||||
|
||||
return private_key;
|
||||
}
|
||||
|
||||
int preload_relay_private_key_cache(void) {
|
||||
if (!db_is_available()) {
|
||||
DEBUG_ERROR("Database not available for relay private key cache preload");
|
||||
return -1;
|
||||
}
|
||||
|
||||
char* private_key = db_get_relay_private_key_hex_dup();
|
||||
if (!private_key || strlen(private_key) != 64) {
|
||||
if (private_key) free(private_key);
|
||||
DEBUG_ERROR("Relay private key not found for cache preload");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(g_cached_relay_privkey, 0, sizeof(g_cached_relay_privkey));
|
||||
strncpy(g_cached_relay_privkey, private_key, sizeof(g_cached_relay_privkey) - 1);
|
||||
g_cached_relay_privkey[sizeof(g_cached_relay_privkey) - 1] = '\0';
|
||||
free(private_key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* get_temp_relay_private_key(void) {
|
||||
if (strlen(g_temp_relay_privkey) == 64) {
|
||||
return g_temp_relay_privkey;
|
||||
@@ -1606,13 +1661,7 @@ int handle_configuration_event(cJSON* event, char* error_message, size_t error_s
|
||||
// Note: Config table is now created via embedded schema in sql_schema.h
|
||||
|
||||
// Get value from config table
|
||||
const char* get_config_value_from_table(const char* key) {
|
||||
if (!db_is_available() || !key) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return db_get_config_value_dup(key);
|
||||
}
|
||||
const char* get_config_value_from_table(const char* key);
|
||||
|
||||
// Set value in config table
|
||||
int set_config_value_in_table(const char* key, const char* value, const char* data_type,
|
||||
@@ -1621,7 +1670,12 @@ int set_config_value_in_table(const char* key, const char* value, const char* da
|
||||
return -1;
|
||||
}
|
||||
|
||||
return db_set_config_value_full(key, value, data_type, description, category, requires_restart);
|
||||
int rc = db_set_config_value_full(key, value, data_type, description, category, requires_restart);
|
||||
if (rc == 0) {
|
||||
invalidate_config_cache();
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Update config in table (simpler version of set_config_value_in_table)
|
||||
@@ -1637,7 +1691,12 @@ int update_config_in_table(const char* key, const char* value) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return db_update_config_value_only(key, value);
|
||||
int rc = db_update_config_value_only(key, value);
|
||||
if (rc == 0) {
|
||||
invalidate_config_cache();
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// DEPRECATED: This function is no longer used in the unified startup flow.
|
||||
@@ -2938,7 +2997,8 @@ int handle_kind_23456_unified(cJSON* event, char* error_message, size_t error_si
|
||||
int handle_auth_query_unified(cJSON* event, const char* query_type, char* error_message, size_t error_size, struct lws* wsi) {
|
||||
// Suppress unused parameter warning
|
||||
(void)wsi;
|
||||
if (!db_is_available()) {
|
||||
void* temp_db = NULL;
|
||||
if (!db_is_available() && config_open_temp_db_connection(&temp_db) != 0) {
|
||||
snprintf(error_message, error_size, "database not available");
|
||||
return -1;
|
||||
}
|
||||
@@ -3030,6 +3090,9 @@ int handle_auth_query_unified(cJSON* event, const char* query_type, char* error_
|
||||
if (!admin_pubkey) {
|
||||
cJSON_Delete(response);
|
||||
cJSON_Delete(results_array);
|
||||
if (temp_db) {
|
||||
config_close_temp_db_connection(temp_db);
|
||||
}
|
||||
snprintf(error_message, error_size, "missing admin pubkey for response");
|
||||
return -1;
|
||||
}
|
||||
@@ -3038,12 +3101,18 @@ int handle_auth_query_unified(cJSON* event, const char* query_type, char* error_
|
||||
if (send_admin_response_event(response, admin_pubkey, wsi) == 0) {
|
||||
cJSON_Delete(response);
|
||||
cJSON_Delete(results_array);
|
||||
if (temp_db) {
|
||||
config_close_temp_db_connection(temp_db);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
cJSON_Delete(response);
|
||||
}
|
||||
|
||||
cJSON_Delete(results_array);
|
||||
if (temp_db) {
|
||||
config_close_temp_db_connection(temp_db);
|
||||
}
|
||||
snprintf(error_message, error_size, "failed to send auth query response");
|
||||
return -1;
|
||||
}
|
||||
@@ -3052,7 +3121,8 @@ int handle_auth_query_unified(cJSON* event, const char* query_type, char* error_
|
||||
int handle_config_query_unified(cJSON* event, const char* query_type, char* error_message, size_t error_size, struct lws* wsi) {
|
||||
// Suppress unused parameter warning
|
||||
(void)wsi;
|
||||
if (!db_is_available()) {
|
||||
void* temp_db = NULL;
|
||||
if (!db_is_available() && config_open_temp_db_connection(&temp_db) != 0) {
|
||||
snprintf(error_message, error_size, "database not available");
|
||||
return -1;
|
||||
}
|
||||
@@ -3145,6 +3215,9 @@ int handle_config_query_unified(cJSON* event, const char* query_type, char* erro
|
||||
if (!admin_pubkey) {
|
||||
cJSON_Delete(response);
|
||||
cJSON_Delete(results_array);
|
||||
if (temp_db) {
|
||||
config_close_temp_db_connection(temp_db);
|
||||
}
|
||||
snprintf(error_message, error_size, "missing admin pubkey for response");
|
||||
return -1;
|
||||
}
|
||||
@@ -3153,12 +3226,18 @@ int handle_config_query_unified(cJSON* event, const char* query_type, char* erro
|
||||
if (send_admin_response_event(response, admin_pubkey, wsi) == 0) {
|
||||
cJSON_Delete(response);
|
||||
cJSON_Delete(results_array);
|
||||
if (temp_db) {
|
||||
config_close_temp_db_connection(temp_db);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
cJSON_Delete(response);
|
||||
}
|
||||
|
||||
cJSON_Delete(results_array);
|
||||
if (temp_db) {
|
||||
config_close_temp_db_connection(temp_db);
|
||||
}
|
||||
snprintf(error_message, error_size, "failed to send config query response");
|
||||
return -1;
|
||||
}
|
||||
@@ -3661,7 +3740,8 @@ int handle_auth_rule_modification_unified(cJSON* event, char* error_message, siz
|
||||
int handle_stats_query_unified(cJSON* event, char* error_message, size_t error_size, struct lws* wsi) {
|
||||
// Suppress unused parameter warning
|
||||
(void)wsi;
|
||||
if (!db_is_available()) {
|
||||
void* temp_db = NULL;
|
||||
if (!db_is_available() && config_open_temp_db_connection(&temp_db) != 0) {
|
||||
snprintf(error_message, error_size, "database not available");
|
||||
return -1;
|
||||
}
|
||||
@@ -3767,6 +3847,9 @@ int handle_stats_query_unified(cJSON* event, char* error_message, size_t error_s
|
||||
|
||||
if (!admin_pubkey) {
|
||||
cJSON_Delete(response);
|
||||
if (temp_db) {
|
||||
config_close_temp_db_connection(temp_db);
|
||||
}
|
||||
snprintf(error_message, error_size, "missing admin pubkey for response");
|
||||
return -1;
|
||||
}
|
||||
@@ -3774,10 +3857,16 @@ int handle_stats_query_unified(cJSON* event, char* error_message, size_t error_s
|
||||
// Send response as signed kind 23457 event
|
||||
if (send_admin_response_event(response, admin_pubkey, wsi) == 0) {
|
||||
cJSON_Delete(response);
|
||||
if (temp_db) {
|
||||
config_close_temp_db_connection(temp_db);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
cJSON_Delete(response);
|
||||
if (temp_db) {
|
||||
config_close_temp_db_connection(temp_db);
|
||||
}
|
||||
snprintf(error_message, error_size, "failed to send stats query response");
|
||||
return -1;
|
||||
}
|
||||
@@ -4454,6 +4543,159 @@ int populate_all_config_values_atomic(const char* admin_pubkey, const char* rela
|
||||
// CONFIGURATION CACHE MANAGEMENT
|
||||
// ================================
|
||||
|
||||
#define CONFIG_CACHE_MAX_ITEMS 256
|
||||
|
||||
typedef struct {
|
||||
char key[128];
|
||||
char value[CONFIG_VALUE_MAX_LENGTH + 1];
|
||||
int in_use;
|
||||
} config_cache_entry_t;
|
||||
|
||||
static config_cache_entry_t g_config_cache[CONFIG_CACHE_MAX_ITEMS];
|
||||
static pthread_mutex_t g_config_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static int find_cache_index_by_key(const char* key) {
|
||||
if (!key) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < CONFIG_CACHE_MAX_ITEMS; i++) {
|
||||
if (g_config_cache[i].in_use && strcmp(g_config_cache[i].key, key) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int find_empty_cache_index(void) {
|
||||
for (int i = 0; i < CONFIG_CACHE_MAX_ITEMS; i++) {
|
||||
if (!g_config_cache[i].in_use) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void clear_config_cache_locked(void) {
|
||||
memset(g_config_cache, 0, sizeof(g_config_cache));
|
||||
}
|
||||
|
||||
void invalidate_config_cache(void) {
|
||||
pthread_mutex_lock(&g_config_cache_mutex);
|
||||
clear_config_cache_locked();
|
||||
pthread_mutex_unlock(&g_config_cache_mutex);
|
||||
}
|
||||
|
||||
void force_config_cache_refresh(void) {
|
||||
invalidate_config_cache();
|
||||
}
|
||||
|
||||
int reload_config_from_table(void) {
|
||||
force_config_cache_refresh();
|
||||
|
||||
if (!db_is_available()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cJSON* rows = db_get_all_config_rows();
|
||||
if (!rows || !cJSON_IsArray(rows)) {
|
||||
if (rows) cJSON_Delete(rows);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&g_config_cache_mutex);
|
||||
cJSON* row = NULL;
|
||||
cJSON_ArrayForEach(row, rows) {
|
||||
if (!cJSON_IsObject(row)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cJSON* key_obj = cJSON_GetObjectItemCaseSensitive(row, "key");
|
||||
cJSON* value_obj = cJSON_GetObjectItemCaseSensitive(row, "value");
|
||||
if (!cJSON_IsString(key_obj) || !cJSON_IsString(value_obj)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const char* key = cJSON_GetStringValue(key_obj);
|
||||
const char* value = cJSON_GetStringValue(value_obj);
|
||||
if (!key || !value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int idx = find_cache_index_by_key(key);
|
||||
if (idx < 0) {
|
||||
idx = find_empty_cache_index();
|
||||
}
|
||||
if (idx < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
g_config_cache[idx].in_use = 1;
|
||||
strncpy(g_config_cache[idx].key, key, sizeof(g_config_cache[idx].key) - 1);
|
||||
g_config_cache[idx].key[sizeof(g_config_cache[idx].key) - 1] = '\0';
|
||||
strncpy(g_config_cache[idx].value, value, sizeof(g_config_cache[idx].value) - 1);
|
||||
g_config_cache[idx].value[sizeof(g_config_cache[idx].value) - 1] = '\0';
|
||||
}
|
||||
pthread_mutex_unlock(&g_config_cache_mutex);
|
||||
|
||||
cJSON_Delete(rows);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* get_config_value_from_table(const char* key) {
|
||||
if (!key) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&g_config_cache_mutex);
|
||||
|
||||
int idx = find_cache_index_by_key(key);
|
||||
if (idx >= 0) {
|
||||
const char* result = strdup(g_config_cache[idx].value);
|
||||
pthread_mutex_unlock(&g_config_cache_mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&g_config_cache_mutex);
|
||||
|
||||
if (!db_is_available()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* db_value = db_get_config_value_dup(key);
|
||||
if (!db_value) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&g_config_cache_mutex);
|
||||
|
||||
idx = find_cache_index_by_key(key);
|
||||
if (idx < 0) {
|
||||
idx = find_empty_cache_index();
|
||||
}
|
||||
|
||||
if (idx >= 0) {
|
||||
g_config_cache[idx].in_use = 1;
|
||||
strncpy(g_config_cache[idx].key, key, sizeof(g_config_cache[idx].key) - 1);
|
||||
g_config_cache[idx].key[sizeof(g_config_cache[idx].key) - 1] = '\0';
|
||||
strncpy(g_config_cache[idx].value, db_value, sizeof(g_config_cache[idx].value) - 1);
|
||||
g_config_cache[idx].value[sizeof(g_config_cache[idx].value) - 1] = '\0';
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&g_config_cache_mutex);
|
||||
|
||||
return db_value;
|
||||
}
|
||||
|
||||
const char* get_admin_pubkey_cached(void) {
|
||||
return get_config_value_from_table("admin_pubkey");
|
||||
}
|
||||
|
||||
const char* get_relay_pubkey_cached(void) {
|
||||
return get_config_value_from_table("relay_pubkey");
|
||||
}
|
||||
|
||||
// ================================
|
||||
// HYBRID CONFIG ACCESS FUNCTIONS
|
||||
|
||||
@@ -77,6 +77,7 @@ char* extract_pubkey_from_filename(const char* filename);
|
||||
int store_relay_private_key(const char* relay_privkey_hex);
|
||||
char* get_relay_private_key(void);
|
||||
const char* get_temp_relay_private_key(void); // For first-time startup only
|
||||
int preload_relay_private_key_cache(void); // Preload relay private key before strict DB mode
|
||||
|
||||
// NIP-42 authentication configuration functions
|
||||
int parse_auth_required_kinds(const char* kinds_str, int* kinds_array, int max_kinds);
|
||||
|
||||
+164
-85
@@ -57,6 +57,34 @@ void db_clear_thread_connection(void) {
|
||||
g_thread_db = NULL;
|
||||
}
|
||||
|
||||
int db_open_worker_connection(const char* db_path, void** out_connection) {
|
||||
if (!out_connection) return -1;
|
||||
*out_connection = NULL;
|
||||
|
||||
const char* effective_path = (db_path && db_path[0] != '\0') ? db_path : g_database_path;
|
||||
if (!effective_path || effective_path[0] == '\0') return -1;
|
||||
|
||||
sqlite3* db = NULL;
|
||||
int rc = sqlite3_open_v2(effective_path, &db, SQLITE_OPEN_READWRITE, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
if (db) sqlite3_close(db);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sqlite3_exec(db, "PRAGMA journal_mode=WAL;", NULL, NULL, NULL);
|
||||
sqlite3_exec(db, "PRAGMA wal_autocheckpoint=0;", NULL, NULL, NULL);
|
||||
sqlite3_busy_timeout(db, 5000);
|
||||
db_set_thread_connection(db);
|
||||
*out_connection = (void*)db;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void db_close_worker_connection(void* connection) {
|
||||
if (!connection) return;
|
||||
db_clear_thread_connection();
|
||||
sqlite3_close((sqlite3*)connection);
|
||||
}
|
||||
|
||||
int db_is_available(void) {
|
||||
return db_active_connection() != NULL;
|
||||
}
|
||||
@@ -143,14 +171,15 @@ void db_finalize_stmt(db_stmt_t* stmt) {
|
||||
|
||||
int db_log_subscription_created(const char* sub_id, const char* wsi_ptr,
|
||||
const char* client_ip, const char* filter_json) {
|
||||
if (!g_db || !sub_id || !wsi_ptr || !client_ip) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !sub_id || !wsi_ptr || !client_ip) return -1;
|
||||
|
||||
const char* sql =
|
||||
"INSERT OR REPLACE INTO subscriptions (subscription_id, wsi_pointer, client_ip, event_type, filter_json) "
|
||||
"VALUES (?, ?, ?, 'created', ?)";
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
|
||||
sqlite3_bind_text(stmt, 1, sub_id, -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_text(stmt, 2, wsi_ptr, -1, SQLITE_TRANSIENT);
|
||||
@@ -163,14 +192,15 @@ int db_log_subscription_created(const char* sub_id, const char* wsi_ptr,
|
||||
}
|
||||
|
||||
int db_log_subscription_closed(const char* sub_id, const char* client_ip) {
|
||||
if (!g_db || !sub_id) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !sub_id) return -1;
|
||||
|
||||
const char* insert_sql =
|
||||
"INSERT INTO subscriptions (subscription_id, wsi_pointer, client_ip, event_type) "
|
||||
"VALUES (?, '', ?, 'closed')";
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
if (sqlite3_prepare_v2(g_db, insert_sql, -1, &stmt, NULL) == SQLITE_OK) {
|
||||
if (sqlite3_prepare_v2(db, insert_sql, -1, &stmt, NULL) == SQLITE_OK) {
|
||||
sqlite3_bind_text(stmt, 1, sub_id, -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_text(stmt, 2, client_ip ? client_ip : "unknown", -1, SQLITE_TRANSIENT);
|
||||
sqlite3_step(stmt);
|
||||
@@ -182,7 +212,7 @@ int db_log_subscription_closed(const char* sub_id, const char* client_ip) {
|
||||
"SET ended_at = strftime('%s', 'now') "
|
||||
"WHERE subscription_id = ? AND event_type = 'created' AND ended_at IS NULL";
|
||||
|
||||
if (sqlite3_prepare_v2(g_db, update_sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
if (sqlite3_prepare_v2(db, update_sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
sqlite3_bind_text(stmt, 1, sub_id, -1, SQLITE_TRANSIENT);
|
||||
int rc = sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
@@ -191,7 +221,8 @@ int db_log_subscription_closed(const char* sub_id, const char* client_ip) {
|
||||
}
|
||||
|
||||
int db_log_subscription_disconnected(const char* client_ip) {
|
||||
if (!g_db || !client_ip) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !client_ip) return -1;
|
||||
|
||||
const char* update_sql =
|
||||
"UPDATE subscriptions "
|
||||
@@ -199,11 +230,11 @@ int db_log_subscription_disconnected(const char* client_ip) {
|
||||
"WHERE client_ip = ? AND event_type = 'created' AND ended_at IS NULL";
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
if (sqlite3_prepare_v2(g_db, update_sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
if (sqlite3_prepare_v2(db, update_sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
|
||||
sqlite3_bind_text(stmt, 1, client_ip, -1, SQLITE_TRANSIENT);
|
||||
int rc = sqlite3_step(stmt);
|
||||
int changes = sqlite3_changes(g_db);
|
||||
int changes = sqlite3_changes(db);
|
||||
sqlite3_finalize(stmt);
|
||||
if (rc != SQLITE_DONE) return -1;
|
||||
|
||||
@@ -212,7 +243,7 @@ int db_log_subscription_disconnected(const char* client_ip) {
|
||||
"INSERT INTO subscriptions (subscription_id, wsi_pointer, client_ip, event_type) "
|
||||
"VALUES ('disconnect', '', ?, 'disconnected')";
|
||||
|
||||
if (sqlite3_prepare_v2(g_db, insert_sql, -1, &stmt, NULL) == SQLITE_OK) {
|
||||
if (sqlite3_prepare_v2(db, insert_sql, -1, &stmt, NULL) == SQLITE_OK) {
|
||||
sqlite3_bind_text(stmt, 1, client_ip, -1, SQLITE_TRANSIENT);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
@@ -223,7 +254,8 @@ int db_log_subscription_disconnected(const char* client_ip) {
|
||||
}
|
||||
|
||||
int db_update_subscription_events_sent(const char* sub_id, int events_sent) {
|
||||
if (!g_db || !sub_id) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !sub_id) return -1;
|
||||
|
||||
const char* sql =
|
||||
"UPDATE subscriptions "
|
||||
@@ -231,7 +263,7 @@ int db_update_subscription_events_sent(const char* sub_id, int events_sent) {
|
||||
"WHERE subscription_id = ? AND event_type = 'created'";
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
|
||||
sqlite3_bind_int(stmt, 1, events_sent);
|
||||
sqlite3_bind_text(stmt, 2, sub_id, -1, SQLITE_TRANSIENT);
|
||||
@@ -242,7 +274,8 @@ int db_update_subscription_events_sent(const char* sub_id, int events_sent) {
|
||||
}
|
||||
|
||||
int db_cleanup_orphaned_subscriptions(void) {
|
||||
if (!g_db) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db) return -1;
|
||||
|
||||
const char* sql =
|
||||
"UPDATE subscriptions "
|
||||
@@ -250,22 +283,23 @@ int db_cleanup_orphaned_subscriptions(void) {
|
||||
"WHERE event_type = 'created' AND ended_at IS NULL";
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
|
||||
int rc = sqlite3_step(stmt);
|
||||
int changes = sqlite3_changes(g_db);
|
||||
int changes = sqlite3_changes(db);
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
return (rc == SQLITE_DONE) ? changes : -1;
|
||||
}
|
||||
|
||||
int db_get_event_pubkey(const char* event_id, char* pubkey_out, size_t pubkey_out_size) {
|
||||
if (!g_db || !event_id || !pubkey_out || pubkey_out_size == 0) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !event_id || !pubkey_out || pubkey_out_size == 0) return -1;
|
||||
|
||||
const char* sql = "SELECT pubkey FROM events WHERE id = ?";
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
|
||||
sqlite3_bind_text(stmt, 1, event_id, -1, SQLITE_TRANSIENT);
|
||||
int rc = sqlite3_step(stmt);
|
||||
@@ -283,18 +317,19 @@ int db_get_event_pubkey(const char* event_id, char* pubkey_out, size_t pubkey_ou
|
||||
}
|
||||
|
||||
int db_delete_event_by_id(const char* event_id, const char* requester_pubkey) {
|
||||
if (!g_db || !event_id || !requester_pubkey) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !event_id || !requester_pubkey) return -1;
|
||||
|
||||
const char* sql = "DELETE FROM events WHERE id = ? AND pubkey = ?";
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
|
||||
sqlite3_bind_text(stmt, 1, event_id, -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_text(stmt, 2, requester_pubkey, -1, SQLITE_TRANSIENT);
|
||||
|
||||
int rc = sqlite3_step(stmt);
|
||||
int changes = sqlite3_changes(g_db);
|
||||
int changes = sqlite3_changes(db);
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
if (rc != SQLITE_DONE) return -1;
|
||||
@@ -303,7 +338,8 @@ int db_delete_event_by_id(const char* event_id, const char* requester_pubkey) {
|
||||
|
||||
int db_delete_events_by_address(const char* pubkey, int kind,
|
||||
const char* d_tag, long before_timestamp) {
|
||||
if (!g_db || !pubkey) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !pubkey) return -1;
|
||||
|
||||
const char* sql_with_d =
|
||||
"DELETE FROM events WHERE kind = ? AND pubkey = ? AND created_at <= ? "
|
||||
@@ -314,7 +350,7 @@ int db_delete_events_by_address(const char* pubkey, int kind,
|
||||
const int has_d = (d_tag && d_tag[0] != '\0');
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
|
||||
if (sqlite3_prepare_v2(g_db, has_d ? sql_with_d : sql_no_d, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
if (sqlite3_prepare_v2(db, has_d ? sql_with_d : sql_no_d, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -326,7 +362,7 @@ int db_delete_events_by_address(const char* pubkey, int kind,
|
||||
}
|
||||
|
||||
int rc = sqlite3_step(stmt);
|
||||
int changes = sqlite3_changes(g_db);
|
||||
int changes = sqlite3_changes(db);
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
if (rc != SQLITE_DONE) return -1;
|
||||
@@ -440,14 +476,15 @@ int db_count_with_sql(const char* sql, const char** bind_params, int bind_param_
|
||||
char* db_execute_readonly_query_json(const char* query, const char* request_id,
|
||||
char* error_message, size_t error_size,
|
||||
int max_rows, int timeout_ms) {
|
||||
if (!g_db || !query || !request_id || !error_message) return NULL;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !query || !request_id || !error_message) return NULL;
|
||||
|
||||
sqlite3_busy_timeout(g_db, timeout_ms > 0 ? timeout_ms : 5000);
|
||||
sqlite3_busy_timeout(db, timeout_ms > 0 ? timeout_ms : 5000);
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
int rc = sqlite3_prepare_v2(g_db, query, -1, &stmt, NULL);
|
||||
int rc = sqlite3_prepare_v2(db, query, -1, &stmt, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
const char* err_msg = sqlite3_errmsg(g_db);
|
||||
const char* err_msg = sqlite3_errmsg(db);
|
||||
snprintf(error_message, error_size, "SQL prepare failed: %s", err_msg ? err_msg : "unknown");
|
||||
return NULL;
|
||||
}
|
||||
@@ -560,7 +597,7 @@ char* db_execute_readonly_query_json(const char* query, const char* request_id,
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
|
||||
const char* err_msg = sqlite3_errmsg(g_db);
|
||||
const char* err_msg = sqlite3_errmsg(db);
|
||||
snprintf(error_message, error_size, "SQL execution failed: %s", err_msg ? err_msg : "unknown");
|
||||
cJSON_Delete(rows);
|
||||
cJSON_Delete(response);
|
||||
@@ -587,11 +624,12 @@ char* db_execute_readonly_query_json(const char* query, const char* request_id,
|
||||
}
|
||||
|
||||
int db_get_total_event_count_ll(long long* out_count) {
|
||||
if (!g_db || !out_count) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !out_count) return -1;
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const char* sql = "SELECT COUNT(*) FROM events";
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
|
||||
long long count = 0;
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
@@ -604,11 +642,12 @@ int db_get_total_event_count_ll(long long* out_count) {
|
||||
}
|
||||
|
||||
int db_get_event_count_since(time_t cutoff, long long* out_count) {
|
||||
if (!g_db || !out_count) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !out_count) return -1;
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const char* sql = "SELECT COUNT(*) FROM events WHERE created_at >= ?";
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
|
||||
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)cutoff);
|
||||
|
||||
@@ -623,11 +662,12 @@ int db_get_event_count_since(time_t cutoff, long long* out_count) {
|
||||
}
|
||||
|
||||
cJSON* db_get_event_kind_distribution_rows(long long* out_total_events) {
|
||||
if (!g_db) return NULL;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db) return NULL;
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const char* sql = "SELECT kind, COUNT(*) as count FROM events GROUP BY kind ORDER BY count DESC";
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) return NULL;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return NULL;
|
||||
|
||||
cJSON* rows = cJSON_CreateArray();
|
||||
if (!rows) {
|
||||
@@ -661,11 +701,12 @@ cJSON* db_get_event_kind_distribution_rows(long long* out_total_events) {
|
||||
}
|
||||
|
||||
cJSON* db_get_top_pubkeys_rows(int limit) {
|
||||
if (!g_db) return NULL;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db) return NULL;
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const char* sql = "SELECT pubkey, COUNT(*) as count FROM events GROUP BY pubkey ORDER BY count DESC LIMIT ?";
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) return NULL;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return NULL;
|
||||
|
||||
sqlite3_bind_int(stmt, 1, limit > 0 ? limit : 10);
|
||||
|
||||
@@ -695,7 +736,8 @@ cJSON* db_get_top_pubkeys_rows(int limit) {
|
||||
}
|
||||
|
||||
cJSON* db_get_subscription_details_rows(void) {
|
||||
if (!g_db) return NULL;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db) return NULL;
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const char* sql =
|
||||
@@ -703,7 +745,7 @@ cJSON* db_get_subscription_details_rows(void) {
|
||||
"FROM active_subscriptions_log "
|
||||
"ORDER BY created_at DESC";
|
||||
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) return NULL;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return NULL;
|
||||
|
||||
cJSON* rows = cJSON_CreateArray();
|
||||
if (!rows) {
|
||||
@@ -743,11 +785,12 @@ cJSON* db_get_subscription_details_rows(void) {
|
||||
}
|
||||
|
||||
cJSON* db_get_all_config_rows(void) {
|
||||
if (!g_db) return NULL;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db) return NULL;
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const char* sql = "SELECT key, value FROM config ORDER BY key";
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) return NULL;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return NULL;
|
||||
|
||||
cJSON* rows = cJSON_CreateArray();
|
||||
if (!rows) {
|
||||
@@ -775,11 +818,12 @@ cJSON* db_get_all_config_rows(void) {
|
||||
}
|
||||
|
||||
char* db_get_config_value_dup(const char* key) {
|
||||
if (!g_db || !key) return NULL;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !key) return NULL;
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const char* sql = "SELECT value FROM config WHERE key = ?";
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) return NULL;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return NULL;
|
||||
|
||||
sqlite3_bind_text(stmt, 1, key, -1, SQLITE_TRANSIENT);
|
||||
|
||||
@@ -795,14 +839,15 @@ char* db_get_config_value_dup(const char* key) {
|
||||
|
||||
int db_set_config_value_full(const char* key, const char* value, const char* data_type,
|
||||
const char* description, const char* category, int requires_restart) {
|
||||
if (!g_db || !key || !value || !data_type) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !key || !value || !data_type) return -1;
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const char* sql =
|
||||
"INSERT OR REPLACE INTO config (key, value, data_type, description, category, requires_restart) "
|
||||
"VALUES (?, ?, ?, ?, ?, ?)";
|
||||
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -819,11 +864,12 @@ int db_set_config_value_full(const char* key, const char* value, const char* dat
|
||||
}
|
||||
|
||||
int db_update_config_value_only(const char* key, const char* value) {
|
||||
if (!g_db || !key || !value) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !key || !value) return -1;
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const char* sql = "UPDATE config SET value = ?, updated_at = strftime('%s', 'now') WHERE key = ?";
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -836,12 +882,13 @@ int db_update_config_value_only(const char* key, const char* value) {
|
||||
}
|
||||
|
||||
int db_upsert_config_value(const char* key, const char* value, const char* data_type) {
|
||||
if (!g_db || !key || !value || !data_type) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !key || !value || !data_type) return -1;
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const char* sql = "INSERT OR REPLACE INTO config (key, value, data_type) VALUES (?, ?, ?)";
|
||||
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -855,11 +902,12 @@ int db_upsert_config_value(const char* key, const char* value, const char* data_
|
||||
}
|
||||
|
||||
int db_store_relay_private_key_hex(const char* relay_privkey_hex) {
|
||||
if (!g_db || !relay_privkey_hex) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !relay_privkey_hex) return -1;
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const char* sql = "INSERT OR REPLACE INTO relay_seckey (private_key_hex) VALUES (?)";
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
|
||||
sqlite3_bind_text(stmt, 1, relay_privkey_hex, -1, SQLITE_TRANSIENT);
|
||||
int rc = sqlite3_step(stmt);
|
||||
@@ -869,11 +917,12 @@ int db_store_relay_private_key_hex(const char* relay_privkey_hex) {
|
||||
}
|
||||
|
||||
char* db_get_relay_private_key_hex_dup(void) {
|
||||
if (!g_db) return NULL;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db) return NULL;
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const char* sql = "SELECT private_key_hex FROM relay_seckey";
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) return NULL;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return NULL;
|
||||
|
||||
char* result = NULL;
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
@@ -886,7 +935,8 @@ char* db_get_relay_private_key_hex_dup(void) {
|
||||
}
|
||||
|
||||
int db_store_config_event(const cJSON* event) {
|
||||
if (!g_db || !event) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !event) return -1;
|
||||
|
||||
cJSON* id_obj = cJSON_GetObjectItemCaseSensitive((cJSON*)event, "id");
|
||||
cJSON* pubkey_obj = cJSON_GetObjectItemCaseSensitive((cJSON*)event, "pubkey");
|
||||
@@ -904,7 +954,7 @@ int db_store_config_event(const cJSON* event) {
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const char* sql = "INSERT OR REPLACE INTO events (id, pubkey, created_at, kind, event_type, content, sig, tags) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
free(tags_str);
|
||||
return -1;
|
||||
}
|
||||
@@ -1017,11 +1067,12 @@ int db_insert_event_with_json(const char* id, const char* pubkey, long long crea
|
||||
}
|
||||
|
||||
int db_get_event_time_bounds(long long* out_min_created_at, long long* out_max_created_at) {
|
||||
if (!g_db || !out_min_created_at || !out_max_created_at) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !out_min_created_at || !out_max_created_at) return -1;
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const char* sql = "SELECT MIN(created_at), MAX(created_at) FROM events";
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1039,11 +1090,12 @@ int db_get_event_time_bounds(long long* out_min_created_at, long long* out_max_c
|
||||
}
|
||||
|
||||
int db_event_id_exists(const char* event_id, int* out_exists) {
|
||||
if (!g_db || !event_id || !out_exists) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !event_id || !out_exists) return -1;
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const char* sql = "SELECT 1 FROM events WHERE id=? LIMIT 1";
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
|
||||
sqlite3_bind_text(stmt, 1, event_id, 64, SQLITE_STATIC);
|
||||
int exists = (sqlite3_step(stmt) == SQLITE_ROW) ? 1 : 0;
|
||||
@@ -1054,13 +1106,14 @@ int db_event_id_exists(const char* event_id, int* out_exists) {
|
||||
}
|
||||
|
||||
cJSON* db_retrieve_event_by_id(const char* event_id) {
|
||||
if (!g_db || !event_id) return NULL;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !event_id) return NULL;
|
||||
|
||||
const char* sql =
|
||||
"SELECT id, pubkey, created_at, kind, content, sig, tags FROM events WHERE id = ?";
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1096,11 +1149,12 @@ cJSON* db_retrieve_event_by_id(const char* event_id) {
|
||||
}
|
||||
|
||||
char* db_get_latest_event_pubkey_for_kind_dup(int kind) {
|
||||
if (!g_db) return NULL;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db) return NULL;
|
||||
|
||||
const char* sql = "SELECT pubkey FROM events WHERE kind = ? ORDER BY created_at DESC LIMIT 1";
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1119,11 +1173,12 @@ char* db_get_latest_event_pubkey_for_kind_dup(int kind) {
|
||||
}
|
||||
|
||||
int db_get_config_row_count(int* out_count) {
|
||||
if (!g_db || !out_count) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !out_count) return -1;
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const char* sql = "SELECT COUNT(*) FROM config";
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1138,15 +1193,16 @@ int db_get_config_row_count(int* out_count) {
|
||||
}
|
||||
|
||||
int db_store_event_tags_cjson(const char* event_id, const cJSON* tags) {
|
||||
if (!g_db || !event_id || !tags || !cJSON_IsArray(tags)) {
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !event_id || !tags || !cJSON_IsArray(tags)) {
|
||||
return 0; // Not an error if no tags
|
||||
}
|
||||
|
||||
const char* sql = "INSERT INTO event_tags (event_id, tag_name, tag_value, tag_index) VALUES (?, ?, ?, ?)";
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
int rc = sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL);
|
||||
int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
DEBUG_ERROR("Failed to prepare event_tags insert: %s", sqlite3_errmsg(g_db));
|
||||
DEBUG_ERROR("Failed to prepare event_tags insert: %s", sqlite3_errmsg(db));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1166,7 +1222,7 @@ int db_store_event_tags_cjson(const char* event_id, const cJSON* tags) {
|
||||
|
||||
rc = sqlite3_step(stmt);
|
||||
if (rc != SQLITE_DONE) {
|
||||
DEBUG_ERROR("Failed to insert event tag: %s", sqlite3_errmsg(g_db));
|
||||
DEBUG_ERROR("Failed to insert event tag: %s", sqlite3_errmsg(db));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1178,10 +1234,11 @@ int db_store_event_tags_cjson(const char* event_id, const cJSON* tags) {
|
||||
}
|
||||
|
||||
int db_populate_event_tags_from_existing(void) {
|
||||
if (!g_db) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db) return -1;
|
||||
|
||||
sqlite3_stmt* check_stmt = NULL;
|
||||
if (sqlite3_prepare_v2(g_db, "SELECT COUNT(*) FROM event_tags", -1, &check_stmt, NULL) != SQLITE_OK) {
|
||||
if (sqlite3_prepare_v2(db, "SELECT COUNT(*) FROM event_tags", -1, &check_stmt, NULL) != SQLITE_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1196,10 +1253,10 @@ int db_populate_event_tags_from_existing(void) {
|
||||
|
||||
const char* sql = "SELECT id, tags FROM events WHERE tags != '[]'";
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
int rc = sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL);
|
||||
int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
|
||||
if (rc != SQLITE_OK) return -1;
|
||||
|
||||
sqlite3_exec(g_db, "BEGIN TRANSACTION", NULL, NULL, NULL);
|
||||
sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, NULL);
|
||||
|
||||
int event_count = 0;
|
||||
while (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
@@ -1217,18 +1274,19 @@ int db_populate_event_tags_from_existing(void) {
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
sqlite3_exec(g_db, "COMMIT", NULL, NULL, NULL);
|
||||
sqlite3_exec(db, "COMMIT", NULL, NULL, NULL);
|
||||
|
||||
DEBUG_INFO("Populated event_tags for %d events", event_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int db_add_auth_rule(const char* rule_type, const char* pattern_type, const char* pattern_value) {
|
||||
if (!g_db || !rule_type || !pattern_type || !pattern_value) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !rule_type || !pattern_type || !pattern_value) return -1;
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const char* sql = "INSERT INTO auth_rules (rule_type, pattern_type, pattern_value) VALUES (?, ?, ?)";
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
|
||||
sqlite3_bind_text(stmt, 1, rule_type, -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_text(stmt, 2, pattern_type, -1, SQLITE_TRANSIENT);
|
||||
@@ -1240,11 +1298,12 @@ int db_add_auth_rule(const char* rule_type, const char* pattern_type, const char
|
||||
}
|
||||
|
||||
int db_remove_auth_rule(const char* rule_type, const char* pattern_type, const char* pattern_value) {
|
||||
if (!g_db || !rule_type || !pattern_type || !pattern_value) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !rule_type || !pattern_type || !pattern_value) return -1;
|
||||
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
const char* sql = "DELETE FROM auth_rules WHERE rule_type = ? AND pattern_type = ? AND pattern_value = ?";
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
|
||||
sqlite3_bind_text(stmt, 1, rule_type, -1, SQLITE_TRANSIENT);
|
||||
sqlite3_bind_text(stmt, 2, pattern_type, -1, SQLITE_TRANSIENT);
|
||||
@@ -1256,15 +1315,16 @@ int db_remove_auth_rule(const char* rule_type, const char* pattern_type, const c
|
||||
}
|
||||
|
||||
int db_delete_wot_whitelist_rules(void) {
|
||||
if (!g_db) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db) return -1;
|
||||
|
||||
const char* sql = "DELETE FROM auth_rules WHERE rule_type = 'wot_whitelist'";
|
||||
int rc = sqlite3_exec(g_db, sql, NULL, NULL, NULL);
|
||||
int rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
|
||||
return (rc == SQLITE_OK) ? 0 : -1;
|
||||
}
|
||||
|
||||
int db_count_wot_whitelist_rules(void) {
|
||||
if (!g_db) return 0;
|
||||
if (!db_is_available()) return 0;
|
||||
|
||||
const char* sql = "SELECT COUNT(*) FROM auth_rules WHERE rule_type = 'wot_whitelist' AND active = 1";
|
||||
int count = 0;
|
||||
@@ -1275,11 +1335,12 @@ int db_count_wot_whitelist_rules(void) {
|
||||
}
|
||||
|
||||
int db_table_exists(const char* table_name, int* out_exists) {
|
||||
if (!g_db || !table_name || !out_exists) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !table_name || !out_exists) return -1;
|
||||
|
||||
const char* sql = "SELECT 1 FROM sqlite_master WHERE type='table' AND name=? LIMIT 1";
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1290,11 +1351,12 @@ int db_table_exists(const char* table_name, int* out_exists) {
|
||||
}
|
||||
|
||||
char* db_get_schema_version_dup(void) {
|
||||
if (!g_db) return NULL;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db) return NULL;
|
||||
|
||||
const char* sql = "SELECT value FROM schema_info WHERE key = 'version'";
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
if (sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1311,8 +1373,25 @@ char* db_get_schema_version_dup(void) {
|
||||
}
|
||||
|
||||
int db_exec_sql(const char* sql) {
|
||||
if (!g_db || !sql) return -1;
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db || !sql) return -1;
|
||||
|
||||
int rc = sqlite3_exec(g_db, sql, NULL, NULL, NULL);
|
||||
int rc = sqlite3_exec(db, sql, NULL, NULL, NULL);
|
||||
return (rc == SQLITE_OK) ? 0 : -1;
|
||||
}
|
||||
|
||||
int db_wal_checkpoint_passive(void) {
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db) return -1;
|
||||
|
||||
int rc = sqlite3_wal_checkpoint_v2(db, NULL, SQLITE_CHECKPOINT_PASSIVE, NULL, NULL);
|
||||
return (rc == SQLITE_OK) ? 0 : -1;
|
||||
}
|
||||
|
||||
int db_wal_checkpoint_truncate(void) {
|
||||
sqlite3* db = db_active_connection();
|
||||
if (!db) return -1;
|
||||
|
||||
int rc = sqlite3_wal_checkpoint_v2(db, NULL, SQLITE_CHECKPOINT_TRUNCATE, NULL, NULL);
|
||||
return (rc == SQLITE_OK) ? 0 : -1;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@ const char* db_get_database_path(void);
|
||||
int db_set_thread_connection(void* connection);
|
||||
void db_clear_thread_connection(void);
|
||||
|
||||
// Worker/runtime SQLite connection lifecycle (kept internal to db_ops.c)
|
||||
int db_open_worker_connection(const char* db_path, void** out_connection);
|
||||
void db_close_worker_connection(void* connection);
|
||||
|
||||
// DB result codes (backend-agnostic)
|
||||
#define DB_OK 0
|
||||
#define DB_ERROR 1
|
||||
@@ -110,5 +114,7 @@ int db_count_wot_whitelist_rules(void);
|
||||
int db_table_exists(const char* table_name, int* out_exists);
|
||||
char* db_get_schema_version_dup(void);
|
||||
int db_exec_sql(const char* sql);
|
||||
int db_wal_checkpoint_passive(void);
|
||||
int db_wal_checkpoint_truncate(void);
|
||||
|
||||
#endif // DB_OPS_H
|
||||
|
||||
File diff suppressed because one or more lines are too long
+23
-1
@@ -3,6 +3,7 @@
|
||||
#include "debug.h"
|
||||
#include "config.h"
|
||||
#include "db_ops.h"
|
||||
#include "thread_pool.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
@@ -251,6 +252,15 @@ void ip_ban_save_to_db(void) {
|
||||
|
||||
// Check if an IP is in the idle_ban_whitelist config (comma-separated list)
|
||||
static int ip_is_whitelisted(const char* ip) {
|
||||
if (!ip) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Always trust loopback to avoid local test/dev self-bans.
|
||||
if (strcmp(ip, "127.0.0.1") == 0 || strcmp(ip, "::1") == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* whitelist = get_config_value("idle_ban_whitelist");
|
||||
if (!whitelist || whitelist[0] == '\0') {
|
||||
if (whitelist) free((char*)whitelist);
|
||||
@@ -556,7 +566,19 @@ void ip_ban_log_stats(void) {
|
||||
last_log = now;
|
||||
|
||||
// Save to DB every 5 minutes
|
||||
ip_ban_save_to_db();
|
||||
if (thread_pool_is_running()) {
|
||||
thread_pool_job_t job;
|
||||
memset(&job, 0, sizeof(job));
|
||||
job.type = THREAD_POOL_JOB_IP_BAN_SAVE;
|
||||
|
||||
thread_pool_status_t rc = thread_pool_submit_write(&job, NULL);
|
||||
if (rc != THREAD_POOL_STATUS_OK) {
|
||||
DEBUG_WARN("Failed to queue IP_BAN_SAVE job (%d); saving synchronously", rc);
|
||||
ip_ban_save_to_db();
|
||||
}
|
||||
} else {
|
||||
ip_ban_save_to_db();
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&g_ban_mutex);
|
||||
int auth_banned_count = 0;
|
||||
|
||||
+45
-3
@@ -981,7 +981,7 @@ int store_event_tags(const char* event_id, cJSON* tags) {
|
||||
// 1 = handled without insert (duplicate or ephemeral)
|
||||
// -1 = failure
|
||||
int store_event_core(cJSON* event) {
|
||||
if (!g_db || !event) {
|
||||
if (!db_is_available() || !event) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1143,7 +1143,7 @@ int store_event(cJSON* event) {
|
||||
// Uses the primary key index — single B-tree lookup, ~10μs.
|
||||
// Call this BEFORE signature verification to skip expensive crypto on duplicates.
|
||||
int event_id_exists_in_db(const char* event_id) {
|
||||
if (!g_db || !event_id || strlen(event_id) != 64) return 0;
|
||||
if (!db_is_available() || !event_id || strlen(event_id) != 64) return 0;
|
||||
|
||||
int exists = 0;
|
||||
if (db_event_id_exists(event_id, &exists) != 0) {
|
||||
@@ -2231,6 +2231,44 @@ int main(int argc, char* argv[]) {
|
||||
nostr_cleanup();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Pre-warm unified config cache while DB is still available.
|
||||
// This is critical because runtime strict mode sets g_db = NULL,
|
||||
// and admin authorization depends on relay_pubkey/admin_pubkey reads.
|
||||
if (reload_config_from_table() != 0) {
|
||||
DEBUG_ERROR("Failed to pre-warm configuration cache from config table");
|
||||
cleanup_configuration_system();
|
||||
nostr_cleanup();
|
||||
close_database();
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* prewarmed_relay_pubkey = get_config_value("relay_pubkey");
|
||||
const char* prewarmed_admin_pubkey = get_config_value("admin_pubkey");
|
||||
if (!prewarmed_relay_pubkey || strlen(prewarmed_relay_pubkey) != 64 ||
|
||||
!prewarmed_admin_pubkey || strlen(prewarmed_admin_pubkey) != 64) {
|
||||
if (prewarmed_relay_pubkey) free((char*)prewarmed_relay_pubkey);
|
||||
if (prewarmed_admin_pubkey) free((char*)prewarmed_admin_pubkey);
|
||||
DEBUG_ERROR("Critical config pre-warm validation failed (relay_pubkey/admin_pubkey missing)");
|
||||
cleanup_configuration_system();
|
||||
nostr_cleanup();
|
||||
close_database();
|
||||
return 1;
|
||||
}
|
||||
free((char*)prewarmed_relay_pubkey);
|
||||
free((char*)prewarmed_admin_pubkey);
|
||||
|
||||
// Preload relay private key runtime cache while DB is still available.
|
||||
// Required for admin command decrypt/encrypt after strict mode sets g_db = NULL.
|
||||
if (preload_relay_private_key_cache() != 0) {
|
||||
DEBUG_ERROR("Failed to pre-warm relay private key cache");
|
||||
cleanup_configuration_system();
|
||||
nostr_cleanup();
|
||||
close_database();
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEBUG_INFO("Configuration cache pre-warmed with relay_pubkey/admin_pubkey and relay private key");
|
||||
|
||||
// Configuration system is now fully initialized with event-based approach
|
||||
// All configuration is loaded from database events
|
||||
@@ -2301,7 +2339,7 @@ int main(int argc, char* argv[]) {
|
||||
if (thread_pool_enabled) {
|
||||
thread_pool_config_t tp_cfg;
|
||||
memset(&tp_cfg, 0, sizeof(tp_cfg));
|
||||
tp_cfg.reader_threads = get_config_int("thread_pool_readers", 4);
|
||||
tp_cfg.reader_threads = get_config_int("thread_pool_readers", 1);
|
||||
tp_cfg.max_queue_depth = get_config_int("thread_pool_max_queue_depth", 4096);
|
||||
tp_cfg.db_path = g_database_path;
|
||||
tp_cfg.wake_loop_cb = wake_event_loop_from_thread_pool;
|
||||
@@ -2315,6 +2353,10 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
// Phase 5 strict mode: remove main-thread fallback to global DB handle.
|
||||
// Runtime DB access must go through thread-bound worker connections.
|
||||
g_db = NULL;
|
||||
|
||||
// Start WebSocket Nostr relay server (port from CLI override or configuration)
|
||||
int result = start_websocket_relay(cli_options.port_override, cli_options.strict_port); // Use CLI port override if specified, otherwise config
|
||||
|
||||
|
||||
+2
-2
@@ -13,8 +13,8 @@
|
||||
// Using CRELAY_ prefix to avoid conflicts with nostr_core_lib VERSION macros
|
||||
#define CRELAY_VERSION_MAJOR 2
|
||||
#define CRELAY_VERSION_MINOR 1
|
||||
#define CRELAY_VERSION_PATCH 4
|
||||
#define CRELAY_VERSION "v2.1.4"
|
||||
#define CRELAY_VERSION_PATCH 9
|
||||
#define CRELAY_VERSION "v2.1.9"
|
||||
|
||||
// Relay metadata (authoritative source for NIP-11 information)
|
||||
#define RELAY_NAME "C-Relay"
|
||||
|
||||
+71
-36
@@ -8,7 +8,7 @@
|
||||
#include <libwebsockets.h>
|
||||
#include "../nostr_core_lib/cjson/cJSON.h"
|
||||
#include "config.h"
|
||||
|
||||
#include "main.h"
|
||||
|
||||
// Forward declarations for configuration functions
|
||||
const char* get_config_value(const char* key);
|
||||
@@ -23,6 +23,67 @@ int get_config_bool(const char* key, int default_value);
|
||||
#define HTTP_STATUS_INTERNAL_SERVER_ERROR 500
|
||||
|
||||
|
||||
#define NIP11_CACHE_TTL_SEC 5
|
||||
|
||||
static pthread_mutex_t g_nip11_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static char* g_nip11_cached_json = NULL;
|
||||
static size_t g_nip11_cached_json_len = 0;
|
||||
static time_t g_nip11_cache_expires_at = 0;
|
||||
|
||||
cJSON* generate_relay_info_json();
|
||||
|
||||
static void invalidate_nip11_cache_locked(void) {
|
||||
if (g_nip11_cached_json) {
|
||||
free(g_nip11_cached_json);
|
||||
g_nip11_cached_json = NULL;
|
||||
}
|
||||
g_nip11_cached_json_len = 0;
|
||||
g_nip11_cache_expires_at = 0;
|
||||
}
|
||||
|
||||
static char* get_nip11_json_cached_dup(size_t* out_len) {
|
||||
time_t now = time(NULL);
|
||||
|
||||
pthread_mutex_lock(&g_nip11_cache_mutex);
|
||||
if (g_nip11_cached_json && now < g_nip11_cache_expires_at) {
|
||||
char* copy = strdup(g_nip11_cached_json);
|
||||
if (copy && out_len) {
|
||||
*out_len = g_nip11_cached_json_len;
|
||||
}
|
||||
pthread_mutex_unlock(&g_nip11_cache_mutex);
|
||||
return copy;
|
||||
}
|
||||
pthread_mutex_unlock(&g_nip11_cache_mutex);
|
||||
|
||||
cJSON* info_json = generate_relay_info_json();
|
||||
if (!info_json) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* fresh_json = cJSON_Print(info_json);
|
||||
cJSON_Delete(info_json);
|
||||
if (!fresh_json) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t fresh_len = strlen(fresh_json);
|
||||
|
||||
pthread_mutex_lock(&g_nip11_cache_mutex);
|
||||
invalidate_nip11_cache_locked();
|
||||
g_nip11_cached_json = strdup(fresh_json);
|
||||
if (g_nip11_cached_json) {
|
||||
g_nip11_cached_json_len = fresh_len;
|
||||
g_nip11_cache_expires_at = now + NIP11_CACHE_TTL_SEC;
|
||||
}
|
||||
pthread_mutex_unlock(&g_nip11_cache_mutex);
|
||||
|
||||
if (out_len) {
|
||||
*out_len = fresh_len;
|
||||
}
|
||||
return fresh_json;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NIP-11 RELAY INFORMATION DOCUMENT
|
||||
@@ -80,8 +141,9 @@ void init_relay_info() {
|
||||
|
||||
// Clean up relay information JSON objects
|
||||
void cleanup_relay_info() {
|
||||
// NIP-11 relay information is now generated dynamically from config table
|
||||
// No cleanup needed - data is fetched directly from database when requested
|
||||
pthread_mutex_lock(&g_nip11_cache_mutex);
|
||||
invalidate_nip11_cache_locked();
|
||||
pthread_mutex_unlock(&g_nip11_cache_mutex);
|
||||
}
|
||||
|
||||
// Generate NIP-11 compliant JSON document
|
||||
@@ -184,14 +246,14 @@ cJSON* generate_relay_info_json() {
|
||||
cJSON_AddStringToObject(info, "software", relay_software);
|
||||
free((char*)relay_software);
|
||||
} else {
|
||||
cJSON_AddStringToObject(info, "software", "https://git.laantungir.net/laantungir/c-relay.git");
|
||||
cJSON_AddStringToObject(info, "software", RELAY_SOFTWARE);
|
||||
}
|
||||
|
||||
if (relay_version && strlen(relay_version) > 0) {
|
||||
cJSON_AddStringToObject(info, "version", relay_version);
|
||||
free((char*)relay_version);
|
||||
} else {
|
||||
cJSON_AddStringToObject(info, "version", "0.2.0");
|
||||
cJSON_AddStringToObject(info, "version", RELAY_VERSION);
|
||||
}
|
||||
|
||||
// Add policies
|
||||
@@ -348,9 +410,10 @@ int handle_nip11_http_request(struct lws* wsi, const char* accept_header) {
|
||||
return -1; // Close connection
|
||||
}
|
||||
|
||||
// Generate relay information JSON
|
||||
cJSON* info_json = generate_relay_info_json();
|
||||
if (!info_json) {
|
||||
// Generate (or fetch cached) relay information JSON
|
||||
size_t json_len = 0;
|
||||
char* json_string = get_nip11_json_cached_dup(&json_len);
|
||||
if (!json_string) {
|
||||
DEBUG_ERROR("Failed to generate relay info JSON");
|
||||
unsigned char buf[LWS_PRE + 256];
|
||||
unsigned char *p = &buf[LWS_PRE];
|
||||
@@ -373,34 +436,6 @@ int handle_nip11_http_request(struct lws* wsi, const char* accept_header) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
char* json_string = cJSON_Print(info_json);
|
||||
cJSON_Delete(info_json);
|
||||
|
||||
if (!json_string) {
|
||||
DEBUG_ERROR("Failed to serialize relay info JSON");
|
||||
unsigned char buf[LWS_PRE + 256];
|
||||
unsigned char *p = &buf[LWS_PRE];
|
||||
unsigned char *start = p;
|
||||
unsigned char *end = &buf[sizeof(buf) - 1];
|
||||
|
||||
if (lws_add_http_header_status(wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, &p, end)) {
|
||||
return -1;
|
||||
}
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char*)"text/plain", 10, &p, end)) {
|
||||
return -1;
|
||||
}
|
||||
if (lws_add_http_header_content_length(wsi, 0, &p, end)) {
|
||||
return -1;
|
||||
}
|
||||
if (lws_finalize_http_header(wsi, &p, end)) {
|
||||
return -1;
|
||||
}
|
||||
lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t json_len = strlen(json_string);
|
||||
|
||||
// Allocate session data to manage buffer lifetime across callbacks
|
||||
struct nip11_session_data* session_data = malloc(sizeof(struct nip11_session_data));
|
||||
if (!session_data) {
|
||||
|
||||
+146
-4
@@ -2,6 +2,7 @@
|
||||
#include <cjson/cJSON.h>
|
||||
#include "debug.h"
|
||||
#include "db_ops.h"
|
||||
#include "thread_pool.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
@@ -10,6 +11,34 @@
|
||||
#include <libwebsockets.h>
|
||||
#include "subscriptions.h"
|
||||
|
||||
static void free_sub_log_created_payload_local(thread_pool_sub_log_created_payload_t* payload) {
|
||||
if (!payload) return;
|
||||
free(payload->sub_id);
|
||||
free(payload->wsi_ptr);
|
||||
free(payload->client_ip);
|
||||
free(payload->filter_json);
|
||||
free(payload);
|
||||
}
|
||||
|
||||
static void free_sub_log_closed_payload_local(thread_pool_sub_log_closed_payload_t* payload) {
|
||||
if (!payload) return;
|
||||
free(payload->sub_id);
|
||||
free(payload->client_ip);
|
||||
free(payload);
|
||||
}
|
||||
|
||||
static void free_sub_log_disconnected_payload_local(thread_pool_sub_log_disconnected_payload_t* payload) {
|
||||
if (!payload) return;
|
||||
free(payload->client_ip);
|
||||
free(payload);
|
||||
}
|
||||
|
||||
static void free_sub_update_events_payload_local(thread_pool_sub_update_events_payload_t* payload) {
|
||||
if (!payload) return;
|
||||
free(payload->sub_id);
|
||||
free(payload);
|
||||
}
|
||||
|
||||
// Forward declarations for logging functions
|
||||
|
||||
// Forward declarations for configuration functions
|
||||
@@ -1040,7 +1069,43 @@ void log_subscription_created(const subscription_t* sub) {
|
||||
cJSON_Delete(filters_array);
|
||||
}
|
||||
|
||||
db_log_subscription_created(sub->id, wsi_str, sub->client_ip, filter_json ? filter_json : "[]");
|
||||
if (!thread_pool_is_running()) {
|
||||
db_log_subscription_created(sub->id, wsi_str, sub->client_ip, filter_json ? filter_json : "[]");
|
||||
if (filter_json) free(filter_json);
|
||||
return;
|
||||
}
|
||||
|
||||
thread_pool_sub_log_created_payload_t* payload = calloc(1, sizeof(*payload));
|
||||
if (!payload) {
|
||||
if (filter_json) free(filter_json);
|
||||
return;
|
||||
}
|
||||
|
||||
payload->sub_id = strdup(sub->id);
|
||||
payload->wsi_ptr = strdup(wsi_str);
|
||||
payload->client_ip = strdup(sub->client_ip);
|
||||
payload->filter_json = strdup(filter_json ? filter_json : "[]");
|
||||
|
||||
if (!payload->sub_id || !payload->wsi_ptr || !payload->client_ip || !payload->filter_json) {
|
||||
free(payload->sub_id);
|
||||
free(payload->wsi_ptr);
|
||||
free(payload->client_ip);
|
||||
free(payload->filter_json);
|
||||
free(payload);
|
||||
if (filter_json) free(filter_json);
|
||||
return;
|
||||
}
|
||||
|
||||
thread_pool_job_t job;
|
||||
memset(&job, 0, sizeof(job));
|
||||
job.type = THREAD_POOL_JOB_LOG_SUB_CREATED;
|
||||
job.payload = payload;
|
||||
job.payload_free = (thread_pool_payload_free_cb)free_sub_log_created_payload_local;
|
||||
|
||||
thread_pool_status_t submit_rc = thread_pool_submit_write(&job, NULL);
|
||||
if (submit_rc != THREAD_POOL_STATUS_OK) {
|
||||
free_sub_log_created_payload_local(payload);
|
||||
}
|
||||
|
||||
if (filter_json) free(filter_json);
|
||||
}
|
||||
@@ -1050,14 +1115,65 @@ void log_subscription_closed(const char* sub_id, const char* client_ip, const ch
|
||||
(void)reason; // Mark as intentionally unused
|
||||
if (!sub_id) return;
|
||||
|
||||
db_log_subscription_closed(sub_id, client_ip);
|
||||
if (!thread_pool_is_running()) {
|
||||
db_log_subscription_closed(sub_id, client_ip);
|
||||
return;
|
||||
}
|
||||
|
||||
thread_pool_sub_log_closed_payload_t* payload = calloc(1, sizeof(*payload));
|
||||
if (!payload) {
|
||||
return;
|
||||
}
|
||||
|
||||
payload->sub_id = strdup(sub_id);
|
||||
payload->client_ip = strdup(client_ip ? client_ip : "unknown");
|
||||
if (!payload->sub_id || !payload->client_ip) {
|
||||
free_sub_log_closed_payload_local(payload);
|
||||
return;
|
||||
}
|
||||
|
||||
thread_pool_job_t job;
|
||||
memset(&job, 0, sizeof(job));
|
||||
job.type = THREAD_POOL_JOB_LOG_SUB_CLOSED;
|
||||
job.payload = payload;
|
||||
job.payload_free = (thread_pool_payload_free_cb)free_sub_log_closed_payload_local;
|
||||
|
||||
thread_pool_status_t submit_rc = thread_pool_submit_write(&job, NULL);
|
||||
if (submit_rc != THREAD_POOL_STATUS_OK) {
|
||||
free_sub_log_closed_payload_local(payload);
|
||||
}
|
||||
}
|
||||
|
||||
// Log subscription disconnection to database
|
||||
void log_subscription_disconnected(const char* client_ip) {
|
||||
if (!client_ip) return;
|
||||
|
||||
db_log_subscription_disconnected(client_ip);
|
||||
if (!thread_pool_is_running()) {
|
||||
db_log_subscription_disconnected(client_ip);
|
||||
return;
|
||||
}
|
||||
|
||||
thread_pool_sub_log_disconnected_payload_t* payload = calloc(1, sizeof(*payload));
|
||||
if (!payload) {
|
||||
return;
|
||||
}
|
||||
|
||||
payload->client_ip = strdup(client_ip);
|
||||
if (!payload->client_ip) {
|
||||
free_sub_log_disconnected_payload_local(payload);
|
||||
return;
|
||||
}
|
||||
|
||||
thread_pool_job_t job;
|
||||
memset(&job, 0, sizeof(job));
|
||||
job.type = THREAD_POOL_JOB_LOG_SUB_DISCONNECTED;
|
||||
job.payload = payload;
|
||||
job.payload_free = (thread_pool_payload_free_cb)free_sub_log_disconnected_payload_local;
|
||||
|
||||
thread_pool_status_t submit_rc = thread_pool_submit_write(&job, NULL);
|
||||
if (submit_rc != THREAD_POOL_STATUS_OK) {
|
||||
free_sub_log_disconnected_payload_local(payload);
|
||||
}
|
||||
}
|
||||
|
||||
// Log event broadcast to database (optional, can be resource intensive)
|
||||
@@ -1085,7 +1201,33 @@ void log_subscription_disconnected(const char* client_ip) {
|
||||
void update_subscription_events_sent(const char* sub_id, int events_sent) {
|
||||
if (!sub_id) return;
|
||||
|
||||
db_update_subscription_events_sent(sub_id, events_sent);
|
||||
if (!thread_pool_is_running()) {
|
||||
db_update_subscription_events_sent(sub_id, events_sent);
|
||||
return;
|
||||
}
|
||||
|
||||
thread_pool_sub_update_events_payload_t* payload = calloc(1, sizeof(*payload));
|
||||
if (!payload) {
|
||||
return;
|
||||
}
|
||||
|
||||
payload->sub_id = strdup(sub_id);
|
||||
payload->events_sent = events_sent;
|
||||
if (!payload->sub_id) {
|
||||
free_sub_update_events_payload_local(payload);
|
||||
return;
|
||||
}
|
||||
|
||||
thread_pool_job_t job;
|
||||
memset(&job, 0, sizeof(job));
|
||||
job.type = THREAD_POOL_JOB_UPDATE_SUB_EVENTS_SENT;
|
||||
job.payload = payload;
|
||||
job.payload_free = (thread_pool_payload_free_cb)free_sub_update_events_payload_local;
|
||||
|
||||
thread_pool_status_t submit_rc = thread_pool_submit_write(&job, NULL);
|
||||
if (submit_rc != THREAD_POOL_STATUS_OK) {
|
||||
free_sub_update_events_payload_local(payload);
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup all subscriptions on startup
|
||||
|
||||
+136
-27
@@ -3,8 +3,8 @@
|
||||
#include "thread_pool.h"
|
||||
#include "debug.h"
|
||||
#include "db_ops.h"
|
||||
#include "ip_ban.h"
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -198,24 +198,12 @@ static void wake_event_loop(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static sqlite3* open_worker_connection(void) {
|
||||
if (g_pool.db_path[0] == '\0') {
|
||||
static void* open_worker_connection(void) {
|
||||
void* db_conn = NULL;
|
||||
if (db_open_worker_connection(g_pool.db_path, &db_conn) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sqlite3* db = NULL;
|
||||
int rc = sqlite3_open_v2(g_pool.db_path, &db, SQLITE_OPEN_READWRITE, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
if (db) {
|
||||
sqlite3_close(db);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sqlite3_exec(db, "PRAGMA journal_mode=WAL;", NULL, NULL, NULL);
|
||||
sqlite3_busy_timeout(db, 5000);
|
||||
|
||||
return db;
|
||||
return db_conn;
|
||||
}
|
||||
|
||||
static void complete_job_with_result(thread_pool_job_node_t* node,
|
||||
@@ -371,6 +359,98 @@ static void execute_store_event_job(thread_pool_job_node_t* node) {
|
||||
"STORE_EVENT completed", out, sizeof(*out));
|
||||
}
|
||||
|
||||
static void execute_sub_log_created_job(thread_pool_job_node_t* node) {
|
||||
thread_pool_sub_log_created_payload_t* payload = (thread_pool_sub_log_created_payload_t*)node->job.payload;
|
||||
if (!payload || !payload->sub_id || !payload->wsi_ptr || !payload->client_ip) {
|
||||
complete_job_with_result(node, THREAD_POOL_STATUS_INTERNAL_ERROR,
|
||||
"SUB_LOG_CREATED payload missing", NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (db_log_subscription_created(payload->sub_id,
|
||||
payload->wsi_ptr,
|
||||
payload->client_ip,
|
||||
payload->filter_json ? payload->filter_json : "[]") != 0) {
|
||||
complete_job_with_result(node, THREAD_POOL_STATUS_INTERNAL_ERROR,
|
||||
"SUB_LOG_CREATED failed", NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
complete_job_with_result(node, THREAD_POOL_STATUS_OK,
|
||||
"SUB_LOG_CREATED completed", NULL, 0);
|
||||
}
|
||||
|
||||
static void execute_sub_log_closed_job(thread_pool_job_node_t* node) {
|
||||
thread_pool_sub_log_closed_payload_t* payload = (thread_pool_sub_log_closed_payload_t*)node->job.payload;
|
||||
if (!payload || !payload->sub_id) {
|
||||
complete_job_with_result(node, THREAD_POOL_STATUS_INTERNAL_ERROR,
|
||||
"SUB_LOG_CLOSED payload missing", NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (db_log_subscription_closed(payload->sub_id, payload->client_ip) != 0) {
|
||||
complete_job_with_result(node, THREAD_POOL_STATUS_INTERNAL_ERROR,
|
||||
"SUB_LOG_CLOSED failed", NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
complete_job_with_result(node, THREAD_POOL_STATUS_OK,
|
||||
"SUB_LOG_CLOSED completed", NULL, 0);
|
||||
}
|
||||
|
||||
static void execute_sub_log_disconnected_job(thread_pool_job_node_t* node) {
|
||||
thread_pool_sub_log_disconnected_payload_t* payload = (thread_pool_sub_log_disconnected_payload_t*)node->job.payload;
|
||||
if (!payload || !payload->client_ip) {
|
||||
complete_job_with_result(node, THREAD_POOL_STATUS_INTERNAL_ERROR,
|
||||
"SUB_LOG_DISCONNECTED payload missing", NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (db_log_subscription_disconnected(payload->client_ip) < 0) {
|
||||
complete_job_with_result(node, THREAD_POOL_STATUS_INTERNAL_ERROR,
|
||||
"SUB_LOG_DISCONNECTED failed", NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
complete_job_with_result(node, THREAD_POOL_STATUS_OK,
|
||||
"SUB_LOG_DISCONNECTED completed", NULL, 0);
|
||||
}
|
||||
|
||||
static void execute_sub_update_events_job(thread_pool_job_node_t* node) {
|
||||
thread_pool_sub_update_events_payload_t* payload = (thread_pool_sub_update_events_payload_t*)node->job.payload;
|
||||
if (!payload || !payload->sub_id) {
|
||||
complete_job_with_result(node, THREAD_POOL_STATUS_INTERNAL_ERROR,
|
||||
"SUB_UPDATE_EVENTS payload missing", NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (db_update_subscription_events_sent(payload->sub_id, payload->events_sent) != 0) {
|
||||
complete_job_with_result(node, THREAD_POOL_STATUS_INTERNAL_ERROR,
|
||||
"SUB_UPDATE_EVENTS failed", NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
complete_job_with_result(node, THREAD_POOL_STATUS_OK,
|
||||
"SUB_UPDATE_EVENTS completed", NULL, 0);
|
||||
}
|
||||
|
||||
static void execute_ip_ban_save_job(thread_pool_job_node_t* node) {
|
||||
ip_ban_save_to_db();
|
||||
complete_job_with_result(node, THREAD_POOL_STATUS_OK,
|
||||
"IP_BAN_SAVE completed", NULL, 0);
|
||||
}
|
||||
|
||||
static void execute_wal_checkpoint_job(thread_pool_job_node_t* node) {
|
||||
if (db_wal_checkpoint_passive() != 0) {
|
||||
complete_job_with_result(node, THREAD_POOL_STATUS_INTERNAL_ERROR,
|
||||
"WAL_CHECKPOINT failed", NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
complete_job_with_result(node, THREAD_POOL_STATUS_OK,
|
||||
"WAL_CHECKPOINT completed", NULL, 0);
|
||||
}
|
||||
|
||||
static void execute_read_job(thread_pool_job_node_t* node) {
|
||||
switch (node->job.type) {
|
||||
case THREAD_POOL_JOB_REQ_QUERY:
|
||||
@@ -391,6 +471,24 @@ static void execute_write_job(thread_pool_job_node_t* node) {
|
||||
case THREAD_POOL_JOB_STORE_EVENT:
|
||||
execute_store_event_job(node);
|
||||
break;
|
||||
case THREAD_POOL_JOB_LOG_SUB_CREATED:
|
||||
execute_sub_log_created_job(node);
|
||||
break;
|
||||
case THREAD_POOL_JOB_LOG_SUB_CLOSED:
|
||||
execute_sub_log_closed_job(node);
|
||||
break;
|
||||
case THREAD_POOL_JOB_LOG_SUB_DISCONNECTED:
|
||||
execute_sub_log_disconnected_job(node);
|
||||
break;
|
||||
case THREAD_POOL_JOB_UPDATE_SUB_EVENTS_SENT:
|
||||
execute_sub_update_events_job(node);
|
||||
break;
|
||||
case THREAD_POOL_JOB_IP_BAN_SAVE:
|
||||
execute_ip_ban_save_job(node);
|
||||
break;
|
||||
case THREAD_POOL_JOB_WAL_CHECKPOINT:
|
||||
execute_wal_checkpoint_job(node);
|
||||
break;
|
||||
default:
|
||||
complete_job_with_result(node, THREAD_POOL_STATUS_NOT_IMPLEMENTED,
|
||||
"Write job type not implemented", NULL, 0);
|
||||
@@ -405,14 +503,12 @@ static void* reader_worker_main(void* arg) {
|
||||
snprintf(thread_name, sizeof(thread_name), "db-read-%d", reader_index);
|
||||
pthread_setname_np(pthread_self(), thread_name);
|
||||
|
||||
sqlite3* worker_db = open_worker_connection();
|
||||
void* worker_db = open_worker_connection();
|
||||
if (!worker_db) {
|
||||
DEBUG_ERROR("Reader worker failed to open SQLite connection");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
db_set_thread_connection(worker_db);
|
||||
|
||||
while (g_pool.running) {
|
||||
thread_pool_job_node_t* node = queue_pop(&g_pool.read_q);
|
||||
if (!node) break;
|
||||
@@ -420,8 +516,7 @@ static void* reader_worker_main(void* arg) {
|
||||
execute_read_job(node);
|
||||
}
|
||||
|
||||
db_clear_thread_connection();
|
||||
sqlite3_close(worker_db);
|
||||
db_close_worker_connection(worker_db);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -430,14 +525,12 @@ static void* writer_worker_main(void* arg) {
|
||||
|
||||
pthread_setname_np(pthread_self(), "db-write");
|
||||
|
||||
sqlite3* worker_db = open_worker_connection();
|
||||
void* worker_db = open_worker_connection();
|
||||
if (!worker_db) {
|
||||
DEBUG_ERROR("Writer worker failed to open SQLite connection");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
db_set_thread_connection(worker_db);
|
||||
|
||||
while (g_pool.running) {
|
||||
thread_pool_job_node_t* node = queue_pop(&g_pool.write_q);
|
||||
if (!node) break;
|
||||
@@ -445,8 +538,11 @@ static void* writer_worker_main(void* arg) {
|
||||
execute_write_job(node);
|
||||
}
|
||||
|
||||
db_clear_thread_connection();
|
||||
sqlite3_close(worker_db);
|
||||
if (db_wal_checkpoint_truncate() != 0) {
|
||||
DEBUG_WARN("Writer shutdown TRUNCATE checkpoint failed");
|
||||
}
|
||||
|
||||
db_close_worker_connection(worker_db);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -573,6 +669,19 @@ thread_pool_status_t thread_pool_submit_write(const thread_pool_job_t* job, uint
|
||||
return submit_to_queue(&g_pool.write_q, job, out_job_id);
|
||||
}
|
||||
|
||||
int thread_pool_submit_wal_checkpoint(void) {
|
||||
if (!thread_pool_is_running()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
thread_pool_job_t job;
|
||||
memset(&job, 0, sizeof(job));
|
||||
job.type = THREAD_POOL_JOB_WAL_CHECKPOINT;
|
||||
|
||||
thread_pool_status_t rc = thread_pool_submit_write(&job, NULL);
|
||||
return (rc == THREAD_POOL_STATUS_OK) ? 0 : -1;
|
||||
}
|
||||
|
||||
int thread_pool_execute_count_sync(const char* sql, const char** bind_params, int bind_param_count, int* out_count) {
|
||||
if (!sql || !out_count) {
|
||||
return -1;
|
||||
|
||||
@@ -13,6 +13,12 @@ typedef enum {
|
||||
THREAD_POOL_JOB_COUNT_QUERY,
|
||||
THREAD_POOL_JOB_STORE_EVENT,
|
||||
THREAD_POOL_JOB_DELETE_EVENT,
|
||||
THREAD_POOL_JOB_LOG_SUB_CREATED,
|
||||
THREAD_POOL_JOB_LOG_SUB_CLOSED,
|
||||
THREAD_POOL_JOB_LOG_SUB_DISCONNECTED,
|
||||
THREAD_POOL_JOB_UPDATE_SUB_EVENTS_SENT,
|
||||
THREAD_POOL_JOB_IP_BAN_SAVE,
|
||||
THREAD_POOL_JOB_WAL_CHECKPOINT,
|
||||
THREAD_POOL_JOB_CUSTOM
|
||||
} thread_pool_job_type_t;
|
||||
|
||||
@@ -95,6 +101,27 @@ typedef struct {
|
||||
int extended_errcode;
|
||||
} thread_pool_store_event_result_t;
|
||||
|
||||
typedef struct {
|
||||
char* sub_id;
|
||||
char* wsi_ptr;
|
||||
char* client_ip;
|
||||
char* filter_json;
|
||||
} thread_pool_sub_log_created_payload_t;
|
||||
|
||||
typedef struct {
|
||||
char* sub_id;
|
||||
char* client_ip;
|
||||
} thread_pool_sub_log_closed_payload_t;
|
||||
|
||||
typedef struct {
|
||||
char* client_ip;
|
||||
} thread_pool_sub_log_disconnected_payload_t;
|
||||
|
||||
typedef struct {
|
||||
char* sub_id;
|
||||
int events_sent;
|
||||
} thread_pool_sub_update_events_payload_t;
|
||||
|
||||
int thread_pool_init(const thread_pool_config_t* config);
|
||||
void thread_pool_shutdown(void);
|
||||
int thread_pool_is_running(void);
|
||||
@@ -102,6 +129,8 @@ int thread_pool_is_running(void);
|
||||
thread_pool_status_t thread_pool_submit_read(const thread_pool_job_t* job, uint64_t* out_job_id);
|
||||
thread_pool_status_t thread_pool_submit_write(const thread_pool_job_t* job, uint64_t* out_job_id);
|
||||
|
||||
int thread_pool_submit_wal_checkpoint(void);
|
||||
|
||||
int thread_pool_execute_count_sync(const char* sql, const char** bind_params, int bind_param_count, int* out_count);
|
||||
int thread_pool_execute_req_sync(const char* sql, const char** bind_params, int bind_param_count,
|
||||
int row_limit, thread_pool_req_result_t** out_result);
|
||||
|
||||
+330
-124
@@ -137,6 +137,26 @@ static pthread_mutex_t g_connections_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
int get_active_connection_count(void) { return g_connection_count; }
|
||||
|
||||
int websocket_get_live_pss(struct lws* wsi, struct per_session_data** out_pss) {
|
||||
if (!wsi || !out_pss) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*out_pss = NULL;
|
||||
|
||||
pthread_mutex_lock(&g_connections_lock);
|
||||
for (int i = 0; i < MAX_TRACKED_CONNECTIONS; i++) {
|
||||
if (g_connections[i].wsi == wsi && g_connections[i].pss != NULL) {
|
||||
*out_pss = g_connections[i].pss;
|
||||
pthread_mutex_unlock(&g_connections_lock);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&g_connections_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void connection_list_add(struct lws* wsi, struct per_session_data* pss) {
|
||||
pthread_mutex_lock(&g_connections_lock);
|
||||
for (int i = 0; i < MAX_TRACKED_CONNECTIONS; i++) {
|
||||
@@ -330,6 +350,7 @@ typedef struct async_event_completion {
|
||||
int success;
|
||||
int should_broadcast;
|
||||
int run_post_actions;
|
||||
char ok_message[128];
|
||||
char error_message[512];
|
||||
struct async_event_completion* next;
|
||||
} async_event_completion_t;
|
||||
@@ -346,6 +367,27 @@ static async_event_completion_t* g_async_event_completion_tail = NULL;
|
||||
static pthread_t g_async_event_worker_thread;
|
||||
static int g_async_event_worker_running = 0;
|
||||
|
||||
typedef struct count_async_state {
|
||||
char sub_id[SUBSCRIPTION_ID_MAX_LENGTH];
|
||||
struct lws* wsi;
|
||||
struct per_session_data* pss_token;
|
||||
int pending_jobs;
|
||||
int total_count;
|
||||
int had_error;
|
||||
char error_message[256];
|
||||
} count_async_state_t;
|
||||
|
||||
typedef struct count_async_completion {
|
||||
count_async_state_t* state;
|
||||
thread_pool_status_t status;
|
||||
int count;
|
||||
struct count_async_completion* next;
|
||||
} count_async_completion_t;
|
||||
|
||||
static pthread_mutex_t g_count_async_completion_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static count_async_completion_t* g_count_async_completion_head = NULL;
|
||||
static count_async_completion_t* g_count_async_completion_tail = NULL;
|
||||
|
||||
static void map_validation_error_message(int validation_result, char* out, size_t out_size) {
|
||||
if (!out || out_size == 0) return;
|
||||
|
||||
@@ -455,8 +497,8 @@ static int event_is_async_eligible(cJSON* event, int* out_kind, char event_id_ou
|
||||
|
||||
int kind = (int)cJSON_GetNumberValue(kind_obj);
|
||||
|
||||
// Keep special/admin paths on main thread for existing behavior.
|
||||
if (kind == 14 || kind == 1059 || kind == 23456) {
|
||||
// Keep admin command path on main thread for existing behavior.
|
||||
if (kind == 23456) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -487,6 +529,12 @@ static void* async_event_worker_main(void* arg) {
|
||||
(void)arg;
|
||||
pthread_setname_np(pthread_self(), "event-worker");
|
||||
|
||||
void* worker_db = NULL;
|
||||
const char* db_path = db_get_database_path();
|
||||
if (db_open_worker_connection(db_path, &worker_db) != 0) {
|
||||
DEBUG_WARN("event-worker: failed to open dedicated DB connection; using default connection context");
|
||||
}
|
||||
|
||||
while (g_async_event_worker_running) {
|
||||
async_event_job_t* job = async_event_job_pop_blocking();
|
||||
if (!job) {
|
||||
@@ -506,38 +554,46 @@ static void* async_event_worker_main(void* arg) {
|
||||
strncpy(completion->event_id, job->event_id, sizeof(completion->event_id) - 1);
|
||||
completion->event_id[sizeof(completion->event_id) - 1] = '\0';
|
||||
|
||||
int validation_result = nostr_validate_unified_request(completion->event_json, strlen(completion->event_json));
|
||||
if (validation_result != NOSTR_SUCCESS) {
|
||||
completion->success = 0;
|
||||
if (job->event_id[0] != '\0' && event_id_exists_in_db(job->event_id)) {
|
||||
completion->success = 1;
|
||||
completion->should_broadcast = 0;
|
||||
map_validation_error_message(validation_result, completion->error_message, sizeof(completion->error_message));
|
||||
completion->run_post_actions = 0;
|
||||
snprintf(completion->ok_message, sizeof(completion->ok_message),
|
||||
"duplicate: already have this event");
|
||||
} else {
|
||||
cJSON* event_obj = cJSON_Parse(completion->event_json);
|
||||
if (!event_obj || !cJSON_IsObject(event_obj)) {
|
||||
int validation_result = nostr_validate_unified_request(completion->event_json, strlen(completion->event_json));
|
||||
if (validation_result != NOSTR_SUCCESS) {
|
||||
completion->success = 0;
|
||||
completion->should_broadcast = 0;
|
||||
strncpy(completion->error_message, "error: failed to parse event", sizeof(completion->error_message) - 1);
|
||||
completion->error_message[sizeof(completion->error_message) - 1] = '\0';
|
||||
map_validation_error_message(validation_result, completion->error_message, sizeof(completion->error_message));
|
||||
} else {
|
||||
if (job->event_kind >= 20000 && job->event_kind < 30000) {
|
||||
completion->success = 1;
|
||||
completion->should_broadcast = 1;
|
||||
completion->run_post_actions = 0;
|
||||
cJSON* event_obj = cJSON_Parse(completion->event_json);
|
||||
if (!event_obj || !cJSON_IsObject(event_obj)) {
|
||||
completion->success = 0;
|
||||
completion->should_broadcast = 0;
|
||||
strncpy(completion->error_message, "error: failed to parse event", sizeof(completion->error_message) - 1);
|
||||
completion->error_message[sizeof(completion->error_message) - 1] = '\0';
|
||||
} else {
|
||||
int core_rc = store_event_core(event_obj);
|
||||
if (core_rc < 0) {
|
||||
completion->success = 0;
|
||||
completion->should_broadcast = 0;
|
||||
completion->run_post_actions = 0;
|
||||
strncpy(completion->error_message, "error: failed to store event", sizeof(completion->error_message) - 1);
|
||||
completion->error_message[sizeof(completion->error_message) - 1] = '\0';
|
||||
} else {
|
||||
if (job->event_kind >= 20000 && job->event_kind < 30000) {
|
||||
completion->success = 1;
|
||||
completion->should_broadcast = 1;
|
||||
completion->run_post_actions = (core_rc == 0);
|
||||
completion->run_post_actions = 0;
|
||||
} else {
|
||||
int core_rc = store_event_core(event_obj);
|
||||
if (core_rc < 0) {
|
||||
completion->success = 0;
|
||||
completion->should_broadcast = 0;
|
||||
completion->run_post_actions = 0;
|
||||
strncpy(completion->error_message, "error: failed to store event", sizeof(completion->error_message) - 1);
|
||||
completion->error_message[sizeof(completion->error_message) - 1] = '\0';
|
||||
} else {
|
||||
completion->success = 1;
|
||||
completion->should_broadcast = 1;
|
||||
completion->run_post_actions = (core_rc == 0);
|
||||
}
|
||||
}
|
||||
cJSON_Delete(event_obj);
|
||||
}
|
||||
cJSON_Delete(event_obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,6 +605,10 @@ static void* async_event_worker_main(void* arg) {
|
||||
free(job);
|
||||
}
|
||||
|
||||
if (worker_db) {
|
||||
db_close_worker_connection(worker_db);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -650,8 +710,9 @@ static int try_submit_async_event(cJSON* event, const char* event_json, struct l
|
||||
static void process_async_event_completions(void) {
|
||||
async_event_completion_t* completion = NULL;
|
||||
while ((completion = async_event_completion_pop()) != NULL) {
|
||||
struct per_session_data* current_pss = (struct per_session_data*)lws_wsi_user(completion->wsi);
|
||||
int target_alive = (current_pss && current_pss == completion->pss_token);
|
||||
struct per_session_data* current_pss = NULL;
|
||||
int target_alive = websocket_get_live_pss(completion->wsi, ¤t_pss) &&
|
||||
current_pss == completion->pss_token;
|
||||
|
||||
int needs_event_obj = completion->run_post_actions ||
|
||||
(target_alive && completion->success && completion->should_broadcast);
|
||||
@@ -684,7 +745,9 @@ static void process_async_event_completions(void) {
|
||||
current_pss,
|
||||
completion->event_id,
|
||||
completion->success,
|
||||
completion->success ? "" : completion->error_message);
|
||||
completion->success
|
||||
? (completion->ok_message[0] ? completion->ok_message : "")
|
||||
: completion->error_message);
|
||||
}
|
||||
|
||||
free(completion->event_json);
|
||||
@@ -692,6 +755,196 @@ static void process_async_event_completions(void) {
|
||||
}
|
||||
}
|
||||
|
||||
static void free_count_payload_ws(void* payload_void) {
|
||||
thread_pool_count_payload_t* payload = (thread_pool_count_payload_t*)payload_void;
|
||||
if (!payload) return;
|
||||
free(payload->sql);
|
||||
if (payload->bind_params) {
|
||||
for (int i = 0; i < payload->bind_param_count; i++) {
|
||||
free(payload->bind_params[i]);
|
||||
}
|
||||
free(payload->bind_params);
|
||||
}
|
||||
free(payload);
|
||||
}
|
||||
|
||||
static void count_async_completion_push(count_async_completion_t* completion) {
|
||||
if (!completion) return;
|
||||
|
||||
pthread_mutex_lock(&g_count_async_completion_mutex);
|
||||
completion->next = NULL;
|
||||
if (!g_count_async_completion_tail) {
|
||||
g_count_async_completion_head = completion;
|
||||
g_count_async_completion_tail = completion;
|
||||
} else {
|
||||
g_count_async_completion_tail->next = completion;
|
||||
g_count_async_completion_tail = completion;
|
||||
}
|
||||
pthread_mutex_unlock(&g_count_async_completion_mutex);
|
||||
}
|
||||
|
||||
static count_async_completion_t* count_async_completion_pop(void) {
|
||||
pthread_mutex_lock(&g_count_async_completion_mutex);
|
||||
count_async_completion_t* completion = g_count_async_completion_head;
|
||||
if (completion) {
|
||||
g_count_async_completion_head = completion->next;
|
||||
if (!g_count_async_completion_head) {
|
||||
g_count_async_completion_tail = NULL;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&g_count_async_completion_mutex);
|
||||
return completion;
|
||||
}
|
||||
|
||||
static void count_async_result_cb(const thread_pool_result_t* result, void* user_ctx) {
|
||||
count_async_state_t* state = (count_async_state_t*)user_ctx;
|
||||
if (!result || !state) {
|
||||
if (result && result->result_data) {
|
||||
free(result->result_data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
count_async_completion_t* completion = calloc(1, sizeof(*completion));
|
||||
if (!completion) {
|
||||
if (result->result_data) {
|
||||
free(result->result_data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
completion->state = state;
|
||||
completion->status = result->status;
|
||||
if (result->status == THREAD_POOL_STATUS_OK && result->result_data) {
|
||||
thread_pool_count_result_t* count_result = (thread_pool_count_result_t*)result->result_data;
|
||||
completion->count = count_result->count;
|
||||
}
|
||||
|
||||
if (result->result_data) {
|
||||
free(result->result_data);
|
||||
}
|
||||
|
||||
count_async_completion_push(completion);
|
||||
if (ws_context) {
|
||||
lws_cancel_service(ws_context);
|
||||
}
|
||||
}
|
||||
|
||||
static int submit_count_query_async(count_async_state_t* state,
|
||||
const char* sql,
|
||||
const char** bind_params,
|
||||
int bind_param_count) {
|
||||
if (!state || !sql) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
thread_pool_count_payload_t* payload = calloc(1, sizeof(*payload));
|
||||
if (!payload) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
payload->sql = strdup(sql);
|
||||
payload->bind_param_count = bind_param_count;
|
||||
if (!payload->sql) {
|
||||
free_count_payload_ws(payload);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bind_param_count > 0) {
|
||||
payload->bind_params = calloc((size_t)bind_param_count, sizeof(char*));
|
||||
if (!payload->bind_params) {
|
||||
free_count_payload_ws(payload);
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < bind_param_count; i++) {
|
||||
const char* value = (bind_params && bind_params[i]) ? bind_params[i] : "";
|
||||
payload->bind_params[i] = strdup(value);
|
||||
if (!payload->bind_params[i]) {
|
||||
free_count_payload_ws(payload);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thread_pool_job_t job;
|
||||
memset(&job, 0, sizeof(job));
|
||||
job.type = THREAD_POOL_JOB_COUNT_QUERY;
|
||||
job.payload = payload;
|
||||
job.payload_free = free_count_payload_ws;
|
||||
job.result_cb = count_async_result_cb;
|
||||
job.result_cb_ctx = state;
|
||||
|
||||
thread_pool_status_t submit_rc = thread_pool_submit_read(&job, NULL);
|
||||
if (submit_rc != THREAD_POOL_STATUS_OK) {
|
||||
free_count_payload_ws(payload);
|
||||
return -1;
|
||||
}
|
||||
|
||||
state->pending_jobs++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void send_count_response(struct lws* wsi, struct per_session_data* pss,
|
||||
const char* sub_id, int total_count) {
|
||||
cJSON* count_response = cJSON_CreateArray();
|
||||
if (!count_response) {
|
||||
return;
|
||||
}
|
||||
|
||||
cJSON_AddItemToArray(count_response, cJSON_CreateString("COUNT"));
|
||||
cJSON_AddItemToArray(count_response, cJSON_CreateString(sub_id));
|
||||
|
||||
cJSON* count_obj = cJSON_CreateObject();
|
||||
cJSON_AddNumberToObject(count_obj, "count", total_count);
|
||||
cJSON_AddItemToArray(count_response, count_obj);
|
||||
|
||||
char* count_str = cJSON_Print(count_response);
|
||||
if (count_str) {
|
||||
size_t count_len = strlen(count_str);
|
||||
if (queue_message(wsi, pss, count_str, count_len, LWS_WRITE_TEXT) != 0) {
|
||||
DEBUG_ERROR("Failed to queue COUNT message");
|
||||
}
|
||||
free(count_str);
|
||||
}
|
||||
|
||||
cJSON_Delete(count_response);
|
||||
}
|
||||
|
||||
static void process_count_async_completions(void) {
|
||||
count_async_completion_t* completion = NULL;
|
||||
while ((completion = count_async_completion_pop()) != NULL) {
|
||||
count_async_state_t* state = completion->state;
|
||||
if (state) {
|
||||
if (completion->status == THREAD_POOL_STATUS_OK) {
|
||||
state->total_count += completion->count;
|
||||
} else {
|
||||
state->had_error = 1;
|
||||
if (state->error_message[0] == '\0') {
|
||||
strncpy(state->error_message, "error: failed to execute count query", sizeof(state->error_message) - 1);
|
||||
state->error_message[sizeof(state->error_message) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
state->pending_jobs--;
|
||||
if (state->pending_jobs <= 0) {
|
||||
struct per_session_data* current_pss = NULL;
|
||||
int target_alive = websocket_get_live_pss(state->wsi, ¤t_pss) &&
|
||||
current_pss == state->pss_token;
|
||||
if (target_alive) {
|
||||
if (state->had_error) {
|
||||
send_notice_message(state->wsi, current_pss, state->error_message[0] ? state->error_message : "error: count query failed");
|
||||
} else {
|
||||
send_count_response(state->wsi, current_pss, state->sub_id, state->total_count);
|
||||
}
|
||||
}
|
||||
free(state);
|
||||
}
|
||||
}
|
||||
|
||||
free(completion);
|
||||
}
|
||||
}
|
||||
|
||||
// Message queue functions for proper libwebsockets pattern
|
||||
|
||||
/**
|
||||
@@ -1315,27 +1568,6 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Early duplicate check: skip expensive crypto for events already in DB.
|
||||
// The event id is a 64-char hex string — look it up via primary key index (~10μs).
|
||||
// This must happen AFTER we have the id string but BEFORE signature verification.
|
||||
cJSON* id_obj_dup = cJSON_GetObjectItemCaseSensitive(event, "id");
|
||||
if (id_obj_dup && cJSON_IsString(id_obj_dup)) {
|
||||
const char* event_id_str = cJSON_GetStringValue(id_obj_dup);
|
||||
if (event_id_str && event_id_exists_in_db(event_id_str)) {
|
||||
// Already have this event — send OK true and skip crypto
|
||||
DEBUG_TRACE("Duplicate event %s — skipping signature verification", event_id_str);
|
||||
char ok_msg[128];
|
||||
snprintf(ok_msg, sizeof(ok_msg),
|
||||
"[\"OK\",\"%s\",true,\"duplicate: already have this event\"]",
|
||||
event_id_str);
|
||||
size_t ok_len = strlen(ok_msg);
|
||||
queue_message(wsi, pss, ok_msg, ok_len, LWS_WRITE_TEXT);
|
||||
free(event_json_str);
|
||||
cJSON_Delete(json);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Try async EVENT offload first (Phase 1).
|
||||
int async_submit_rc = try_submit_async_event(event, event_json_str, wsi, pss);
|
||||
if (async_submit_rc == 0) {
|
||||
@@ -1888,10 +2120,15 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
|
||||
return 0;
|
||||
}
|
||||
|
||||
handle_count_message(subscription_id, filters, wsi, pss);
|
||||
int count_result = handle_count_message(subscription_id, filters, wsi, pss);
|
||||
|
||||
// Clean up the filters array we created
|
||||
cJSON_Delete(filters);
|
||||
|
||||
if (count_result == HANDLE_REQ_ASYNC_PENDING) {
|
||||
cJSON_Delete(json);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else if (strcmp(msg_type, "CLOSE") == 0) {
|
||||
// Handle CLOSE message
|
||||
@@ -2127,25 +2364,6 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Early duplicate check: skip expensive crypto for events already in DB.
|
||||
cJSON* id_obj_dup2 = cJSON_GetObjectItemCaseSensitive(event, "id");
|
||||
if (id_obj_dup2 && cJSON_IsString(id_obj_dup2)) {
|
||||
const char* event_id_str2 = cJSON_GetStringValue(id_obj_dup2);
|
||||
if (event_id_str2 && event_id_exists_in_db(event_id_str2)) {
|
||||
DEBUG_TRACE("Duplicate event %s — skipping signature verification", event_id_str2);
|
||||
char ok_msg2[128];
|
||||
snprintf(ok_msg2, sizeof(ok_msg2),
|
||||
"[\"OK\",\"%s\",true,\"duplicate: already have this event\"]",
|
||||
event_id_str2);
|
||||
size_t ok_len2 = strlen(ok_msg2);
|
||||
queue_message(wsi, pss, ok_msg2, ok_len2, LWS_WRITE_TEXT);
|
||||
free(event_json_str);
|
||||
cJSON_Delete(json);
|
||||
free(message);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Try async EVENT offload first (Phase 1).
|
||||
int async_submit_rc = try_submit_async_event(event, event_json_str, wsi, pss);
|
||||
if (async_submit_rc == 0) {
|
||||
@@ -2683,10 +2901,16 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
|
||||
return 0;
|
||||
}
|
||||
|
||||
handle_count_message(subscription_id, filters, wsi, pss);
|
||||
int count_result = handle_count_message(subscription_id, filters, wsi, pss);
|
||||
|
||||
// Clean up the filters array we created
|
||||
cJSON_Delete(filters);
|
||||
|
||||
if (count_result == HANDLE_REQ_ASYNC_PENDING) {
|
||||
cJSON_Delete(json);
|
||||
free(message);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else if (strcmp(msg_type, "CLOSE") == 0) {
|
||||
// Handle CLOSE message
|
||||
@@ -3201,6 +3425,9 @@ int start_websocket_relay(int port_override, int strict_port) {
|
||||
// Drain completed async EVENT jobs and emit OK/broadcast on service thread.
|
||||
process_async_event_completions();
|
||||
|
||||
// Drain completed async COUNT jobs and emit COUNT/NOTICE on service thread.
|
||||
process_count_async_completions();
|
||||
|
||||
// Check if it's time to post status update
|
||||
time_t current_time = time(NULL);
|
||||
int status_post_hours = hot_cfg_kind_1_status_posts_hours();
|
||||
@@ -3230,6 +3457,10 @@ int start_websocket_relay(int port_override, int strict_port) {
|
||||
int idle_timeout_sec = hot_cfg_idle_connection_timeout_sec();
|
||||
check_idle_connections(idle_timeout_sec);
|
||||
|
||||
if (thread_pool_submit_wal_checkpoint() != 0) {
|
||||
DEBUG_TRACE("WAL checkpoint submit skipped or failed");
|
||||
}
|
||||
|
||||
if (max_connection_seconds > 0) {
|
||||
check_connection_age(max_connection_seconds);
|
||||
} else {
|
||||
@@ -3433,7 +3664,16 @@ int handle_count_message(const char* sub_id, cJSON* filters, struct lws *wsi, st
|
||||
int bind_param_count = 0;
|
||||
int bind_param_capacity = 0;
|
||||
|
||||
int total_count = 0;
|
||||
count_async_state_t* async_state = calloc(1, sizeof(*async_state));
|
||||
if (!async_state) {
|
||||
DEBUG_ERROR("Failed to allocate COUNT async state");
|
||||
return 0;
|
||||
}
|
||||
|
||||
strncpy(async_state->sub_id, sub_id ? sub_id : "", sizeof(async_state->sub_id) - 1);
|
||||
async_state->sub_id[sizeof(async_state->sub_id) - 1] = '\0';
|
||||
async_state->wsi = wsi;
|
||||
async_state->pss_token = pss;
|
||||
|
||||
// Process each filter in the array
|
||||
for (int i = 0; i < cJSON_GetArraySize(filters); i++) {
|
||||
@@ -3678,68 +3918,34 @@ int handle_count_message(const char* sub_id, cJSON* filters, struct lws *wsi, st
|
||||
remaining = sizeof(sql) - strlen(sql);
|
||||
}
|
||||
|
||||
// Execute count query
|
||||
|
||||
// Start query timing
|
||||
struct timespec query_start, query_end;
|
||||
clock_gettime(CLOCK_MONOTONIC, &query_start);
|
||||
|
||||
// Execute count query via thread pool helper
|
||||
int filter_count = 0;
|
||||
if (thread_pool_execute_count_sync(sql, (const char**)bind_params, bind_param_count, &filter_count) != 0) {
|
||||
DEBUG_ERROR("Failed to execute COUNT query via db_ops/thread_pool");
|
||||
continue;
|
||||
// Submit COUNT query asynchronously to DB reader pool.
|
||||
if (submit_count_query_async(async_state, sql, (const char**)bind_params, bind_param_count) != 0) {
|
||||
DEBUG_ERROR("Failed to submit COUNT query async");
|
||||
strncpy(async_state->error_message, "error: failed to submit count query", sizeof(async_state->error_message) - 1);
|
||||
async_state->error_message[sizeof(async_state->error_message) - 1] = '\0';
|
||||
async_state->had_error = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Stop query timing and log
|
||||
clock_gettime(CLOCK_MONOTONIC, &query_end);
|
||||
long elapsed_us = (query_end.tv_sec - query_start.tv_sec) * 1000000L +
|
||||
(query_end.tv_nsec - query_start.tv_nsec) / 1000L;
|
||||
|
||||
log_query_execution("COUNT", sub_id, pss ? pss->client_ip : NULL,
|
||||
sql, elapsed_us, 1); // COUNT always returns 1 row
|
||||
|
||||
total_count += filter_count;
|
||||
}
|
||||
|
||||
// Total count calculated
|
||||
|
||||
// Send COUNT response - NIP-45 format: ["COUNT", <subscription_id>, {"count": <count>}]
|
||||
cJSON* count_response = cJSON_CreateArray();
|
||||
cJSON_AddItemToArray(count_response, cJSON_CreateString("COUNT"));
|
||||
cJSON_AddItemToArray(count_response, cJSON_CreateString(sub_id));
|
||||
|
||||
// Create count object as per NIP-45 specification
|
||||
cJSON* count_obj = cJSON_CreateObject();
|
||||
cJSON_AddNumberToObject(count_obj, "count", total_count);
|
||||
cJSON_AddItemToArray(count_response, count_obj);
|
||||
|
||||
char *count_str = cJSON_Print(count_response);
|
||||
if (count_str) {
|
||||
size_t count_len = strlen(count_str);
|
||||
|
||||
// DEBUG: Log WebSocket frame details before sending
|
||||
DEBUG_TRACE("WS_FRAME_SEND: type=COUNT len=%zu data=%.100s%s",
|
||||
count_len,
|
||||
count_str,
|
||||
count_len > 100 ? "..." : "");
|
||||
|
||||
// Queue message for proper libwebsockets pattern
|
||||
if (queue_message(wsi, pss, count_str, count_len, LWS_WRITE_TEXT) != 0) {
|
||||
DEBUG_ERROR("Failed to queue COUNT message");
|
||||
}
|
||||
|
||||
free(count_str);
|
||||
}
|
||||
cJSON_Delete(count_response);
|
||||
|
||||
// Cleanup bind params
|
||||
// Cleanup bind params from the final filter iteration.
|
||||
for (int i = 0; i < bind_param_count; i++) {
|
||||
free(bind_params[i]);
|
||||
}
|
||||
free(bind_params);
|
||||
|
||||
return total_count;
|
||||
if (async_state->pending_jobs <= 0) {
|
||||
if (async_state->had_error) {
|
||||
send_notice_message(wsi, pss,
|
||||
async_state->error_message[0] ? async_state->error_message : "error: count query failed");
|
||||
} else {
|
||||
send_count_response(wsi, pss, sub_id, 0);
|
||||
}
|
||||
free(async_state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return HANDLE_REQ_ASYNC_PENDING;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -99,6 +99,10 @@ struct per_session_data {
|
||||
// Get current active WebSocket connection count
|
||||
int get_active_connection_count(void);
|
||||
|
||||
// Safely resolve per-session data only for currently tracked live WebSocket sessions.
|
||||
// Returns 1 and sets *out_pss on success, otherwise returns 0.
|
||||
int websocket_get_live_pss(struct lws* wsi, struct per_session_data** out_pss);
|
||||
|
||||
// Actual relay port bound by libwebsockets at runtime (after fallback/retry logic)
|
||||
extern int g_relay_port;
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
2026-04-01 09:57:22 - ==========================================
|
||||
2026-04-01 09:57:22 - C-Relay Comprehensive Test Suite Runner
|
||||
2026-04-01 09:57:22 - ==========================================
|
||||
2026-04-01 09:57:22 - Relay URL: ws://127.0.0.1:8888
|
||||
2026-04-01 09:57:22 - Log file: test_results_20260401_095722.log
|
||||
2026-04-01 09:57:22 - Report file: test_report_20260401_095722.html
|
||||
2026-04-01 09:57:22 -
|
||||
2026-04-01 09:57:22 - Checking relay status at ws://127.0.0.1:8888...
|
||||
2026-04-01 09:57:22 - \033[0;32m✓ Relay HTTP endpoint is accessible\033[0m
|
||||
2026-04-01 09:57:22 -
|
||||
2026-04-01 09:57:22 - Starting comprehensive test execution...
|
||||
2026-04-01 09:57:22 -
|
||||
2026-04-01 09:57:22 - \033[0;34m=== SECURITY TEST SUITES ===\033[0m
|
||||
2026-04-01 09:57:22 - ==========================================
|
||||
2026-04-01 09:57:22 - Running Test Suite: SQL Injection Tests
|
||||
2026-04-01 09:57:22 - Description: Comprehensive SQL injection vulnerability testing
|
||||
2026-04-01 09:57:22 - ==========================================
|
||||
2026-04-01 09:57:22 - \033[0;31mERROR: Test script sql_injection_tests.sh not found\033[0m
|
||||
@@ -1,18 +0,0 @@
|
||||
2026-04-01 11:01:47 - ==========================================
|
||||
2026-04-01 11:01:47 - C-Relay Comprehensive Test Suite Runner
|
||||
2026-04-01 11:01:47 - ==========================================
|
||||
2026-04-01 11:01:47 - Relay URL: ws://127.0.0.1:8888
|
||||
2026-04-01 11:01:47 - Log file: test_results_20260401_110147.log
|
||||
2026-04-01 11:01:47 - Report file: test_report_20260401_110147.html
|
||||
2026-04-01 11:01:47 -
|
||||
2026-04-01 11:01:47 - Checking relay status at ws://127.0.0.1:8888...
|
||||
2026-04-01 11:01:47 - \033[0;32m✓ Relay HTTP endpoint is accessible\033[0m
|
||||
2026-04-01 11:01:47 -
|
||||
2026-04-01 11:01:47 - Starting comprehensive test execution...
|
||||
2026-04-01 11:01:47 -
|
||||
2026-04-01 11:01:47 - \033[0;34m=== SECURITY TEST SUITES ===\033[0m
|
||||
2026-04-01 11:01:47 - ==========================================
|
||||
2026-04-01 11:01:47 - Running Test Suite: SQL Injection Tests
|
||||
2026-04-01 11:01:47 - Description: Comprehensive SQL injection vulnerability testing
|
||||
2026-04-01 11:01:47 - ==========================================
|
||||
2026-04-01 11:01:47 - \033[0;31mERROR: Test script sql_injection_tests.sh not found\033[0m
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +0,0 @@
|
||||
Profiling PID: 2040140
|
||||
CLK_TCK=100
|
||||
Starting perf record in background...
|
||||
perf_pid=2040808
|
||||
Done. Artifacts in /tmp/c_relay_thread_profile_20260401_154500
|
||||
@@ -1,421 +0,0 @@
|
||||
timestamp,tid,thread_name,cpu_pct,delta_ticks,total_ticks
|
||||
1775058301,2040140",unknown,0.00,0,3950
|
||||
1775058301,2040150",unknown,0.00,0,9
|
||||
1775058301,2040151",unknown,0.00,0,8
|
||||
1775058301,2040152",unknown,0.00,0,11
|
||||
1775058301,2040153",unknown,0.00,0,11
|
||||
1775058301,2040154",unknown,0.00,0,0
|
||||
1775058301,2040155",unknown,0.00,0,0
|
||||
1775058311,2040140",unknown,62.10,621,4571
|
||||
1775058311,2040150",unknown,0.20,2,11
|
||||
1775058311,2040151",unknown,0.10,1,9
|
||||
1775058311,2040152",unknown,0.10,1,12
|
||||
1775058311,2040153",unknown,0.00,0,11
|
||||
1775058311,2040154",unknown,0.00,0,0
|
||||
1775058311,2040155",unknown,0.00,0,0
|
||||
1775058321,2040140",unknown,65.20,652,5223
|
||||
1775058321,2040150",unknown,0.20,2,13
|
||||
1775058321,2040151",unknown,0.20,2,11
|
||||
1775058321,2040152",unknown,0.30,3,15
|
||||
1775058321,2040153",unknown,0.20,2,13
|
||||
1775058321,2040154",unknown,0.00,0,0
|
||||
1775058321,2040155",unknown,0.00,0,0
|
||||
1775058331,2040140",unknown,83.80,838,6061
|
||||
1775058331,2040150",unknown,0.00,0,13
|
||||
1775058331,2040151",unknown,0.00,0,11
|
||||
1775058331,2040152",unknown,0.00,0,15
|
||||
1775058331,2040153",unknown,0.00,0,13
|
||||
1775058331,2040154",unknown,0.00,0,0
|
||||
1775058331,2040155",unknown,0.00,0,0
|
||||
1775058341,2040140",unknown,100.20,1002,7063
|
||||
1775058341,2040150",unknown,0.00,0,13
|
||||
1775058341,2040151",unknown,0.00,0,11
|
||||
1775058341,2040152",unknown,0.00,0,15
|
||||
1775058341,2040153",unknown,0.00,0,13
|
||||
1775058341,2040154",unknown,0.00,0,0
|
||||
1775058341,2040155",unknown,0.00,0,0
|
||||
1775058351,2040140",unknown,100.30,1003,8066
|
||||
1775058351,2040150",unknown,0.00,0,13
|
||||
1775058351,2040151",unknown,0.00,0,11
|
||||
1775058351,2040152",unknown,0.10,1,16
|
||||
1775058351,2040153",unknown,0.00,0,13
|
||||
1775058351,2040154",unknown,0.00,0,0
|
||||
1775058351,2040155",unknown,0.00,0,0
|
||||
1775058361,2040140",unknown,89.50,895,8961
|
||||
1775058361,2040150",unknown,0.10,1,14
|
||||
1775058361,2040151",unknown,0.00,0,11
|
||||
1775058361,2040152",unknown,0.00,0,16
|
||||
1775058361,2040153",unknown,0.00,0,13
|
||||
1775058361,2040154",unknown,0.00,0,0
|
||||
1775058361,2040155",unknown,0.00,0,0
|
||||
1775058371,2040140",unknown,21.20,212,9173
|
||||
1775058371,2040150",unknown,0.00,0,14
|
||||
1775058371,2040151",unknown,0.00,0,11
|
||||
1775058371,2040152",unknown,0.00,0,16
|
||||
1775058371,2040153",unknown,0.00,0,13
|
||||
1775058371,2040154",unknown,0.00,0,0
|
||||
1775058371,2040155",unknown,0.00,0,0
|
||||
1775058381,2040140",unknown,36.40,364,9537
|
||||
1775058381,2040150",unknown,0.10,1,15
|
||||
1775058381,2040151",unknown,0.10,1,12
|
||||
1775058381,2040152",unknown,0.10,1,17
|
||||
1775058381,2040153",unknown,0.00,0,13
|
||||
1775058381,2040154",unknown,0.00,0,0
|
||||
1775058381,2040155",unknown,0.00,0,0
|
||||
1775058391,2040140",unknown,35.30,353,9890
|
||||
1775058391,2040150",unknown,0.00,0,15
|
||||
1775058391,2040151",unknown,0.00,0,12
|
||||
1775058391,2040152",unknown,0.00,0,17
|
||||
1775058391,2040153",unknown,0.00,0,13
|
||||
1775058391,2040154",unknown,0.00,0,0
|
||||
1775058391,2040155",unknown,0.00,0,0
|
||||
1775058401,2040140",unknown,42.80,428,10318
|
||||
1775058401,2040150",unknown,0.30,3,18
|
||||
1775058401,2040151",unknown,0.20,2,14
|
||||
1775058401,2040152",unknown,0.30,3,20
|
||||
1775058401,2040153",unknown,0.30,3,16
|
||||
1775058401,2040154",unknown,0.00,0,0
|
||||
1775058401,2040155",unknown,0.00,0,0
|
||||
1775058411,2040140",unknown,73.50,735,11053
|
||||
1775058411,2040150",unknown,0.40,4,22
|
||||
1775058411,2040151",unknown,0.20,2,16
|
||||
1775058411,2040152",unknown,0.40,4,24
|
||||
1775058411,2040153",unknown,0.20,2,18
|
||||
1775058411,2040154",unknown,0.00,0,0
|
||||
1775058411,2040155",unknown,0.00,0,0
|
||||
1775058421,2040140",unknown,33.60,336,11389
|
||||
1775058421,2040150",unknown,0.00,0,22
|
||||
1775058421,2040151",unknown,0.00,0,16
|
||||
1775058421,2040152",unknown,0.00,0,24
|
||||
1775058421,2040153",unknown,0.10,1,19
|
||||
1775058421,2040154",unknown,0.00,0,0
|
||||
1775058421,2040155",unknown,0.00,0,0
|
||||
1775058431,2040140",unknown,57.20,572,11961
|
||||
1775058431,2040150",unknown,0.00,0,22
|
||||
1775058431,2040151",unknown,0.10,1,17
|
||||
1775058431,2040152",unknown,0.10,1,25
|
||||
1775058431,2040153",unknown,0.00,0,19
|
||||
1775058431,2040154",unknown,0.00,0,0
|
||||
1775058431,2040155",unknown,0.00,0,0
|
||||
1775058441,2040140",unknown,96.70,967,12928
|
||||
1775058441,2040150",unknown,0.00,0,22
|
||||
1775058441,2040151",unknown,0.00,0,17
|
||||
1775058441,2040152",unknown,0.00,0,25
|
||||
1775058441,2040153",unknown,0.00,0,19
|
||||
1775058441,2040154",unknown,0.00,0,0
|
||||
1775058441,2040155",unknown,0.00,0,0
|
||||
1775058451,2040140",unknown,100.30,1003,13931
|
||||
1775058451,2040150",unknown,0.10,1,23
|
||||
1775058451,2040151",unknown,0.10,1,18
|
||||
1775058451,2040152",unknown,0.10,1,26
|
||||
1775058451,2040153",unknown,0.00,0,19
|
||||
1775058451,2040154",unknown,0.00,0,0
|
||||
1775058451,2040155",unknown,0.00,0,0
|
||||
1775058461,2040140",unknown,98.40,984,14915
|
||||
1775058461,2040150",unknown,0.10,1,24
|
||||
1775058461,2040151",unknown,0.30,3,21
|
||||
1775058461,2040152",unknown,0.10,1,27
|
||||
1775058461,2040153",unknown,0.20,2,21
|
||||
1775058461,2040154",unknown,0.00,0,0
|
||||
1775058461,2040155",unknown,0.00,0,0
|
||||
1775058471,2040140",unknown,62.90,629,15544
|
||||
1775058471,2040150",unknown,0.00,0,24
|
||||
1775058471,2040151",unknown,0.20,2,23
|
||||
1775058471,2040152",unknown,0.00,0,27
|
||||
1775058471,2040153",unknown,0.10,1,22
|
||||
1775058471,2040154",unknown,0.00,0,0
|
||||
1775058471,2040155",unknown,0.20,2,2
|
||||
1775058481,2040140",unknown,83.20,832,16376
|
||||
1775058481,2040150",unknown,0.20,2,26
|
||||
1775058481,2040151",unknown,0.00,0,23
|
||||
1775058481,2040152",unknown,0.20,2,29
|
||||
1775058481,2040153",unknown,0.00,0,22
|
||||
1775058481,2040154",unknown,0.00,0,0
|
||||
1775058481,2040155",unknown,0.00,0,2
|
||||
1775058491,2040140",unknown,100.30,1003,17379
|
||||
1775058491,2040150",unknown,0.00,0,26
|
||||
1775058491,2040151",unknown,0.00,0,23
|
||||
1775058491,2040152",unknown,0.00,0,29
|
||||
1775058491,2040153",unknown,0.00,0,22
|
||||
1775058491,2040154",unknown,0.00,0,0
|
||||
1775058491,2040155",unknown,0.00,0,2
|
||||
1775058501,2040140",unknown,63.30,633,18012
|
||||
1775058501,2040150",unknown,0.10,1,27
|
||||
1775058501,2040151",unknown,0.10,1,24
|
||||
1775058501,2040152",unknown,0.30,3,32
|
||||
1775058501,2040153",unknown,0.20,2,24
|
||||
1775058501,2040154",unknown,0.00,0,0
|
||||
1775058501,2040155",unknown,0.00,0,2
|
||||
1775058511,2040140",unknown,57.40,574,18586
|
||||
1775058511,2040150",unknown,0.00,0,27
|
||||
1775058511,2040151",unknown,0.10,1,25
|
||||
1775058511,2040152",unknown,0.00,0,32
|
||||
1775058511,2040153",unknown,0.00,0,24
|
||||
1775058511,2040154",unknown,0.00,0,0
|
||||
1775058511,2040155",unknown,0.00,0,2
|
||||
1775058521,2040140",unknown,18.70,187,18773
|
||||
1775058521,2040150",unknown,0.10,1,28
|
||||
1775058521,2040151",unknown,0.00,0,25
|
||||
1775058521,2040152",unknown,0.00,0,32
|
||||
1775058521,2040153",unknown,0.00,0,24
|
||||
1775058521,2040154",unknown,0.00,0,0
|
||||
1775058521,2040155",unknown,0.00,0,2
|
||||
1775058531,2040140",unknown,66.20,662,19435
|
||||
1775058531,2040150",unknown,0.00,0,28
|
||||
1775058531,2040151",unknown,0.10,1,26
|
||||
1775058531,2040152",unknown,0.00,0,32
|
||||
1775058531,2040153",unknown,0.00,0,24
|
||||
1775058531,2040154",unknown,0.00,0,0
|
||||
1775058531,2040155",unknown,0.00,0,2
|
||||
1775058541,2040140",unknown,89.10,891,20326
|
||||
1775058541,2040150",unknown,0.00,0,28
|
||||
1775058541,2040151",unknown,0.00,0,26
|
||||
1775058541,2040152",unknown,0.10,1,33
|
||||
1775058541,2040153",unknown,0.00,0,24
|
||||
1775058541,2040154",unknown,0.00,0,0
|
||||
1775058541,2040155",unknown,0.00,0,2
|
||||
1775058551,2040140",unknown,38.10,381,20707
|
||||
1775058551,2040150",unknown,0.10,1,29
|
||||
1775058551,2040151",unknown,0.00,0,26
|
||||
1775058551,2040152",unknown,0.00,0,33
|
||||
1775058551,2040153",unknown,0.00,0,24
|
||||
1775058551,2040154",unknown,0.00,0,0
|
||||
1775058551,2040155",unknown,0.00,0,2
|
||||
1775058562,2040140",unknown,69.20,692,21399
|
||||
1775058562,2040150",unknown,0.00,0,29
|
||||
1775058562,2040151",unknown,0.20,2,28
|
||||
1775058562,2040152",unknown,0.00,0,33
|
||||
1775058562,2040153",unknown,0.10,1,25
|
||||
1775058562,2040154",unknown,0.00,0,0
|
||||
1775058562,2040155",unknown,0.00,0,2
|
||||
1775058572,2040140",unknown,92.80,928,22327
|
||||
1775058572,2040150",unknown,0.00,0,29
|
||||
1775058572,2040151",unknown,0.00,0,28
|
||||
1775058572,2040152",unknown,0.00,0,33
|
||||
1775058572,2040153",unknown,0.00,0,25
|
||||
1775058572,2040154",unknown,0.00,0,0
|
||||
1775058572,2040155",unknown,0.00,0,2
|
||||
1775058582,2040140",unknown,91.30,913,23240
|
||||
1775058582,2040150",unknown,0.10,1,30
|
||||
1775058582,2040151",unknown,0.00,0,28
|
||||
1775058582,2040152",unknown,0.10,1,34
|
||||
1775058582,2040153",unknown,0.00,0,25
|
||||
1775058582,2040154",unknown,0.00,0,0
|
||||
1775058582,2040155",unknown,0.00,0,2
|
||||
1775058592,2040140",unknown,94.60,946,24186
|
||||
1775058592,2040150",unknown,0.00,0,30
|
||||
1775058592,2040151",unknown,0.00,0,28
|
||||
1775058592,2040152",unknown,0.10,1,35
|
||||
1775058592,2040153",unknown,0.10,1,26
|
||||
1775058592,2040154",unknown,0.00,0,0
|
||||
1775058592,2040155",unknown,0.00,0,2
|
||||
1775058602,2040140",unknown,45.50,455,24641
|
||||
1775058602,2040150",unknown,0.00,0,30
|
||||
1775058602,2040151",unknown,0.00,0,28
|
||||
1775058602,2040152",unknown,0.00,0,35
|
||||
1775058602,2040153",unknown,0.00,0,26
|
||||
1775058602,2040154",unknown,0.00,0,0
|
||||
1775058602,2040155",unknown,0.00,0,2
|
||||
1775058612,2040140",unknown,64.50,645,25286
|
||||
1775058612,2040150",unknown,0.00,0,30
|
||||
1775058612,2040151",unknown,0.10,1,29
|
||||
1775058612,2040152",unknown,0.00,0,35
|
||||
1775058612,2040153",unknown,0.10,1,27
|
||||
1775058612,2040154",unknown,0.00,0,0
|
||||
1775058612,2040155",unknown,0.00,0,2
|
||||
1775058622,2040140",unknown,21.10,211,25497
|
||||
1775058622,2040150",unknown,0.00,0,30
|
||||
1775058622,2040151",unknown,0.00,0,29
|
||||
1775058622,2040152",unknown,0.00,0,35
|
||||
1775058622,2040153",unknown,0.00,0,27
|
||||
1775058622,2040154",unknown,0.00,0,0
|
||||
1775058622,2040155",unknown,0.00,0,2
|
||||
1775058632,2040140",unknown,26.60,266,25763
|
||||
1775058632,2040150",unknown,0.20,2,32
|
||||
1775058632,2040151",unknown,0.10,1,30
|
||||
1775058632,2040152",unknown,0.00,0,35
|
||||
1775058632,2040153",unknown,0.00,0,27
|
||||
1775058632,2040154",unknown,0.10,1,1
|
||||
1775058632,2040155",unknown,0.00,0,2
|
||||
1775058642,2040140",unknown,51.80,518,26281
|
||||
1775058642,2040150",unknown,0.00,0,32
|
||||
1775058642,2040151",unknown,0.10,1,31
|
||||
1775058642,2040152",unknown,0.00,0,35
|
||||
1775058642,2040153",unknown,0.00,0,27
|
||||
1775058642,2040154",unknown,0.00,0,1
|
||||
1775058642,2040155",unknown,0.00,0,2
|
||||
1775058652,2040140",unknown,28.40,284,26565
|
||||
1775058652,2040150",unknown,0.00,0,32
|
||||
1775058652,2040151",unknown,0.10,1,32
|
||||
1775058652,2040152",unknown,0.10,1,36
|
||||
1775058652,2040153",unknown,0.20,2,29
|
||||
1775058652,2040154",unknown,0.00,0,1
|
||||
1775058652,2040155",unknown,0.00,0,2
|
||||
1775058662,2040140",unknown,14.30,143,26708
|
||||
1775058662,2040150",unknown,0.20,2,34
|
||||
1775058662,2040151",unknown,0.10,1,33
|
||||
1775058662,2040152",unknown,0.40,4,40
|
||||
1775058662,2040153",unknown,0.30,3,32
|
||||
1775058662,2040154",unknown,0.00,0,1
|
||||
1775058662,2040155",unknown,0.00,0,2
|
||||
1775058672,2040140",unknown,69.20,692,27400
|
||||
1775058672,2040150",unknown,0.20,2,36
|
||||
1775058672,2040151",unknown,0.00,0,33
|
||||
1775058672,2040152",unknown,0.20,2,42
|
||||
1775058672,2040153",unknown,0.10,1,33
|
||||
1775058672,2040154",unknown,0.00,0,1
|
||||
1775058672,2040155",unknown,0.00,0,2
|
||||
1775058682,2040140",unknown,71.10,711,28111
|
||||
1775058682,2040150",unknown,0.30,3,39
|
||||
1775058682,2040151",unknown,0.20,2,35
|
||||
1775058682,2040152",unknown,0.00,0,42
|
||||
1775058682,2040153",unknown,0.10,1,34
|
||||
1775058682,2040154",unknown,0.00,0,1
|
||||
1775058682,2040155",unknown,0.00,0,2
|
||||
1775058692,2040140",unknown,99.40,994,29105
|
||||
1775058692,2040150",unknown,0.00,0,39
|
||||
1775058692,2040151",unknown,0.00,0,35
|
||||
1775058692,2040152",unknown,0.00,0,42
|
||||
1775058692,2040153",unknown,0.00,0,34
|
||||
1775058692,2040154",unknown,0.00,0,1
|
||||
1775058692,2040155",unknown,0.00,0,2
|
||||
1775058702,2040140",unknown,30.60,306,29411
|
||||
1775058702,2040150",unknown,0.10,1,40
|
||||
1775058702,2040151",unknown,0.10,1,36
|
||||
1775058702,2040152",unknown,0.20,2,44
|
||||
1775058702,2040153",unknown,0.20,2,36
|
||||
1775058702,2040154",unknown,0.00,0,1
|
||||
1775058702,2040155",unknown,0.00,0,2
|
||||
1775058712,2040140",unknown,14.70,147,29558
|
||||
1775058712,2040150",unknown,0.00,0,40
|
||||
1775058712,2040151",unknown,0.00,0,36
|
||||
1775058712,2040152",unknown,0.10,1,45
|
||||
1775058712,2040153",unknown,0.00,0,36
|
||||
1775058712,2040154",unknown,0.10,1,2
|
||||
1775058712,2040155",unknown,0.00,0,2
|
||||
1775058722,2040140",unknown,14.20,142,29700
|
||||
1775058722,2040150",unknown,0.00,0,40
|
||||
1775058722,2040151",unknown,0.10,1,37
|
||||
1775058722,2040152",unknown,0.10,1,46
|
||||
1775058722,2040153",unknown,0.00,0,36
|
||||
1775058722,2040154",unknown,0.00,0,2
|
||||
1775058722,2040155",unknown,0.00,0,2
|
||||
1775058732,2040140",unknown,29.20,292,29992
|
||||
1775058732,2040150",unknown,0.10,1,41
|
||||
1775058732,2040151",unknown,0.00,0,37
|
||||
1775058732,2040152",unknown,0.00,0,46
|
||||
1775058732,2040153",unknown,0.00,0,36
|
||||
1775058732,2040154",unknown,0.00,0,2
|
||||
1775058732,2040155",unknown,0.00,0,2
|
||||
1775058742,2040140",unknown,29.80,298,30290
|
||||
1775058742,2040150",unknown,0.00,0,41
|
||||
1775058742,2040151",unknown,0.00,0,37
|
||||
1775058742,2040152",unknown,0.10,1,47
|
||||
1775058742,2040153",unknown,0.00,0,36
|
||||
1775058742,2040154",unknown,0.00,0,2
|
||||
1775058742,2040155",unknown,0.00,0,2
|
||||
1775058752,2040140",unknown,48.20,482,30772
|
||||
1775058752,2040150",unknown,0.00,0,41
|
||||
1775058752,2040151",unknown,0.00,0,37
|
||||
1775058752,2040152",unknown,0.00,0,47
|
||||
1775058752,2040153",unknown,0.10,1,37
|
||||
1775058752,2040154",unknown,0.00,0,2
|
||||
1775058752,2040155",unknown,0.00,0,2
|
||||
1775058762,2040140",unknown,28.10,281,31053
|
||||
1775058762,2040150",unknown,0.00,0,41
|
||||
1775058762,2040151",unknown,0.00,0,37
|
||||
1775058762,2040152",unknown,0.00,0,47
|
||||
1775058762,2040153",unknown,0.00,0,37
|
||||
1775058762,2040154",unknown,0.00,0,2
|
||||
1775058762,2040155",unknown,0.00,0,2
|
||||
1775058772,2040140",unknown,40.80,408,31461
|
||||
1775058772,2040150",unknown,0.10,1,42
|
||||
1775058772,2040151",unknown,0.10,1,38
|
||||
1775058772,2040152",unknown,0.10,1,48
|
||||
1775058772,2040153",unknown,0.10,1,38
|
||||
1775058772,2040154",unknown,0.00,0,2
|
||||
1775058772,2040155",unknown,0.00,0,2
|
||||
1775058782,2040140",unknown,98.90,989,32450
|
||||
1775058782,2040150",unknown,0.30,3,45
|
||||
1775058782,2040151",unknown,0.00,0,38
|
||||
1775058782,2040152",unknown,0.30,3,51
|
||||
1775058782,2040153",unknown,0.10,1,39
|
||||
1775058782,2040154",unknown,0.00,0,2
|
||||
1775058782,2040155",unknown,0.10,1,3
|
||||
1775058792,2040140",unknown,59.50,595,33045
|
||||
1775058792,2040150",unknown,0.20,2,47
|
||||
1775058792,2040151",unknown,0.10,1,39
|
||||
1775058792,2040152",unknown,0.10,1,52
|
||||
1775058792,2040153",unknown,0.10,1,40
|
||||
1775058792,2040154",unknown,0.00,0,2
|
||||
1775058792,2040155",unknown,0.00,0,3
|
||||
1775058802,2040140",unknown,47.10,471,33516
|
||||
1775058802,2040150",unknown,0.00,0,47
|
||||
1775058802,2040151",unknown,0.00,0,39
|
||||
1775058802,2040152",unknown,0.00,0,52
|
||||
1775058802,2040153",unknown,0.10,1,41
|
||||
1775058802,2040154",unknown,0.00,0,2
|
||||
1775058802,2040155",unknown,0.10,1,4
|
||||
1775058812,2040140",unknown,50.60,506,34022
|
||||
1775058812,2040150",unknown,0.00,0,47
|
||||
1775058812,2040151",unknown,0.00,0,39
|
||||
1775058812,2040152",unknown,0.10,1,53
|
||||
1775058812,2040153",unknown,0.00,0,41
|
||||
1775058812,2040154",unknown,0.00,0,2
|
||||
1775058812,2040155",unknown,0.10,1,5
|
||||
1775058822,2040140",unknown,28.10,281,34303
|
||||
1775058822,2040150",unknown,0.00,0,47
|
||||
1775058822,2040151",unknown,0.00,0,39
|
||||
1775058822,2040152",unknown,0.00,0,53
|
||||
1775058822,2040153",unknown,0.00,0,41
|
||||
1775058822,2040154",unknown,0.00,0,2
|
||||
1775058822,2040155",unknown,0.00,0,5
|
||||
1775058832,2040140",unknown,75.30,753,35056
|
||||
1775058832,2040150",unknown,0.10,1,48
|
||||
1775058832,2040151",unknown,0.10,1,40
|
||||
1775058832,2040152",unknown,0.10,1,54
|
||||
1775058832,2040153",unknown,0.10,1,42
|
||||
1775058832,2040154",unknown,0.00,0,2
|
||||
1775058832,2040155",unknown,0.00,0,5
|
||||
1775058842,2040140",unknown,37.20,372,35428
|
||||
1775058842,2040150",unknown,0.00,0,48
|
||||
1775058842,2040151",unknown,0.00,0,40
|
||||
1775058842,2040152",unknown,0.00,0,54
|
||||
1775058842,2040153",unknown,0.00,0,42
|
||||
1775058842,2040154",unknown,0.00,0,2
|
||||
1775058842,2040155",unknown,0.00,0,5
|
||||
1775058852,2040140",unknown,27.00,270,35698
|
||||
1775058852,2040150",unknown,0.20,2,50
|
||||
1775058852,2040151",unknown,0.20,2,42
|
||||
1775058852,2040152",unknown,0.30,3,57
|
||||
1775058852,2040153",unknown,0.20,2,44
|
||||
1775058852,2040154",unknown,0.00,0,2
|
||||
1775058852,2040155",unknown,0.00,0,5
|
||||
1775058862,2040140",unknown,46.30,463,36161
|
||||
1775058862,2040150",unknown,0.00,0,50
|
||||
1775058862,2040151",unknown,0.10,1,43
|
||||
1775058862,2040152",unknown,0.20,2,59
|
||||
1775058862,2040153",unknown,0.00,0,44
|
||||
1775058862,2040154",unknown,0.00,0,2
|
||||
1775058862,2040155",unknown,0.00,0,5
|
||||
1775058872,2040140",unknown,14.00,140,36301
|
||||
1775058872,2040150",unknown,0.00,0,50
|
||||
1775058872,2040151",unknown,0.00,0,43
|
||||
1775058872,2040152",unknown,0.00,0,59
|
||||
1775058872,2040153",unknown,0.00,0,44
|
||||
1775058872,2040154",unknown,0.00,0,2
|
||||
1775058872,2040155",unknown,0.00,0,5
|
||||
1775058882,2040140",unknown,56.20,562,36863
|
||||
1775058882,2040150",unknown,0.00,0,50
|
||||
1775058882,2040151",unknown,0.10,1,44
|
||||
1775058882,2040152",unknown,0.10,1,60
|
||||
1775058882,2040153",unknown,0.00,0,44
|
||||
1775058882,2040154",unknown,0.00,0,2
|
||||
1775058882,2040155",unknown,0.00,0,5
|
||||
1775058893,2040140",unknown,35.60,356,37219
|
||||
1775058893,2040150",unknown,0.20,2,52
|
||||
1775058893,2040151",unknown,0.10,1,45
|
||||
1775058893,2040152",unknown,0.10,1,61
|
||||
1775058893,2040153",unknown,0.10,1,45
|
||||
1775058893,2040154",unknown,0.00,0,2
|
||||
1775058893,2040155",unknown,0.00,0,5
|
||||
|
Can't render this file because it contains an unexpected character in line 2 and column 19.
|
@@ -1,14 +0,0 @@
|
||||
==========================================
|
||||
Thread CPU Summary (avg + max over run)
|
||||
==========================================
|
||||
Run timestamp (UTC): 20260401_154500
|
||||
Duration: 600s, Interval: 10s
|
||||
|
||||
2040140" unknown 55.45 100.30
|
||||
2040152" unknown 0.08 0.40
|
||||
2040150" unknown 0.07 0.40
|
||||
2040151" unknown 0.06 0.30
|
||||
2040153" unknown 0.06 0.30
|
||||
2040155" unknown 0.01 0.20
|
||||
2040154" unknown 0.00 0.10
|
||||
TID THREAD AVG_CPU% MAX_CPU%
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -1,5 +0,0 @@
|
||||
Profiling PID: 2040140
|
||||
CLK_TCK=100
|
||||
Starting perf record in background...
|
||||
perf_pid=2046339
|
||||
Done. Artifacts in /tmp/c_relay_thread_profile_20260401_155603
|
||||
@@ -1,372 +0,0 @@
|
||||
timestamp,tid,thread_name,cpu_pct,delta_ticks,total_ticks
|
||||
1775058964,2040140,lws-main,0.00,0,42849
|
||||
1775058964,2040150,db-read-1,0.00,0,58
|
||||
1775058964,2040151,db-read-2,0.00,0,54
|
||||
1775058964,2040152,db-read-3,0.10,1,68
|
||||
1775058964,2040153,db-read-4,0.00,0,53
|
||||
1775058964,2040154,db-write,0.00,0,2
|
||||
1775058964,2040155,event-worker,0.00,0,5
|
||||
1775058974,2040140,lws-main,59.30,593,43442
|
||||
1775058974,2040150,db-read-1,0.00,0,58
|
||||
1775058974,2040151,db-read-2,0.00,0,54
|
||||
1775058974,2040152,db-read-3,0.10,1,69
|
||||
1775058974,2040153,db-read-4,0.00,0,53
|
||||
1775058974,2040154,db-write,0.00,0,2
|
||||
1775058974,2040155,event-worker,0.00,0,5
|
||||
1775058984,2040140,lws-main,67.40,674,44116
|
||||
1775058984,2040150,db-read-1,0.00,0,58
|
||||
1775058984,2040151,db-read-2,0.00,0,54
|
||||
1775058984,2040152,db-read-3,0.00,0,69
|
||||
1775058984,2040153,db-read-4,0.10,1,54
|
||||
1775058984,2040154,db-write,0.00,0,2
|
||||
1775058984,2040155,event-worker,0.00,0,5
|
||||
1775058994,2040140,lws-main,98.70,987,45103
|
||||
1775058994,2040150,db-read-1,0.10,1,59
|
||||
1775058994,2040151,db-read-2,0.00,0,54
|
||||
1775058994,2040152,db-read-3,0.00,0,69
|
||||
1775058994,2040153,db-read-4,0.00,0,54
|
||||
1775058994,2040154,db-write,0.00,0,2
|
||||
1775058994,2040155,event-worker,0.00,0,5
|
||||
1775059004,2040140,lws-main,71.00,710,45813
|
||||
1775059004,2040150,db-read-1,0.00,0,59
|
||||
1775059004,2040151,db-read-2,0.00,0,54
|
||||
1775059004,2040152,db-read-3,0.10,1,70
|
||||
1775059004,2040153,db-read-4,0.10,1,55
|
||||
1775059004,2040154,db-write,0.00,0,2
|
||||
1775059004,2040155,event-worker,0.00,0,5
|
||||
1775059014,2040140,lws-main,14.70,147,45960
|
||||
1775059014,2040150,db-read-1,0.10,1,60
|
||||
1775059014,2040151,db-read-2,0.30,3,57
|
||||
1775059014,2040152,db-read-3,0.10,1,71
|
||||
1775059014,2040153,db-read-4,0.10,1,56
|
||||
1775059014,2040154,db-write,0.00,0,2
|
||||
1775059014,2040155,event-worker,0.00,0,5
|
||||
1775059024,2040140,lws-main,47.70,477,46437
|
||||
1775059024,2040150,db-read-1,0.00,0,60
|
||||
1775059024,2040151,db-read-2,0.00,0,57
|
||||
1775059024,2040152,db-read-3,0.00,0,71
|
||||
1775059024,2040153,db-read-4,0.00,0,56
|
||||
1775059024,2040154,db-write,0.00,0,2
|
||||
1775059024,2040155,event-worker,0.00,0,5
|
||||
1775059034,2040140,lws-main,99.50,995,47432
|
||||
1775059034,2040150,db-read-1,0.10,1,61
|
||||
1775059034,2040151,db-read-2,0.10,1,58
|
||||
1775059034,2040152,db-read-3,0.10,1,72
|
||||
1775059034,2040153,db-read-4,0.00,0,56
|
||||
1775059034,2040154,db-write,0.10,1,3
|
||||
1775059034,2040155,event-worker,0.00,0,5
|
||||
1775059044,2040140,lws-main,88.50,885,48317
|
||||
1775059044,2040150,db-read-1,0.20,2,63
|
||||
1775059044,2040151,db-read-2,0.10,1,59
|
||||
1775059044,2040152,db-read-3,0.10,1,73
|
||||
1775059044,2040153,db-read-4,0.20,2,58
|
||||
1775059044,2040154,db-write,0.00,0,3
|
||||
1775059044,2040155,event-worker,0.00,0,5
|
||||
1775059054,2040140,lws-main,67.70,677,48994
|
||||
1775059054,2040150,db-read-1,0.00,0,63
|
||||
1775059054,2040151,db-read-2,0.00,0,59
|
||||
1775059054,2040152,db-read-3,0.00,0,73
|
||||
1775059054,2040153,db-read-4,0.00,0,58
|
||||
1775059054,2040154,db-write,0.00,0,3
|
||||
1775059054,2040155,event-worker,0.00,0,5
|
||||
1775059064,2040140,lws-main,53.10,531,49525
|
||||
1775059064,2040150,db-read-1,0.40,4,67
|
||||
1775059064,2040151,db-read-2,0.40,4,63
|
||||
1775059064,2040152,db-read-3,0.20,2,75
|
||||
1775059064,2040153,db-read-4,0.00,0,58
|
||||
1775059064,2040154,db-write,0.00,0,3
|
||||
1775059064,2040155,event-worker,0.00,0,5
|
||||
1775059074,2040140,lws-main,61.60,616,50141
|
||||
1775059074,2040150,db-read-1,0.30,3,70
|
||||
1775059074,2040151,db-read-2,0.20,2,65
|
||||
1775059074,2040152,db-read-3,0.10,1,76
|
||||
1775059074,2040153,db-read-4,0.20,2,60
|
||||
1775059074,2040154,db-write,0.00,0,3
|
||||
1775059074,2040155,event-worker,0.00,0,5
|
||||
1775059084,2040140,lws-main,96.20,962,51103
|
||||
1775059084,2040150,db-read-1,0.00,0,70
|
||||
1775059084,2040151,db-read-2,0.20,2,67
|
||||
1775059084,2040152,db-read-3,0.40,4,80
|
||||
1775059084,2040153,db-read-4,0.10,1,61
|
||||
1775059084,2040154,db-write,0.10,1,4
|
||||
1775059084,2040155,event-worker,0.00,0,5
|
||||
1775059094,2040140,lws-main,53.60,536,51639
|
||||
1775059094,2040150,db-read-1,0.10,1,71
|
||||
1775059094,2040151,db-read-2,0.20,2,69
|
||||
1775059094,2040152,db-read-3,0.00,0,80
|
||||
1775059094,2040153,db-read-4,0.00,0,61
|
||||
1775059094,2040154,db-write,0.00,0,4
|
||||
1775059094,2040155,event-worker,0.00,0,5
|
||||
1775059105,2040140,lws-main,51.40,514,52153
|
||||
1775059105,2040150,db-read-1,0.10,1,72
|
||||
1775059105,2040151,db-read-2,0.00,0,69
|
||||
1775059105,2040152,db-read-3,0.00,0,80
|
||||
1775059105,2040153,db-read-4,0.10,1,62
|
||||
1775059105,2040154,db-write,0.00,0,4
|
||||
1775059105,2040155,event-worker,0.00,0,5
|
||||
1775059115,2040140,lws-main,78.50,785,52938
|
||||
1775059115,2040150,db-read-1,0.00,0,72
|
||||
1775059115,2040151,db-read-2,0.00,0,69
|
||||
1775059115,2040152,db-read-3,0.00,0,80
|
||||
1775059115,2040153,db-read-4,0.00,0,62
|
||||
1775059115,2040154,db-write,0.00,0,4
|
||||
1775059115,2040155,event-worker,0.00,0,5
|
||||
1775059125,2040140,lws-main,40.70,407,53345
|
||||
1775059125,2040150,db-read-1,0.00,0,72
|
||||
1775059125,2040151,db-read-2,0.00,0,69
|
||||
1775059125,2040152,db-read-3,0.10,1,81
|
||||
1775059125,2040153,db-read-4,0.10,1,63
|
||||
1775059125,2040154,db-write,0.00,0,4
|
||||
1775059125,2040155,event-worker,0.00,0,5
|
||||
1775059135,2040140,lws-main,41.00,410,53755
|
||||
1775059135,2040150,db-read-1,0.00,0,72
|
||||
1775059135,2040151,db-read-2,0.00,0,69
|
||||
1775059135,2040152,db-read-3,0.00,0,81
|
||||
1775059135,2040153,db-read-4,0.00,0,63
|
||||
1775059135,2040154,db-write,0.00,0,4
|
||||
1775059135,2040155,event-worker,0.00,0,5
|
||||
1775059145,2040140,lws-main,58.70,587,54342
|
||||
1775059145,2040150,db-read-1,0.00,0,72
|
||||
1775059145,2040151,db-read-2,0.00,0,69
|
||||
1775059145,2040152,db-read-3,0.00,0,81
|
||||
1775059145,2040153,db-read-4,0.00,0,63
|
||||
1775059145,2040154,db-write,0.00,0,4
|
||||
1775059145,2040155,event-worker,0.00,0,5
|
||||
1775059155,2040140,lws-main,28.40,284,54626
|
||||
1775059155,2040150,db-read-1,0.20,2,74
|
||||
1775059155,2040151,db-read-2,0.20,2,71
|
||||
1775059155,2040152,db-read-3,0.10,1,82
|
||||
1775059155,2040153,db-read-4,0.10,1,64
|
||||
1775059155,2040154,db-write,0.00,0,4
|
||||
1775059155,2040155,event-worker,0.00,0,5
|
||||
1775059165,2040140,lws-main,89.80,898,55524
|
||||
1775059165,2040150,db-read-1,0.30,3,77
|
||||
1775059165,2040151,db-read-2,0.20,2,73
|
||||
1775059165,2040152,db-read-3,0.30,3,85
|
||||
1775059165,2040153,db-read-4,0.10,1,65
|
||||
1775059165,2040154,db-write,0.00,0,4
|
||||
1775059165,2040155,event-worker,0.00,0,5
|
||||
1775059175,2040140,lws-main,100.20,1002,56526
|
||||
1775059175,2040150,db-read-1,0.00,0,77
|
||||
1775059175,2040151,db-read-2,0.00,0,73
|
||||
1775059175,2040152,db-read-3,0.10,1,86
|
||||
1775059175,2040153,db-read-4,0.20,2,67
|
||||
1775059175,2040154,db-write,0.00,0,4
|
||||
1775059175,2040155,event-worker,0.00,0,5
|
||||
1775059185,2040140,lws-main,100.20,1002,57528
|
||||
1775059185,2040150,db-read-1,0.20,2,79
|
||||
1775059185,2040151,db-read-2,0.20,2,75
|
||||
1775059185,2040152,db-read-3,0.10,1,87
|
||||
1775059185,2040153,db-read-4,0.20,2,69
|
||||
1775059185,2040154,db-write,0.00,0,4
|
||||
1775059185,2040155,event-worker,0.00,0,5
|
||||
1775059195,2040140,lws-main,75.70,757,58285
|
||||
1775059195,2040150,db-read-1,0.20,2,81
|
||||
1775059195,2040151,db-read-2,0.20,2,77
|
||||
1775059195,2040152,db-read-3,0.20,2,89
|
||||
1775059195,2040153,db-read-4,0.20,2,71
|
||||
1775059195,2040154,db-write,0.00,0,4
|
||||
1775059195,2040155,event-worker,0.00,0,5
|
||||
1775059205,2040140,lws-main,77.70,777,59062
|
||||
1775059205,2040150,db-read-1,0.20,2,83
|
||||
1775059205,2040151,db-read-2,0.30,3,80
|
||||
1775059205,2040152,db-read-3,0.50,5,94
|
||||
1775059205,2040153,db-read-4,0.30,3,74
|
||||
1775059205,2040154,db-write,0.00,0,4
|
||||
1775059205,2040155,event-worker,0.10,1,6
|
||||
1775059215,2040140,lws-main,99.60,996,60058
|
||||
1775059215,2040150,db-read-1,0.40,4,87
|
||||
1775059215,2040151,db-read-2,0.40,4,84
|
||||
1775059215,2040152,db-read-3,0.10,1,95
|
||||
1775059215,2040153,db-read-4,0.20,2,76
|
||||
1775059215,2040154,db-write,0.00,0,4
|
||||
1775059215,2040155,event-worker,0.00,0,6
|
||||
1775059225,2040140,lws-main,100.30,1003,61061
|
||||
1775059225,2040150,db-read-1,0.00,0,87
|
||||
1775059225,2040151,db-read-2,0.10,1,85
|
||||
1775059225,2040152,db-read-3,0.10,1,96
|
||||
1775059225,2040153,db-read-4,0.20,2,78
|
||||
1775059225,2040154,db-write,0.00,0,4
|
||||
1775059225,2040155,event-worker,0.00,0,6
|
||||
1775059235,2040140,lws-main,100.10,1001,62062
|
||||
1775059235,2040150,db-read-1,0.10,1,88
|
||||
1775059235,2040151,db-read-2,0.00,0,85
|
||||
1775059235,2040152,db-read-3,0.00,0,96
|
||||
1775059235,2040153,db-read-4,0.00,0,78
|
||||
1775059235,2040154,db-write,0.00,0,4
|
||||
1775059235,2040155,event-worker,0.00,0,6
|
||||
1775059245,2040140,lws-main,98.10,981,63043
|
||||
1775059245,2040150,db-read-1,0.10,1,89
|
||||
1775059245,2040151,db-read-2,0.00,0,85
|
||||
1775059245,2040152,db-read-3,0.20,2,98
|
||||
1775059245,2040153,db-read-4,0.10,1,79
|
||||
1775059245,2040154,db-write,0.00,0,4
|
||||
1775059245,2040155,event-worker,0.00,0,6
|
||||
1775059255,2040140,lws-main,54.10,541,63584
|
||||
1775059255,2040150,db-read-1,0.20,2,91
|
||||
1775059255,2040151,db-read-2,0.50,5,90
|
||||
1775059255,2040152,db-read-3,0.50,5,103
|
||||
1775059255,2040153,db-read-4,0.50,5,84
|
||||
1775059255,2040154,db-write,0.00,0,4
|
||||
1775059255,2040155,event-worker,0.00,0,6
|
||||
1775059265,2040140,lws-main,82.80,828,64412
|
||||
1775059265,2040150,db-read-1,0.00,0,91
|
||||
1775059265,2040151,db-read-2,0.00,0,90
|
||||
1775059265,2040152,db-read-3,0.00,0,103
|
||||
1775059265,2040153,db-read-4,0.00,0,84
|
||||
1775059265,2040154,db-write,0.00,0,4
|
||||
1775059265,2040155,event-worker,0.00,0,6
|
||||
1775059275,2040140,lws-main,99.90,999,65411
|
||||
1775059275,2040150,db-read-1,0.10,1,92
|
||||
1775059275,2040151,db-read-2,0.00,0,90
|
||||
1775059275,2040152,db-read-3,0.00,0,103
|
||||
1775059275,2040153,db-read-4,0.00,0,84
|
||||
1775059275,2040154,db-write,0.00,0,4
|
||||
1775059275,2040155,event-worker,0.00,0,6
|
||||
1775059285,2040140,lws-main,58.30,583,65994
|
||||
1775059285,2040150,db-read-1,0.00,0,92
|
||||
1775059285,2040151,db-read-2,0.10,1,91
|
||||
1775059285,2040152,db-read-3,0.10,1,104
|
||||
1775059285,2040153,db-read-4,0.00,0,84
|
||||
1775059285,2040154,db-write,0.00,0,4
|
||||
1775059285,2040155,event-worker,0.00,0,6
|
||||
1775059295,2040140,lws-main,42.60,426,66420
|
||||
1775059295,2040150,db-read-1,0.30,3,95
|
||||
1775059295,2040151,db-read-2,0.10,1,92
|
||||
1775059295,2040152,db-read-3,0.10,1,105
|
||||
1775059295,2040153,db-read-4,0.20,2,86
|
||||
1775059295,2040154,db-write,0.00,0,4
|
||||
1775059295,2040155,event-worker,0.00,0,6
|
||||
1775059305,2040140,lws-main,16.20,162,66582
|
||||
1775059305,2040150,db-read-1,0.20,2,97
|
||||
1775059305,2040151,db-read-2,0.00,0,92
|
||||
1775059305,2040152,db-read-3,0.10,1,106
|
||||
1775059305,2040153,db-read-4,0.10,1,87
|
||||
1775059305,2040154,db-write,0.00,0,4
|
||||
1775059305,2040155,event-worker,0.00,0,6
|
||||
1775059315,2040140,lws-main,100.30,1003,67585
|
||||
1775059315,2040150,db-read-1,0.00,0,97
|
||||
1775059315,2040151,db-read-2,0.00,0,92
|
||||
1775059315,2040152,db-read-3,0.00,0,106
|
||||
1775059315,2040153,db-read-4,0.00,0,87
|
||||
1775059315,2040154,db-write,0.00,0,4
|
||||
1775059315,2040155,event-worker,0.00,0,6
|
||||
1775059325,2040140,lws-main,66.00,660,68245
|
||||
1775059325,2040150,db-read-1,0.20,2,99
|
||||
1775059325,2040151,db-read-2,0.50,5,97
|
||||
1775059325,2040152,db-read-3,0.20,2,108
|
||||
1775059325,2040153,db-read-4,0.20,2,89
|
||||
1775059325,2040154,db-write,0.00,0,4
|
||||
1775059325,2040155,event-worker,0.00,0,6
|
||||
1775059335,2040140,lws-main,21.70,217,68462
|
||||
1775059335,2040150,db-read-1,0.00,0,99
|
||||
1775059335,2040151,db-read-2,0.00,0,97
|
||||
1775059335,2040152,db-read-3,0.00,0,108
|
||||
1775059335,2040153,db-read-4,0.00,0,89
|
||||
1775059335,2040154,db-write,0.00,0,4
|
||||
1775059335,2040155,event-worker,0.00,0,6
|
||||
1775059345,2040140,lws-main,47.00,470,68932
|
||||
1775059345,2040150,db-read-1,0.30,3,102
|
||||
1775059345,2040151,db-read-2,0.30,3,100
|
||||
1775059345,2040152,db-read-3,0.90,9,117
|
||||
1775059345,2040153,db-read-4,0.20,2,91
|
||||
1775059345,2040154,db-write,0.00,0,4
|
||||
1775059345,2040155,event-worker,0.00,0,6
|
||||
1775059355,2040140,lws-main,54.40,544,69476
|
||||
1775059355,2040150,db-read-1,0.00,0,102
|
||||
1775059355,2040151,db-read-2,0.00,0,100
|
||||
1775059355,2040152,db-read-3,0.00,0,117
|
||||
1775059355,2040153,db-read-4,0.00,0,91
|
||||
1775059355,2040154,db-write,0.00,0,4
|
||||
1775059355,2040155,event-worker,0.00,0,6
|
||||
1775059365,2040140,lws-main,99.70,997,70473
|
||||
1775059365,2040150,db-read-1,0.10,1,103
|
||||
1775059365,2040151,db-read-2,0.10,1,101
|
||||
1775059365,2040152,db-read-3,0.00,0,117
|
||||
1775059365,2040153,db-read-4,0.00,0,91
|
||||
1775059365,2040154,db-write,0.00,0,4
|
||||
1775059365,2040155,event-worker,0.00,0,6
|
||||
1775059375,2040140,lws-main,46.20,462,70935
|
||||
1775059375,2040150,db-read-1,0.20,2,105
|
||||
1775059375,2040151,db-read-2,0.10,1,102
|
||||
1775059375,2040152,db-read-3,0.40,4,121
|
||||
1775059375,2040153,db-read-4,0.20,2,93
|
||||
1775059375,2040154,db-write,0.00,0,4
|
||||
1775059375,2040155,event-worker,0.00,0,6
|
||||
1775059385,2040140,lws-main,69.00,690,71625
|
||||
1775059385,2040150,db-read-1,0.10,1,106
|
||||
1775059385,2040151,db-read-2,0.00,0,102
|
||||
1775059385,2040152,db-read-3,0.10,1,122
|
||||
1775059385,2040153,db-read-4,0.10,1,94
|
||||
1775059385,2040154,db-write,0.00,0,4
|
||||
1775059385,2040155,event-worker,0.00,0,6
|
||||
1775059395,2040140,lws-main,71.50,715,72340
|
||||
1775059395,2040150,db-read-1,0.00,0,106
|
||||
1775059395,2040151,db-read-2,0.20,2,104
|
||||
1775059395,2040152,db-read-3,0.10,1,123
|
||||
1775059395,2040153,db-read-4,0.30,3,97
|
||||
1775059395,2040154,db-write,0.00,0,4
|
||||
1775059395,2040155,event-worker,0.00,0,6
|
||||
1775059405,2040140,lws-main,100.10,1001,73341
|
||||
1775059405,2040150,db-read-1,0.20,2,108
|
||||
1775059405,2040151,db-read-2,0.00,0,104
|
||||
1775059405,2040152,db-read-3,0.00,0,123
|
||||
1775059405,2040153,db-read-4,0.20,2,99
|
||||
1775059405,2040154,db-write,0.00,0,4
|
||||
1775059405,2040155,event-worker,0.00,0,6
|
||||
1775059415,2040140,lws-main,100.20,1002,74343
|
||||
1775059415,2040150,db-read-1,0.30,3,111
|
||||
1775059415,2040151,db-read-2,0.20,2,106
|
||||
1775059415,2040152,db-read-3,0.20,2,125
|
||||
1775059415,2040153,db-read-4,0.30,3,102
|
||||
1775059415,2040154,db-write,0.10,1,5
|
||||
1775059415,2040155,event-worker,0.00,0,6
|
||||
1775059425,2040140,lws-main,97.40,974,75317
|
||||
1775059425,2040150,db-read-1,0.10,1,112
|
||||
1775059425,2040151,db-read-2,0.10,1,107
|
||||
1775059425,2040152,db-read-3,0.30,3,128
|
||||
1775059425,2040153,db-read-4,0.10,1,103
|
||||
1775059425,2040154,db-write,0.00,0,5
|
||||
1775059425,2040155,event-worker,0.00,0,6
|
||||
1775059435,2040140,lws-main,80.60,806,76123
|
||||
1775059435,2040150,db-read-1,0.10,1,113
|
||||
1775059435,2040151,db-read-2,0.20,2,109
|
||||
1775059435,2040152,db-read-3,0.10,1,129
|
||||
1775059435,2040153,db-read-4,0.10,1,104
|
||||
1775059435,2040154,db-write,0.00,0,5
|
||||
1775059435,2040155,event-worker,0.00,0,6
|
||||
1775059445,2040140,lws-main,40.70,407,76530
|
||||
1775059445,2040150,db-read-1,0.10,1,114
|
||||
1775059445,2040151,db-read-2,0.00,0,109
|
||||
1775059445,2040152,db-read-3,0.20,2,131
|
||||
1775059445,2040153,db-read-4,0.10,1,105
|
||||
1775059445,2040154,db-write,0.00,0,5
|
||||
1775059445,2040155,event-worker,0.00,0,6
|
||||
1775059456,2040140,lws-main,56.00,560,77090
|
||||
1775059456,2040150,db-read-1,0.00,0,114
|
||||
1775059456,2040151,db-read-2,0.20,2,111
|
||||
1775059456,2040152,db-read-3,0.00,0,131
|
||||
1775059456,2040153,db-read-4,0.10,1,106
|
||||
1775059456,2040154,db-write,0.00,0,5
|
||||
1775059456,2040155,event-worker,0.00,0,6
|
||||
1775059466,2040140,lws-main,53.20,532,77622
|
||||
1775059466,2040150,db-read-1,0.00,0,114
|
||||
1775059466,2040151,db-read-2,0.00,0,111
|
||||
1775059466,2040152,db-read-3,0.00,0,131
|
||||
1775059466,2040153,db-read-4,0.00,0,106
|
||||
1775059466,2040154,db-write,0.00,0,5
|
||||
1775059466,2040155,event-worker,0.00,0,6
|
||||
1775059476,2040140,lws-main,96.70,967,78589
|
||||
1775059476,2040150,db-read-1,0.00,0,114
|
||||
1775059476,2040151,db-read-2,0.00,0,111
|
||||
1775059476,2040152,db-read-3,0.00,0,131
|
||||
1775059476,2040153,db-read-4,0.00,0,106
|
||||
1775059476,2040154,db-write,0.00,0,5
|
||||
1775059476,2040155,event-worker,0.00,0,6
|
||||
1775059486,2040140,lws-main,67.60,676,79265
|
||||
1775059486,2040150,db-read-1,0.20,2,116
|
||||
1775059486,2040151,db-read-2,0.00,0,111
|
||||
1775059486,2040152,db-read-3,0.00,0,131
|
||||
1775059486,2040153,db-read-4,0.00,0,106
|
||||
1775059486,2040154,db-write,0.00,0,5
|
||||
1775059486,2040155,event-worker,0.00,0,6
|
||||
|
@@ -1,14 +0,0 @@
|
||||
==========================================
|
||||
Thread CPU Summary (avg + max over run)
|
||||
==========================================
|
||||
Run timestamp (UTC): 20260401_155603
|
||||
Duration: 600s, Interval: 10s
|
||||
|
||||
2040140 lws-main 68.71 100.30
|
||||
2040152 db-read-3 0.12 0.90
|
||||
2040150 db-read-1 0.11 0.40
|
||||
2040151 db-read-2 0.11 0.50
|
||||
2040153 db-read-4 0.10 0.50
|
||||
2040154 db-write 0.01 0.10
|
||||
2040155 event-worker 0.00 0.10
|
||||
TID THREAD AVG_CPU% MAX_CPU%
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +0,0 @@
|
||||
Profiling PID: 2083904
|
||||
CLK_TCK=100
|
||||
Starting perf record in background...
|
||||
perf_pid=2086924
|
||||
Done. Artifacts in /tmp/c_relay_thread_profile_20260401_181751
|
||||
@@ -1,211 +0,0 @@
|
||||
timestamp,tid,thread_name,cpu_pct,delta_ticks,total_ticks
|
||||
1775067472,2083904,lws-main,0.00,0,17710
|
||||
1775067472,2083906,db-read-1,0.00,0,33
|
||||
1775067472,2083907,db-read-2,0.00,0,29
|
||||
1775067472,2083908,db-read-3,0.00,0,31
|
||||
1775067472,2083909,db-read-4,0.00,0,41
|
||||
1775067472,2083910,db-write,0.00,0,0
|
||||
1775067472,2083911,event-worker,0.00,0,0
|
||||
1775067482,2083904,lws-main,53.40,534,18244
|
||||
1775067482,2083906,db-read-1,0.20,2,35
|
||||
1775067482,2083907,db-read-2,0.00,0,29
|
||||
1775067482,2083908,db-read-3,0.10,1,32
|
||||
1775067482,2083909,db-read-4,0.00,0,41
|
||||
1775067482,2083910,db-write,0.00,0,0
|
||||
1775067482,2083911,event-worker,0.00,0,0
|
||||
1775067492,2083904,lws-main,100.30,1003,19247
|
||||
1775067492,2083906,db-read-1,0.00,0,35
|
||||
1775067492,2083907,db-read-2,0.00,0,29
|
||||
1775067492,2083908,db-read-3,0.00,0,32
|
||||
1775067492,2083909,db-read-4,0.00,0,41
|
||||
1775067492,2083910,db-write,0.00,0,0
|
||||
1775067492,2083911,event-worker,0.00,0,0
|
||||
1775067502,2083904,lws-main,100.30,1003,20250
|
||||
1775067502,2083906,db-read-1,0.00,0,35
|
||||
1775067502,2083907,db-read-2,0.00,0,29
|
||||
1775067502,2083908,db-read-3,0.00,0,32
|
||||
1775067502,2083909,db-read-4,0.00,0,41
|
||||
1775067502,2083910,db-write,0.00,0,0
|
||||
1775067502,2083911,event-worker,0.00,0,0
|
||||
1775067512,2083904,lws-main,95.70,957,21207
|
||||
1775067512,2083906,db-read-1,0.00,0,35
|
||||
1775067512,2083907,db-read-2,0.10,1,30
|
||||
1775067512,2083908,db-read-3,0.00,0,32
|
||||
1775067512,2083909,db-read-4,0.00,0,41
|
||||
1775067512,2083910,db-write,0.00,0,0
|
||||
1775067512,2083911,event-worker,0.00,0,0
|
||||
1775067522,2083904,lws-main,73.70,737,21944
|
||||
1775067522,2083906,db-read-1,0.00,0,35
|
||||
1775067522,2083907,db-read-2,0.00,0,30
|
||||
1775067522,2083908,db-read-3,0.00,0,32
|
||||
1775067522,2083909,db-read-4,0.00,0,41
|
||||
1775067522,2083910,db-write,0.00,0,0
|
||||
1775067522,2083911,event-worker,0.00,0,0
|
||||
1775067532,2083904,lws-main,9.80,98,22042
|
||||
1775067532,2083906,db-read-1,0.00,0,35
|
||||
1775067532,2083907,db-read-2,0.00,0,30
|
||||
1775067532,2083908,db-read-3,0.10,1,33
|
||||
1775067532,2083909,db-read-4,0.10,1,42
|
||||
1775067532,2083910,db-write,0.00,0,0
|
||||
1775067532,2083911,event-worker,0.00,0,0
|
||||
1775067542,2083904,lws-main,28.80,288,22330
|
||||
1775067542,2083906,db-read-1,0.20,2,37
|
||||
1775067542,2083907,db-read-2,0.40,4,34
|
||||
1775067542,2083908,db-read-3,0.10,1,34
|
||||
1775067542,2083909,db-read-4,0.20,2,44
|
||||
1775067542,2083910,db-write,0.00,0,0
|
||||
1775067542,2083911,event-worker,0.00,0,0
|
||||
1775067552,2083904,lws-main,37.80,378,22708
|
||||
1775067552,2083906,db-read-1,0.20,2,39
|
||||
1775067552,2083907,db-read-2,0.20,2,36
|
||||
1775067552,2083908,db-read-3,0.40,4,38
|
||||
1775067552,2083909,db-read-4,0.10,1,45
|
||||
1775067552,2083910,db-write,0.00,0,0
|
||||
1775067552,2083911,event-worker,0.00,0,0
|
||||
1775067563,2083904,lws-main,89.40,894,23602
|
||||
1775067563,2083906,db-read-1,0.00,0,39
|
||||
1775067563,2083907,db-read-2,0.10,1,37
|
||||
1775067563,2083908,db-read-3,0.00,0,38
|
||||
1775067563,2083909,db-read-4,0.10,1,46
|
||||
1775067563,2083910,db-write,0.00,0,0
|
||||
1775067563,2083911,event-worker,0.00,0,0
|
||||
1775067573,2083904,lws-main,99.50,995,24597
|
||||
1775067573,2083906,db-read-1,0.00,0,39
|
||||
1775067573,2083907,db-read-2,0.00,0,37
|
||||
1775067573,2083908,db-read-3,0.00,0,38
|
||||
1775067573,2083909,db-read-4,0.00,0,46
|
||||
1775067573,2083910,db-write,0.00,0,0
|
||||
1775067573,2083911,event-worker,0.00,0,0
|
||||
1775067583,2083904,lws-main,100.20,1002,25599
|
||||
1775067583,2083906,db-read-1,0.00,0,39
|
||||
1775067583,2083907,db-read-2,0.00,0,37
|
||||
1775067583,2083908,db-read-3,0.00,0,38
|
||||
1775067583,2083909,db-read-4,0.00,0,46
|
||||
1775067583,2083910,db-write,0.00,0,0
|
||||
1775067583,2083911,event-worker,0.00,0,0
|
||||
1775067593,2083904,lws-main,100.20,1002,26601
|
||||
1775067593,2083906,db-read-1,0.00,0,39
|
||||
1775067593,2083907,db-read-2,0.00,0,37
|
||||
1775067593,2083908,db-read-3,0.00,0,38
|
||||
1775067593,2083909,db-read-4,0.00,0,46
|
||||
1775067593,2083910,db-write,0.00,0,0
|
||||
1775067593,2083911,event-worker,0.00,0,0
|
||||
1775067603,2083904,lws-main,89.20,892,27493
|
||||
1775067603,2083906,db-read-1,0.60,6,45
|
||||
1775067603,2083907,db-read-2,0.20,2,39
|
||||
1775067603,2083908,db-read-3,0.40,4,42
|
||||
1775067603,2083909,db-read-4,0.60,6,52
|
||||
1775067603,2083910,db-write,0.00,0,0
|
||||
1775067603,2083911,event-worker,0.00,0,0
|
||||
1775067613,2083904,lws-main,76.10,761,28254
|
||||
1775067613,2083906,db-read-1,0.00,0,45
|
||||
1775067613,2083907,db-read-2,0.00,0,39
|
||||
1775067613,2083908,db-read-3,0.00,0,42
|
||||
1775067613,2083909,db-read-4,0.00,0,52
|
||||
1775067613,2083910,db-write,0.00,0,0
|
||||
1775067613,2083911,event-worker,0.00,0,0
|
||||
1775067623,2083904,lws-main,97.90,979,29233
|
||||
1775067623,2083906,db-read-1,0.10,1,46
|
||||
1775067623,2083907,db-read-2,0.20,2,41
|
||||
1775067623,2083908,db-read-3,0.00,0,42
|
||||
1775067623,2083909,db-read-4,0.00,0,52
|
||||
1775067623,2083910,db-write,0.00,0,0
|
||||
1775067623,2083911,event-worker,0.00,0,0
|
||||
1775067633,2083904,lws-main,45.40,454,29687
|
||||
1775067633,2083906,db-read-1,0.00,0,46
|
||||
1775067633,2083907,db-read-2,0.00,0,41
|
||||
1775067633,2083908,db-read-3,0.10,1,43
|
||||
1775067633,2083909,db-read-4,0.00,0,52
|
||||
1775067633,2083910,db-write,0.00,0,0
|
||||
1775067633,2083911,event-worker,0.00,0,0
|
||||
1775067643,2083904,lws-main,100.40,1004,30691
|
||||
1775067643,2083906,db-read-1,0.00,0,46
|
||||
1775067643,2083907,db-read-2,0.00,0,41
|
||||
1775067643,2083908,db-read-3,0.00,0,43
|
||||
1775067643,2083909,db-read-4,0.00,0,52
|
||||
1775067643,2083910,db-write,0.00,0,0
|
||||
1775067643,2083911,event-worker,0.00,0,0
|
||||
1775067653,2083904,lws-main,100.20,1002,31693
|
||||
1775067653,2083906,db-read-1,0.10,1,47
|
||||
1775067653,2083907,db-read-2,0.00,0,41
|
||||
1775067653,2083908,db-read-3,0.10,1,44
|
||||
1775067653,2083909,db-read-4,0.10,1,53
|
||||
1775067653,2083910,db-write,0.00,0,0
|
||||
1775067653,2083911,event-worker,0.00,0,0
|
||||
1775067663,2083904,lws-main,68.40,684,32377
|
||||
1775067663,2083906,db-read-1,0.10,1,48
|
||||
1775067663,2083907,db-read-2,0.20,2,43
|
||||
1775067663,2083908,db-read-3,0.10,1,45
|
||||
1775067663,2083909,db-read-4,0.10,1,54
|
||||
1775067663,2083910,db-write,0.00,0,0
|
||||
1775067663,2083911,event-worker,0.00,0,0
|
||||
1775067673,2083904,lws-main,29.60,296,32673
|
||||
1775067673,2083906,db-read-1,0.10,1,49
|
||||
1775067673,2083907,db-read-2,0.10,1,44
|
||||
1775067673,2083908,db-read-3,0.20,2,47
|
||||
1775067673,2083909,db-read-4,0.20,2,56
|
||||
1775067673,2083910,db-write,0.00,0,0
|
||||
1775067673,2083911,event-worker,0.00,0,0
|
||||
1775067683,2083904,lws-main,58.30,583,33256
|
||||
1775067683,2083906,db-read-1,0.40,4,53
|
||||
1775067683,2083907,db-read-2,0.40,4,48
|
||||
1775067683,2083908,db-read-3,0.40,4,51
|
||||
1775067683,2083909,db-read-4,0.60,6,62
|
||||
1775067683,2083910,db-write,0.00,0,0
|
||||
1775067683,2083911,event-worker,0.10,1,1
|
||||
1775067693,2083904,lws-main,52.90,529,33785
|
||||
1775067693,2083906,db-read-1,0.10,1,54
|
||||
1775067693,2083907,db-read-2,0.20,2,50
|
||||
1775067693,2083908,db-read-3,0.10,1,52
|
||||
1775067693,2083909,db-read-4,0.10,1,63
|
||||
1775067693,2083910,db-write,0.00,0,0
|
||||
1775067693,2083911,event-worker,0.00,0,1
|
||||
1775067703,2083904,lws-main,43.10,431,34216
|
||||
1775067703,2083906,db-read-1,0.10,1,55
|
||||
1775067703,2083907,db-read-2,0.00,0,50
|
||||
1775067703,2083908,db-read-3,0.00,0,52
|
||||
1775067703,2083909,db-read-4,0.10,1,64
|
||||
1775067703,2083910,db-write,0.00,0,0
|
||||
1775067703,2083911,event-worker,0.00,0,1
|
||||
1775067713,2083904,lws-main,60.20,602,34818
|
||||
1775067713,2083906,db-read-1,0.00,0,55
|
||||
1775067713,2083907,db-read-2,0.00,0,50
|
||||
1775067713,2083908,db-read-3,0.00,0,52
|
||||
1775067713,2083909,db-read-4,0.00,0,64
|
||||
1775067713,2083910,db-write,0.00,0,0
|
||||
1775067713,2083911,event-worker,0.00,0,1
|
||||
1775067723,2083904,lws-main,100.40,1004,35822
|
||||
1775067723,2083906,db-read-1,0.00,0,55
|
||||
1775067723,2083907,db-read-2,0.00,0,50
|
||||
1775067723,2083908,db-read-3,0.00,0,52
|
||||
1775067723,2083909,db-read-4,0.00,0,64
|
||||
1775067723,2083910,db-write,0.00,0,0
|
||||
1775067723,2083911,event-worker,0.00,0,1
|
||||
1775067733,2083904,lws-main,100.20,1002,36824
|
||||
1775067733,2083906,db-read-1,0.00,0,55
|
||||
1775067733,2083907,db-read-2,0.00,0,50
|
||||
1775067733,2083908,db-read-3,0.00,0,52
|
||||
1775067733,2083909,db-read-4,0.00,0,64
|
||||
1775067733,2083910,db-write,0.00,0,0
|
||||
1775067733,2083911,event-worker,0.00,0,1
|
||||
1775067743,2083904,lws-main,100.20,1002,37826
|
||||
1775067743,2083906,db-read-1,0.00,0,55
|
||||
1775067743,2083907,db-read-2,0.00,0,50
|
||||
1775067743,2083908,db-read-3,0.20,2,54
|
||||
1775067743,2083909,db-read-4,0.00,0,64
|
||||
1775067743,2083910,db-write,0.00,0,0
|
||||
1775067743,2083911,event-worker,0.00,0,1
|
||||
1775067753,2083904,lws-main,93.70,937,38763
|
||||
1775067753,2083906,db-read-1,0.20,2,57
|
||||
1775067753,2083907,db-read-2,0.20,2,52
|
||||
1775067753,2083908,db-read-3,0.10,1,55
|
||||
1775067753,2083909,db-read-4,0.20,2,66
|
||||
1775067753,2083910,db-write,0.10,1,1
|
||||
1775067753,2083911,event-worker,0.00,0,1
|
||||
1775067763,2083904,lws-main,100.10,1001,39764
|
||||
1775067763,2083906,db-read-1,0.00,0,57
|
||||
1775067763,2083907,db-read-2,0.00,0,52
|
||||
1775067763,2083908,db-read-3,0.00,0,55
|
||||
1775067763,2083909,db-read-4,0.00,0,66
|
||||
1775067763,2083910,db-write,0.00,0,1
|
||||
1775067763,2083911,event-worker,0.00,0,1
|
||||
|
@@ -1,14 +0,0 @@
|
||||
==========================================
|
||||
Thread CPU Summary (avg + max over run)
|
||||
==========================================
|
||||
Run timestamp (UTC): 20260401_181751
|
||||
Duration: 300s, Interval: 10s
|
||||
|
||||
2083904 lws-main 73.51 100.40
|
||||
2083906 db-read-1 0.08 0.60
|
||||
2083907 db-read-2 0.08 0.40
|
||||
2083908 db-read-3 0.08 0.40
|
||||
2083909 db-read-4 0.08 0.60
|
||||
2083910 db-write 0.00 0.10
|
||||
2083911 event-worker 0.00 0.10
|
||||
TID THREAD AVG_CPU% MAX_CPU%
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +0,0 @@
|
||||
Profiling PID: 2083904
|
||||
CLK_TCK=100
|
||||
Starting perf record in background...
|
||||
perf_pid=2094527
|
||||
Done. Artifacts in /tmp/c_relay_thread_profile_20260401_183846
|
||||
@@ -1,211 +0,0 @@
|
||||
timestamp,tid,thread_name,cpu_pct,delta_ticks,total_ticks
|
||||
1775068727,2083904,lws-main,0.20,2,102303
|
||||
1775068727,2083906,db-read-1,0.00,0,153
|
||||
1775068727,2083907,db-read-2,0.00,0,145
|
||||
1775068727,2083908,db-read-3,0.00,0,145
|
||||
1775068727,2083909,db-read-4,0.00,0,160
|
||||
1775068727,2083910,db-write,0.00,0,4
|
||||
1775068727,2083911,event-worker,0.00,0,11
|
||||
1775068737,2083904,lws-main,100.20,1002,103305
|
||||
1775068737,2083906,db-read-1,0.00,0,153
|
||||
1775068737,2083907,db-read-2,0.10,1,146
|
||||
1775068737,2083908,db-read-3,0.00,0,145
|
||||
1775068737,2083909,db-read-4,0.00,0,160
|
||||
1775068737,2083910,db-write,0.00,0,4
|
||||
1775068737,2083911,event-worker,0.00,0,11
|
||||
1775068747,2083904,lws-main,100.30,1003,104308
|
||||
1775068747,2083906,db-read-1,0.00,0,153
|
||||
1775068747,2083907,db-read-2,0.00,0,146
|
||||
1775068747,2083908,db-read-3,0.10,1,146
|
||||
1775068747,2083909,db-read-4,0.10,1,161
|
||||
1775068747,2083910,db-write,0.00,0,4
|
||||
1775068747,2083911,event-worker,0.00,0,11
|
||||
1775068757,2083904,lws-main,100.20,1002,105310
|
||||
1775068757,2083906,db-read-1,0.00,0,153
|
||||
1775068757,2083907,db-read-2,0.00,0,146
|
||||
1775068757,2083908,db-read-3,0.00,0,146
|
||||
1775068757,2083909,db-read-4,0.00,0,161
|
||||
1775068757,2083910,db-write,0.00,0,4
|
||||
1775068757,2083911,event-worker,0.00,0,11
|
||||
1775068767,2083904,lws-main,100.20,1002,106312
|
||||
1775068767,2083906,db-read-1,0.00,0,153
|
||||
1775068767,2083907,db-read-2,0.00,0,146
|
||||
1775068767,2083908,db-read-3,0.00,0,146
|
||||
1775068767,2083909,db-read-4,0.00,0,161
|
||||
1775068767,2083910,db-write,0.00,0,4
|
||||
1775068767,2083911,event-worker,0.00,0,11
|
||||
1775068777,2083904,lws-main,81.10,811,107123
|
||||
1775068777,2083906,db-read-1,0.00,0,153
|
||||
1775068777,2083907,db-read-2,0.00,0,146
|
||||
1775068777,2083908,db-read-3,0.10,1,147
|
||||
1775068777,2083909,db-read-4,0.00,0,161
|
||||
1775068777,2083910,db-write,0.00,0,4
|
||||
1775068777,2083911,event-worker,0.00,0,11
|
||||
1775068787,2083904,lws-main,7.40,74,107197
|
||||
1775068787,2083906,db-read-1,0.00,0,153
|
||||
1775068787,2083907,db-read-2,0.00,0,146
|
||||
1775068787,2083908,db-read-3,0.00,0,147
|
||||
1775068787,2083909,db-read-4,0.00,0,161
|
||||
1775068787,2083910,db-write,0.00,0,4
|
||||
1775068787,2083911,event-worker,0.00,0,11
|
||||
1775068797,2083904,lws-main,50.30,503,107700
|
||||
1775068797,2083906,db-read-1,0.30,3,156
|
||||
1775068797,2083907,db-read-2,0.30,3,149
|
||||
1775068797,2083908,db-read-3,0.30,3,150
|
||||
1775068797,2083909,db-read-4,0.20,2,163
|
||||
1775068797,2083910,db-write,0.00,0,4
|
||||
1775068797,2083911,event-worker,0.00,0,11
|
||||
1775068807,2083904,lws-main,58.00,580,108280
|
||||
1775068807,2083906,db-read-1,0.00,0,156
|
||||
1775068807,2083907,db-read-2,0.00,0,149
|
||||
1775068807,2083908,db-read-3,0.00,0,150
|
||||
1775068807,2083909,db-read-4,0.00,0,163
|
||||
1775068807,2083910,db-write,0.00,0,4
|
||||
1775068807,2083911,event-worker,0.00,0,11
|
||||
1775068818,2083904,lws-main,58.40,584,108864
|
||||
1775068818,2083906,db-read-1,0.10,1,157
|
||||
1775068818,2083907,db-read-2,0.10,1,150
|
||||
1775068818,2083908,db-read-3,0.10,1,151
|
||||
1775068818,2083909,db-read-4,0.30,3,166
|
||||
1775068818,2083910,db-write,0.00,0,4
|
||||
1775068818,2083911,event-worker,0.00,0,11
|
||||
1775068828,2083904,lws-main,43.30,433,109297
|
||||
1775068828,2083906,db-read-1,0.00,0,157
|
||||
1775068828,2083907,db-read-2,0.00,0,150
|
||||
1775068828,2083908,db-read-3,0.00,0,151
|
||||
1775068828,2083909,db-read-4,0.20,2,168
|
||||
1775068828,2083910,db-write,0.00,0,4
|
||||
1775068828,2083911,event-worker,0.20,2,13
|
||||
1775068838,2083904,lws-main,29.00,290,109587
|
||||
1775068838,2083906,db-read-1,0.20,2,159
|
||||
1775068838,2083907,db-read-2,0.00,0,150
|
||||
1775068838,2083908,db-read-3,0.10,1,152
|
||||
1775068838,2083909,db-read-4,0.00,0,168
|
||||
1775068838,2083910,db-write,0.00,0,4
|
||||
1775068838,2083911,event-worker,0.00,0,13
|
||||
1775068848,2083904,lws-main,37.00,370,109957
|
||||
1775068848,2083906,db-read-1,0.00,0,159
|
||||
1775068848,2083907,db-read-2,0.10,1,151
|
||||
1775068848,2083908,db-read-3,0.00,0,152
|
||||
1775068848,2083909,db-read-4,0.00,0,168
|
||||
1775068848,2083910,db-write,0.00,0,4
|
||||
1775068848,2083911,event-worker,0.00,0,13
|
||||
1775068858,2083904,lws-main,48.40,484,110441
|
||||
1775068858,2083906,db-read-1,0.10,1,160
|
||||
1775068858,2083907,db-read-2,0.10,1,152
|
||||
1775068858,2083908,db-read-3,0.10,1,153
|
||||
1775068858,2083909,db-read-4,0.20,2,170
|
||||
1775068858,2083910,db-write,0.00,0,4
|
||||
1775068858,2083911,event-worker,0.00,0,13
|
||||
1775068868,2083904,lws-main,45.00,450,110891
|
||||
1775068868,2083906,db-read-1,0.00,0,160
|
||||
1775068868,2083907,db-read-2,0.10,1,153
|
||||
1775068868,2083908,db-read-3,0.00,0,153
|
||||
1775068868,2083909,db-read-4,0.00,0,170
|
||||
1775068868,2083910,db-write,0.00,0,4
|
||||
1775068868,2083911,event-worker,0.00,0,13
|
||||
1775068878,2083904,lws-main,21.00,210,111101
|
||||
1775068878,2083906,db-read-1,0.00,0,160
|
||||
1775068878,2083907,db-read-2,0.00,0,153
|
||||
1775068878,2083908,db-read-3,0.00,0,153
|
||||
1775068878,2083909,db-read-4,0.00,0,170
|
||||
1775068878,2083910,db-write,0.00,0,4
|
||||
1775068878,2083911,event-worker,0.00,0,13
|
||||
1775068888,2083904,lws-main,36.40,364,111465
|
||||
1775068888,2083906,db-read-1,0.00,0,160
|
||||
1775068888,2083907,db-read-2,0.30,3,156
|
||||
1775068888,2083908,db-read-3,0.10,1,154
|
||||
1775068888,2083909,db-read-4,0.00,0,170
|
||||
1775068888,2083910,db-write,0.00,0,4
|
||||
1775068888,2083911,event-worker,0.00,0,13
|
||||
1775068898,2083904,lws-main,44.10,441,111906
|
||||
1775068898,2083906,db-read-1,0.00,0,160
|
||||
1775068898,2083907,db-read-2,0.00,0,156
|
||||
1775068898,2083908,db-read-3,0.00,0,154
|
||||
1775068898,2083909,db-read-4,0.00,0,170
|
||||
1775068898,2083910,db-write,0.00,0,4
|
||||
1775068898,2083911,event-worker,0.00,0,13
|
||||
1775068908,2083904,lws-main,19.70,197,112103
|
||||
1775068908,2083906,db-read-1,0.20,2,162
|
||||
1775068908,2083907,db-read-2,0.10,1,157
|
||||
1775068908,2083908,db-read-3,0.00,0,154
|
||||
1775068908,2083909,db-read-4,0.10,1,171
|
||||
1775068908,2083910,db-write,0.00,0,4
|
||||
1775068908,2083911,event-worker,0.00,0,13
|
||||
1775068918,2083904,lws-main,83.20,832,112935
|
||||
1775068918,2083906,db-read-1,0.30,3,165
|
||||
1775068918,2083907,db-read-2,0.30,3,160
|
||||
1775068918,2083908,db-read-3,0.20,2,156
|
||||
1775068918,2083909,db-read-4,0.20,2,173
|
||||
1775068918,2083910,db-write,0.00,0,4
|
||||
1775068918,2083911,event-worker,0.00,0,13
|
||||
1775068928,2083904,lws-main,37.40,374,113309
|
||||
1775068928,2083906,db-read-1,0.00,0,165
|
||||
1775068928,2083907,db-read-2,0.00,0,160
|
||||
1775068928,2083908,db-read-3,0.10,1,157
|
||||
1775068928,2083909,db-read-4,0.00,0,173
|
||||
1775068928,2083910,db-write,0.00,0,4
|
||||
1775068928,2083911,event-worker,0.00,0,13
|
||||
1775068938,2083904,lws-main,59.80,598,113907
|
||||
1775068938,2083906,db-read-1,0.00,0,165
|
||||
1775068938,2083907,db-read-2,0.00,0,160
|
||||
1775068938,2083908,db-read-3,0.10,1,158
|
||||
1775068938,2083909,db-read-4,0.00,0,173
|
||||
1775068938,2083910,db-write,0.00,0,4
|
||||
1775068938,2083911,event-worker,0.00,0,13
|
||||
1775068948,2083904,lws-main,61.20,612,114519
|
||||
1775068948,2083906,db-read-1,0.30,3,168
|
||||
1775068948,2083907,db-read-2,0.20,2,162
|
||||
1775068948,2083908,db-read-3,0.10,1,159
|
||||
1775068948,2083909,db-read-4,0.40,4,177
|
||||
1775068948,2083910,db-write,0.00,0,4
|
||||
1775068948,2083911,event-worker,0.10,1,14
|
||||
1775068958,2083904,lws-main,65.30,653,115172
|
||||
1775068958,2083906,db-read-1,0.00,0,168
|
||||
1775068958,2083907,db-read-2,0.10,1,163
|
||||
1775068958,2083908,db-read-3,0.10,1,160
|
||||
1775068958,2083909,db-read-4,0.20,2,179
|
||||
1775068958,2083910,db-write,0.00,0,4
|
||||
1775068958,2083911,event-worker,0.00,0,14
|
||||
1775068968,2083904,lws-main,23.00,230,115402
|
||||
1775068968,2083906,db-read-1,0.00,0,168
|
||||
1775068968,2083907,db-read-2,0.00,0,163
|
||||
1775068968,2083908,db-read-3,0.00,0,160
|
||||
1775068968,2083909,db-read-4,0.00,0,179
|
||||
1775068968,2083910,db-write,0.00,0,4
|
||||
1775068968,2083911,event-worker,0.00,0,14
|
||||
1775068978,2083904,lws-main,79.80,798,116200
|
||||
1775068978,2083906,db-read-1,0.40,4,172
|
||||
1775068978,2083907,db-read-2,0.10,1,164
|
||||
1775068978,2083908,db-read-3,0.10,1,161
|
||||
1775068978,2083909,db-read-4,0.20,2,181
|
||||
1775068978,2083910,db-write,0.00,0,4
|
||||
1775068978,2083911,event-worker,0.00,0,14
|
||||
1775068988,2083904,lws-main,70.70,707,116907
|
||||
1775068988,2083906,db-read-1,0.00,0,172
|
||||
1775068988,2083907,db-read-2,0.00,0,164
|
||||
1775068988,2083908,db-read-3,0.10,1,162
|
||||
1775068988,2083909,db-read-4,0.00,0,181
|
||||
1775068988,2083910,db-write,0.00,0,4
|
||||
1775068988,2083911,event-worker,0.00,0,14
|
||||
1775068998,2083904,lws-main,23.00,230,117137
|
||||
1775068998,2083906,db-read-1,0.00,0,172
|
||||
1775068998,2083907,db-read-2,0.00,0,164
|
||||
1775068998,2083908,db-read-3,0.00,0,162
|
||||
1775068998,2083909,db-read-4,0.00,0,181
|
||||
1775068998,2083910,db-write,0.00,0,4
|
||||
1775068998,2083911,event-worker,0.00,0,14
|
||||
1775069008,2083904,lws-main,66.00,660,117797
|
||||
1775069008,2083906,db-read-1,0.30,3,175
|
||||
1775069008,2083907,db-read-2,0.40,4,168
|
||||
1775069008,2083908,db-read-3,0.40,4,166
|
||||
1775069008,2083909,db-read-4,0.30,3,184
|
||||
1775069008,2083910,db-write,0.00,0,4
|
||||
1775069008,2083911,event-worker,0.00,0,14
|
||||
1775069018,2083904,lws-main,80.00,800,118597
|
||||
1775069018,2083906,db-read-1,0.00,0,175
|
||||
1775069018,2083907,db-read-2,0.00,0,168
|
||||
1775069018,2083908,db-read-3,0.00,0,166
|
||||
1775069018,2083909,db-read-4,0.00,0,184
|
||||
1775069018,2083910,db-write,0.00,0,4
|
||||
1775069018,2083911,event-worker,0.00,0,14
|
||||
|
@@ -1,14 +0,0 @@
|
||||
==========================================
|
||||
Thread CPU Summary (avg + max over run)
|
||||
==========================================
|
||||
Run timestamp (UTC): 20260401_183846
|
||||
Duration: 300s, Interval: 10s
|
||||
|
||||
2083904 lws-main 54.32 100.30
|
||||
2083907 db-read-2 0.08 0.40
|
||||
2083909 db-read-4 0.08 0.40
|
||||
2083906 db-read-1 0.07 0.40
|
||||
2083908 db-read-3 0.07 0.40
|
||||
2083911 event-worker 0.01 0.20
|
||||
2083910 db-write 0.00 0.00
|
||||
TID THREAD AVG_CPU% MAX_CPU%
|
||||
BIN
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
Profiling PID: 2224084
|
||||
CLK_TCK=100
|
||||
Starting perf record in background...
|
||||
perf_pid=2224152
|
||||
Done. Artifacts in /tmp/c_relay_thread_profile_20260402_002056
|
||||
@@ -0,0 +1,241 @@
|
||||
timestamp,tid,thread_name,cpu_pct,delta_ticks,total_ticks
|
||||
1775089257,2224084,lws-main,0.00,0,17
|
||||
1775089257,2224086,db-read-1,0.00,0,0
|
||||
1775089257,2224087,db-write,0.00,0,0
|
||||
1775089257,2224088,event-worker,0.00,0,0
|
||||
1775089262,2224084,lws-main,0.00,0,17
|
||||
1775089262,2224086,db-read-1,0.20,1,1
|
||||
1775089262,2224087,db-write,10.40,52,52
|
||||
1775089262,2224088,event-worker,0.00,0,0
|
||||
1775089267,2224084,lws-main,0.20,1,18
|
||||
1775089267,2224086,db-read-1,0.20,1,2
|
||||
1775089267,2224087,db-write,2.60,13,65
|
||||
1775089267,2224088,event-worker,0.00,0,0
|
||||
1775089272,2224084,lws-main,0.00,0,18
|
||||
1775089272,2224086,db-read-1,0.40,2,4
|
||||
1775089272,2224087,db-write,0.20,1,66
|
||||
1775089272,2224088,event-worker,0.00,0,0
|
||||
1775089277,2224084,lws-main,0.00,0,18
|
||||
1775089277,2224086,db-read-1,0.20,1,5
|
||||
1775089277,2224087,db-write,96.00,480,546
|
||||
1775089277,2224088,event-worker,0.00,0,0
|
||||
1775089282,2224084,lws-main,0.60,3,21
|
||||
1775089282,2224086,db-read-1,1.20,6,11
|
||||
1775089282,2224087,db-write,100.20,501,1047
|
||||
1775089282,2224088,event-worker,0.00,0,0
|
||||
1775089287,2224084,lws-main,1.00,5,26
|
||||
1775089287,2224086,db-read-1,1.00,5,16
|
||||
1775089287,2224087,db-write,100.00,500,1547
|
||||
1775089287,2224088,event-worker,0.00,0,0
|
||||
1775089292,2224084,lws-main,1.40,7,33
|
||||
1775089292,2224086,db-read-1,10.20,51,67
|
||||
1775089292,2224087,db-write,100.40,502,2049
|
||||
1775089292,2224088,event-worker,0.00,0,0
|
||||
1775089297,2224084,lws-main,0.40,2,35
|
||||
1775089297,2224086,db-read-1,1.20,6,73
|
||||
1775089297,2224087,db-write,100.40,502,2551
|
||||
1775089297,2224088,event-worker,0.00,0,0
|
||||
1775089302,2224084,lws-main,0.00,0,35
|
||||
1775089302,2224086,db-read-1,0.20,1,74
|
||||
1775089302,2224087,db-write,100.20,501,3052
|
||||
1775089302,2224088,event-worker,0.00,0,0
|
||||
1775089307,2224084,lws-main,0.20,1,36
|
||||
1775089307,2224086,db-read-1,0.00,0,74
|
||||
1775089307,2224087,db-write,100.20,501,3553
|
||||
1775089307,2224088,event-worker,0.00,0,0
|
||||
1775089312,2224084,lws-main,0.20,1,37
|
||||
1775089312,2224086,db-read-1,1.00,5,79
|
||||
1775089312,2224087,db-write,100.40,502,4055
|
||||
1775089312,2224088,event-worker,0.00,0,0
|
||||
1775089317,2224084,lws-main,0.00,0,37
|
||||
1775089317,2224086,db-read-1,0.40,2,81
|
||||
1775089317,2224087,db-write,100.20,501,4556
|
||||
1775089317,2224088,event-worker,0.00,0,0
|
||||
1775089322,2224084,lws-main,0.40,2,39
|
||||
1775089322,2224086,db-read-1,0.20,1,82
|
||||
1775089322,2224087,db-write,99.80,499,5055
|
||||
1775089322,2224088,event-worker,0.00,0,0
|
||||
1775089327,2224084,lws-main,0.00,0,39
|
||||
1775089327,2224086,db-read-1,0.00,0,82
|
||||
1775089327,2224087,db-write,100.20,501,5556
|
||||
1775089327,2224088,event-worker,0.00,0,0
|
||||
1775089332,2224084,lws-main,0.40,2,41
|
||||
1775089332,2224086,db-read-1,0.20,1,83
|
||||
1775089332,2224087,db-write,100.00,500,6056
|
||||
1775089332,2224088,event-worker,0.00,0,0
|
||||
1775089337,2224084,lws-main,0.00,0,41
|
||||
1775089337,2224086,db-read-1,0.20,1,84
|
||||
1775089337,2224087,db-write,100.20,501,6557
|
||||
1775089337,2224088,event-worker,0.00,0,0
|
||||
1775089343,2224084,lws-main,0.40,2,43
|
||||
1775089343,2224086,db-read-1,0.20,1,85
|
||||
1775089343,2224087,db-write,100.20,501,7058
|
||||
1775089343,2224088,event-worker,0.00,0,0
|
||||
1775089348,2224084,lws-main,0.00,0,43
|
||||
1775089348,2224086,db-read-1,0.20,1,86
|
||||
1775089348,2224087,db-write,100.00,500,7558
|
||||
1775089348,2224088,event-worker,0.00,0,0
|
||||
1775089353,2224084,lws-main,0.40,2,45
|
||||
1775089353,2224086,db-read-1,0.20,1,87
|
||||
1775089353,2224087,db-write,100.20,501,8059
|
||||
1775089353,2224088,event-worker,0.00,0,0
|
||||
1775089358,2224084,lws-main,0.20,1,46
|
||||
1775089358,2224086,db-read-1,0.20,1,88
|
||||
1775089358,2224087,db-write,100.20,501,8560
|
||||
1775089358,2224088,event-worker,0.00,0,0
|
||||
1775089363,2224084,lws-main,0.80,4,50
|
||||
1775089363,2224086,db-read-1,0.80,4,92
|
||||
1775089363,2224087,db-write,100.20,501,9061
|
||||
1775089363,2224088,event-worker,0.00,0,0
|
||||
1775089368,2224084,lws-main,0.20,1,51
|
||||
1775089368,2224086,db-read-1,0.60,3,95
|
||||
1775089368,2224087,db-write,100.20,501,9562
|
||||
1775089368,2224088,event-worker,0.00,0,0
|
||||
1775089373,2224084,lws-main,0.40,2,53
|
||||
1775089373,2224086,db-read-1,0.40,2,97
|
||||
1775089373,2224087,db-write,100.00,500,10062
|
||||
1775089373,2224088,event-worker,0.00,0,0
|
||||
1775089378,2224084,lws-main,0.00,0,53
|
||||
1775089378,2224086,db-read-1,0.20,1,98
|
||||
1775089378,2224087,db-write,67.40,337,10399
|
||||
1775089378,2224088,event-worker,0.00,0,0
|
||||
1775089383,2224084,lws-main,0.20,1,54
|
||||
1775089383,2224086,db-read-1,0.00,0,98
|
||||
1775089383,2224087,db-write,99.80,499,10898
|
||||
1775089383,2224088,event-worker,0.00,0,0
|
||||
1775089388,2224084,lws-main,0.20,1,55
|
||||
1775089388,2224086,db-read-1,0.20,1,99
|
||||
1775089388,2224087,db-write,99.80,499,11397
|
||||
1775089388,2224088,event-worker,0.00,0,0
|
||||
1775089393,2224084,lws-main,0.20,1,56
|
||||
1775089393,2224086,db-read-1,0.40,2,101
|
||||
1775089393,2224087,db-write,100.20,501,11898
|
||||
1775089393,2224088,event-worker,0.00,0,0
|
||||
1775089398,2224084,lws-main,0.20,1,57
|
||||
1775089398,2224086,db-read-1,0.00,0,101
|
||||
1775089398,2224087,db-write,44.00,220,12118
|
||||
1775089398,2224088,event-worker,0.00,0,0
|
||||
1775089403,2224084,lws-main,0.20,1,58
|
||||
1775089403,2224086,db-read-1,0.00,0,101
|
||||
1775089403,2224087,db-write,31.00,155,12273
|
||||
1775089403,2224088,event-worker,0.00,0,0
|
||||
1775089408,2224084,lws-main,0.00,0,58
|
||||
1775089408,2224086,db-read-1,0.00,0,101
|
||||
1775089408,2224087,db-write,8.80,44,12317
|
||||
1775089408,2224088,event-worker,0.00,0,0
|
||||
1775089413,2224084,lws-main,0.20,1,59
|
||||
1775089413,2224086,db-read-1,0.40,2,103
|
||||
1775089413,2224087,db-write,80.40,402,12719
|
||||
1775089413,2224088,event-worker,0.20,1,1
|
||||
1775089418,2224084,lws-main,0.20,1,60
|
||||
1775089418,2224086,db-read-1,0.00,0,103
|
||||
1775089418,2224087,db-write,37.20,186,12905
|
||||
1775089418,2224088,event-worker,0.00,0,1
|
||||
1775089423,2224084,lws-main,0.20,1,61
|
||||
1775089423,2224086,db-read-1,0.20,1,104
|
||||
1775089423,2224087,db-write,43.00,215,13120
|
||||
1775089423,2224088,event-worker,0.00,0,1
|
||||
1775089428,2224084,lws-main,0.00,0,61
|
||||
1775089428,2224086,db-read-1,0.00,0,104
|
||||
1775089428,2224087,db-write,14.80,74,13194
|
||||
1775089428,2224088,event-worker,0.00,0,1
|
||||
1775089433,2224084,lws-main,0.20,1,62
|
||||
1775089433,2224086,db-read-1,0.20,1,105
|
||||
1775089433,2224087,db-write,39.40,197,13391
|
||||
1775089433,2224088,event-worker,0.00,0,1
|
||||
1775089438,2224084,lws-main,0.20,1,63
|
||||
1775089438,2224086,db-read-1,0.80,4,109
|
||||
1775089438,2224087,db-write,100.20,501,13892
|
||||
1775089438,2224088,event-worker,0.00,0,1
|
||||
1775089443,2224084,lws-main,0.20,1,64
|
||||
1775089443,2224086,db-read-1,0.00,0,109
|
||||
1775089443,2224087,db-write,100.40,502,14394
|
||||
1775089443,2224088,event-worker,0.00,0,1
|
||||
1775089448,2224084,lws-main,0.20,1,65
|
||||
1775089448,2224086,db-read-1,0.00,0,109
|
||||
1775089448,2224087,db-write,100.00,500,14894
|
||||
1775089448,2224088,event-worker,0.00,0,1
|
||||
1775089453,2224084,lws-main,0.00,0,65
|
||||
1775089453,2224086,db-read-1,0.40,2,111
|
||||
1775089453,2224087,db-write,100.20,501,15395
|
||||
1775089453,2224088,event-worker,0.00,0,1
|
||||
1775089458,2224084,lws-main,0.20,1,66
|
||||
1775089458,2224086,db-read-1,0.60,3,114
|
||||
1775089458,2224087,db-write,84.00,420,15815
|
||||
1775089458,2224088,event-worker,0.00,0,1
|
||||
1775089463,2224084,lws-main,0.00,0,66
|
||||
1775089463,2224086,db-read-1,0.00,0,114
|
||||
1775089463,2224087,db-write,32.00,160,15975
|
||||
1775089463,2224088,event-worker,0.00,0,1
|
||||
1775089468,2224084,lws-main,0.20,1,67
|
||||
1775089468,2224086,db-read-1,0.20,1,115
|
||||
1775089468,2224087,db-write,7.80,39,16014
|
||||
1775089468,2224088,event-worker,0.00,0,1
|
||||
1775089473,2224084,lws-main,0.20,1,68
|
||||
1775089473,2224086,db-read-1,0.20,1,116
|
||||
1775089473,2224087,db-write,42.60,213,16227
|
||||
1775089473,2224088,event-worker,0.00,0,1
|
||||
1775089478,2224084,lws-main,0.20,1,69
|
||||
1775089478,2224086,db-read-1,0.20,1,117
|
||||
1775089478,2224087,db-write,63.00,315,16542
|
||||
1775089478,2224088,event-worker,0.00,0,1
|
||||
1775089483,2224084,lws-main,0.00,0,69
|
||||
1775089483,2224086,db-read-1,0.20,1,118
|
||||
1775089483,2224087,db-write,50.80,254,16796
|
||||
1775089483,2224088,event-worker,0.00,0,1
|
||||
1775089488,2224084,lws-main,0.20,1,70
|
||||
1775089488,2224086,db-read-1,0.20,1,119
|
||||
1775089488,2224087,db-write,93.80,469,17265
|
||||
1775089488,2224088,event-worker,0.00,0,1
|
||||
1775089493,2224084,lws-main,0.00,0,70
|
||||
1775089493,2224086,db-read-1,0.00,0,119
|
||||
1775089493,2224087,db-write,100.40,502,17767
|
||||
1775089493,2224088,event-worker,0.00,0,1
|
||||
1775089498,2224084,lws-main,0.20,1,71
|
||||
1775089498,2224086,db-read-1,0.20,1,120
|
||||
1775089498,2224087,db-write,100.40,502,18269
|
||||
1775089498,2224088,event-worker,0.00,0,1
|
||||
1775089503,2224084,lws-main,0.20,1,72
|
||||
1775089503,2224086,db-read-1,0.00,0,120
|
||||
1775089503,2224087,db-write,100.20,501,18770
|
||||
1775089503,2224088,event-worker,0.00,0,1
|
||||
1775089508,2224084,lws-main,0.00,0,72
|
||||
1775089508,2224086,db-read-1,0.60,3,123
|
||||
1775089508,2224087,db-write,100.20,501,19271
|
||||
1775089508,2224088,event-worker,0.00,0,1
|
||||
1775089513,2224084,lws-main,0.20,1,73
|
||||
1775089513,2224086,db-read-1,0.20,1,124
|
||||
1775089513,2224087,db-write,100.20,501,19772
|
||||
1775089513,2224088,event-worker,0.00,0,1
|
||||
1775089518,2224084,lws-main,0.20,1,74
|
||||
1775089518,2224086,db-read-1,0.40,2,126
|
||||
1775089518,2224087,db-write,75.00,375,20147
|
||||
1775089518,2224088,event-worker,0.00,0,1
|
||||
1775089523,2224084,lws-main,0.00,0,74
|
||||
1775089523,2224086,db-read-1,0.40,2,128
|
||||
1775089523,2224087,db-write,43.40,217,20364
|
||||
1775089523,2224088,event-worker,0.00,0,1
|
||||
1775089528,2224084,lws-main,4.60,23,97
|
||||
1775089528,2224086,db-read-1,4.00,20,148
|
||||
1775089528,2224087,db-write,40.80,204,20568
|
||||
1775089528,2224088,event-worker,0.20,1,2
|
||||
1775089533,2224084,lws-main,3.40,17,114
|
||||
1775089533,2224086,db-read-1,3.20,16,164
|
||||
1775089533,2224087,db-write,98.80,494,21062
|
||||
1775089533,2224088,event-worker,0.20,1,3
|
||||
1775089538,2224084,lws-main,0.20,1,115
|
||||
1775089538,2224086,db-read-1,0.40,2,166
|
||||
1775089538,2224087,db-write,100.40,502,21564
|
||||
1775089538,2224088,event-worker,0.00,0,3
|
||||
1775089543,2224084,lws-main,0.20,1,116
|
||||
1775089543,2224086,db-read-1,0.20,1,167
|
||||
1775089543,2224087,db-write,100.20,501,22065
|
||||
1775089543,2224088,event-worker,0.00,0,3
|
||||
1775089548,2224084,lws-main,0.00,0,116
|
||||
1775089548,2224086,db-read-1,0.20,1,168
|
||||
1775089548,2224087,db-write,100.40,502,22567
|
||||
1775089548,2224088,event-worker,0.00,0,3
|
||||
1775089553,2224084,lws-main,0.20,1,117
|
||||
1775089553,2224086,db-read-1,0.20,1,169
|
||||
1775089553,2224087,db-write,100.40,502,23069
|
||||
1775089553,2224088,event-worker,0.00,0,3
|
||||
|
@@ -0,0 +1,11 @@
|
||||
==========================================
|
||||
Thread CPU Summary (avg + max over run)
|
||||
==========================================
|
||||
Run timestamp (UTC): 20260402_002056
|
||||
Duration: 300s, Interval: 5s
|
||||
|
||||
2224087 db-write 76.90 100.40
|
||||
2224086 db-read-1 0.56 10.20
|
||||
2224084 lws-main 0.33 4.60
|
||||
2224088 event-worker 0.01 0.20
|
||||
TID THREAD AVG_CPU% MAX_CPU%
|
||||
BIN
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
Profiling PID: 2242661
|
||||
CLK_TCK=100
|
||||
Starting perf record in background...
|
||||
perf_pid=2242812
|
||||
Done. Artifacts in /tmp/c_relay_thread_profile_20260402_011703
|
||||
@@ -0,0 +1,145 @@
|
||||
timestamp,tid,thread_name,cpu_pct,delta_ticks,total_ticks
|
||||
1775092623,2242661,lws-main,0.00,0,34
|
||||
1775092623,2242664,db-read-1,0.00,0,21
|
||||
1775092623,2242665,db-write,0.40,2,1055
|
||||
1775092623,2242666,event-worker,0.00,0,0
|
||||
1775092628,2242661,lws-main,0.00,0,34
|
||||
1775092628,2242664,db-read-1,0.00,0,21
|
||||
1775092628,2242665,db-write,92.20,461,1516
|
||||
1775092628,2242666,event-worker,0.00,0,0
|
||||
1775092633,2242661,lws-main,0.00,0,34
|
||||
1775092633,2242664,db-read-1,0.00,0,21
|
||||
1775092633,2242665,db-write,0.00,0,1516
|
||||
1775092633,2242666,event-worker,0.00,0,0
|
||||
1775092638,2242661,lws-main,0.20,1,35
|
||||
1775092638,2242664,db-read-1,0.00,0,21
|
||||
1775092638,2242665,db-write,26.80,134,1650
|
||||
1775092638,2242666,event-worker,0.00,0,0
|
||||
1775092643,2242661,lws-main,0.00,0,35
|
||||
1775092643,2242664,db-read-1,0.20,1,22
|
||||
1775092643,2242665,db-write,13.60,68,1718
|
||||
1775092643,2242666,event-worker,0.00,0,0
|
||||
1775092648,2242661,lws-main,0.00,0,35
|
||||
1775092648,2242664,db-read-1,0.00,0,22
|
||||
1775092648,2242665,db-write,13.60,68,1786
|
||||
1775092648,2242666,event-worker,0.00,0,0
|
||||
1775092654,2242661,lws-main,0.20,1,36
|
||||
1775092654,2242664,db-read-1,0.40,2,24
|
||||
1775092654,2242665,db-write,0.00,0,1786
|
||||
1775092654,2242666,event-worker,0.00,0,0
|
||||
1775092659,2242661,lws-main,0.00,0,36
|
||||
1775092659,2242664,db-read-1,0.00,0,24
|
||||
1775092659,2242665,db-write,0.20,1,1787
|
||||
1775092659,2242666,event-worker,0.00,0,0
|
||||
1775092664,2242661,lws-main,1.80,9,45
|
||||
1775092664,2242664,db-read-1,2.00,10,34
|
||||
1775092664,2242665,db-write,27.60,138,1925
|
||||
1775092664,2242666,event-worker,0.20,1,1
|
||||
1775092669,2242661,lws-main,0.20,1,46
|
||||
1775092669,2242664,db-read-1,0.20,1,35
|
||||
1775092669,2242665,db-write,14.00,70,1995
|
||||
1775092669,2242666,event-worker,0.20,1,2
|
||||
1775092674,2242661,lws-main,0.40,2,48
|
||||
1775092674,2242664,db-read-1,0.20,1,36
|
||||
1775092674,2242665,db-write,34.80,174,2169
|
||||
1775092674,2242666,event-worker,0.20,1,3
|
||||
1775092679,2242661,lws-main,0.00,0,48
|
||||
1775092679,2242664,db-read-1,0.40,2,38
|
||||
1775092679,2242665,db-write,66.80,334,2503
|
||||
1775092679,2242666,event-worker,0.00,0,3
|
||||
1775092684,2242661,lws-main,0.00,0,48
|
||||
1775092684,2242664,db-read-1,1.00,5,43
|
||||
1775092684,2242665,db-write,21.60,108,2611
|
||||
1775092684,2242666,event-worker,0.00,0,3
|
||||
1775092689,2242661,lws-main,0.40,2,50
|
||||
1775092689,2242664,db-read-1,0.20,1,44
|
||||
1775092689,2242665,db-write,54.80,274,2885
|
||||
1775092689,2242666,event-worker,0.00,0,3
|
||||
1775092694,2242661,lws-main,0.20,1,51
|
||||
1775092694,2242664,db-read-1,0.20,1,45
|
||||
1775092694,2242665,db-write,67.20,336,3221
|
||||
1775092694,2242666,event-worker,0.00,0,3
|
||||
1775092699,2242661,lws-main,0.00,0,51
|
||||
1775092699,2242664,db-read-1,0.60,3,48
|
||||
1775092699,2242665,db-write,100.20,501,3722
|
||||
1775092699,2242666,event-worker,0.00,0,3
|
||||
1775092704,2242661,lws-main,0.40,2,53
|
||||
1775092704,2242664,db-read-1,0.40,2,50
|
||||
1775092704,2242665,db-write,93.00,465,4187
|
||||
1775092704,2242666,event-worker,0.00,0,3
|
||||
1775092709,2242661,lws-main,0.20,1,54
|
||||
1775092709,2242664,db-read-1,0.40,2,52
|
||||
1775092709,2242665,db-write,27.60,138,4325
|
||||
1775092709,2242666,event-worker,0.00,0,3
|
||||
1775092714,2242661,lws-main,0.20,1,55
|
||||
1775092714,2242664,db-read-1,0.40,2,54
|
||||
1775092714,2242665,db-write,90.20,451,4776
|
||||
1775092714,2242666,event-worker,0.00,0,3
|
||||
1775092719,2242661,lws-main,0.20,1,56
|
||||
1775092719,2242664,db-read-1,0.20,1,55
|
||||
1775092719,2242665,db-write,100.00,500,5276
|
||||
1775092719,2242666,event-worker,0.00,0,3
|
||||
1775092724,2242661,lws-main,0.00,0,56
|
||||
1775092724,2242664,db-read-1,0.00,0,55
|
||||
1775092724,2242665,db-write,100.20,501,5777
|
||||
1775092724,2242666,event-worker,0.00,0,3
|
||||
1775092729,2242661,lws-main,0.20,1,57
|
||||
1775092729,2242664,db-read-1,0.20,1,56
|
||||
1775092729,2242665,db-write,100.20,501,6278
|
||||
1775092729,2242666,event-worker,0.00,0,3
|
||||
1775092734,2242661,lws-main,0.20,1,58
|
||||
1775092734,2242664,db-read-1,0.20,1,57
|
||||
1775092734,2242665,db-write,100.40,502,6780
|
||||
1775092734,2242666,event-worker,0.00,0,3
|
||||
1775092739,2242661,lws-main,0.00,0,58
|
||||
1775092739,2242664,db-read-1,0.00,0,57
|
||||
1775092739,2242665,db-write,99.80,499,7279
|
||||
1775092739,2242666,event-worker,0.00,0,3
|
||||
1775092744,2242661,lws-main,0.20,1,59
|
||||
1775092744,2242664,db-read-1,0.00,0,57
|
||||
1775092744,2242665,db-write,100.60,503,7782
|
||||
1775092744,2242666,event-worker,0.00,0,3
|
||||
1775092749,2242661,lws-main,0.00,0,59
|
||||
1775092749,2242664,db-read-1,0.00,0,57
|
||||
1775092749,2242665,db-write,100.00,500,8282
|
||||
1775092749,2242666,event-worker,0.00,0,3
|
||||
1775092754,2242661,lws-main,0.20,1,60
|
||||
1775092754,2242664,db-read-1,0.20,1,58
|
||||
1775092754,2242665,db-write,30.40,152,8434
|
||||
1775092754,2242666,event-worker,0.00,0,3
|
||||
1775092759,2242661,lws-main,0.00,0,60
|
||||
1775092759,2242664,db-read-1,0.00,0,58
|
||||
1775092759,2242665,db-write,53.40,267,8701
|
||||
1775092759,2242666,event-worker,0.00,0,3
|
||||
1775092764,2242661,lws-main,0.40,2,62
|
||||
1775092764,2242664,db-read-1,0.00,0,58
|
||||
1775092764,2242665,db-write,50.00,250,8951
|
||||
1775092764,2242666,event-worker,0.00,0,3
|
||||
1775092769,2242661,lws-main,0.00,0,62
|
||||
1775092769,2242664,db-read-1,0.20,1,59
|
||||
1775092769,2242665,db-write,57.60,288,9239
|
||||
1775092769,2242666,event-worker,0.00,0,3
|
||||
1775092774,2242661,lws-main,0.20,1,63
|
||||
1775092774,2242664,db-read-1,0.20,1,60
|
||||
1775092774,2242665,db-write,54.40,272,9511
|
||||
1775092774,2242666,event-worker,0.20,1,4
|
||||
1775092779,2242661,lws-main,0.00,0,63
|
||||
1775092779,2242664,db-read-1,0.20,1,61
|
||||
1775092779,2242665,db-write,49.20,246,9757
|
||||
1775092779,2242666,event-worker,0.00,0,4
|
||||
1775092784,2242661,lws-main,0.20,1,64
|
||||
1775092784,2242664,db-read-1,0.00,0,61
|
||||
1775092784,2242665,db-write,31.00,155,9912
|
||||
1775092784,2242666,event-worker,0.00,0,4
|
||||
1775092789,2242661,lws-main,0.20,1,65
|
||||
1775092789,2242664,db-read-1,0.00,0,61
|
||||
1775092789,2242665,db-write,66.80,334,10246
|
||||
1775092789,2242666,event-worker,0.00,0,4
|
||||
1775092794,2242661,lws-main,0.00,0,65
|
||||
1775092794,2242664,db-read-1,0.20,1,62
|
||||
1775092794,2242665,db-write,40.20,201,10447
|
||||
1775092794,2242666,event-worker,0.00,0,4
|
||||
1775092799,2242661,lws-main,0.20,1,66
|
||||
1775092799,2242664,db-read-1,0.20,1,63
|
||||
1775092799,2242665,db-write,92.40,462,10909
|
||||
1775092799,2242666,event-worker,0.00,0,4
|
||||
|
@@ -0,0 +1,11 @@
|
||||
==========================================
|
||||
Thread CPU Summary (avg + max over run)
|
||||
==========================================
|
||||
Run timestamp (UTC): 20260402_011703
|
||||
Duration: 180s, Interval: 5s
|
||||
|
||||
2242665 db-write 54.76 100.60
|
||||
2242664 db-read-1 0.23 2.00
|
||||
2242661 lws-main 0.18 1.80
|
||||
2242666 event-worker 0.02 0.20
|
||||
TID THREAD AVG_CPU% MAX_CPU%
|
||||
Binary file not shown.
@@ -0,0 +1,622 @@
|
||||
# To display the perf.data header info, please use --header/--header-only options.
|
||||
#
|
||||
#
|
||||
# Total Lost Samples: 0
|
||||
#
|
||||
# Samples: 73K of event 'task-clock:ppp'
|
||||
# Event count (approx.): 18314000000
|
||||
#
|
||||
# Overhead Samples Command Symbol IPC [IPC Coverage]
|
||||
# ........ ............ ............ .............................................. ....................
|
||||
#
|
||||
13.73% 10055 db-write [.] sqlite3BtreeTableMoveto - -
|
||||
|
|
||||
---sqlite3BtreeTableMoveto
|
||||
|
|
||||
|--3.11%--0xfdd00007f040000
|
||||
|
|
||||
|--3.03%--0xfdd75007f000001
|
||||
|
|
||||
|--2.68%--0xfdd75007f040000
|
||||
|
|
||||
--2.25%--0xfdd00007f000001
|
||||
|
||||
10.11% 7408 db-write [.] sqlite3VdbeExec - -
|
||||
|
|
||||
---sqlite3VdbeExec
|
||||
|
|
||||
--4.88%--0
|
||||
|
||||
7.76% 5685 db-write [.] sqlite3GetVarint - -
|
||||
|
|
||||
---sqlite3GetVarint
|
||||
|
|
||||
|--2.86%--0xfdd00007f040000
|
||||
|
|
||||
|--2.61%--0xfdd75007f040000
|
||||
|
|
||||
|--0.76%--0xfdd75007f000001
|
||||
|
|
||||
--0.59%--0xfdd00007f000001
|
||||
|
||||
7.71% 5647 db-write [k] rep_movs_alternative - -
|
||||
|
|
||||
---rep_movs_alternative
|
||||
copy_page_to_iter
|
||||
filemap_read
|
||||
generic_file_read_iter
|
||||
ext4_file_read_iter
|
||||
vfs_read
|
||||
__x64_sys_pread64
|
||||
x64_sys_call
|
||||
do_syscall_64
|
||||
entry_SYSCALL_64_after_hwframe
|
||||
sccp
|
||||
|
||||
7.04% 5154 db-write [.] pcache1Fetch - -
|
||||
|
|
||||
---pcache1Fetch
|
||||
|
||||
5.84% 4275 db-write [.] memcpy - -
|
||||
|
|
||||
---memcpy
|
||||
|
||||
5.27% 3857 db-write [.] sccp - -
|
||||
|
|
||||
---sccp
|
||||
|
||||
4.31% 3154 db-write [k] do_syscall_64 - -
|
||||
|
|
||||
---do_syscall_64
|
||||
entry_SYSCALL_64_after_hwframe
|
||||
|
|
||||
--4.30%--sccp
|
||||
|
||||
2.81% 2059 db-write [k] filemap_get_read_batch - -
|
||||
|
|
||||
---filemap_get_read_batch
|
||||
|
|
||||
--2.80%--filemap_get_pages
|
||||
filemap_read
|
||||
generic_file_read_iter
|
||||
ext4_file_read_iter
|
||||
vfs_read
|
||||
__x64_sys_pread64
|
||||
x64_sys_call
|
||||
do_syscall_64
|
||||
entry_SYSCALL_64_after_hwframe
|
||||
sccp
|
||||
|
||||
2.45% 1798 db-write [.] getPageNormal - -
|
||||
|
|
||||
---getPageNormal
|
||||
|
|
||||
--0.82%--0x75d555b7ac18
|
||||
0xa02000100010500
|
||||
0x200
|
||||
|
||||
2.27% 1661 db-write [.] getCellInfo - -
|
||||
|
|
||||
---getCellInfo
|
||||
|
|
||||
|--1.16%--0x75d555b872d8
|
||||
|
|
||||
--0.85%--0
|
||||
|
||||
1.87% 1371 db-write [k] __fdget - -
|
||||
|
|
||||
---__fdget
|
||||
|
|
||||
--1.85%--__x64_sys_pread64
|
||||
x64_sys_call
|
||||
do_syscall_64
|
||||
entry_SYSCALL_64_after_hwframe
|
||||
sccp
|
||||
|
||||
1.83% 1340 db-write [.] pcache1Unpin - -
|
||||
|
|
||||
---pcache1Unpin
|
||||
|
||||
1.55% 1134 db-write [.] pread - -
|
||||
|
|
||||
---pread
|
||||
|
||||
1.53% 1123 db-write [.] getAndInitPage - -
|
||||
|
|
||||
---getAndInitPage
|
||||
|
|
||||
--0.91%--0x75d555b7ac18
|
||||
0xa02000100010500
|
||||
0x200
|
||||
|
||||
1.45% 1063 db-write [.] sqlite3BtreeNext.isra.0 - -
|
||||
|
|
||||
---sqlite3BtreeNext.isra.0
|
||||
|
|
||||
--1.29%--0
|
||||
|
||||
1.40% 1023 db-write [.] sqlite3VdbeIdxRowid - -
|
||||
|
|
||||
---sqlite3VdbeIdxRowid
|
||||
|
||||
1.34% 979 db-write [.] btreeParseCellPtr - -
|
||||
|
|
||||
---btreeParseCellPtr
|
||||
|
|
||||
--0.99%--0
|
||||
|
||||
1.19% 874 db-write [.] pcache1FetchStage2 - -
|
||||
|
|
||||
---pcache1FetchStage2
|
||||
|
||||
1.01% 742 db-write [.] sqlite3PcacheRelease - -
|
||||
|
|
||||
---sqlite3PcacheRelease
|
||||
|
||||
1.01% 741 db-write [.] sqlite3VdbeRecordCompareWithSkip - -
|
||||
|
|
||||
---sqlite3VdbeRecordCompareWithSkip
|
||||
|
||||
0.97% 709 db-write [.] memcmp - -
|
||||
|
|
||||
---memcmp
|
||||
|
||||
0.95% 699 db-write [.] walFindFrame.constprop.0 - -
|
||||
|
|
||||
---walFindFrame.constprop.0
|
||||
|
||||
0.95% 698 db-write [.] moveToChild - -
|
||||
|
|
||||
---moveToChild
|
||||
|
|
||||
--0.56%--0xfdd00007f040000
|
||||
|
||||
0.90% 662 db-write [.] moveToRoot - -
|
||||
|
|
||||
---moveToRoot
|
||||
|
||||
0.88% 646 db-write [k] xas_load - -
|
||||
|
|
||||
---xas_load
|
||||
|
|
||||
--0.87%--filemap_get_read_batch
|
||||
filemap_get_pages
|
||||
filemap_read
|
||||
generic_file_read_iter
|
||||
ext4_file_read_iter
|
||||
vfs_read
|
||||
__x64_sys_pread64
|
||||
x64_sys_call
|
||||
do_syscall_64
|
||||
entry_SYSCALL_64_after_hwframe
|
||||
sccp
|
||||
|
||||
0.84% 615 db-write [.] sqlite3VdbeSerialGet - -
|
||||
|
|
||||
---sqlite3VdbeSerialGet
|
||||
|
||||
0.73% 535 db-write [k] filemap_read - -
|
||||
|
|
||||
---filemap_read
|
||||
|
|
||||
--0.71%--generic_file_read_iter
|
||||
ext4_file_read_iter
|
||||
vfs_read
|
||||
__x64_sys_pread64
|
||||
x64_sys_call
|
||||
do_syscall_64
|
||||
entry_SYSCALL_64_after_hwframe
|
||||
sccp
|
||||
|
||||
0.73% 533 db-write [.] vdbeCompareMemString - -
|
||||
|
|
||||
---vdbeCompareMemString
|
||||
|
||||
0.72% 528 db-write [.] btreeParseCellPtrIndex - -
|
||||
|
|
||||
---btreeParseCellPtrIndex
|
||||
0x75d555b872d8
|
||||
|
||||
0.68% 499 db-write [.] readDbPage - -
|
||||
|
|
||||
---readDbPage
|
||||
|
|
||||
--0.67%--0xa02000100010500
|
||||
0x200
|
||||
|
||||
0.64% 470 db-write [.] sqlite3VdbeFinishMoveto - -
|
||||
|
|
||||
---sqlite3VdbeFinishMoveto
|
||||
0
|
||||
|
||||
0.55% 401 db-write [.] decodeFlags - -
|
||||
|
|
||||
---decodeFlags
|
||||
|
||||
0.50% 365 db-write [k] xas_descend - -
|
||||
0.49% 362 db-write [k] aa_file_perm - -
|
||||
0.48% 351 db-write [.] sqlite3MemCompare - -
|
||||
0.48% 348 db-write [k] __fsnotify_parent - -
|
||||
0.47% 346 db-write [.] btreeInitPage - -
|
||||
0.45% 330 db-write [k] rw_verify_area - -
|
||||
0.45% 327 db-write [.] unixRead - -
|
||||
0.41% 303 db-write [.] sqlite3PagerUnrefNotNull - -
|
||||
0.27% 197 db-write [k] xas_start - -
|
||||
0.25% 186 db-write [.] binCollFunc - -
|
||||
0.22% 163 db-write [k] vfs_read - -
|
||||
0.14% 99 db-write [.] btreeNext.constprop.0 - -
|
||||
0.11% 82 db-write [k] ext4_file_read_iter - -
|
||||
0.11% 79 db-write [k] apparmor_file_permission - -
|
||||
0.10% 76 db-write [k] fput - -
|
||||
0.08% 61 db-write [.] moveToLeftmost - -
|
||||
0.08% 56 db-write [k] atime_needs_update - -
|
||||
0.08% 55 db-write [k] filemap_get_pages - -
|
||||
0.07% 50 db-write [k] copy_page_to_iter - -
|
||||
0.07% 49 db-write [k] __x64_sys_pread64 - -
|
||||
0.06% 46 db-write [k] _copy_to_iter - -
|
||||
0.05% 37 db-write [k] __xas_next - -
|
||||
0.05% 33 db-write [.] walHashGet - -
|
||||
0.04% 32 db-write [k] __rcu_read_lock - -
|
||||
0.04% 29 db-write [k] __rcu_read_unlock - -
|
||||
0.04% 29 db-write [k] current_time - -
|
||||
0.04% 28 db-write [k] security_file_permission - -
|
||||
0.04% 27 db-write [k] ktime_get_coarse_real_ts64 - -
|
||||
0.03% 24 db-read-1 [k] rep_movs_alternative - -
|
||||
0.03% 24 db-write [k] folio_mark_accessed - -
|
||||
0.03% 24 db-write [k] generic_file_read_iter - -
|
||||
0.03% 24 lws-main [.] remove_subscription_from_kind_index.part.0 - -
|
||||
0.03% 22 db-write [k] __x86_indirect_thunk_rax - -
|
||||
0.03% 21 db-read-1 [.] sqlite3VdbeExec - -
|
||||
0.03% 21 db-write [.] pcacheFetchFinishWithInit - -
|
||||
0.03% 20 db-read-1 [k] do_syscall_64 - -
|
||||
0.03% 19 db-write [.] btreeParseCellAdjustSizeForOverflow.isra.0 - -
|
||||
0.03% 19 lws-main [k] sock_poll - -
|
||||
0.02% 18 db-write [k] touch_atime - -
|
||||
0.02% 16 db-write [k] __cond_resched - -
|
||||
0.02% 15 db-read-1 [.] pcache1Fetch - -
|
||||
0.02% 15 db-write [k] syscall_exit_to_user_mode_prepare - -
|
||||
0.02% 15 db-write [k] x64_sys_call - -
|
||||
0.02% 14 db-read-1 [.] sccp - -
|
||||
0.02% 13 db-read-1 [.] __libc_malloc_impl - -
|
||||
0.02% 13 db-read-1 [k] filemap_get_read_batch - -
|
||||
0.02% 12 db-read-1 [k] __fdget - -
|
||||
0.02% 12 lws-main [k] _raw_spin_unlock_irqrestore - -
|
||||
0.02% 11 db-write [k] handle_softirqs - -
|
||||
0.02% 11 lws-main [.] has_subscriptions_for_kind - -
|
||||
0.01% 10 db-read-1 [.] sqlite3BtreeTableMoveto - -
|
||||
0.01% 10 lws-main [.] __libc_malloc_impl - -
|
||||
0.01% 9 db-read-1 [.] pread - -
|
||||
0.01% 9 lws-main [.] sccp - -
|
||||
0.01% 8 db-read-1 [.] pcache1FetchStage2 - -
|
||||
0.01% 8 db-write [.] __syscall_ret - -
|
||||
0.01% 8 lws-main [.] cJSON_IsNumber - -
|
||||
0.01% 8 lws-main [.] memcpy - -
|
||||
0.01% 7 db-read-1 [k] do_user_addr_fault - -
|
||||
0.01% 7 db-read-1 [.] sqlite3GetVarint - -
|
||||
0.01% 7 db-write [k] _raw_spin_unlock_irqrestore - -
|
||||
0.01% 7 db-write [k] make_vfsuid - -
|
||||
0.01% 6 db-read-1 [k] _raw_spin_unlock_irqrestore - -
|
||||
0.01% 6 db-read-1 [k] clear_page_orig - -
|
||||
0.01% 6 db-read-1 [k] xas_load - -
|
||||
0.01% 6 db-write [k] _raw_spin_unlock_irq - -
|
||||
0.01% 5 db-read-1 [k] __fsnotify_parent - -
|
||||
0.01% 5 db-read-1 [.] getAndInitPage - -
|
||||
0.01% 5 db-read-1 [.] walFindFrame.constprop.0 - -
|
||||
0.01% 5 db-read-1 [k] xas_descend - -
|
||||
0.01% 5 db-write [k] clear_page_orig - -
|
||||
0.01% 5 db-write [k] finish_task_switch.isra.0 - -
|
||||
0.01% 5 db-write [k] iowrite16 - -
|
||||
0.01% 5 db-write [k] make_vfsgid - -
|
||||
0.01% 5 db-write [.] sqlite3BtreeIndexMoveto - -
|
||||
0.01% 5 lws-main [k] __fdget - -
|
||||
0.01% 4 db-read-1 [.] __pthread_mutex_timedlock - -
|
||||
0.01% 4 db-read-1 [k] aa_file_perm - -
|
||||
0.01% 4 db-read-1 [.] btreeParseCellPtr - -
|
||||
0.01% 4 db-read-1 [.] memcpy - -
|
||||
0.01% 4 db-read-1 [.] sqlite3VdbeRecordCompareWithSkip - -
|
||||
0.01% 4 db-write [k] do_user_addr_fault - -
|
||||
0.01% 4 db-write [k] syscall_exit_to_user_mode - -
|
||||
0.01% 4 event-worker [.] secp256k1_fe_mul_inner - -
|
||||
0.01% 4 lws-main [.] _lws_plat_service_tsi.part.0 - -
|
||||
0.01% 4 lws-main [.] alloc_slot - -
|
||||
0.01% 4 lws-main [k] fput - -
|
||||
0.01% 4 lws-main [.] strlen - -
|
||||
0.01% 4 lws-main [k] tcp_poll - -
|
||||
0.00% 3 db-read-1 [.] __pthread_mutex_lock - -
|
||||
0.00% 3 db-read-1 [k] blk_cgroup_congested - -
|
||||
0.00% 3 db-read-1 [k] filemap_read - -
|
||||
0.00% 3 db-read-1 [.] getCellInfo - -
|
||||
0.00% 3 db-read-1 [.] sqlite3PcacheRelease - -
|
||||
0.00% 3 db-read-1 [.] whereScanNext - -
|
||||
0.00% 3 db-write [k] ___slab_alloc - -
|
||||
0.00% 3 db-write [k] __lruvec_stat_mod_folio - -
|
||||
0.00% 3 db-write [k] __next_zones_zonelist - -
|
||||
0.00% 3 db-write [k] smp_call_function_many_cond - -
|
||||
0.00% 3 db-write [.] sqlite3DbMallocRawNN - -
|
||||
0.00% 3 db-write [.] strlen - -
|
||||
0.00% 3 db-write [.] yy_reduce.isra.0 - -
|
||||
0.00% 3 lws-main [.] cJSON_IsArray - -
|
||||
0.00% 3 lws-main [k] do_syscall_64 - -
|
||||
0.00% 3 lws-main [k] finish_task_switch.isra.0 - -
|
||||
0.00% 3 lws-main [.] get_config_value_from_table - -
|
||||
0.00% 2 db-read-1 [.] __libc_free - -
|
||||
0.00% 2 db-read-1 [k] __lruvec_stat_mod_folio - -
|
||||
0.00% 2 db-read-1 [.] __pthread_mutex_unlock - -
|
||||
0.00% 2 db-read-1 [k] __rcu_read_lock - -
|
||||
0.00% 2 db-read-1 [.] btreeInitPage - -
|
||||
0.00% 2 db-read-1 [.] decodeFlags - -
|
||||
0.00% 2 db-read-1 [k] down_write - -
|
||||
0.00% 2 db-read-1 [.] moveToRoot - -
|
||||
0.00% 2 db-read-1 [k] native_write_msr - -
|
||||
0.00% 2 db-read-1 [.] pcache1Unpin - -
|
||||
0.00% 2 db-read-1 [.] propagateConstantExprRewrite - -
|
||||
0.00% 2 db-read-1 [.] readDbPage - -
|
||||
0.00% 2 db-read-1 [.] sqlite3BtreeIndexMoveto - -
|
||||
0.00% 2 db-read-1 [.] sqlite3BtreeNext.isra.0 - -
|
||||
0.00% 2 db-read-1 [.] sqlite3WhereBegin - -
|
||||
0.00% 2 db-read-1 [.] unixRead - -
|
||||
0.00% 2 db-read-1 [.] whereLoopAddBtreeIndex - -
|
||||
0.00% 2 db-read-1 [k] xas_start - -
|
||||
0.00% 2 db-write [k] inode_to_bdi - -
|
||||
0.00% 2 db-write [k] kmem_cache_alloc - -
|
||||
0.00% 2 db-write [k] native_write_msr - -
|
||||
0.00% 2 db-write [k] pvclock_clocksource_read_nowd - -
|
||||
0.00% 2 db-write [.] pwrite - -
|
||||
0.00% 2 db-write [.] sqlite3WalCheckpoint - -
|
||||
0.00% 2 lws-main [.] __libc_free - -
|
||||
0.00% 2 lws-main [.] __lock - -
|
||||
0.00% 2 lws-main [.] __unlock - -
|
||||
0.00% 2 lws-main [k] __x86_indirect_thunk_rax - -
|
||||
0.00% 2 lws-main [.] broadcast_event_to_subscriptions - -
|
||||
0.00% 2 lws-main [.] decfloat - -
|
||||
0.00% 2 lws-main [k] do_user_addr_fault - -
|
||||
0.00% 2 lws-main [k] eventfd_poll - -
|
||||
0.00% 2 lws-main [k] nft_do_chain - -
|
||||
0.00% 2 lws-main [.] nostr_relay_callback - -
|
||||
0.00% 2 lws-main [.] print_value - -
|
||||
0.00% 2 lws-main [k] pvclock_clocksource_read_nowd - -
|
||||
0.00% 2 lws-main [.] strcmp - -
|
||||
0.00% 2 lws-main [k] tcp_in_window - -
|
||||
0.00% 1 db-read-1 [k] ___slab_alloc - -
|
||||
0.00% 1 db-read-1 [k] __anon_vma_interval_tree_remove - -
|
||||
0.00% 1 db-read-1 [k] __raw_callee_save___pv_queued_spin_unlock - -
|
||||
0.00% 1 db-read-1 [k] __rcu_read_unlock - -
|
||||
0.00% 1 db-read-1 [.] __timedwait_cp - -
|
||||
0.00% 1 db-read-1 [k] __tlb_remove_page_size - -
|
||||
0.00% 1 db-read-1 [.] allocateCursor - -
|
||||
0.00% 1 db-read-1 [k] anon_vma_interval_tree_insert - -
|
||||
0.00% 1 db-read-1 [.] binCollFunc - -
|
||||
0.00% 1 db-read-1 [.] btreeBeginTrans - -
|
||||
0.00% 1 db-read-1 [.] btreeParseCellPtrIndex - -
|
||||
0.00% 1 db-read-1 [k] current_obj_cgroup - -
|
||||
0.00% 1 db-read-1 [k] do_vmi_align_munmap - -
|
||||
0.00% 1 db-read-1 [.] exprDup - -
|
||||
0.00% 1 db-read-1 [.] exprNodeIsConstant - -
|
||||
0.00% 1 db-read-1 [k] finish_task_switch.isra.0 - -
|
||||
0.00% 1 db-read-1 [k] folio_add_lru - -
|
||||
0.00% 1 db-read-1 [k] folio_add_new_anon_rmap - -
|
||||
0.00% 1 db-read-1 [.] free_req_payload_main.part.0 - -
|
||||
0.00% 1 db-read-1 [k] futex_q_lock - -
|
||||
0.00% 1 db-read-1 [.] getPageNormal - -
|
||||
0.00% 1 db-read-1 [k] get_mem_cgroup_from_mm - -
|
||||
0.00% 1 db-read-1 [.] get_meta - -
|
||||
0.00% 1 db-read-1 [k] handle_softirqs - -
|
||||
0.00% 1 db-read-1 [k] hugepage_pmd_enabled - -
|
||||
0.00% 1 db-read-1 [.] indexCellCompare.isra.0 - -
|
||||
0.00% 1 db-read-1 [k] kmem_cache_alloc - -
|
||||
0.00% 1 db-read-1 [k] kmem_cache_free - -
|
||||
0.00% 1 db-read-1 [k] lock_vma_under_rcu - -
|
||||
0.00% 1 db-read-1 [k] make_vfsuid - -
|
||||
0.00% 1 db-read-1 [k] mas_walk - -
|
||||
0.00% 1 db-read-1 [k] mem_cgroup_commit_charge - -
|
||||
0.00% 1 db-read-1 [.] memcmp - -
|
||||
0.00% 1 db-read-1 [k] obj_cgroup_uncharge_pages - -
|
||||
0.00% 1 db-read-1 [k] post_alloc_hook - -
|
||||
0.00% 1 db-read-1 [.] pthreadMutexLeave - -
|
||||
0.00% 1 db-read-1 [k] rcu_nocb_unlock_irqrestore.part.0 - -
|
||||
0.00% 1 db-read-1 [.] resolveP2Values - -
|
||||
0.00% 1 db-read-1 [k] rw_verify_area - -
|
||||
0.00% 1 db-read-1 [k] smp_call_function_many_cond - -
|
||||
0.00% 1 db-read-1 [.] sqlite3CodeRhsOfIN - -
|
||||
0.00% 1 db-read-1 [.] sqlite3DbMallocRawNN - -
|
||||
0.00% 1 db-read-1 [.] sqlite3DbNNFreeNN - -
|
||||
0.00% 1 db-read-1 [.] sqlite3ExprIfFalse - -
|
||||
0.00% 1 db-read-1 [.] sqlite3GetVarint32 - -
|
||||
0.00% 1 db-read-1 [.] sqlite3KeyInfoAlloc - -
|
||||
0.00% 1 db-read-1 [.] sqlite3MemCompare - -
|
||||
0.00% 1 db-read-1 [.] sqlite3Select - -
|
||||
0.00% 1 db-read-1 [.] sqlite3SelectPopWith - -
|
||||
0.00% 1 db-read-1 [.] sqlite3SrcListShiftJoinType.isra.0 - -
|
||||
0.00% 1 db-read-1 [.] sqlite3VdbeFinishMoveto - -
|
||||
0.00% 1 db-read-1 [.] sqlite3VdbeFreeCursorNN - -
|
||||
0.00% 1 db-read-1 [.] sqlite3VdbeMemFromBtree - -
|
||||
0.00% 1 db-read-1 [.] sqlite3VdbeSerialGet - -
|
||||
0.00% 1 db-read-1 [.] sqlite3WalkSelect - -
|
||||
0.00% 1 db-read-1 [.] sqlite3WhereExprUsageNN - -
|
||||
0.00% 1 db-read-1 [k] uncharge_batch - -
|
||||
0.00% 1 db-read-1 [.] unixShmBarrier - -
|
||||
0.00% 1 db-read-1 [k] update_blocked_averages - -
|
||||
0.00% 1 db-read-1 [k] vm_area_dup - -
|
||||
0.00% 1 db-read-1 [k] vm_unmapped_area - -
|
||||
0.00% 1 db-read-1 [k] vma_adjust_trans_huge - -
|
||||
0.00% 1 db-read-1 [.] whereLoopFindLesser - -
|
||||
0.00% 1 db-read-1 [.] wherePathSolver.isra.0 - -
|
||||
0.00% 1 db-read-1 [.] yy_reduce.isra.0 - -
|
||||
0.00% 1 db-read-1 [k] zap_pte_range - -
|
||||
0.00% 1 db-write [k] __block_commit_write - -
|
||||
0.00% 1 db-write [.] __libc_free - -
|
||||
0.00% 1 db-write [.] __libc_malloc_impl - -
|
||||
0.00% 1 db-write [k] __memcg_slab_post_alloc_hook - -
|
||||
0.00% 1 db-write [k] __mmap_region - -
|
||||
0.00% 1 db-write [k] __mod_memcg_lruvec_state - -
|
||||
0.00% 1 db-write [.] __pthread_mutex_unlock - -
|
||||
0.00% 1 db-write [k] __pv_queued_spin_lock_slowpath - -
|
||||
0.00% 1 db-write [k] __radix_tree_lookup - -
|
||||
0.00% 1 db-write [k] __rb_insert_augmented - -
|
||||
0.00% 1 db-write [k] __sg_alloc_table - -
|
||||
0.00% 1 db-write [k] __slab_free - -
|
||||
0.00% 1 db-write [k] __sock_wfree - -
|
||||
0.00% 1 db-write [k] __tlb_remove_page_size - -
|
||||
0.00% 1 db-write [k] _raw_read_lock - -
|
||||
0.00% 1 db-write [k] _raw_spin_lock - -
|
||||
0.00% 1 db-write [.] accessPayload - -
|
||||
0.00% 1 db-write [.] applyAffinity - -
|
||||
0.00% 1 db-write [k] balance_dirty_pages_ratelimited_flags - -
|
||||
0.00% 1 db-write [k] blk_finish_plug - -
|
||||
0.00% 1 db-write [k] blkcg_set_ioprio - -
|
||||
0.00% 1 db-write [k] count_memcg_events.constprop.0 - -
|
||||
0.00% 1 db-write [k] crc32_body - -
|
||||
0.00% 1 db-write [.] dbReallocFinish - -
|
||||
0.00% 1 db-write [k] ext4_da_map_blocks.constprop.0 - -
|
||||
0.00% 1 db-write [k] ext4_mb_mark_context - -
|
||||
0.00% 1 db-write [k] ext4_readahead - -
|
||||
0.00% 1 db-write [k] ext4_sb_block_valid - -
|
||||
0.00% 1 db-write [k] fault_in_readable - -
|
||||
0.00% 1 db-write [k] file_modified - -
|
||||
0.00% 1 db-write [k] filemap_get_entry - -
|
||||
0.00% 1 db-write [k] flock64_to_posix_lock - -
|
||||
0.00% 1 db-write [k] folio_add_lru - -
|
||||
0.00% 1 db-write [k] folio_add_new_anon_rmap - -
|
||||
0.00% 1 db-write [k] folio_mapping - -
|
||||
0.00% 1 db-write [k] futex_q_lock - -
|
||||
0.00% 1 db-write [.] getDigits - -
|
||||
0.00% 1 db-write [k] get_mem_cgroup_from_mm - -
|
||||
0.00% 1 db-write [.] get_meta - -
|
||||
0.00% 1 db-write [k] get_pfnblock_flags_mask - -
|
||||
0.00% 1 db-write [k] get_unmapped_area - -
|
||||
0.00% 1 db-write [k] handle_mm_fault - -
|
||||
0.00% 1 db-write [k] jbd2_journal_dirty_metadata - -
|
||||
0.00% 1 db-write [k] kfree - -
|
||||
0.00% 1 db-write [k] kmem_cache_free - -
|
||||
0.00% 1 db-write [k] lock_vma_under_rcu - -
|
||||
0.00% 1 db-write [k] lruvec_stat_mod_folio - -
|
||||
0.00% 1 db-write [k] mas_leaf_max_gap - -
|
||||
0.00% 1 db-write [k] mem_cgroup_commit_charge - -
|
||||
0.00% 1 db-write [k] mem_cgroup_flush_stats.part.0 - -
|
||||
0.00% 1 db-write [k] mempool_alloc_slab - -
|
||||
0.00% 1 db-write [k] mod_delayed_work_on - -
|
||||
0.00% 1 db-write [k] net_rx_action - -
|
||||
0.00% 1 db-write [k] nf_conntrack_tcp_packet - -
|
||||
0.00% 1 db-write [.] pagerUnlockAndRollback - -
|
||||
0.00% 1 db-write [.] pcache1Free - -
|
||||
0.00% 1 db-write [k] perf_event_mmap - -
|
||||
0.00% 1 db-write [k] perf_event_mmap_event - -
|
||||
0.00% 1 db-write [k] pmd_val - -
|
||||
0.00% 1 db-write [.] pthreadMutexAlloc - -
|
||||
0.00% 1 db-write [k] qdisc_pkt_len_init - -
|
||||
0.00% 1 db-write [.] queue_pop - -
|
||||
0.00% 1 db-write [.] releaseMemArray.part.0 - -
|
||||
0.00% 1 db-write [k] release_pages - -
|
||||
0.00% 1 db-write [k] scsi_mq_get_budget - -
|
||||
0.00% 1 db-write [.] seekAndWriteFd - -
|
||||
0.00% 1 db-write [k] sk_forced_mem_schedule - -
|
||||
0.00% 1 db-write [k] slab_update_freelist.isra.0 - -
|
||||
0.00% 1 db-write [.] sqlite3AtoF - -
|
||||
0.00% 1 db-write [.] sqlite3BeginWriteOperation - -
|
||||
0.00% 1 db-write [.] sqlite3ExprDeleteNN - -
|
||||
0.00% 1 db-write [.] sqlite3GenerateRowDelete - -
|
||||
0.00% 1 db-write [.] sqlite3GetToken - -
|
||||
0.00% 1 db-write [.] sqlite3GetVarint32 - -
|
||||
0.00% 1 db-write [.] sqlite3KeyInfoOfIndex - -
|
||||
0.00% 1 db-write [.] sqlite3LocateTable - -
|
||||
0.00% 1 db-write [.] sqlite3OpenTableAndIndices - -
|
||||
0.00% 1 db-write [.] sqlite3RunParser - -
|
||||
0.00% 1 db-write [.] sqlite3TriggerList.isra.0 - -
|
||||
0.00% 1 db-write [.] sqlite3Update.constprop.0 - -
|
||||
0.00% 1 db-write [.] sqlite3VdbeFreeCursorNN - -
|
||||
0.00% 1 db-write [k] update_blocked_averages - -
|
||||
0.00% 1 db-write [k] userfaultfd_unmap_complete - -
|
||||
0.00% 1 db-write [k] virtscsi_queuecommand - -
|
||||
0.00% 1 db-write [k] vm_unmapped_area - -
|
||||
0.00% 1 db-write [.] walChecksumBytes - -
|
||||
0.00% 1 db-write [.] walIndexAppend - -
|
||||
0.00% 1 db-write [.] walMerge - -
|
||||
0.00% 1 db-write [k] xas_find - -
|
||||
0.00% 1 db-write [k] zap_pte_range - -
|
||||
0.00% 1 event-worker [k] __fdget_raw - -
|
||||
0.00% 1 event-worker [k] _raw_spin_unlock_irq - -
|
||||
0.00% 1 event-worker [k] iowrite16 - -
|
||||
0.00% 1 event-worker [.] memchr - -
|
||||
0.00% 1 event-worker [.] print_value - -
|
||||
0.00% 1 event-worker [.] sqlite3AuthCheck - -
|
||||
0.00% 1 event-worker [.] sqlite3KeyInfoAlloc - -
|
||||
0.00% 1 lws-main [k] __alloc_pages - -
|
||||
0.00% 1 lws-main [k] __alloc_skb - -
|
||||
0.00% 1 lws-main [k] __free_pages - -
|
||||
0.00% 1 lws-main [k] __mmap_region - -
|
||||
0.00% 1 lws-main [k] __mod_timer - -
|
||||
0.00% 1 lws-main [k] __pollwait - -
|
||||
0.00% 1 lws-main [.] __pthread_mutex_unlock - -
|
||||
0.00% 1 lws-main [k] __pv_queued_spin_lock_slowpath - -
|
||||
0.00% 1 lws-main [k] __raw_spin_lock_irqsave - -
|
||||
0.00% 1 lws-main [k] __rcu_read_unlock - -
|
||||
0.00% 1 lws-main [k] __sock_wfree - -
|
||||
0.00% 1 lws-main [k] __sys_sendto - -
|
||||
0.00% 1 lws-main [k] __tcp_transmit_skb - -
|
||||
0.00% 1 lws-main [.] __vdso_clock_gettime - -
|
||||
0.00% 1 lws-main [k] __x64_sys_sendto - -
|
||||
0.00% 1 lws-main [k] _raw_spin_lock - -
|
||||
0.00% 1 lws-main [k] apparmor_file_permission - -
|
||||
0.00% 1 lws-main [k] arch_get_unmapped_area_topdown - -
|
||||
0.00% 1 lws-main [.] cJSON_Delete - -
|
||||
0.00% 1 lws-main [.] cJSON_Duplicate_rec - -
|
||||
0.00% 1 lws-main [.] cJSON_GetNumberValue - -
|
||||
0.00% 1 lws-main [k] call_rcu - -
|
||||
0.00% 1 lws-main [k] clear_page_orig - -
|
||||
0.00% 1 lws-main [k] cond_accept_memory - -
|
||||
0.00% 1 lws-main [.] copysignl - -
|
||||
0.00% 1 lws-main [k] do_poll.constprop.0 - -
|
||||
0.00% 1 lws-main [k] do_sys_poll - -
|
||||
0.00% 1 lws-main [k] find_exception - -
|
||||
0.00% 1 lws-main [k] futex_q_lock - -
|
||||
0.00% 1 lws-main [k] get_l4proto - -
|
||||
0.00% 1 lws-main [.] get_meta - -
|
||||
0.00% 1 lws-main [k] get_page_from_freelist - -
|
||||
0.00% 1 lws-main [.] handle_req_message - -
|
||||
0.00% 1 lws-main [.] ip_ban_cleanup - -
|
||||
0.00% 1 lws-main [k] ip_finish_output - -
|
||||
0.00% 1 lws-main [k] ip_rcv_core - -
|
||||
0.00% 1 lws-main [k] ipv4_conntrack_defrag - -
|
||||
0.00% 1 lws-main [k] kmem_cache_free - -
|
||||
0.00% 1 lws-main [k] kvm_clock_get_cycles - -
|
||||
0.00% 1 lws-main [.] lws_check_utf8 - -
|
||||
0.00% 1 lws-main [.] lws_handle_POLLOUT_event - -
|
||||
0.00% 1 lws-main [.] lws_parse_ws - -
|
||||
0.00% 1 lws-main [.] lws_set_timeout - -
|
||||
0.00% 1 lws-main [.] lws_ssl_capable_read_no_ssl - -
|
||||
0.00% 1 lws-main [.] lws_tls_fake_POLLIN_for_buffered - -
|
||||
0.00% 1 lws-main [.] lws_write - -
|
||||
0.00% 1 lws-main [k] mas_ascend - -
|
||||
0.00% 1 lws-main [k] mas_wr_append - -
|
||||
0.00% 1 lws-main [k] mod_memcg_state - -
|
||||
0.00% 1 lws-main [k] native_write_msr - -
|
||||
0.00% 1 lws-main [k] nf_confirm - -
|
||||
0.00% 1 lws-main [.] nontrivial_free - -
|
||||
0.00% 1 lws-main [.] parse_string - -
|
||||
0.00% 1 lws-main [k] perf_iterate_ctx - -
|
||||
0.00% 1 lws-main [k] poll_select_set_timeout - -
|
||||
0.00% 1 lws-main [.] printf_core - -
|
||||
0.00% 1 lws-main [k] refill_stock - -
|
||||
0.00% 1 lws-main [.] refresh_hot_config_if_needed - -
|
||||
0.00% 1 lws-main [k] rep_movs_alternative - -
|
||||
0.00% 1 lws-main [.] rops_handle_POLLIN_ws - -
|
||||
0.00% 1 lws-main [k] sk_forced_mem_schedule - -
|
||||
0.00% 1 lws-main [k] skb_copy_bits - -
|
||||
0.00% 1 lws-main [k] skb_page_frag_refill - -
|
||||
0.00% 1 lws-main [k] skb_release_data - -
|
||||
0.00% 1 lws-main [k] tcp_ack_update_window.isra.0 - -
|
||||
0.00% 1 lws-main [k] tcp_chrono_stop - -
|
||||
0.00% 1 lws-main [k] tcp_current_mss - -
|
||||
0.00% 1 lws-main [k] tcp_data_queue - -
|
||||
0.00% 1 lws-main [k] tcp_sendmsg_locked - -
|
||||
0.00% 1 lws-main [k] tcp_v4_rcv - -
|
||||
0.00% 1 lws-main [k] tcp_write_xmit - -
|
||||
0.00% 1 lws-main [k] up_read - -
|
||||
0.00% 1 lws-main [.] validate_filter_array - -
|
||||
0.00% 1 lws-main [.] validate_filter_values - -
|
||||
0.00% 1 lws-main [.] vfprintf - -
|
||||
|
||||
|
||||
#
|
||||
# (Cannot load tips.txt file, please install perf!)
|
||||
#
|
||||
@@ -0,0 +1,5 @@
|
||||
Profiling PID: 2245961
|
||||
CLK_TCK=100
|
||||
Starting perf record in background...
|
||||
perf_pid=2246179
|
||||
Done. Artifacts in /tmp/c_relay_thread_profile_20260402_012527
|
||||
@@ -0,0 +1,49 @@
|
||||
timestamp,tid,thread_name,cpu_pct,delta_ticks,total_ticks
|
||||
1775093128,2245961,lws-main,0.00,0,36
|
||||
1775093128,2245969,db-read-1,0.00,0,26
|
||||
1775093128,2245970,db-write,0.00,0,540
|
||||
1775093128,2245971,event-worker,0.00,0,0
|
||||
1775093133,2245961,lws-main,0.20,1,37
|
||||
1775093133,2245969,db-read-1,0.00,0,26
|
||||
1775093133,2245970,db-write,0.20,1,541
|
||||
1775093133,2245971,event-worker,0.00,0,0
|
||||
1775093138,2245961,lws-main,0.20,1,38
|
||||
1775093138,2245969,db-read-1,0.20,1,27
|
||||
1775093138,2245970,db-write,27.60,138,679
|
||||
1775093138,2245971,event-worker,0.00,0,0
|
||||
1775093143,2245961,lws-main,0.00,0,38
|
||||
1775093143,2245969,db-read-1,0.00,0,27
|
||||
1775093143,2245970,db-write,0.00,0,679
|
||||
1775093143,2245971,event-worker,0.00,0,0
|
||||
1775093148,2245961,lws-main,0.00,0,38
|
||||
1775093148,2245969,db-read-1,0.60,3,30
|
||||
1775093148,2245970,db-write,27.40,137,816
|
||||
1775093148,2245971,event-worker,0.00,0,0
|
||||
1775093153,2245961,lws-main,0.20,1,39
|
||||
1775093153,2245969,db-read-1,0.20,1,31
|
||||
1775093153,2245970,db-write,67.20,336,1152
|
||||
1775093153,2245971,event-worker,0.00,0,0
|
||||
1775093158,2245961,lws-main,0.20,1,40
|
||||
1775093158,2245969,db-read-1,0.20,1,32
|
||||
1775093158,2245970,db-write,40.00,200,1352
|
||||
1775093158,2245971,event-worker,0.00,0,0
|
||||
1775093163,2245961,lws-main,0.00,0,40
|
||||
1775093163,2245969,db-read-1,0.20,1,33
|
||||
1775093163,2245970,db-write,27.00,135,1487
|
||||
1775093163,2245971,event-worker,0.00,0,0
|
||||
1775093168,2245961,lws-main,0.20,1,41
|
||||
1775093168,2245969,db-read-1,0.00,0,33
|
||||
1775093168,2245970,db-write,26.60,133,1620
|
||||
1775093168,2245971,event-worker,0.00,0,0
|
||||
1775093173,2245961,lws-main,0.00,0,41
|
||||
1775093173,2245969,db-read-1,0.00,0,33
|
||||
1775093173,2245970,db-write,0.00,0,1620
|
||||
1775093173,2245971,event-worker,0.00,0,0
|
||||
1775093178,2245961,lws-main,0.20,1,42
|
||||
1775093178,2245969,db-read-1,0.00,0,33
|
||||
1775093178,2245970,db-write,64.40,322,1942
|
||||
1775093178,2245971,event-worker,0.00,0,0
|
||||
1775093183,2245961,lws-main,0.00,0,42
|
||||
1775093183,2245969,db-read-1,0.40,2,35
|
||||
1775093183,2245970,db-write,56.40,282,2224
|
||||
1775093183,2245971,event-worker,0.00,0,0
|
||||
|
@@ -0,0 +1,11 @@
|
||||
==========================================
|
||||
Thread CPU Summary (avg + max over run)
|
||||
==========================================
|
||||
Run timestamp (UTC): 20260402_012527
|
||||
Duration: 60s, Interval: 5s
|
||||
|
||||
2245970 db-write 28.07 67.20
|
||||
2245969 db-read-1 0.15 0.60
|
||||
2245961 lws-main 0.10 0.20
|
||||
2245971 event-worker 0.00 0.00
|
||||
TID THREAD AVG_CPU% MAX_CPU%
|
||||
Reference in New Issue
Block a user