[NEW] Introduce lttng based tracing (#2070)

## Introduce

In a production environment, it's quite challenging to figure out why a
Valkey is under high load. Right now, tools like INFO or slowlog can
offer some clues. But if the Valkey can't respond, we might not get any
information at all.
Usually, we have to rely on tools like `strace` or `perf` to find the
root cause. If we set up trace points in advance during the project
development, we can quickly pinpoint performance issues.

In this current PR, support has been added for all latency sampling
points. Also, information reporting for command execution has been
added. At the same time, it supports dynamically turning on or off the
information reporting as required. The trace feature is implemented
based on LTTng, and this capability is supported in projects like QEMU,
Ceph.

## How to use

Building Valkey with LTTng support:

```
USE_LTTNG=yes make
```

Open event report:
```
config set trace-events "sys server db cluster aof commands"
```

Events are classified as follows:
- sys (System-level operations)
- server (Server core logic)
- db (Database core operations)
- cluster (Cluster configuration operations)
- aof (AOF persistence operations)
- commands(Command execution information)

## How to trace

Enable lttng trace events dynamically:
```
~# lttng destroy valkey
~# lttng create valkey
~# lttng enable-event -u valkey:*
~# lttng track -u -p `pidof valkey-server`
~# lttng start
~# lttng stop
~# lttng view
```

Examples (a client run 'SET', another run 'keys'):

```
[15:30:19.334463706] (+0.000001243) libai valkey:command_call: { cpu_id = 15 }, { name = "set", duration = 0 }
[15:30:19.334465183] (+0.000001477) libai valkey:command_call: { cpu_id = 15 }, { name = "set", duration = 1 }
[15:30:19.334466516] (+0.000001333) libai valkey:command_call: { cpu_id = 15 }, { name = "set", duration = 0 }
[15:30:19.334467738] (+0.000001222) libai valkey:command_call: { cpu_id = 15 }, { name = "set", duration = 0 }
[15:30:19.334469105] (+0.000001367) libai valkey:command_call: { cpu_id = 15 }, { name = "set", duration = 1 }
[15:30:19.334470327] (+0.000001222) libai valkey:command_call: { cpu_id = 15 }, { name = "set", duration = 0 }
[15:30:19.369348485] (+0.034878158) libai valkey:command_call: { cpu_id = 15 }, { name = "keys", duration = 34874 }
[15:30:19.369698322] (+0.000349837) libai valkey:command_call: { cpu_id = 15 }, { name = "set", duration = 4 }
[15:30:19.369702327] (+0.000004005) libai valkey:command_call: { cpu_id = 15 }, { name = "set", duration = 2 }

```

Then we can use another script to analyze topN slow commands and other
system
level events.

About performance overhead (valkey-benchmark -t get -n 1000000 --threads
4):
1> no lttng builtin: 285632.69 requests per second
2> lttng builtin, no trace: 285551.09 requests per second (almost 0
overhead)
3> lttng builtin, trace commands: 266595.59 requests per second (about
~6.6 overhead)

Generally valkey-server would not run in full utilization, the overhead
is acceptable.

## Problem analysis

Add prot and conn field into trace command

Run benchmark tool:
```
GET: rps=227428.0 (overall: 222756.2) avg_msec=0.114 (overall: 0.117)
GET: rps=225248.0 (overall: 223005.2) avg_msec=0.115 (overall: 0.117)
GET: rps=167474.1 (overall: 217942.2) avg_msec=0.193 (overall: 0.122) --> performance drop
GET: rps=220192.0 (overall: 218129.5) avg_msec=0.118 (overall: 0.122)
GET: rps=222868.0 (overall: 218493.7) avg_msec=0.117 (overall: 0.121)

```
Run another 'keys *' command in another connection, lead benchmark
performance
drop.

At the same time, lttng traces events:
```
[21:16:30.420997167] (+0.000004064) zhenwei valkey:command_call: { cpu_id = 6 }, { prot = "tcp", conn = "127.0.0.1:6379-127.0.0.1:54668", name = "get", duration = 1 }
[21:16:30.421001262] (+0.000004095) zhenwei valkey:command_call: { cpu_id = 6 }, { prot = "tcp", conn = "127.0.0.1:6379-127.0.0.1:54782", name = "get", duration = 1 }
[21:16:30.485562459] (+0.064561197) zhenwei valkey:command_call: { cpu_id = 6 }, { prot = "tcp", conn = "127.0.0.1:6379-127.0.0.1:54386", name = "keys", duration = 64551 } --> root cause
[21:16:30.485583101] (+0.000020642) zhenwei valkey:command_call: { cpu_id = 6 }, { prot = "tcp", conn = "127.0.0.1:6379-127.0.0.1:54522", name = "get", duration = 1 }
[21:16:30.485763891] (+0.000180790) zhenwei valkey:command_call: { cpu_id = 6 }, { prot = "tcp", conn = "127.0.0.1:6379-127.0.0.1:54542", name = "get", duration = 1 }
[21:16:30.485766451] (+0.000002560) zhenwei valkey:command_call: { cpu_id = 6 }, { prot = "tcp", conn = "127.0.0.1:6379-127.0.0.1:54438", name = "get", duration = 1 }
```

From this change, we can see that connection
127.0.0.1:6379-127.0.0.1:54386
affects other connections.

---------

Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
Signed-off-by: artikell <739609084@qq.com>
Signed-off-by: skyfirelee <739609084@qq.com>
Co-authored-by: zhenwei pi <pizhenwei@bytedance.com>
This commit is contained in:
skyfirelee 2025-06-09 05:39:57 +08:00 committed by GitHub
parent 838ba44cd6
commit 1941d28acd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 1242 additions and 39 deletions

View File

@ -827,6 +827,47 @@ jobs:
if: true && !contains(github.event.inputs.skiptests, 'unittest')
run: ./src/valkey-unit-tests
test-ubuntu-lttng:
runs-on: ubuntu-latest
if: |
(github.event_name == 'workflow_dispatch' ||
(github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
(github.event_name == 'pull_request' && (contains(github.event.pull_request.labels.*.name, 'run-extra-tests') || github.event.pull_request.base.ref != 'unstable'))) &&
!contains(github.event.inputs.skipjobs, 'lttng')
timeout-minutes: 1440
steps:
- name: prep
if: github.event_name == 'workflow_dispatch'
run: |
echo "GITHUB_REPOSITORY=${{github.event.inputs.use_repo}}" >> $GITHUB_ENV
echo "GITHUB_HEAD_REF=${{github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
echo "skipjobs: ${{github.event.inputs.skipjobs}}"
echo "skiptests: ${{github.event.inputs.skiptests}}"
echo "test_args: ${{github.event.inputs.test_args}}"
echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
repository: ${{ env.GITHUB_REPOSITORY }}
ref: ${{ env.GITHUB_HEAD_REF }}
- name: make
run: |
sudo apt-get update && sudo apt-get install lttng-tools lttng-modules-dkms liblttng-ust-dev
make -j4 USE_LTTNG=yes
- name: testprep
run: sudo apt-get install tcl8.6 tclx
- name: test
if: true && !contains(github.event.inputs.skiptests, 'valkey')
run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --verbose --dump-logs ${{github.event.inputs.test_args}}
- name: module api test
if: true && !contains(github.event.inputs.skiptests, 'modules')
run: CFLAGS='-Werror' ./runtest-moduleapi --verbose --dump-logs ${{github.event.inputs.test_args}}
- name: sentinel tests
if: true && !contains(github.event.inputs.skiptests, 'sentinel')
run: ./runtest-sentinel ${{github.event.inputs.cluster_test_args}}
- name: cluster tests
if: true && !contains(github.event.inputs.skiptests, 'cluster')
run: ./runtest-cluster ${{github.event.inputs.cluster_test_args}}
test-rpm-distros-jemalloc:
if: |
(github.event_name == 'workflow_dispatch' ||

View File

@ -104,6 +104,13 @@ set(VALKEY_SERVER_SRCS
${CMAKE_SOURCE_DIR}/src/lua/function_lua.c
${CMAKE_SOURCE_DIR}/src/lua/engine_lua.c
${CMAKE_SOURCE_DIR}/src/lua/debug_lua.c
${CMAKE_SOURCE_DIR}/src/trace/trace.c
${CMAKE_SOURCE_DIR}/src/trace/trace_aof.c
${CMAKE_SOURCE_DIR}/src/trace/trace_commands.c
${CMAKE_SOURCE_DIR}/src/trace/trace_db.c
${CMAKE_SOURCE_DIR}/src/trace/trace_cluster.c
${CMAKE_SOURCE_DIR}/src/trace/trace_server.c
${CMAKE_SOURCE_DIR}/src/trace/trace_bgsave.c
${CMAKE_SOURCE_DIR}/src/commands.c
${CMAKE_SOURCE_DIR}/src/strl.c
${CMAKE_SOURCE_DIR}/src/connection.c

View File

@ -14,3 +14,4 @@ sha1.*
sha256.*
siphash.c
strl.c
trace/trace_*

View File

@ -295,6 +295,11 @@ ifeq ($(MALLOC),jemalloc)
FINAL_LIBS := ../deps/jemalloc/lib/libjemalloc.a $(FINAL_LIBS)
endif
ifeq ($(USE_LTTNG),yes)
FINAL_CFLAGS+=-DUSE_LTTNG
FINAL_LIBS += -llttng-ust
endif
# LIBSSL & LIBCRYPTO
LIBSSL_LIBS=
LIBSSL_PKGCONFIG := $(shell $(PKG_CONFIG) --exists libssl && echo $$?)
@ -386,7 +391,7 @@ else
MAYBE_UNINSTALL_REDIS_SYMLINK=
endif
SERVER_CC=$(QUIET_CC)$(CC) $(FINAL_CFLAGS)
SERVER_CC=$(QUIET_CC)$(CC) $(FINAL_CFLAGS) -I.
SERVER_AR=$(QUIET_AR)$(AR)
SERVER_LD=$(QUIET_LINK)$(CC) $(FINAL_LDFLAGS)
ENGINE_INSTALL=$(QUIET_INSTALL)$(INSTALL)
@ -417,7 +422,9 @@ endif
ENGINE_NAME=valkey
SERVER_NAME=$(ENGINE_NAME)-server$(PROG_SUFFIX)
ENGINE_SENTINEL_NAME=$(ENGINE_NAME)-sentinel$(PROG_SUFFIX)
ENGINE_TRACE_OBJ=trace/trace.o trace/trace_commands.o trace/trace_db.o trace/trace_bgsave.o trace/trace_cluster.o trace/trace_server.o trace/trace_aof.o
ENGINE_SERVER_OBJ=threads_mngr.o adlist.o quicklist.o ae.o anet.o dict.o hashtable.o kvstore.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o memory_prefetch.o io_threads.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o cluster_legacy.o cluster_slot_stats.o crc16.o endianconv.o commandlog.o eval.o bio.o rio.o rand.o memtest.o syscheck.o crcspeed.o crccombine.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o valkey-check-rdb.o valkey-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o allocator_defrag.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o lolwut6.o acl.o tracking.o socket.o tls.o sha256.o timeout.o setcpuaffinity.o monotonic.o mt19937-64.o resp_parser.o call_reply.o script.o functions.o commands.o strl.o connection.o unix.o logreqres.o rdma.o scripting_engine.o lua/script_lua.o lua/function_lua.o lua/engine_lua.o lua/debug_lua.o
ENGINE_SERVER_OBJ+=$(ENGINE_TRACE_OBJ)
ENGINE_CLI_NAME=$(ENGINE_NAME)-cli$(PROG_SUFFIX)
ENGINE_CLI_OBJ=anet.o adlist.o dict.o valkey-cli.o zmalloc.o release.o ae.o serverassert.o crcspeed.o crccombine.o crc64.o siphash.o crc16.o monotonic.o cli_common.o mt19937-64.o strl.o cli_commands.o sds.o util.o sha256.o
ENGINE_BENCHMARK_NAME=$(ENGINE_NAME)-benchmark$(PROG_SUFFIX)
@ -541,6 +548,9 @@ DEP = $(ENGINE_SERVER_OBJ:%.o=%.d) $(ENGINE_CLI_OBJ:%.o=%.d) $(ENGINE_BENCHMARK_
lua/%.o: lua/%.c .make-prerequisites
$(SERVER_CC) -MMD -o $@ -c $<
trace/%.o: trace/%.c .make-prerequisites
$(SERVER_CC) -Itrace -MMD -o $@ -c $<
unit/%.o: unit/%.c .make-prerequisites
$(SERVER_CC) -MMD -o $@ -c $<
@ -564,7 +574,7 @@ endif
commands.c: $(COMMANDS_DEF_FILENAME).def
clean:
rm -rf $(SERVER_NAME) $(ENGINE_SENTINEL_NAME) $(ENGINE_CLI_NAME) $(ENGINE_BENCHMARK_NAME) $(ENGINE_CHECK_RDB_NAME) $(ENGINE_CHECK_AOF_NAME) $(ENGINE_UNIT_TESTS) $(ENGINE_LIB_NAME) unit/*.o unit/*.d lua/*.o lua/*.d *.o *.gcda *.gcno *.gcov valkey.info lcov-html Makefile.dep *.so
rm -rf $(SERVER_NAME) $(ENGINE_SENTINEL_NAME) $(ENGINE_CLI_NAME) $(ENGINE_BENCHMARK_NAME) $(ENGINE_CHECK_RDB_NAME) $(ENGINE_CHECK_AOF_NAME) $(ENGINE_UNIT_TESTS) $(ENGINE_LIB_NAME) unit/*.o unit/*.d lua/*.o lua/*.d trace/*.o trace/*.d *.o *.gcda *.gcno *.gcov valkey.info lcov-html Makefile.dep *.so
rm -f $(DEP)
.PHONY: clean

View File

@ -1129,12 +1129,16 @@ void flushAppendOnlyFile(int force) {
* useful for graphing / monitoring purposes. */
if (sync_in_progress) {
latencyAddSampleIfNeeded("aof-write-pending-fsync", latency);
latencyTraceIfNeeded(aof, aof_write_pending_fsync, latency);
} else if (hasActiveChildProcess()) {
latencyAddSampleIfNeeded("aof-write-active-child", latency);
latencyTraceIfNeeded(aof, aof_write_active_child, latency);
} else {
latencyAddSampleIfNeeded("aof-write-alone", latency);
latencyTraceIfNeeded(aof, aof_write_alone, latency);
}
latencyAddSampleIfNeeded("aof-write", latency);
latencyTraceIfNeeded(aof, aof_write, latency);
/* We performed the write so reset the postponed flush sentinel to zero. */
server.aof_flush_postponed_start = 0;
@ -1248,6 +1252,8 @@ try_fsync:
}
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("aof-fsync-always", latency);
latencyTraceIfNeeded(aof, aof_fsync_always, latency);
server.aof_last_incr_fsync_offset = server.aof_last_incr_size;
server.aof_last_fsync = server.mstime;
atomic_store_explicit(&server.fsynced_reploff_pending, server.primary_repl_offset, memory_order_relaxed);
@ -2501,6 +2507,7 @@ off_t getAppendOnlyFileSize(sds filename, int *status) {
}
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("aof-fstat", latency);
latencyTraceIfNeeded(aof, aof_fstat, latency);
sdsfree(aof_filepath);
return size;
}
@ -2577,6 +2584,7 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
}
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("aof-rename", latency);
latencyTraceIfNeeded(aof, aof_rename, latency);
serverLog(LL_NOTICE, "Successfully renamed the temporary AOF base file %s into %s", tmpfile, new_base_filename);
/* Rename the temporary incr aof file to 'new_incr_filename'. */
@ -2603,6 +2611,7 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
}
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("aof-rename", latency);
latencyTraceIfNeeded(aof, aof_rename, latency);
serverLog(LL_NOTICE, "Successfully renamed the temporary AOF incr file %s into %s", temp_incr_aof_name,
new_incr_filename);
sdsfree(temp_incr_filepath);

View File

@ -148,7 +148,8 @@ void updateStatsOnUnblock(client *c, long blocked_us, long reply_us, int failed_
commandlogPushCurrentCommand(c, c->lastcmd);
c->duration = 0;
/* Log the reply duration event. */
latencyAddSampleIfNeeded("command-unblocking", reply_us / 1000);
latencyAddSampleIfNeeded("command-unblocking", reply_us);
latencyTraceIfNeeded(server, command_unblocking, reply_us);
}
/* This function is called in the beforeSleep() function of the event loop

View File

@ -857,7 +857,7 @@ int clusterSaveConfig(int do_fsync) {
}
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("cluster-config-open", latency);
latencyTraceIfNeeded(cluster, cluster_config_open, latency);
latencyStartMonitor(latency);
while (offset < content_size) {
written_bytes = write(fd, ci + offset, content_size - offset);
@ -871,7 +871,7 @@ int clusterSaveConfig(int do_fsync) {
}
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("cluster-config-write", latency);
latencyTraceIfNeeded(cluster, cluster_config_write, latency);
if (do_fsync) {
latencyStartMonitor(latency);
server.cluster->todo_before_sleep &= ~CLUSTER_TODO_FSYNC_CONFIG;
@ -881,6 +881,7 @@ int clusterSaveConfig(int do_fsync) {
}
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("cluster-config-fsync", latency);
latencyTraceIfNeeded(cluster, cluster_config_fsync, latency);
}
latencyStartMonitor(latency);
@ -890,7 +891,7 @@ int clusterSaveConfig(int do_fsync) {
}
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("cluster-config-rename", latency);
latencyTraceIfNeeded(cluster, cluster_config_rename, latency);
if (do_fsync) {
latencyStartMonitor(latency);
if (fsyncFileDir(server.cluster_configfile) == -1) {
@ -899,6 +900,7 @@ int clusterSaveConfig(int do_fsync) {
}
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("cluster-config-dir-fsync", latency);
latencyTraceIfNeeded(cluster, cluster_config_dir_fsync, latency);
}
retval = C_OK; /* If we reached this point, everything is fine. */
@ -908,12 +910,14 @@ cleanup:
close(fd);
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("cluster-config-close", latency);
latencyTraceIfNeeded(cluster, cluster_config_close, latency);
}
if (retval == C_ERR) {
latencyStartMonitor(latency);
unlink(tmpfilename);
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("cluster-config-unlink", latency);
latencyTraceIfNeeded(cluster, cluster_config_unlink, latency);
}
sdsfree(tmpfilename);
sdsfree(ci);

