44# SPDX-License-Identifier: BSD-3-Clause
55#
66
7+ import random
78import time
89import pytest
910
11+ from datetime import timedelta
12+
1013from api .cas import casadm
1114from api .cas .cache_config import (
1215 CacheMode ,
1316 CleaningPolicy ,
1417 FlushParametersAcp ,
1518 FlushParametersAlru ,
1619 Time ,
20+ SeqCutOffPolicy ,
1721)
1822from storage_devices .disk import DiskType , DiskTypeSet , DiskTypeLowerThan
1923from core .test_run import TestRun
24+ from test_tools .iostat import IOstatBasic
2025from type_def .size import Size , Unit
2126from test_tools .udev import Udev
2227from test_tools .fio .fio import Fio
@@ -106,7 +111,7 @@ def test_cleaning_policies_in_write_back(cleaning_policy: CleaningPolicy):
106111@pytest .mark .parametrize ("cleaning_policy" , CleaningPolicy )
107112@pytest .mark .require_disk ("cache" , DiskTypeSet ([DiskType .optane , DiskType .nand ]))
108113@pytest .mark .require_disk ("core" , DiskTypeLowerThan ("cache" ))
109- def test_cleaning_policies_in_write_through (cleaning_policy ):
114+ def test_cleaning_policies_in_write_through (cleaning_policy : CleaningPolicy ):
110115 """
111116 title: Test for cleaning policy operation in Write-Through cache mode.
112117 description: |
@@ -257,7 +262,7 @@ def check_cleaning_policy_operation(
257262 case CleaningPolicy .nop :
258263 if (
259264 core_writes_after_wait_for_cleaning != Size .zero ()
260- or core_writes_before_wait_for_cleaning != Size .zero ()
265+ or core_writes_before_wait_for_cleaning != Size .zero ()
261266 ):
262267 TestRun .LOGGER .error (
263268 "NOP cleaning policy is not working properly! "
@@ -275,3 +280,121 @@ def check_cleaning_policy_operation(
275280 "ACP cleaning policy is not working properly! "
276281 "Core writes should increase in time while cleaning dirty data"
277282 )
283+
284+
285+ @pytest .mark .require_disk ("cache" , DiskTypeSet ([DiskType .optane , DiskType .nand ]))
286+ @pytest .mark .require_disk ("core" , DiskTypeLowerThan ("cache" ))
287+ def test_alru_change_trigger_dirty_ratio_during_io ():
288+ """
289+ title: Test ALRU with trigger dirty ratio param during I/O
290+ description: |
291+ Verify that ALRU is able to start cleaning to expected dirty ratio under constant I/O.
292+ pass_criteria:
293+ - Dirty cache lines are being cleaned after trigger dirty ratio change during I/O.
294+ - Dirty cache lines are cleaned to expected dirty ratio after stopping I/O
295+ """
296+ iterations = 10
297+
298+ with TestRun .step ("Prepare cache and core devices" ):
299+ cache_dev = TestRun .disks ["cache" ]
300+ core_dev = TestRun .disks ["core" ]
301+
302+ cache_size = Size (1 , Unit .GiB )
303+ cache_dev .create_partitions ([cache_size ])
304+ core_dev .create_partitions ([Size (2 , Unit .GiB )])
305+
306+ with TestRun .step (f"Disable udev" ):
307+ Udev .disable ()
308+
309+ with TestRun .step ("Start cache" ):
310+ cache = casadm .start_cache (cache_dev .partitions [0 ], force = True , cache_mode = CacheMode .WB )
311+
312+ with TestRun .step ("Add core" ):
313+ core = cache .add_core (core_dev .partitions [0 ])
314+
315+ with TestRun .step ("Set params for ALRU cleaning policy" ):
316+ params = FlushParametersAlru .default_alru_params ()
317+ params .wake_up_time = Time (seconds = 1 )
318+ params .staleness_time = Time (seconds = 3600 )
319+ cache .set_params_alru (alru_params = params )
320+
321+ with TestRun .step ("Disable sequential cut-off and set cleaning to ALRU" ):
322+ cache .set_seq_cutoff_policy (SeqCutOffPolicy .never )
323+ cache .set_cleaning_policy (CleaningPolicy .alru )
324+
325+ for _ in TestRun .iteration (
326+ range (0 , iterations ),
327+ "Start changing trigger dirty ratio param during I/O and check if flush occurred" ,
328+ ):
329+
330+ params = FlushParametersAlru .default_alru_params ()
331+
332+ fio = (
333+ Fio ()
334+ .create_command ()
335+ .io_engine (IoEngine .libaio )
336+ .block_size (Size (4 , Unit .KiB ))
337+ .target (core )
338+ .direct ()
339+ .time_based ()
340+ .run_time (timedelta (minutes = 10 ))
341+ .read_write (ReadWrite .randwrite )
342+ )
343+
344+ dirty_ratio_test_threshold = random .randint (0 , 100 )
345+
346+ with TestRun .step ("Disable cache cleaning" ):
347+ cache .set_seq_cutoff_policy (SeqCutOffPolicy .never )
348+
349+ with TestRun .step ("Start running I/O to exported object in background" ):
350+ fio_pid = fio .run_in_background ()
351+
352+ with TestRun .step ("Wait until dirty data on cache exceed dirty ratio threshold" ):
353+
354+ while TestRun .executor .check_if_process_exists (fio_pid ):
355+ dirty_blocks_percentage_on_cache = cache .get_statistics (
356+ percentage_val = True
357+ ).usage_stats .dirty
358+
359+ if dirty_blocks_percentage_on_cache >= dirty_ratio_test_threshold :
360+ break
361+ time .sleep (5 )
362+
363+ with TestRun .step ("Set cache cleaning policy to alru" ):
364+ params .trigger_dirty_ratio = dirty_ratio_test_threshold
365+ cache .set_params_alru (alru_params = params )
366+
367+ with TestRun .step ("Check if cleaning started after changing cleaning policy" ):
368+ time .sleep (5 )
369+
370+ iostat_core = IOstatBasic .get_iostat_list ([core_dev .get_device_id ()])
371+ core_writes = iostat_core [0 ].total_writes
372+
373+ if core_writes == Size .zero ():
374+ TestRun .fail (f"Cleaning on cache haven`t started" )
375+
376+ with TestRun .step ("Stop I/O to exported object" ):
377+ TestRun .executor .kill_process (fio_pid )
378+
379+ with TestRun .step ("Check if cache has been cleaned to set threshold after stopping I/O" ):
380+ max_cleaning_time = timedelta (seconds = 60 )
381+ t_end = time .time () + max_cleaning_time .seconds
382+
383+ while time .time () < t_end :
384+ dirty_blocks_on_cache_before = cache .get_statistics (
385+ percentage_val = True ).usage_stats .dirty
386+ time .sleep (20 )
387+ dirty_blocks_on_cache_after = cache .get_statistics (
388+ percentage_val = True ).usage_stats .dirty
389+ if dirty_blocks_on_cache_before == dirty_blocks_on_cache_after :
390+ break
391+
392+ dirty_blocks_cache_percentage = cache .get_statistics (
393+ percentage_val = True
394+ ).usage_stats .dirty
395+
396+ if not dirty_ratio_test_threshold == dirty_blocks_cache_percentage :
397+ TestRun .fail ("Dirty block percentage outside of defined range" )
398+
399+ with TestRun .step ("Purge cache" ):
400+ casadm .purge_cache (cache_id = cache .cache_id )
0 commit comments