This is an automated email from the ASF dual-hosted git repository.

vatamane pushed a commit to branch view-btree-cache
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit ff56e6d850f58552c96c01d27a088952ade9bc22
Author: Nick Vatamaniuc <[email protected]>
AuthorDate: Thu Jan 29 00:14:53 2026 -0500

    Use BTree cache for views
    
    In #5625 we introduced a BTree cache for dbs, and since view files
    also use BTrees, let's use a cache for them as well. This should help
    with concurrent view queries.
    
    I test the improvments I used k6 for benchmarking with a 1M doc, q=16
    db, and a view with 10M rows. With a 400 rps request arrival rate saw
    more than a 50% improvement in average, p90, and p95 latencies:
    
      * Average:  14 -> 7 msec
      * Median:   12 -> 7 msec
      * P90       21 -> 10 msec
      * P95       27 -> 12 msec
      * Max       120 -> 77 msec
    
    Since view results could have large kp node values due to custom
    reduce functions, add max term limit for cache entries. To avoid
    adding yet another config value use a few multiple of BTree chunk
    size. This should help avoid config values clashing if users raise the
    chunk size but forget to raise their cache term limit (it would render
    the cache unusuable suddenly).
    
    More detailed test results along with a test at a higher depth of 4 to
    show further improvements.
    
    ```
    BENCH_RATE=400 BENCH_DURATION=5m BENCH_VIEW_LIMIT=10 k6 run 
./k6_couchdb_constant_arrival_view_query.js
    
        HTTP
        http_req_duration..............: avg=14.65ms min=2.08ms med=12.7ms  
max=120.08ms p(90)=20.53ms p(95)=26.78ms
          { expected_response:true }...: avg=14.65ms min=2.08ms med=12.7ms  
max=120.08ms p(90)=20.53ms p(95)=26.78ms
          { name:view_get }............: avg=14.65ms min=2.93ms med=12.7ms  
max=120.08ms p(90)=20.53ms p(95)=26.78ms
        http_req_failed................: 0.00%  0 out of 120002
        http_reqs......................: 120002 399.891866/s
    ```
    
    ```
    $ BENCH_RATE=400 BENCH_DURATION=5m BENCH_VIEW_LIMIT=10 k6 run 
./k6_couchdb_constant_arrival_view_query.js
    
        HTTP
        http_req_duration..............: avg=7.45ms min=2.38ms med=6.9ms  
max=77.78ms p(90)=10.21ms p(95)=11.5ms
          { expected_response:true }...: avg=7.45ms min=2.38ms med=6.9ms  
max=77.78ms p(90)=10.21ms p(95)=11.5ms
          { name:view_get }............: avg=7.45ms min=2.38ms med=6.9ms  
max=77.78ms p(90)=10.21ms p(95)=11.49ms
        http_req_failed................: 0.00%  0 out of 120004
        http_reqs......................: 120004 399.799018/s
    ```
    
    ```
    $ BENCH_RATE=400 BENCH_DURATION=5m BENCH_VIEW_LIMIT=10 k6 run 
./k6_couchdb_constant_arrival_view_query.js
    
        HTTP
        http_req_duration..............: avg=6.21ms min=2.22ms med=5.78ms 
max=77ms    p(90)=8.4ms  p(95)=9.5ms
          { expected_response:true }...: avg=6.21ms min=2.22ms med=5.78ms 
max=77ms    p(90)=8.4ms  p(95)=9.5ms
          { name:view_get }............: avg=6.21ms min=2.22ms med=5.78ms 
max=77ms    p(90)=8.4ms  p(95)=9.5ms
        http_req_failed................: 0.00%  0 out of 120003
        http_reqs......................: 120003 399.931891/s
    
    ```
---
 rel/overlay/etc/default.ini                |  4 ++++
 src/couch/src/couch_bt_engine_cache.erl    | 20 ++++++++++++++------
 src/couch/src/couch_btree.erl              |  1 +
 src/couch_mrview/src/couch_mrview_util.erl | 11 +++++++++--
 4 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/rel/overlay/etc/default.ini b/rel/overlay/etc/default.ini
index 69aae2ad8..d599656b1 100644
--- a/rel/overlay/etc/default.ini
+++ b/rel/overlay/etc/default.ini
@@ -178,6 +178,10 @@ view_index_dir = {{view_index_dir}}
 ; caching set the value to 0
 ;db_btree_cache_depth = 3
 
+; Cache view btree nodes up to this depth only. Works like db_btree_cache_depth
+; but for map-reduce (view) b-trees.
+;view_btree_cache_depth = 3
+
 [purge]
 ; Allowed maximum number of accumulated revisions in one purge request
 ;max_revisions_number = infinity
diff --git a/src/couch/src/couch_bt_engine_cache.erl 
b/src/couch/src/couch_bt_engine_cache.erl
index a39564957..0b3d02704 100644
--- a/src/couch/src/couch_bt_engine_cache.erl
+++ b/src/couch/src/couch_bt_engine_cache.erl
@@ -13,6 +13,7 @@
 -module(couch_bt_engine_cache).
 
 -include_lib("stdlib/include/ms_transform.hrl").
