From 802ee5cb9079a89df88579379cf05674cec69200 Mon Sep 17 00:00:00 2001 From: Konstantin Knizhnik Date: Wed, 5 Mar 2025 10:23:14 +0200 Subject: [PATCH] Add performance test for prefetch in LFC --- test_runner/performance/test_lfc_prefetch.py | 91 ++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 test_runner/performance/test_lfc_prefetch.py diff --git a/test_runner/performance/test_lfc_prefetch.py b/test_runner/performance/test_lfc_prefetch.py new file mode 100644 index 0000000000..e4c2d6ae7a --- /dev/null +++ b/test_runner/performance/test_lfc_prefetch.py @@ -0,0 +1,91 @@ +from __future__ import annotations + +import random +import threading +import time + +import pytest +from fixtures.log_helper import log +from fixtures.neon_fixtures import NeonEnv +from fixtures.utils import USE_LFC + + +@pytest.mark.timeout(1000) +@pytest.mark.skipif(not USE_LFC, reason="LFC is disabled, skipping") +def test_lfc_prefetch(neon_simple_env: NeonEnv): + """ + Test resizing the Local File Cache + """ + env = neon_simple_env + endpoint = env.endpoints.create_start( + "main", + config_lines=[ + "neon.max_file_cache_size=10MB", + "neon.file_cache_size_limit=10MB", + "effective_io_concurrency=100", + "shared_buffers=1MB", + "enable_bitmapscan=off", + "enable_seqscan=off", + "autovacuum=off", + "statement_timeout=0", + "neon.store_prefetch_result_in_lfc=on", + ], + ) + n_records = 10000 # 80Mb table + top_n = n_records // 4 # 20Mb - should be larger than LFC size + test_time = 100.0 # seconds + n_readers = 10 + n_writers = 2 + + conn = endpoint.connect() + cur = conn.cursor() + cur.execute( + "create table account(id integer primary key, balance integer default 0, filler text default repeat('?',1000)) with (fillfactor=10)" + ) + cur.execute(f"insert into account values (generate_series(1,{n_records}))") + cur.execute("vacuum account") + + def reader(): + conn = endpoint.connect() + cur = conn.cursor() + i = 0 + while running: + cur.execute( + f"select sum(balance) from (select balance from account order by id limit {top_n}) s" + ) + sum = cur.fetchall()[0][0] + assert sum == 0 # check consistency + i += 1 + log.info(f"Did {i} index scans") + + def writer(): + conn = endpoint.connect() + cur = conn.cursor() + i = 0 + while running: + r1 = random.randint(1, top_n) + r2 = random.randint(1, top_n) + # avoid deadlock by ordering src and dst + src = min(r1, r2) + dst = max(r1, r2) + cur.execute( + f"update account set balance=balance-1 where id={src}; update account set balance=balance+1 where id={dst}" + ) + i += 1 + log.info(f"Did {i} updates") + + readers = [threading.Thread(target=reader) for _ in range(n_readers)] + writers = [threading.Thread(target=writer) for _ in range(n_writers)] + + running = True + for t in readers: + t.start() + for t in writers: + t.start() + + time.sleep(test_time) + running = False + for t in readers: + t.join() + for t in writers: + t.join()