diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml index 48cbb28ee1..3735144551 100644 --- a/.github/workflows/daily.yml +++ b/.github/workflows/daily.yml @@ -375,10 +375,10 @@ jobs: run: sudo apt-get install tcl8.6 tclx - name: test if: true && !contains(github.event.inputs.skiptests, 'valkey') - run: ./runtest --config io-threads 2 --config events-per-io-thread 0 --accurate --verbose --tags network --dump-logs ${{github.event.inputs.test_args}} + run: ./runtest --io-threads --accurate --verbose --tags network --dump-logs ${{github.event.inputs.test_args}} - name: cluster tests if: true && !contains(github.event.inputs.skiptests, 'cluster') - run: ./runtest-cluster --config io-threads 2 --config events-per-io-thread 0 ${{github.event.inputs.cluster_test_args}} + run: ./runtest-cluster --io-threads ${{github.event.inputs.cluster_test_args}} test-ubuntu-reclaim-cache: runs-on: ubuntu-latest diff --git a/tests/support/server.tcl b/tests/support/server.tcl index cc8a9ea64f..2a5e2dd525 100644 --- a/tests/support/server.tcl +++ b/tests/support/server.tcl @@ -241,6 +241,11 @@ proc tags_acceptable {tags err_return} { return 0 } + if {$::io_threads && [lsearch $tags "io-threads:skip"] >= 0} { + set err "Not supported in io-threads mode" + return 0 + } + return 1 } @@ -497,6 +502,12 @@ proc start_server {options {code undefined}} { dict set config "tls-ca-cert-file" [format "%s/tests/tls/ca.crt" [pwd]] dict set config "loglevel" "debug" } + + if {$::io_threads} { + dict set config "io-threads" 2 + dict set config "events-per-io-thread" 0 + } + foreach line $data { if {[string length $line] > 0 && [string index $line 0] ne "#"} { set elements [split $line " "] diff --git a/tests/test_helper.tcl b/tests/test_helper.tcl index ae784271c9..112c52f1a1 100644 --- a/tests/test_helper.tcl +++ b/tests/test_helper.tcl @@ -41,6 +41,7 @@ set ::traceleaks 0 set ::valgrind 0 set ::durable 0 set ::tls 0 +set ::io_threads 0 set ::tls_module 0 set ::stack_logging 0 set ::verbose 0 @@ -576,6 +577,7 @@ proc print_help_screen {} { "--loops Execute the specified set of tests several times." "--wait-server Wait after server is started (so that you can attach a debugger)." "--dump-logs Dump server log on test failure." + "--io-threads Run tests with IO threads." "--tls Run tests in TLS mode." "--tls-module Run tests in TLS mode with Valkey module." "--host Run tests against an external host." @@ -630,6 +632,8 @@ for {set j 0} {$j < [llength $argv]} {incr j} { } } elseif {$opt eq {--quiet}} { set ::quiet 1 + } elseif {$opt eq {--io-threads}} { + set ::io_threads 1 } elseif {$opt eq {--tls} || $opt eq {--tls-module}} { package require tls 1.6 set ::tls 1 diff --git a/tests/unit/info.tcl b/tests/unit/info.tcl index 52821579c5..278a1d8e33 100644 --- a/tests/unit/info.tcl +++ b/tests/unit/info.tcl @@ -308,51 +308,49 @@ start_server {tags {"info" "external:skip"}} { assert_equal "count=2" [errorstat ERR] } - # skip the following 2 tests if we are running with io-threads as the eventloop metrics are different in that case. - if {[r config get io-threads] eq "io-threads 1"} { - test {stats: eventloop metrics} { - set info1 [r info stats] - set cycle1 [getInfoProperty $info1 eventloop_cycles] - set el_sum1 [getInfoProperty $info1 eventloop_duration_sum] - set cmd_sum1 [getInfoProperty $info1 eventloop_duration_cmd_sum] - assert_morethan $cycle1 0 - assert_morethan $el_sum1 0 - assert_morethan $cmd_sum1 0 - after 110 ;# default hz is 10, wait for a cron tick. - set info2 [r info stats] - set cycle2 [getInfoProperty $info2 eventloop_cycles] - set el_sum2 [getInfoProperty $info2 eventloop_duration_sum] - set cmd_sum2 [getInfoProperty $info2 eventloop_duration_cmd_sum] - if {$::verbose} { puts "eventloop metrics cycle1: $cycle1, cycle2: $cycle2" } - assert_morethan $cycle2 $cycle1 - assert_lessthan $cycle2 [expr $cycle1+10] ;# we expect 2 or 3 cycles here, but allow some tolerance - if {$::verbose} { puts "eventloop metrics el_sum1: $el_sum1, el_sum2: $el_sum2" } - assert_morethan $el_sum2 $el_sum1 - assert_lessthan $el_sum2 [expr $el_sum1+30000] ;# we expect roughly 100ms here, but allow some tolerance - if {$::verbose} { puts "eventloop metrics cmd_sum1: $cmd_sum1, cmd_sum2: $cmd_sum2" } - assert_morethan $cmd_sum2 $cmd_sum1 - assert_lessthan $cmd_sum2 [expr $cmd_sum1+15000] ;# we expect about tens of ms here, but allow some tolerance - } - - test {stats: instantaneous metrics} { - r config resetstat - set retries 0 - for {set retries 1} {$retries < 4} {incr retries} { - after 1600 ;# hz is 10, wait for 16 cron tick so that sample array is fulfilled - set value [s instantaneous_eventloop_cycles_per_sec] - if {$value > 0} break - } - - assert_lessthan $retries 4 - if {$::verbose} { puts "instantaneous metrics instantaneous_eventloop_cycles_per_sec: $value" } - assert_morethan $value 0 - assert_lessthan $value [expr $retries*15] ;# default hz is 10 - set value [s instantaneous_eventloop_duration_usec] - if {$::verbose} { puts "instantaneous metrics instantaneous_eventloop_duration_usec: $value" } - assert_morethan $value 0 - assert_lessthan $value [expr $retries*22000] ;# default hz is 10, so duration < 1000 / 10, allow some tolerance + test {stats: eventloop metrics} { + set info1 [r info stats] + set cycle1 [getInfoProperty $info1 eventloop_cycles] + set el_sum1 [getInfoProperty $info1 eventloop_duration_sum] + set cmd_sum1 [getInfoProperty $info1 eventloop_duration_cmd_sum] + assert_morethan $cycle1 0 + assert_morethan $el_sum1 0 + assert_morethan $cmd_sum1 0 + after 110 ;# default hz is 10, wait for a cron tick. + set info2 [r info stats] + set cycle2 [getInfoProperty $info2 eventloop_cycles] + set el_sum2 [getInfoProperty $info2 eventloop_duration_sum] + set cmd_sum2 [getInfoProperty $info2 eventloop_duration_cmd_sum] + if {$::verbose} { puts "eventloop metrics cycle1: $cycle1, cycle2: $cycle2" } + assert_morethan $cycle2 $cycle1 + assert_lessthan $cycle2 [expr $cycle1+10] ;# we expect 2 or 3 cycles here, but allow some tolerance + if {$::verbose} { puts "eventloop metrics el_sum1: $el_sum1, el_sum2: $el_sum2" } + assert_morethan $el_sum2 $el_sum1 + assert_lessthan $el_sum2 [expr $el_sum1+30000] ;# we expect roughly 100ms here, but allow some tolerance + if {$::verbose} { puts "eventloop metrics cmd_sum1: $cmd_sum1, cmd_sum2: $cmd_sum2" } + assert_morethan $cmd_sum2 $cmd_sum1 + assert_lessthan $cmd_sum2 [expr $cmd_sum1+15000] ;# we expect about tens of ms here, but allow some tolerance + } {} {io-threads:skip} ; # skip with io-threads as the eventloop metrics are different in that case. + + test {stats: instantaneous metrics} { + r config resetstat + set retries 0 + for {set retries 1} {$retries < 4} {incr retries} { + after 1600 ;# hz is 10, wait for 16 cron tick so that sample array is fulfilled + set value [s instantaneous_eventloop_cycles_per_sec] + if {$value > 0} break } - } + + assert_lessthan $retries 4 + if {$::verbose} { puts "instantaneous metrics instantaneous_eventloop_cycles_per_sec: $value" } + assert_morethan $value 0 + assert_lessthan $value [expr $retries*15] ;# default hz is 10 + set value [s instantaneous_eventloop_duration_usec] + if {$::verbose} { puts "instantaneous metrics instantaneous_eventloop_duration_usec: $value" } + assert_morethan $value 0 + assert_lessthan $value [expr $retries*22000] ;# default hz is 10, so duration < 1000 / 10, allow some tolerance + } {} {io-threads:skip} ; # skip with io-threads as the eventloop metrics are different in that case. + test {stats: debug metrics} { # make sure debug info is hidden diff --git a/tests/unit/maxmemory.tcl b/tests/unit/maxmemory.tcl index 3ea80bb365..75ec1ce02d 100644 --- a/tests/unit/maxmemory.tcl +++ b/tests/unit/maxmemory.tcl @@ -456,74 +456,70 @@ start_server {tags {"maxmemory external:skip"}} { } {4098} } -start_server {tags {"maxmemory external:skip"}} { +# Skip the following test when running with IO threads +# With IO threads, we asynchronously write to tracking clients. +# This invalidates the assumption that their output buffers will be free within the same event loop. +start_server {tags {"maxmemory external:skip io-threads:skip"}} { + test {client tracking don't cause eviction feedback loop} { + r config set latency-tracking no + r config set maxmemory 0 + r config set maxmemory-policy allkeys-lru + r config set maxmemory-eviction-tenacity 100 + # 10 clients listening on tracking messages + set clients {} + for {set j 0} {$j < 10} {incr j} { + lappend clients [valkey_deferring_client] + } + foreach rd $clients { + $rd HELLO 3 + $rd read ; # Consume the HELLO reply + $rd CLIENT TRACKING on + $rd read ; # Consume the CLIENT reply + } - # Skip the following test when running with IO threads - # With IO threads, we asynchronously write to tracking clients. - # This invalidates the assumption that their output buffers will be free within the same event loop. - if {[r config get io-threads] eq "io-threads 1"} { - test {client tracking don't cause eviction feedback loop} { - r config set latency-tracking no - r config set maxmemory 0 - r config set maxmemory-policy allkeys-lru - r config set maxmemory-eviction-tenacity 100 - - # 10 clients listening on tracking messages - set clients {} - for {set j 0} {$j < 10} {incr j} { - lappend clients [valkey_deferring_client] - } - foreach rd $clients { - $rd HELLO 3 - $rd read ; # Consume the HELLO reply - $rd CLIENT TRACKING on - $rd read ; # Consume the CLIENT reply - } - - # populate 300 keys, with long key name and short value - for {set j 0} {$j < 300} {incr j} { - set key $j[string repeat x 1000] - r set $key x - - # for each key, enable caching for this key - foreach rd $clients { - $rd get $key - $rd read - } - } - - # we need to wait one second for the client querybuf excess memory to be - # trimmed by cron, otherwise the INFO used_memory and CONFIG maxmemory - # below (on slow machines) won't be "atomic" and won't trigger eviction. - after 1100 - - # set the memory limit which will cause a few keys to be evicted - # we need to make sure to evict keynames of a total size of more than - # 16kb since the (PROTO_REPLY_CHUNK_BYTES), only after that the - # invalidation messages have a chance to trigger further eviction. - set used [s used_memory] - set limit [expr {$used - 40000}] - r config set maxmemory $limit - - # make sure some eviction happened - set evicted [s evicted_keys] - if {$::verbose} { puts "evicted: $evicted" } - - # make sure we didn't drain the database - assert_range [r dbsize] 200 300 - - assert_range $evicted 10 50 + # populate 300 keys, with long key name and short value + for {set j 0} {$j < 300} {incr j} { + set key $j[string repeat x 1000] + r set $key x + + # for each key, enable caching for this key foreach rd $clients { - $rd read ;# make sure we have some invalidation message waiting - $rd close + $rd get $key + $rd read } - - # eviction continues (known problem described in #8069) - # for now this test only make sures the eviction loop itself doesn't - # have feedback loop - set evicted [s evicted_keys] - if {$::verbose} { puts "evicted: $evicted" } } + + # we need to wait one second for the client querybuf excess memory to be + # trimmed by cron, otherwise the INFO used_memory and CONFIG maxmemory + # below (on slow machines) won't be "atomic" and won't trigger eviction. + after 1100 + + # set the memory limit which will cause a few keys to be evicted + # we need to make sure to evict keynames of a total size of more than + # 16kb since the (PROTO_REPLY_CHUNK_BYTES), only after that the + # invalidation messages have a chance to trigger further eviction. + set used [s used_memory] + set limit [expr {$used - 40000}] + r config set maxmemory $limit + + # make sure some eviction happened + set evicted [s evicted_keys] + if {$::verbose} { puts "evicted: $evicted" } + + # make sure we didn't drain the database + assert_range [r dbsize] 200 300 + + assert_range $evicted 10 50 + foreach rd $clients { + $rd read ;# make sure we have some invalidation message waiting + $rd close + } + + # eviction continues (known problem described in #8069) + # for now this test only make sures the eviction loop itself doesn't + # have feedback loop + set evicted [s evicted_keys] + if {$::verbose} { puts "evicted: $evicted" } } } diff --git a/tests/unit/memefficiency.tcl b/tests/unit/memefficiency.tcl index 0793736abf..098899c45c 100644 --- a/tests/unit/memefficiency.tcl +++ b/tests/unit/memefficiency.tcl @@ -404,8 +404,6 @@ run_solo {defrag} { r save ;# saving an rdb iterates over all the data / pointers } {OK} - # Skip the following two tests if we are running with IO threads, as the IO threads allocate the command arguments in a different arena. As a result, fragmentation is not as expected. - if {[r config get io-threads] eq "io-threads 1"} { test "Active defrag pubsub: $type" { r flushdb r config resetstat @@ -503,8 +501,7 @@ run_solo {defrag} { $rd_pubsub read } $rd_pubsub close - } - } ;# io-threads + } {} {io-threads:skip} ; # skip with io-threads as the threads may allocate the command arguments in a different arena. As a result, fragmentation is not as expected. if {$type eq "standalone"} { ;# skip in cluster mode test "Active defrag big list: $type" {