+-include_lib("couch/include/couch_db.hrl").
 
 % Main API
 %
@@ -52,7 +53,7 @@
 -define(MISSES, misses).
 -define(FULL, full).
 
--record(cache, {tid, max_size}).
+-record(cache, {tid, max_size, max_term}).
 
 % Main API
 
@@ -60,11 +61,11 @@ insert(Key, Term) ->
     insert(Key, Term, 1).
 
 insert(Key, Term, Priority) when is_integer(Priority) ->
-    Priority1 = min(?MAX_PRIORITY, max(0, Priority)),
     case get_cache(Key) of
-        #cache{tid = Tid, max_size = Max} ->
-            case ets:info(Tid, memory) < Max of
+        #cache{tid = Tid, max_size = Max, max_term = MaxTerm} ->
+            case ets:info(Tid, memory) < Max andalso ?term_size(Term) =< 
MaxTerm of
                 true ->
+                    Priority1 = min(?MAX_PRIORITY, max(0, Priority)),
                     case ets:insert_new(Tid, {Key, Priority1, Term}) of
                         true ->
                             true;
@@ -107,11 +108,13 @@ info() ->
         Caches when is_tuple(Caches) ->
             SizeMem = [info(C) || C <- tuple_to_list(Caches)],
             MaxMem = [Max || #cache{max_size = Max} <- tuple_to_list(Caches)],
+            #cache{max_term = MaxTerm} = element(1, Caches),
             {Sizes, Mem} = lists:unzip(SizeMem),
             #{
                 size => lists:sum(Sizes),
                 memory => lists:sum(Mem),
                 max_memory => lists:sum(MaxMem) * wordsize(),
+                max_term => MaxTerm,
                 full => sample_metric(?FULL),
                 hits => sample_metric(?HITS),
                 misses => sample_metric(?MISSES),
@@ -207,8 +210,13 @@ new() ->
     Opts = [public, {write_concurrency, true}, {read_concurrency, true}],
     Max0 = round(max_size() / wordsize() / shard_count()),
     % Some per-table overhead for the table metadata
-    Max = Max0 + round(250 * 1024 / wordsize()),
-    #cache{tid = ets:new(?MODULE, Opts), max_size = Max}.
+    MaxSize = Max0 + round(250 * 1024 / wordsize()),
+    MaxTerm = couch_btree:get_chunk_size() * 4,
+    #cache{
+        tid = ets:new(?MODULE, Opts),
+        max_size = MaxSize,
+        max_term = MaxTerm
+    }.
 
 get_cache(Term) ->
     case persistent_term:get(?PTERM_KEY, undefined) of
diff --git a/src/couch/src/couch_btree.erl b/src/couch/src/couch_btree.erl
index 1519b1fbc..1c349d002 100644
--- a/src/couch/src/couch_btree.erl
+++ b/src/couch/src/couch_btree.erl
@@ -17,6 +17,7 @@
 -export([fold_reduce/4, lookup/2, set_options/2]).
 -export([is_btree/1, get_state/1, get_fd/1, get_reduce_fun/1]).
 -export([extract/2, assemble/3, less/3]).
+-export([get_chunk_size/0]).
 
 -include_lib("couch/include/couch_db.hrl").
 
diff --git a/src/couch_mrview/src/couch_mrview_util.erl 
b/src/couch_mrview/src/couch_mrview_util.erl
index 5405e8db8..494f5b3ec 100644
--- a/src/couch_mrview/src/couch_mrview_util.erl
+++ b/src/couch_mrview/src/couch_mrview_util.erl
@@ -61,6 +61,8 @@
         (C >= $A andalso C =< $F))
 ).
 
+-define(DEFAULT_BTREE_CACHE_DEPTH, 3).
+
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("couch_mrview/include/couch_mrview.hrl").
 
@@ -369,7 +371,8 @@ init_state(Db, Fd, State, Header) ->
     }} = maybe_update_header(Header),
 
     IdBtOpts = [
-        {compression, couch_compress:get_compression_method()}
+        {compression, couch_compress:get_compression_method()},
+        {cache_depth, btree_cache_depth()}
     ],
     {ok, IdBtree} = couch_btree:open(IdBtreeState, Fd, IdBtOpts),
 
@@ -394,7 +397,8 @@ open_view(_Db, Fd, Lang, ViewState, View) ->
     ViewBtOpts = [
         {less, LessFun},
         {reduce, ReduceFun},
-        {compression, Compression}
+        {compression, Compression},
+        {cache_depth, btree_cache_depth()}
     ],
     {ok, Btree} = couch_btree:open(BTState, Fd, ViewBtOpts),
 
@@ -1365,3 +1369,6 @@ compact_on_collator_upgrade() ->
 
 commit_on_header_upgrade() ->
     config:get_boolean("view_upgrade", "commit_on_header_upgrade", true).
+
+btree_cache_depth() ->
+    config:get_integer("bt_engine_cache", "view_btree_cache_depth", 
?DEFAULT_BTREE_CACHE_DEPTH).

Reply via email to