View File

@ -34,6 +34,7 @@
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/uio.h>
#include "ae.h"
@ -41,6 +42,11 @@
#define CONN_INFO_LEN 32
#define CONN_ADDR_STR_LEN 128 /* Similar to INET6_ADDRSTRLEN, hoping to handle other protocols. */
#define NET_HOST_STR_LEN 256 /* Longest valid hostname */
#define NET_IP_STR_LEN 46 /* INET6_ADDRSTRLEN is 46, but we need to be sure */
#define NET_ADDR_STR_LEN (NET_IP_STR_LEN + 32) /* Must be enough for ip:port */
#define NET_HOST_PORT_STR_LEN (NET_HOST_STR_LEN + 32) /* Must be enough for hostname:port */
struct aeEventLoop;
typedef struct connection connection;
typedef struct connListener connListener;
@ -58,6 +64,14 @@ typedef enum {
#define CONN_FLAG_WRITE_BARRIER (1 << 1) /* Write barrier requested */
#define CONN_FLAG_ALLOW_ACCEPT_OFFLOAD (1 << 2) /* Connection accept can be offloaded to IO threads. */
typedef enum {
CONN_TYPE_ID_INVALID = 0,
CONN_TYPE_ID_SOCKET,
CONN_TYPE_ID_UNIX,
CONN_TYPE_ID_TLS,
CONN_TYPE_ID_RDMA,
} ConnectionTypeId;
#define CONN_TYPE_SOCKET "tcp"
#define CONN_TYPE_UNIX "unix"
#define CONN_TYPE_TLS "tls"
@ -68,6 +82,7 @@ typedef void (*ConnectionCallbackFunc)(struct connection *conn);
typedef struct ConnectionType {
/* connection type */
int (*get_type_id)(struct connection *conn);
const char *(*get_type)(struct connection *conn);
/* connection type initialize & finalize & configure */
@ -295,6 +310,13 @@ static inline const char *connGetType(connection *conn) {
return conn->type->get_type(conn);
}
static inline int connGetTypeId(connection *conn) {
if (!conn || conn->type->get_type_id == NULL) {
return CONN_TYPE_ID_INVALID;
}
return conn->type->get_type_id(conn);
}
static inline int connLastErrorRetryable(connection *conn) {
return conn->last_errno == EINTR;
}

View File

@ -1816,6 +1816,7 @@ void deleteExpiredKeyAndPropagateWithDictIndex(serverDb *db, robj *keyobj, int d
dbGenericDeleteWithDictIndex(db, keyobj, server.lazyfree_lazy_expire, DB_FLAG_KEY_EXPIRED, dict_index);
latencyEndMonitor(expire_latency);
latencyAddSampleIfNeeded("expire-del", expire_latency);
latencyTraceIfNeeded(db, expire_del, expire_latency);
notifyKeyspaceEvent(NOTIFY_EXPIRED, "expired", keyobj, db->id);
signalModifiedKey(NULL, db, keyobj);
propagateDeletion(db, keyobj, server.lazyfree_lazy_expire);

View File

@ -1187,7 +1187,7 @@ static long long activeDefragTimeProc(struct aeEventLoop *eventLoop, long long i
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("active-defrag-cycle", latency);
latencyTraceIfNeeded(db, active_defrag_cycle, latency);
if (haveMoreWork) {
return computeDelayMs(endtime);
} else {

View File

@ -671,6 +671,7 @@ int performEvictions(void) {
dbGenericDelete(db, keyobj, server.lazyfree_lazy_eviction, DB_FLAG_KEY_EVICTED);
latencyEndMonitor(eviction_latency);
latencyAddSampleIfNeeded("eviction-del", eviction_latency);
latencyTraceIfNeeded(db, eviction_del, eviction_latency);
delta -= (long long)zmalloc_used_memory();
mem_freed += delta;
server.stat_evictedkeys++;
@ -734,10 +735,12 @@ cant_free:
}
latencyEndMonitor(lazyfree_latency);
latencyAddSampleIfNeeded("eviction-lazyfree", lazyfree_latency);
latencyTraceIfNeeded(db, eviction_lazyfree, lazyfree_latency);
}
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("eviction-cycle", latency);
latencyTraceIfNeeded(db, eviction_cycle, latency);
update_metrics:
if (result == EVICT_RUNNING || result == EVICT_FAIL) {

View File

@ -359,7 +359,8 @@ void activeExpireCycle(int type) {
elapsed = ustime() - start;
server.stat_expire_cycle_time_used += elapsed;
latencyAddSampleIfNeeded("expire-cycle", elapsed / 1000);
latencyAddSampleIfNeeded("expire-cycle", elapsed);
latencyTraceIfNeeded(db, expire_cycle, elapsed);
/* Update our estimate of keys existing but yet to be expired.
* Running average with this sample accounting for 5%. */

View File

@ -76,7 +76,8 @@ void latencyMonitorInit(void) {
* This function is usually called via latencyAddSampleIfNeeded(), that
* is a macro that only adds the sample if the latency is higher than
* server.latency_monitor_threshold. */
void latencyAddSample(const char *event, mstime_t latency) {
void latencyAddSample(const char *event, ustime_t latency_us) {
mstime_t latency = latency_us / 1000;
struct latencyTimeSeries *ts = dictFetchValue(server.latency_events, event);
time_t now = time(NULL);
int prev;

View File

@ -34,8 +34,14 @@
#ifndef __LATENCY_H
#define __LATENCY_H
#include "trace/trace.h"
#define LATENCY_TS_LEN 160 /* History length for every monitored event. */
#ifndef LATENCY_TRACE_SWITCH
#define LATENCY_TRACE_SWITCH 0
#endif
/* Representation of a latency sample: the sampling time and the latency
* observed in milliseconds. */
struct latencySample {
@ -64,14 +70,14 @@ struct latencyStats {
};
void latencyMonitorInit(void);
void latencyAddSample(const char *event, mstime_t latency);
void latencyAddSample(const char *event, ustime_t latency);
/* Latency monitoring macros. */
/* Start monitoring an event. We just set the current time. */
#define latencyStartMonitor(var) \
if (server.latency_monitor_threshold) { \
var = mstime(); \
if (server.latency_monitor_threshold || LATENCY_TRACE_SWITCH) { \
var = ustime(); \
} else { \
var = 0; \
}
@ -79,13 +85,13 @@ void latencyAddSample(const char *event, mstime_t latency);
/* End monitoring an event, compute the difference with the current time
* to check the amount of time elapsed. */
#define latencyEndMonitor(var) \
if (server.latency_monitor_threshold) { \
var = mstime() - var; \
if (server.latency_monitor_threshold || LATENCY_TRACE_SWITCH) { \
var = ustime() - var; \
}
/* Add the sample only if the elapsed time is >= to the configured threshold. */
#define latencyAddSampleIfNeeded(event, var) \
if (server.latency_monitor_threshold && (var) >= server.latency_monitor_threshold) latencyAddSample((event), (var));
if (server.latency_monitor_threshold && (var) >= server.latency_monitor_threshold * 1000) latencyAddSample((event), (var));
/* Remove time from a nested event. */
#define latencyRemoveNestedEvent(event_var, nested_var) event_var += nested_var;

View File

@ -7717,7 +7717,7 @@ void VM__Assert(const char *estr, const char *file, int line) {
* command. The call is skipped if the latency is smaller than the configured
* latency-monitor-threshold. */
void VM_LatencyAddSample(const char *event, mstime_t latency) {
latencyAddSampleIfNeeded(event, latency);
latencyAddSampleIfNeeded(event, latency * 1000);
}
/* --------------------------------------------------------------------------

View File

@ -1690,11 +1690,12 @@ void acceptCommonHandler(connection *conn, struct ClientFlags flags, char *ip) {
client *c;
UNUSED(ip);
if (connGetState(conn) != CONN_STATE_ACCEPTING) {
char addr[NET_ADDR_STR_LEN] = {0};
char laddr[NET_ADDR_STR_LEN] = {0};
connFormatAddr(conn, addr, sizeof(addr), 1);
connFormatAddr(conn, laddr, sizeof(addr), 0);
if (connGetState(conn) != CONN_STATE_ACCEPTING) {
serverLog(LL_VERBOSE, "Accepted client connection in error state: %s (addr=%s laddr=%s)",
connGetLastError(conn), addr, laddr);
connClose(conn);
@ -1727,10 +1728,6 @@ void acceptCommonHandler(connection *conn, struct ClientFlags flags, char *ip) {
/* Create connection and client */
if ((c = createClient(conn)) == NULL) {
char addr[NET_ADDR_STR_LEN] = {0};
char laddr[NET_ADDR_STR_LEN] = {0};
connFormatAddr(conn, addr, sizeof(addr), 1);
connFormatAddr(conn, laddr, sizeof(addr), 0);
serverLog(LL_WARNING, "Error registering fd event for the new client connection: %s (addr=%s laddr=%s)",
connGetLastError(conn), addr, laddr);
connClose(conn); /* May be already closed, just ignore errors */

View File

@ -3478,6 +3478,7 @@ static void backgroundSaveDoneHandlerDisk(int exitcode, int bysignal, time_t sav
rdbRemoveTempFile(server.child_pid, 0);
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("rdb-unlink-temp-file", latency);
latencyTraceIfNeeded(bgsave, rdb_unlink_temp_file, latency);
/* SIGUSR1 is whitelisted, so we have a way to kill a child without
* triggering an error condition. */
if (bysignal != SIGUSR1) server.lastbgsave_status = C_ERR;

View File

@ -1520,6 +1520,12 @@ static const char *connRdmaGetType(connection *conn) {
return CONN_TYPE_RDMA;
}
static int connRdmaGetTypeId(connection *conn) {
UNUSED(conn);
return CONN_TYPE_ID_RDMA;
}
static int rdmaServer(char *err, int port, char *bindaddr, int af, rdma_listener *rdma_listener) {
int ret = ANET_OK, rv, afonly = 1;
char _port[6]; /* strlen("65535") */
@ -1814,6 +1820,7 @@ static void updateRdmaState(struct connection *conn) {
static ConnectionType CT_RDMA = {
/* connection type */
.get_type_id = connRdmaGetTypeId,
.get_type = connRdmaGetType,
/* connection type initialize & finalize & configure */

View File

@ -822,7 +822,7 @@ void sentinelRunPendingScripts(void) {
sj->flags |= SENTINEL_SCRIPT_RUNNING;
sj->start_time = mstime();
sj->retry_num++;
pid = fork();
pid = valkey_fork();
if (pid == -1) {
/* Parent (fork error).

View File

@ -52,6 +52,8 @@
#include "lua/debug_lua.h"
#include "eval.h"
#include "trace/trace_commands.h"
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
@ -1743,6 +1745,7 @@ void whileBlockedCron(void) {
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("while-blocked-cron", latency);
latencyTraceIfNeeded(server, while_blocked_cron, latency);
/* We received a SIGTERM during loading, shutting down here in a safe way,
* as it isn't ok doing so inside the signal handler. */
@ -1885,7 +1888,9 @@ void beforeSleep(struct aeEventLoop *eventLoop) {
if (server.aof_state == AOF_ON || server.aof_state == AOF_WAIT_REWRITE) flushAppendOnlyFile(0);
/* Record time consumption of AOF writing. */
durationAddSample(EL_DURATION_TYPE_AOF, getMonotonicUs() - aof_start_time);
monotime aof_duration = getMonotonicUs() - aof_start_time;
durationAddSample(EL_DURATION_TYPE_AOF, aof_duration);
latencyTraceIfNeeded(aof, aof_flush, aof_duration);
/* Update the fsynced replica offset.
* If an initial rewrite is in progress then not all data is guaranteed to have actually been
@ -1929,9 +1934,11 @@ void beforeSleep(struct aeEventLoop *eventLoop) {
if (server.el_start > 0) {
monotime el_duration = getMonotonicUs() - server.el_start;
durationAddSample(EL_DURATION_TYPE_EL, el_duration);
latencyTraceIfNeeded(server, eventloop, el_duration);
}
server.el_cron_duration += duration_before_aof + duration_after_write;
durationAddSample(EL_DURATION_TYPE_CRON, server.el_cron_duration);
latencyTraceIfNeeded(server, eventloop_cron, server.el_cron_duration);
server.el_cron_duration = 0;
/* Record max command count per cycle. */
if (server.stat_numcommands > server.el_cmd_cnt_start) {
@ -1973,6 +1980,7 @@ void afterSleep(struct aeEventLoop *eventLoop, int numevents) {
moduleFireServerEvent(VALKEYMODULE_EVENT_EVENTLOOP, VALKEYMODULE_SUBEVENT_EVENTLOOP_AFTER_SLEEP, NULL);
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("module-acquire-GIL", latency);
latencyTraceIfNeeded(server, module_acquire_gil, latency);
}
/* Set the eventloop start time. */
server.el_start = getMonotonicUs();
@ -3742,6 +3750,7 @@ void call(client *c, int flags) {
else
duration = ustime() - call_timer;
valkey_commands_trace(valkey_commands, command_call, connGetTypeId(c->conn), getClientPeerId(c), getClientPeerId(c), real_cmd->declared_name, duration);
c->duration += duration;
dirty = server.dirty - dirty;
if (dirty < 0) dirty = 0;
@ -3772,7 +3781,12 @@ void call(client *c, int flags) {
* a MULTI-EXEC from inside an AOF). */
if (update_command_stats) {
char *latency_event = (real_cmd->flags & CMD_FAST) ? "fast-command" : "command";
latencyAddSampleIfNeeded(latency_event, duration / 1000);
latencyAddSampleIfNeeded(latency_event, duration);
if (real_cmd->flags & CMD_FAST) {
latencyTraceIfNeeded(server, fast_command, duration);
} else {
latencyTraceIfNeeded(server, command, duration);
}
if (server.execution_nesting == 0) durationAddSample(EL_DURATION_TYPE_CMD, duration);
}
@ -6378,7 +6392,7 @@ void createPidFile(void) {
void daemonize(void) {
int fd;
if (fork() != 0) exit(0); /* parent exits */
if (valkey_fork() != 0) exit(0); /* parent exits */
setsid(); /* create a new session */
/* Every output goes to /dev/null. If the server is daemonized but
@ -6572,7 +6586,7 @@ int serverFork(int purpose) {
int childpid;
long long start = ustime();
if ((childpid = fork()) == 0) {
if ((childpid = valkey_fork()) == 0) {
/* Child.
*
* The order of setting things up follows some reasoning:
@ -6602,7 +6616,8 @@ int serverFork(int purpose) {
server.stat_fork_time = ustime() - start;
server.stat_fork_rate =
(double)zmalloc_used_memory() * 1000000 / server.stat_fork_time / (1024 * 1024 * 1024); /* GB per second. */
latencyAddSampleIfNeeded("fork", server.stat_fork_time / 1000);
latencyAddSampleIfNeeded("fork", server.stat_fork_time);
latencyTraceIfNeeded(bgsave, fork, server.stat_fork_time);
/* The child_pid and child_type are only for mutually exclusive children.
* other child types should handle and store their pid's in dedicated variables.

View File

@ -82,6 +82,13 @@ typedef long long ustime_t; /* microsecond time type. */
#include "rax.h" /* Radix tree */
#include "connection.h" /* Connection abstraction */
#include "memory_prefetch.h"
#include "trace/trace.h"
#ifdef USE_LTTNG
#define valkey_fork() do_fork()
#else
#define valkey_fork() fork()
#endif
#define dismissMemory zmadvise_dontneed
@ -137,10 +144,6 @@ struct hdr_histogram;
#define CONFIG_DEFAULT_PID_FILE "/var/run/valkey.pid"
#define CONFIG_DEFAULT_BINDADDR_COUNT 2
#define CONFIG_DEFAULT_BINDADDR {"*", "-::*"}
#define NET_HOST_STR_LEN 256 /* Longest valid hostname */
#define NET_IP_STR_LEN 46 /* INET6_ADDRSTRLEN is 46, but we need to be sure */
#define NET_ADDR_STR_LEN (NET_IP_STR_LEN + 32) /* Must be enough for ip:port */
#define NET_HOST_PORT_STR_LEN (NET_HOST_STR_LEN + 32) /* Must be enough for hostname:port */
#define CONFIG_BINDADDR_MAX 16
#define CONFIG_MIN_RESERVED_FDS 32
#define CONFIG_DEFAULT_PROC_TITLE_TEMPLATE "{title} {listen-addr} {server-mode}"

View File

@ -53,6 +53,10 @@
#define likely(x) (x)
#endif
#ifdef assert
#undef assert
#endif
#define assert(_e) (likely((_e)) ? (void)0 : (_serverAssert(#_e, __FILE__, __LINE__), valkey_unreachable()))
#define panic(...) _serverPanic(__FILE__, __LINE__, __VA_ARGS__), valkey_unreachable()

View File

@ -406,8 +406,15 @@ static const char *connSocketGetType(connection *conn) {
return CONN_TYPE_SOCKET;
}
static int connSocketGetTypeId(connection *conn) {
(void)conn;
return CONN_TYPE_ID_SOCKET;
}
static ConnectionType CT_Socket = {
/* connection type */
.get_type_id = connSocketGetTypeId,
.get_type = connSocketGetType,
/* connection type initialize & finalize & configure */

View File

@ -1120,6 +1120,12 @@ static const char *connTLSGetType(connection *conn_) {
return CONN_TYPE_TLS;
}
static int connTLSGetTypeId(connection *conn_) {
(void)conn_;
return CONN_TYPE_ID_TLS;
}
static int tlsHasPendingData(void) {
if (!pending_list) return 0;
return listLength(pending_list) > 0;
@ -1166,6 +1172,7 @@ static sds connTLSGetPeerCert(connection *conn_) {
static ConnectionType CT_TLS = {
/* connection type */
.get_type_id = connTLSGetTypeId,
.get_type = connTLSGetType,
/* connection type initialize & finalize & configure */

112
src/trace/README.md Normal file
View File

@ -0,0 +1,112 @@
## Introduction
This directory contains the implementation of tracing using [LTTng](https://lttng.org/) (Linux Trace Toolkit Next Generation).
## LTTng Installation
To install LTTng on your Linux system, follow the instructions provided in the [LTTng documentation](https://lttng.org/download/)
> Dependency LTTNG version is greater than 2.12.
### Install from package manager
#### [Ubuntu](https://lttng.org/docs/v2.13/#doc-ubuntu)
LTTng 2.13 is available on Ubuntu 22.04 LTS *Jammy Jellyfish*, Ubuntu 23.04 *Lunar Lobster*, and Ubuntu 23.10 *Mantic Minotaur*. For previous supported releases of Ubuntu, [use the LTTng Stable 2.13 PPA](https://lttng.org/docs/v2.13/#doc-ubuntu-ppa).
To install LTTng 2.13 on Ubuntu 22.04 LTS *Jammy Jellyfish*:
1. Install the main LTTng 2.13 packages:
```
apt-get install lttng-tools
apt-get install lttng-modules-dkms
apt-get install liblttng-ust-dev
```
#### [Debian](https://lttng.org/docs/v2.13/#doc-debian)
To install LTTng 2.13 on Debian 12 *bookworm*:
1. Install the main LTTng 2.13 packages:
```
apt install lttng-modules-dkms
apt install liblttng-ust-dev
apt install lttng-tools
```
## LTTng QuickStart
LTTng is an open source tracing framework for Linux that provides highly efficient and low-overhead tracing capabilities. It allows developers to trace both kernel and user-space applications.
Building Valkey with LTTng support:
```
USE_LTTNG=yes make
```
Enable lttng trace events dynamically:
```
~# lttng destroy valkey
~# lttng create valkey
~# lttng enable-event -u 'valkey_server:*'
~# lttng track -u -p `pidof valkey-server`
~# lttng start
~# lttng stop
~# lttng view
```
Examples (a client run 'SET', another run 'keys'):
```
...
[15:30:19.334467738] (+0.000001222) libai valkey:command_call: { cpu_id = 15 }, { name = "set", duration = 0 }
[15:30:19.334469105] (+0.000001367) libai valkey:command_call: { cpu_id = 15 }, { name = "set", duration = 1 }
[15:30:19.334470327] (+0.000001222) libai valkey:command_call: { cpu_id = 15 }, { name = "set", duration = 0 }
[15:30:19.369348485] (+0.034878158) libai valkey:command_call: { cpu_id = 15 }, { name = "keys", duration = 34874 }
[15:30:19.369698322] (+0.000349837) libai valkey:command_call: { cpu_id = 15 }, { name = "set", duration = 4 }
[15:30:19.369702327] (+0.000004005) libai valkey:command_call: { cpu_id = 15 }, { name = "set", duration = 2 }
[15:30:19.369704098] (+0.000001771) libai valkey:command_call: { cpu_id = 15 }, { name = "set", duration = 1 }
[15:30:19.369705884] (+0.000001786) libai valkey:command_call: { cpu_id = 15 }, { name = "set", duration = 0 }
...
```
Then we can use another script to analyze topN slow commands and other system
level events.
About performance overhead (valkey-benchmark -t get -n 1000000 --threads 4):
1> no lttng builtin: 285632.69 requests per second
2> lttng builtin, no trace: 285551.09 requests per second (almost 0 overhead)
3> lttng builtin, trace commands: 266595.59 requests per second (about ~6.6 overhead)
Generally valkey-server would not run in full utilization, the overhead is acceptable.
## Supported Events
| event | provider |
| -------------------------- | ----------------- |
| command_call | valkey_commands |
| rdb_unlink_temp_file | valkey_bgsave |
| fork | valkey_bgsave |
| while_blocked_cron | valkey_server |
| module_acquire_gil | valkey_server |
| command_unblocking | valkey_server |
| expire_del | valkey_db |
| active_defrag_cycle | valkey_db |
| eviction_del | valkey_db |
| eviction_lazyfree | valkey_db |
| eviction_cycle | valkey_db |
| expire_cycle | valkey_db |
| cluster_config_open | valkey_cluster |
| cluster_config_write | valkey_cluster |
| cluster_config_fsync | valkey_cluster |
| cluster_config_rename | valkey_cluster |
| cluster_config_dir_fsync | valkey_cluster |
| cluster_config_close | valkey_cluster |
| cluster_config_unlink | valkey_cluster |
| aof_write_pending_fsync | valkey_aof |
| aof_write_active_child | valkey_aof |
| aof_write_alone | valkey_aof |
| aof_write | valkey_aof |
| aof_fsync_always | valkey_aof |
| aof_fstat | valkey_aof |
| aof_rename | valkey_aof |

35
src/trace/trace.c Normal file
View File

@ -0,0 +1,35 @@
/*
* Copyright (c) Valkey Contributors
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
/* ==========================================================================
* trace.c - support generic tracing layers.
* --------------------------------------------------------------------------
* Copyright (C) 2025 zhenwei pi <zhenwei.pi@linux.dev>
* Copyright (C) 2025 zhiqiang li <lizhiqiang.sf@bytedance.com>
*
* This work is licensed under BSD 3-Clause, License 1 of the COPYING file in
* the top-level directory.
* ==========================================================================
*/
#include "trace.h"
#include <errno.h>
#ifdef USE_LTTNG
pid_t do_fork(void) {
sigset_t sigset;
int saved_errno;
lttng_ust_before_fork(&sigset);
int childpid = fork();
saved_errno = errno;
if (childpid != 0) {
lttng_ust_after_fork_parent(&sigset);
} else {
lttng_ust_after_fork_child(&sigset);
}
errno = saved_errno;
return childpid;
}
#endif

43
src/trace/trace.h Normal file
View File

@ -0,0 +1,43 @@
/*
* Copyright (c) Valkey Contributors
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
/* ==========================================================================
* trace.h - support generic tracing layers.
* --------------------------------------------------------------------------
* Copyright (C) 2025 zhenwei pi <zhenwei.pi@linux.dev>
* Copyright (C) 2025 zhiqiang li <lizhiqiang.sf@bytedance.com>
*
* This work is licensed under BSD 3-Clause, License 1 of the COPYING file in
* the top-level directory.
* ==========================================================================
*/
#if !defined(__VALKEY_TRACE_H__)
#define __VALKEY_TRACE_H__
#include "trace_aof.h"
#include "trace_cluster.h"
#include "trace_server.h"
#include "trace_db.h"
#include "trace_bgsave.h"
#include "trace_commands.h"
#ifdef USE_LTTNG
#include <lttng/ust-fork.h>
#define LATENCY_TRACE_SWITCH 1
pid_t do_fork(void);
#define latencyTraceIfNeeded(type, event, var) \
valkey_##type##_trace(valkey_##type, event, (var));
#else
#define latencyTraceIfNeeded(type, event, var) \
do { \
} while (0)
#endif
#endif /* __VALKEY_TRACE_H__ */

20
src/trace/trace_aof.c Normal file
View File

@ -0,0 +1,20 @@
/*
* Copyright (c) Valkey Contributors
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
/* ==========================================================================
* trace_aof.c - support lttng tracing for aof events.
* --------------------------------------------------------------------------
* Copyright (C) 2025 zhenwei pi <zhenwei.pi@linux.dev>
* Copyright (C) 2025 zhiqiang li <lizhiqiang.sf@bytedance.com>
*
* This work is licensed under BSD 3-Clause, License 1 of the COPYING file in
* the top-level directory.
* ==========================================================================
*/
#define LTTNG_UST_TRACEPOINT_CREATE_PROBES
#define LTTNG_UST_TRACEPOINT_DEFINE
#include "trace_aof.h"

149
src/trace/trace_aof.h Normal file
View File

@ -0,0 +1,149 @@
/*
* Copyright (c) Valkey Contributors
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
/* ==========================================================================
* trace_aof.h - support lttng tracing for aof events.
* --------------------------------------------------------------------------
* Copyright (C) 2025 zhenwei pi <zhenwei.pi@linux.dev>
* Copyright (C) 2025 zhiqiang li <lizhiqiang.sf@bytedance.com>
*
* This work is licensed under BSD 3-Clause, License 1 of the COPYING file in
* the top-level directory.
* ==========================================================================
*/
#ifdef USE_LTTNG
#undef LTTNG_UST_TRACEPOINT_PROVIDER
#define LTTNG_UST_TRACEPOINT_PROVIDER valkey_aof
#undef LTTNG_UST_TRACEPOINT_INCLUDE
#define LTTNG_UST_TRACEPOINT_INCLUDE "./trace_aof.h"
#if !defined(__VALKEY_TRACE_AOF_H__) || defined(LTTNG_UST_TRACEPOINT_HEADER_MULTI_READ)
#define __VALKEY_TRACE_AOF_H__
#include <lttng/tracepoint.h>
LTTNG_UST_TRACEPOINT_EVENT_CLASS(
/* Tracepoint class provider name */
valkey_aof,
/* Tracepoint class name */
valkey_aof_class,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
),
/* List of fields of eventual event (output) */
LTTNG_UST_TP_FIELDS(
lttng_ust_field_integer(uint64_t, duration, duration)
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_aof, valkey_aof_class, valkey_aof, aof_write_pending_fsync,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_aof, valkey_aof_class, valkey_aof, aof_write_active_child,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_aof, valkey_aof_class, valkey_aof, aof_write_alone,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_aof, valkey_aof_class, valkey_aof, aof_write,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_aof, valkey_aof_class, valkey_aof, aof_fsync_always,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_aof, valkey_aof_class, valkey_aof, aof_fstat,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_aof, valkey_aof_class, valkey_aof, aof_rename,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_aof, valkey_aof_class, valkey_aof, aof_flush,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
#define valkey_aof_trace(...) lttng_ust_tracepoint(__VA_ARGS__)
#endif /* __VALKEY_TRACE_AOF_H__ */
#include <lttng/tracepoint-event.h>
#else /* USE_LTTNG */
#ifndef __VALKEY_TRACE_AOF_H__
#define __VALKEY_TRACE_AOF_H__
/* avoid compiler warning on empty source file */
static inline void __valkey_aof_trace(void) {
}
#define valkey_aof_trace(...) \
do { \
} while (0)
#endif /* __VALKEY_TRACE_AOF_H__ */
#endif /* USE_LTTNG */

20
src/trace/trace_bgsave.c Normal file
View File

@ -0,0 +1,20 @@
/*
* Copyright (c) Valkey Contributors
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
/* ==========================================================================
* trace_sys.c - support lttng tracing for system events.
* --------------------------------------------------------------------------
* Copyright (C) 2025 zhenwei pi <zhenwei.pi@linux.dev>
* Copyright (C) 2025 zhiqiang li <lizhiqiang.sf@bytedance.com>
*
* This work is licensed under BSD 3-Clause, License 1 of the COPYING file in
* the top-level directory.
* ==========================================================================
*/
#define LTTNG_UST_TRACEPOINT_CREATE_PROBES
#define LTTNG_UST_TRACEPOINT_DEFINE
#include "trace_bgsave.h"

89
src/trace/trace_bgsave.h Normal file
View File

@ -0,0 +1,89 @@
/*
* Copyright (c) Valkey Contributors
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
/* ==========================================================================
* trace_bgsave.h - support lttng tracing for background Save.
* --------------------------------------------------------------------------
* Copyright (C) 2025 zhenwei pi <zhenwei.pi@linux.dev>
* Copyright (C) 2025 zhiqiang li <lizhiqiang.sf@bytedance.com>
*
* This work is licensed under BSD 3-Clause, License 1 of the COPYING file in
* the top-level directory.
* ==========================================================================
*/
#ifdef USE_LTTNG
#undef LTTNG_UST_TRACEPOINT_PROVIDER
#define LTTNG_UST_TRACEPOINT_PROVIDER valkey_bgsave
#undef LTTNG_UST_TRACEPOINT_INCLUDE
#define LTTNG_UST_TRACEPOINT_INCLUDE "./trace_bgsave.h"
#if !defined(__VALKEY_TRACE_SYS_H__) || defined(LTTNG_UST_TRACEPOINT_HEADER_MULTI_READ)
#define __VALKEY_TRACE_SYS_H__
#include <lttng/tracepoint.h>
LTTNG_UST_TRACEPOINT_EVENT_CLASS(
/* Tracepoint class provider name */
valkey_bgsave,
/* Tracepoint class name */
valkey_bgsave_class,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
),
/* List of fields of eventual event (output) */
LTTNG_UST_TP_FIELDS(
lttng_ust_field_integer(uint64_t, duration, duration)
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_bgsave, valkey_bgsave_class, valkey_bgsave, fork,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_bgsave, valkey_bgsave_class, valkey_bgsave, rdb_unlink_temp_file,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
#define valkey_bgsave_trace(...) lttng_ust_tracepoint(__VA_ARGS__)
#endif /* __VALKEY_TRACE_SYS_H__ */
#include <lttng/tracepoint-event.h>
#else /* USE_LTTNG */
#ifndef __VALKEY_TRACE_SYS_H__
#define __VALKEY_TRACE_SYS_H__
/* avoid compiler warning on empty source file */
static inline void __valkey_bgsave_trace(void) {
}
#define valkey_bgsave_trace(...) \
do { \
} while (0)
#endif /* __VALKEY_TRACE_SYS_H__ */
#endif /* USE_LTTNG */

20
src/trace/trace_cluster.c Normal file
View File

@ -0,0 +1,20 @@
/*
* Copyright (c) Valkey Contributors
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
/* ==========================================================================
* trace_cluster.c - support lttng tracing for cluster events.
* --------------------------------------------------------------------------
* Copyright (C) 2025 zhenwei pi <zhenwei.pi@linux.dev>
* Copyright (C) 2025 zhiqiang li <lizhiqiang.sf@bytedance.com>
*
* This work is licensed under BSD 3-Clause, License 1 of the COPYING file in
* the top-level directory.
* ==========================================================================
*/
#define LTTNG_UST_TRACEPOINT_CREATE_PROBES
#define LTTNG_UST_TRACEPOINT_DEFINE
#include "trace_cluster.h"

139
src/trace/trace_cluster.h Normal file
View File

@ -0,0 +1,139 @@
/*
* Copyright (c) Valkey Contributors
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
/* ==========================================================================
* trace_cluster.h - support lttng tracing for cluster events.
* --------------------------------------------------------------------------
* Copyright (C) 2025 zhenwei pi <zhenwei.pi@linux.dev>
* Copyright (C) 2025 zhiqiang li <lizhiqiang.sf@bytedance.com>
*
* This work is licensed under BSD 3-Clause, License 1 of the COPYING file in
* the top-level directory.
* ==========================================================================
*/
#ifdef USE_LTTNG
#undef LTTNG_UST_TRACEPOINT_PROVIDER
#define LTTNG_UST_TRACEPOINT_PROVIDER valkey_cluster
#undef LTTNG_UST_TRACEPOINT_INCLUDE
#define LTTNG_UST_TRACEPOINT_INCLUDE "./trace_cluster.h"
#if !defined(__VALKEY_TRACE_CLUSTER_H__) || defined(LTTNG_UST_TRACEPOINT_HEADER_MULTI_READ)
#define __VALKEY_TRACE_CLUSTER_H__
#include <lttng/tracepoint.h>
LTTNG_UST_TRACEPOINT_EVENT_CLASS(
/* Tracepoint class provider name */
valkey_cluster,
/* Tracepoint class name */
valkey_cluster_class,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
),
/* List of fields of eventual event (output) */
LTTNG_UST_TP_FIELDS(
lttng_ust_field_integer(uint64_t, duration, duration)
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_cluster, valkey_cluster_class, valkey_cluster, cluster_config_open,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_cluster, valkey_cluster_class, valkey_cluster, cluster_config_write,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_cluster, valkey_cluster_class, valkey_cluster, cluster_config_fsync,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_cluster, valkey_cluster_class, valkey_cluster, cluster_config_rename,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_cluster, valkey_cluster_class, valkey_cluster, cluster_config_dir_fsync,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_cluster, valkey_cluster_class, valkey_cluster, cluster_config_close,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_cluster, valkey_cluster_class, valkey_cluster, cluster_config_unlink,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
#define valkey_cluster_trace(...) lttng_ust_tracepoint(__VA_ARGS__)
#endif /* __VALKEY_TRACE_CLUSTER_H__ */
#include <lttng/tracepoint-event.h>
#else /* USE_LTTNG */
#ifndef __VALKEY_TRACE_CLUSTER_H__
#define __VALKEY_TRACE_CLUSTER_H__
/* avoid compiler warning on empty source file */
static inline void __valkey_cluster_trace(void) {
}
#define valkey_cluster_trace(...) \
do { \
} while (0)
#endif /* __VALKEY_TRACE_CLUSTER_H__ */
#endif /* USE_LTTNG */

View File

@ -0,0 +1,20 @@
/*
* Copyright (c) Valkey Contributors
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
/* ==========================================================================
* trace_commands.c - support lttng tracing for commands events.
* --------------------------------------------------------------------------
* Copyright (C) 2025 zhenwei pi <zhenwei.pi@linux.dev>
* Copyright (C) 2025 zhiqiang li <lizhiqiang.sf@bytedance.com>
*
* This work is licensed under BSD 3-Clause, License 1 of the COPYING file in
* the top-level directory.
* ==========================================================================
*/
#define LTTNG_UST_TRACEPOINT_CREATE_PROBES
#define LTTNG_UST_TRACEPOINT_DEFINE
#include "trace_commands.h"

View File

@ -0,0 +1,93 @@
/*
* Copyright (c) Valkey Contributors
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
/* ==========================================================================
* trace_commands.h - support lttng tracing for commands events.
* --------------------------------------------------------------------------
* Copyright (C) 2025 zhenwei pi <zhenwei.pi@linux.dev>
* Copyright (C) 2025 zhiqiang li <lizhiqiang.sf@bytedance.com>
*
* This work is licensed under BSD 3-Clause, License 1 of the COPYING file in
* the top-level directory.
* ==========================================================================
*/
#ifdef USE_LTTNG
#undef LTTNG_UST_TRACEPOINT_PROVIDER
#define LTTNG_UST_TRACEPOINT_PROVIDER valkey_commands
#undef LTTNG_UST_TRACEPOINT_INCLUDE
#define LTTNG_UST_TRACEPOINT_INCLUDE "./trace_commands.h"
#if !defined(__VALKEY_TRACE_COMMANDS_H__) || defined(LTTNG_UST_TRACEPOINT_HEADER_MULTI_READ)
#define __VALKEY_TRACE_COMMANDS_H__
#include <lttng/tracepoint.h>
LTTNG_UST_TRACEPOINT_ENUM(
/* Tracepoint provider name */
valkey_commands,
/* Tracepoint connection type enum */
valkey_conn_type_enum,
/* Tracepoint connection type enum values, Source: ConnectionTypeId */
LTTNG_UST_TP_ENUM_VALUES(
lttng_ust_field_enum_value("SOCKET", 1)
lttng_ust_field_enum_value("UNIX", 2)
lttng_ust_field_enum_value("TLS", 3)
lttng_ust_field_enum_value("RDMA", 4)
)
)
LTTNG_UST_TRACEPOINT_EVENT(
/* Tracepoint provider name */
valkey_commands,
/* Tracepoint name */
command_call,
/* Input arguments */
LTTNG_UST_TP_ARGS(
int, prot,
const char *, saddr,
const char *, daddr,
const char *, name,
uint64_t, duration
),
/* Output event fields */
LTTNG_UST_TP_FIELDS(
lttng_ust_field_enum(valkey_commands, valkey_conn_type_enum, int, enum_field, prot)
lttng_ust_field_string(saddr, saddr)
lttng_ust_field_string(daddr, daddr)
lttng_ust_field_string(name, name)
lttng_ust_field_integer(uint64_t, duration, duration)
)
)
#define valkey_commands_trace(...) lttng_ust_tracepoint(__VA_ARGS__)
#endif /* __VALKEY_TRACE_COMMANDS_H__ */
#include <lttng/tracepoint-event.h>
#else /* USE_LTTNG */
#ifndef __VALKEY_TRACE_COMMANDS_H__
#define __VALKEY_TRACE_COMMANDS_H__
/* avoid compiler warning on empty source file */
static inline void __valkey_commands_trace(void) {
}
#define valkey_commands_trace(...) \
do { \
} while (0)
#endif /* __VALKEY_TRACE_COMMANDS_H__ */
#endif /* USE_LTTNG */

20
src/trace/trace_db.c Normal file
View File

@ -0,0 +1,20 @@
/*
* Copyright (c) Valkey Contributors
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
/* ==========================================================================
* trace_db.c - support lttng tracing for db events.
* --------------------------------------------------------------------------
* Copyright (C) 2025 zhenwei pi <zhenwei.pi@linux.dev>
* Copyright (C) 2025 zhiqiang li <lizhiqiang.sf@bytedance.com>
*
* This work is licensed under BSD 3-Clause, License 1 of the COPYING file in
* the top-level directory.
* ==========================================================================
*/
#define LTTNG_UST_TRACEPOINT_CREATE_PROBES
#define LTTNG_UST_TRACEPOINT_DEFINE
#include "trace_db.h"

129
src/trace/trace_db.h Normal file
View File

@ -0,0 +1,129 @@
/*
* Copyright (c) Valkey Contributors
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
/* ==========================================================================
* trace_db.h - support lttng tracing for db events.
* --------------------------------------------------------------------------
* Copyright (C) 2025 zhenwei pi <zhenwei.pi@linux.dev>
* Copyright (C) 2025 zhiqiang li <lizhiqiang.sf@bytedance.com>
*
* This work is licensed under BSD 3-Clause, License 1 of the COPYING file in
* the top-level directory.
* ==========================================================================
*/
#ifdef USE_LTTNG
#undef LTTNG_UST_TRACEPOINT_PROVIDER
#define LTTNG_UST_TRACEPOINT_PROVIDER valkey_db
#undef LTTNG_UST_TRACEPOINT_INCLUDE
#define LTTNG_UST_TRACEPOINT_INCLUDE "./trace_db.h"
#if !defined(__VALKEY_TRACE_DB_H__) || defined(LTTNG_UST_TRACEPOINT_HEADER_MULTI_READ)
#define __VALKEY_TRACE_DB_H__
#include <lttng/tracepoint.h>
LTTNG_UST_TRACEPOINT_EVENT_CLASS(
/* Tracepoint class provider name */
valkey_db,
/* Tracepoint class name */
valkey_db_class,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
),
/* List of fields of eventual event (output) */
LTTNG_UST_TP_FIELDS(
lttng_ust_field_integer(uint64_t, duration, duration)
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_db, valkey_db_class, valkey_db, expire_del,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_db, valkey_db_class, valkey_db, active_defrag_cycle,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_db, valkey_db_class, valkey_db, eviction_del,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_db, valkey_db_class, valkey_db, eviction_lazyfree,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_db, valkey_db_class, valkey_db, eviction_cycle,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_db, valkey_db_class, valkey_db, expire_cycle,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
#define valkey_db_trace(...) lttng_ust_tracepoint(__VA_ARGS__)
#endif /* __VALKEY_TRACE_DB_H__ */
#include <lttng/tracepoint-event.h>
#else /* USE_LTTNG */
#ifndef __VALKEY_TRACE_DB_H__
#define __VALKEY_TRACE_DB_H__
/* avoid compiler warning on empty source file */
static inline void __valkey_db_trace(void) {
}
#define valkey_db_trace(...) \
do { \
} while (0)
#endif /* __VALKEY_TRACE_DB_H__ */
#endif /* USE_LTTNG */

20
src/trace/trace_server.c Normal file
View File

@ -0,0 +1,20 @@
/*
* Copyright (c) Valkey Contributors
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
/* ==========================================================================
* trace_server.c - support lttng tracing for server events.
* --------------------------------------------------------------------------
* Copyright (C) 2025 zhenwei pi <zhenwei.pi@linux.dev>
* Copyright (C) 2025 zhiqiang li <lizhiqiang.sf@bytedance.com>
*
* This work is licensed under BSD 3-Clause, License 1 of the COPYING file in
* the top-level directory.
* ==========================================================================
*/
#define LTTNG_UST_TRACEPOINT_CREATE_PROBES
#define LTTNG_UST_TRACEPOINT_DEFINE
#include "trace_server.h"

139
src/trace/trace_server.h Normal file
View File

@ -0,0 +1,139 @@
/*
* Copyright (c) Valkey Contributors
* All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
/* ==========================================================================
* trace_server.h - support lttng tracing for server events.
* --------------------------------------------------------------------------
* Copyright (C) 2025 zhenwei pi <zhenwei.pi@linux.dev>
* Copyright (C) 2025 zhiqiang li <lizhiqiang.sf@bytedance.com>
*
* This work is licensed under BSD 3-Clause, License 1 of the COPYING file in
* the top-level directory.
* ==========================================================================
*/
#ifdef USE_LTTNG
#undef LTTNG_UST_TRACEPOINT_PROVIDER
#define LTTNG_UST_TRACEPOINT_PROVIDER valkey_server
#undef LTTNG_UST_TRACEPOINT_INCLUDE
#define LTTNG_UST_TRACEPOINT_INCLUDE "./trace_server.h"
#if !defined(__VALKEY_TRACE_SERVER_H__) || defined(LTTNG_UST_TRACEPOINT_HEADER_MULTI_READ)
#define __VALKEY_TRACE_SERVER_H__
#include <lttng/tracepoint.h>
LTTNG_UST_TRACEPOINT_EVENT_CLASS(
/* Tracepoint class provider name */
valkey_server,
/* Tracepoint class name */
valkey_server_class,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
),
/* List of fields of eventual event (output) */
LTTNG_UST_TP_FIELDS(
lttng_ust_field_integer(uint64_t, duration, duration)
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_server, valkey_server_class, valkey_server, command_unblocking,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_server, valkey_server_class, valkey_server, while_blocked_cron,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_server, valkey_server_class, valkey_server, eventloop,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_server, valkey_server_class, valkey_server, eventloop_cron,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_server, valkey_server_class, valkey_server, module_acquire_gil,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_server, valkey_server_class, valkey_server, command,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
/* Name of the tracepoint class provider */
valkey_server, valkey_server_class, valkey_server, fast_command,
/* List of tracepoint arguments (input) */
LTTNG_UST_TP_ARGS(
uint64_t, duration
)
)
#define valkey_server_trace(...) lttng_ust_tracepoint(__VA_ARGS__)
#endif /* __VALKEY_TRACE_SERVER_H__ */
#include <lttng/tracepoint-event.h>
#else /* USE_LTTNG */
#ifndef __VALKEY_TRACE_SERVER_H__
#define __VALKEY_TRACE_SERVER_H__
/* avoid compiler warning on empty source file */
static inline void __valkey_server_trace(void) {
}
#define valkey_server_trace(...) \
do { \
} while (0)
#endif /* __VALKEY_TRACE_SERVER_H__ */
#endif /* USE_LTTNG */

View File

@ -35,6 +35,12 @@ static const char *connUnixGetType(connection *conn) {
return CONN_TYPE_UNIX;
}
static int connUnixGetTypeId(connection *conn) {
UNUSED(conn);
return CONN_TYPE_ID_UNIX;
}
static void connUnixEventHandler(struct aeEventLoop *el, int fd, void *clientData, int mask) {
connectionTypeTcp()->ae_handler(el, fd, clientData, mask);
}
@ -165,6 +171,7 @@ static ssize_t connUnixSyncReadLine(connection *conn, char *ptr, ssize_t size, l
static ConnectionType CT_Unix = {
/* connection type */
.get_type_id = connUnixGetTypeId,
.get_type = connUnixGetType,
/* connection type initialize & finalize & configure */