def test_add_remove_30core(pyocf_ctx): # Start cache device cache_device = RamVolume(S.from_MiB(50)) cache = Cache.start_on_device(cache_device) core_devices = [] core_amount = 30 # Add 50 cores and check stats after each addition for i in range(0, core_amount): stats = cache.get_stats() assert stats["conf"]["core_count"] == i core_device = RamVolume(S.from_MiB(10)) core = Core.using_device(core_device, name=f"core{i}") core_devices.append(core) cache.add_core(core) # Remove 50 cores and check stats before each removal for i in range(0, core_amount): stats = cache.get_stats() assert stats["conf"]["core_count"] == core_amount - i cache.remove_core(core_devices[i]) # Check statistics stats = cache.get_stats() assert stats["conf"]["core_count"] == 0
def test_10add_remove_with_io(pyocf_ctx): # Start cache device cache_device = RamVolume(S.from_MiB(50)) cache = Cache.start_on_device(cache_device) # Create core device core_device = RamVolume(S.from_MiB(10)) core = Core.using_device(core_device) # Add and remove core 10 times in a loop with io in between for i in range(0, 10): cache.add_core(core) vol = CoreVolume(core, open=True) stats = cache.get_stats() assert stats["conf"]["core_count"] == 1 write_data = Data.from_string("Test data") io = vol.new_io(cache.get_default_queue(), S.from_sector(1).B, write_data.size, IoDir.WRITE, 0, 0) io.set_data(write_data) cmpl = OcfCompletion([("err", c_int)]) io.callback = cmpl.callback io.submit() cmpl.wait() cache.remove_core(core) stats = cache.get_stats() assert stats["conf"]["core_count"] == 0
def test_neg_cache_set_seq_cut_off_threshold(pyocf_ctx, cm, cls): """ Test whether it is possible to change cache seq cut-off threshold to invalid value :param pyocf_ctx: basic pyocf context fixture :param cm: cache mode we start with :param cls: cache line size we start with :return: """ # Start cache device cache_device = RamVolume(S.from_MiB(50)) cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls) # Create 2 core devices core_device1 = RamVolume(S.from_MiB(10)) core1 = Core.using_device(core_device1, name="core1") core_device2 = RamVolume(S.from_MiB(10)) core2 = Core.using_device(core_device2, name="core2") # Add cores cache.add_core(core1) cache.add_core(core2) # Change cache seq cut off policy to invalid one and check if failed for i in RandomGenerator(DefaultRanges.UINT32): if i in ConfValidValues.seq_cutoff_threshold_rage: continue with pytest.raises( OcfError, match="Error setting cache seq cut off policy threshold"): cache.set_seq_cut_off_threshold(i) print(f"\n{i}")
def test_neg_core_set_seq_cut_off_policy(pyocf_ctx, cm, cls): """ Test whether it is possible to change core seq cut-off policy to invalid value :param pyocf_ctx: basic pyocf context fixture :param cm: cache mode we start with :param cls: cache line size we start with :return: """ # Start cache device cache_device = RamVolume(S.from_MiB(50)) cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls) # Create core device core_device = RamVolume(S.from_MiB(10)) core = Core.using_device(core_device) # Add core cache.add_core(core) # Change core seq cut off policy to invalid one and check if failed for i in RandomGenerator(DefaultRanges.UINT32): if i in [item.value for item in SeqCutOffPolicy]: continue with pytest.raises(OcfError, match="Error setting core seq cut off policy"): core.set_seq_cut_off_policy(i) print(f"\n{i}")
def test_eviction_two_cores(pyocf_ctx, mode: CacheMode, cls: CacheLineSize): """Test if eviction works correctly when remapping cachelines between distinct cores.""" cache_device = RamVolume(Size.from_MiB(50)) core_device1 = RamVolume(Size.from_MiB(40)) core_device2 = RamVolume(Size.from_MiB(40)) cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls) cache.set_seq_cut_off_policy(SeqCutOffPolicy.NEVER) cache_size = cache.get_stats()["conf"]["size"] core1 = Core.using_device(core_device1, name="core1") core2 = Core.using_device(core_device2, name="core2") cache.add_core(core1) vol1 = CoreVolume(core1, open=True) cache.add_core(core2) vol2 = CoreVolume(core2, open=True) valid_io_size = Size.from_B(cache_size.B) test_data = Data(valid_io_size) send_io(core1, test_data) send_io(core2, test_data) stats1 = core1.get_stats() stats2 = core2.get_stats() # IO to the second core should evict all the data from the first core assert stats1["usage"]["occupancy"]["value"] == 0 assert stats2["usage"]["occupancy"]["value"] == valid_io_size.blocks_4k
def test_adding_core_already_used(pyocf_ctx, cache_mode, cls): # Start first cache device cache_device1 = RamVolume(S.from_MiB(50)) cache1 = Cache.start_on_device(cache_device1, cache_mode=cache_mode, cache_line_size=cls, name="cache1") # Start second cache device cache_device2 = RamVolume(S.from_MiB(50)) cache2 = Cache.start_on_device(cache_device2, cache_mode=cache_mode, cache_line_size=cls, name="cache2") # Create core device core_device = RamVolume(S.from_MiB(10)) core = Core.using_device(core_device) # Add core to first cache cache1.add_core(core) # Check that it is not possible to add core to second cache with pytest.raises(OcfError): cache2.add_core(core) # Check that core count is as expected stats = cache1.get_stats() assert stats["conf"]["core_count"] == 1 stats = cache2.get_stats() assert stats["conf"]["core_count"] == 0
def test_adding_to_random_cache(pyocf_ctx): cache_devices = [] core_devices = {} cache_amount = 5 core_amount = 30 # Create 5 cache devices for i in range(0, cache_amount): cache_device = RamVolume(S.from_MiB(50)) cache = Cache.start_on_device(cache_device, name=f"cache{i}") cache_devices.append(cache) # Create 50 core devices and add to random cache for i in range(0, core_amount): core_device = RamVolume(S.from_MiB(10)) core = Core.using_device(core_device, name=f"core{i}") core_devices[core] = randint(0, cache_amount - 1) cache_devices[core_devices[core]].add_core(core) # Count expected number of cores per cache count_dict = {} for i in range(0, cache_amount): count_dict[i] = sum(k == i for k in core_devices.values()) # Check if cache statistics are as expected for i in range(0, cache_amount): stats = cache_devices[i].get_stats() assert stats["conf"]["core_count"] == count_dict[i]
def test_surprise_shutdown_swap_core(pyocf_ctx): core_device_1 = RamVolume(S.from_MiB(10), uuid="dev1") core_device_2 = RamVolume(S.from_MiB(10), uuid="dev2") core1 = Core.using_device(core_device_1, name="core1") core2 = Core.using_device(core_device_2, name="core2") def prepare(cache): cache.add_core(core1) cache.save() cache.remove_core(core1) cache.save() def tested_func(cache): cache.add_core(core2) def check_func(cache, error_triggered): stats = cache.get_stats() assert stats["conf"]["core_count"] == (0 if error_triggered else 1) with pytest.raises(OcfError): core1 = cache.get_core_by_name("core1") if error_triggered: with pytest.raises(OcfError): core2 = cache.get_core_by_name("core2") else: core2 = cache.get_core_by_name("core2") assert core2.device.uuid == "dev2" mngmt_op_surprise_shutdown_test(pyocf_ctx, tested_func, prepare, check_func)
def test_load_with_changed_core_size(pyocf_ctx, cache_mode, cls): """ Test changing volume size before load :param pyocf_ctx: basic pyocf context fixture :param cm: cache mode we start with :param cls: cache line size we start with """ # Start cache device cache_device = RamVolume(S.from_MiB(50)) cache = Cache.start_on_device(cache_device, cache_mode=cache_mode, cache_line_size=cls) # Add core to cache core_device = RamVolume(S.from_MiB(10)) core = Core.using_device(core_device) cache.add_core(core) # Stop cache cache.stop() # Change core device size core_device.resize(S.from_MiB(12)) # Load cache with changed core size with pytest.raises(OcfError, match="OCF_ERR_CORE_SIZE_MISMATCH"): cache = Cache.load_from_device(cache_device)
def test_cache_change_seq_cut_off_policy(pyocf_ctx, cm, cls): # Start cache device cache_device = RamVolume(S.from_MiB(50)) cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls) # Create 2 core devices core_device1 = RamVolume(S.from_MiB(10)) core1 = Core.using_device(core_device1, name="core1") core_device2 = RamVolume(S.from_MiB(10)) core2 = Core.using_device(core_device2, name="core2") # Add cores cache.add_core(core1) cache.add_core(core2) # Check all possible seq cut off policy switches for seq_from in SeqCutOffPolicy: for seq_to in SeqCutOffPolicy: cache.set_seq_cut_off_policy(seq_from.value) # Check if seq cut off policy is correct stats = core1.get_stats() assert stats["seq_cutoff_policy"] == seq_from.value stats = core2.get_stats() assert stats["seq_cutoff_policy"] == seq_from.value cache.set_seq_cut_off_policy(seq_to.value) # Check if seq cut off policy is correct stats = core1.get_stats() assert stats["seq_cutoff_policy"] == seq_to.value stats = core2.get_stats() assert stats["seq_cutoff_policy"] == seq_to.value
def test_secure_erase_simple_io_cleaning(): """ Perform simple IO which will trigger WB cleaning. Track all the data from cleaner (locked) and make sure they are erased and unlocked after use. 1. Start cache in WB mode 2. Write single sector at LBA 0 3. Read whole cache line at LBA 0 4. Assert that 3. triggered cleaning 5. Check if all locked Data copies were erased and unlocked """ ctx = OcfCtx( OcfLib.getInstance(), b"Security tests ctx", DefaultLogger(LogLevel.WARN), DataCopyTracer, Cleaner, ) ctx.register_volume_type(RamVolume) cache_device = RamVolume(S.from_MiB(50)) cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WB) core_device = RamVolume(S.from_MiB(100)) core = Core.using_device(core_device) cache.add_core(core) vol = CoreVolume(core, open=True) queue = cache.get_default_queue() read_data = Data(S.from_sector(1).B) io = vol.new_io(queue, S.from_sector(1).B, read_data.size, IoDir.WRITE, 0, 0) io.set_data(read_data) cmpl = OcfCompletion([("err", c_int)]) io.callback = cmpl.callback io.submit() cmpl.wait() read_data = Data(S.from_sector(8).B) io = vol.new_io(queue, S.from_sector(1).B, read_data.size, IoDir.READ, 0, 0) io.set_data(read_data) cmpl = OcfCompletion([("err", c_int)]) io.callback = cmpl.callback io.submit() cmpl.wait() stats = cache.get_stats() ctx.exit() assert (len(DataCopyTracer.needs_erase) == 0 ), "Not all locked Data instances were secure erased!" assert (len(DataCopyTracer.locked_instances) == 0 ), "Not all locked Data instances were unlocked!" assert (stats["usage"]["clean"]["value"]) > 0, "Cleaner didn't run!"
def test_surprise_shutdown_stop_cache(pyocf_ctx): core_device = RamVolume(S.from_MiB(10)) error_triggered = True error_io_seq_no = 0 io_offset = mngmt_op_surprise_shutdown_test_io_offset while error_triggered: # Start cache device without error injection error_io = {IoDir.WRITE: error_io_seq_no} device = ErrorDevice( mngmt_op_surprise_shutdown_test_cache_size, error_seq_no=error_io, armed=False ) # setup cache and insert some data cache = Cache.start_on_device(device, cache_mode=CacheMode.WB) core = Core(device=core_device) cache.add_core(core) vol = CoreVolume(core, open=True) ocf_write(vol, cache.get_default_queue(), 0xAA, io_offset) # start error injection device.arm() try: cache.stop() status = OcfErrorCode.OCF_OK except OcfError as ex: status = ex.error_code # if error was injected we expect mngmt op error error_triggered = device.error_triggered() if error_triggered: assert status == OcfErrorCode.OCF_ERR_WRITE_CACHE else: assert status == 0 if not error_triggered: break # disable error injection and load the cache device.disarm() cache = None assert core_device.get_bytes()[io_offset] == VOLUME_POISON cache = Cache.load_from_device(device, open_cores=False) stats = cache.get_stats() if stats["conf"]["core_count"] == 1: assert stats["usage"]["occupancy"]["value"] == 1 core = Core(device=core_device) cache.add_core(core, try_add=True) vol = CoreVolume(core, open=True) assert ocf_read(vol, cache.get_default_queue(), io_offset) == 0xAA cache.stop() # advance error injection point error_io_seq_no += 1
def test_load_cache_recovery(pyocf_ctx): cache_device = RamVolume(S.from_MiB(50)) cache = Cache.start_on_device(cache_device) device_copy = cache_device.get_copy() cache.stop() cache = Cache.load_from_device(device_copy)
def test_write_size_greater_than_cache(pyocf_ctx, mode: CacheMode, cls: CacheLineSize): """Test if eviction does not occur when IO greater than cache size is submitted.""" cache_device = RamVolume(Size.from_MiB(50)) core_device = RamVolume(Size.from_MiB(200)) cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls) cache_size = cache.get_stats()["conf"]["size"] core = Core.using_device(core_device) cache.add_core(core) vol = CoreVolume(core, open=True) cache.set_seq_cut_off_policy(SeqCutOffPolicy.NEVER) valid_io_size = Size.from_B(cache_size.B // 2) test_data = Data(valid_io_size) send_io(core, test_data) stats = core.cache.get_stats() first_block_sts = stats["block"] first_usage_sts = stats["usage"] pt_writes_first = stats["req"]["wr_pt"] assert stats["usage"]["occupancy"]["value"] == ( valid_io_size.B / Size.from_KiB(4).B ), "Occupancy after first IO" prev_writes_to_core = stats["block"]["core_volume_wr"]["value"] # Anything below 200 MiB is a valid size (less than core device size) # Writing over cache size (to the offset above first io) in this case should go # directly to core and shouldn't trigger eviction io_size_bigger_than_cache = Size.from_MiB(100) io_offset = valid_io_size test_data = Data(io_size_bigger_than_cache) send_io(core, test_data, io_offset) if mode is not CacheMode.WT: # Flush first write cache.flush() stats = core.cache.get_stats() second_block_sts = stats["block"] second_usage_sts = stats["usage"] pt_writes_second = stats["req"]["wr_pt"] # Second write shouldn't affect cache and should go directly to core. # Cache occupancy shouldn't change # Second IO should go in PT assert first_usage_sts["occupancy"] == second_usage_sts["occupancy"] assert pt_writes_first["value"] == 0 assert pt_writes_second["value"] == 1 assert second_block_sts["cache_volume_wr"]["value"] == valid_io_size.blocks_4k assert ( second_block_sts["core_volume_wr"]["value"] == valid_io_size.blocks_4k + io_size_bigger_than_cache.blocks_4k )
def test_attach_different_size(pyocf_ctx, new_cache_size, mode: CacheMode, cls: CacheLineSize): """Start cache and add partition with limited occupancy. Fill partition with data, attach cache with different size and trigger IO. Verify if occupancy thresold is respected with both original and new cache device. """ cache_device = RamVolume(Size.from_MiB(100)) core_device = RamVolume(Size.from_MiB(100)) cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls) core = Core.using_device(core_device) cache.add_core(core) vol = CoreVolume(core, open=True) queue = cache.get_default_queue() cache.configure_partition(part_id=1, name="test_part", max_size=50, priority=1) cache.set_seq_cut_off_policy(SeqCutOffPolicy.NEVER) cache_size = cache.get_stats()["conf"]["size"] block_size = 4096 data = bytes(block_size) for i in range(cache_size.blocks_4k): io_to_exp_obj(vol, queue, block_size * i, block_size, data, 0, IoDir.WRITE, 1, 0) part_current_size = CacheLines( cache.get_partition_info(part_id=1)["_curr_size"], cls) assert part_current_size.blocks_4k == cache_size.blocks_4k * 0.5 cache.detach_device() new_cache_device = RamVolume(Size.from_MiB(new_cache_size)) cache.attach_device(new_cache_device, force=True) cache_size = cache.get_stats()["conf"]["size"] for i in range(cache_size.blocks_4k): io_to_exp_obj(vol, queue, block_size * i, block_size, data, 0, IoDir.WRITE, 1, 0) part_current_size = CacheLines( cache.get_partition_info(part_id=1)["_curr_size"], cls) assert part_current_size.blocks_4k == cache_size.blocks_4k * 0.5
def prepare_cache_and_core(core_size: Size, cache_size: Size = Size.from_MiB(50)): cache_device = RamVolume(cache_size) core_device = RamVolume(core_size) cache = Cache.start_on_device(cache_device) core = Core.using_device(core_device) cache.add_core(core) vol = CoreVolume(core, open=True) queue = cache.get_default_queue() return vol, queue
def test_neg_set_nhit_promotion_policy_param_threshold(pyocf_ctx, cm, cls): """ Test whether it is possible to set invalid promotion policy param INSERTION_THRESHOLD for nhit promotion policy :param pyocf_ctx: basic pyocf context fixture :param cm: cache mode we start with :param cls: cache line size we start with :return: """ # Start cache device cache_device = RamVolume(S.from_MiB(50)) cache = Cache.start_on_device( cache_device, cache_mode=cm, cache_line_size=cls, promotion_policy=PromotionPolicy.NHIT, ) # Set to invalid promotion policy insertion threshold and check if failed for i in RandomGenerator(DefaultRanges.UINT32): if i in ConfValidValues.promotion_nhit_insertion_threshold_range: continue with pytest.raises(OcfError, match="Error setting promotion policy parameter"): cache.set_promotion_policy_param(PromotionPolicy.NHIT, NhitParams.INSERTION_THRESHOLD, i) print(f"\n{i}")
def test_surprise_shutdown_set_promotion_policy_param(pyocf_ctx): core_device = RamVolume(S.from_MiB(10)) core = Core(device=core_device) for pp in PromotionPolicy: if pp == PromotionPolicy.ALWAYS: continue if pp == PromotionPolicy.NHIT: params = NhitParams else: # add handler for new policy here assert False for p in params: def prepare(cache): cache.add_core(core) cache.set_promotion_policy(pp) cache.save() def test(cache): val = None if pp == PromotionPolicy.NHIT: if p == NhitParams.INSERTION_THRESHOLD: val = 500 elif p == NhitParams.TRIGGER_THRESHOLD: val = 50 else: # add handler for new param here assert False cache.set_promotion_policy_param(pp, p, val) cache.save() mngmt_op_surprise_shutdown_test(pyocf_ctx, test, prepare, None)
def test_start_stop_multiple(pyocf_ctx): """Starting/stopping multiple caches. Check whether OCF allows for starting multiple caches and stopping them in random order """ caches = [] caches_no = randrange(6, 11) for i in range(1, caches_no): cache_device = RamVolume(Size.from_MiB(50)) cache_name = f"cache{i}" cache_mode = CacheMode(randrange(0, len(CacheMode))) size = 4096 * 2**randrange(0, len(CacheLineSize)) cache_line_size = CacheLineSize(size) cache = Cache.start_on_device(cache_device, name=cache_name, cache_mode=cache_mode, cache_line_size=cache_line_size) caches.append(cache) stats = cache.get_stats() assert stats["conf"]["cache_mode"] == cache_mode, "Cache mode" assert stats["conf"][ "cache_line_size"] == cache_line_size, "Cache line size" assert stats["conf"]["cache_name"] == cache_name, "Cache name" caches.sort(key=lambda e: randrange(1000)) for cache in caches: logger.info("Getting stats before stopping cache") stats = cache.get_stats() cache_name = stats["conf"]["cache_name"] cache.stop() assert get_cache_by_name( pyocf_ctx, cache_name) != 0, "Try getting cache after stopping it"
def test_neg_set_acp_param_value(pyocf_ctx, cm, cls, param): """ Test whether it is possible to set invalid value to any of acp cleaning policy params :param pyocf_ctx: basic pyocf context fixture :param cm: cache mode we start with :param cls: cache line size we start with :param param: acp parameter to fuzz :return: """ # Start cache device cache_device = RamVolume(S.from_MiB(50)) cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls) cache.set_cleaning_policy(CleaningPolicy.ACP) # Set to invalid acp param value and check if failed valid_range = get_acp_param_valid_rage(param) for i in RandomGenerator(DefaultRanges.UINT32): if i in valid_range: continue with pytest.raises(OcfError, match="Error setting cleaning policy param"): cache.set_cleaning_policy_param(CleaningPolicy.ACP, param, i) print(f"\n{i}")
def test_fuzzy_start_name(pyocf_ctx, string_randomize, cm, cls): """ Test whether it is possible to start cache with various cache name value. :param pyocf_ctx: basic pyocf context fixture :param string_randomize: fuzzed cache name value to start cache with :param cm: cache mode value to start cache with :param cls: cache line size value to start cache with """ cache_device = RamVolume(Size.from_MiB(50)) incorrect_values = [''] try: cache = Cache.start_on_device(cache_device, name=string_randomize, cache_mode=cm, cache_line_size=cls) except OcfError: if string_randomize not in incorrect_values: logger.error( f"Cache did not start properly with correct name value: '{string_randomize}'" ) return if string_randomize in incorrect_values: logger.error( f"Cache started with incorrect name value: '{string_randomize}'") cache.stop()
def test_neg_set_nhit_promotion_policy_param(pyocf_ctx, cm, cls): """ Test whether it is possible to set invalid promotion policy param id for nhit promotion policy :param pyocf_ctx: basic pyocf context fixture :param cm: cache mode we start with :param cls: cache line size we start with :return: """ # Start cache device cache_device = RamVolume(S.from_MiB(50)) cache = Cache.start_on_device( cache_device, cache_mode=cm, cache_line_size=cls, promotion_policy=PromotionPolicy.NHIT, ) # Set invalid promotion policy param id and check if failed for i in RandomGenerator(DefaultRanges.UINT8): if i in [item.value for item in NhitParams]: continue with pytest.raises(OcfError, match="Error setting promotion policy parameter"): cache.set_promotion_policy_param(PromotionPolicy.NHIT, i, 1) print(f"\n{i}")
def test_start_params(pyocf_ctx, mode: CacheMode, cls: CacheLineSize, layout: MetadataLayout): """Starting cache with different parameters. Check if cache starts without errors. If possible check whether cache reports properly set parameters. """ cache_device = RamVolume(Size.from_MiB(50)) queue_size = randrange(60000, 2**32) unblock_size = randrange(1, queue_size) volatile_metadata = randrange(2) == 1 unaligned_io = randrange(2) == 1 submit_fast = randrange(2) == 1 name = "test" logger.info("[STAGE] Start cache") cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls, name=name, metadata_volatile=volatile_metadata, max_queue_size=queue_size, queue_unblock_size=unblock_size, pt_unaligned_io=unaligned_io, use_submit_fast=submit_fast) stats = cache.get_stats() assert stats["conf"]["cache_mode"] == mode, "Cache mode" assert stats["conf"]["cache_line_size"] == cls, "Cache line size" assert cache.get_name() == name, "Cache name"
def test_load_cache(pyocf_ctx): cache_device = RamVolume(S.from_MiB(50)) cache = Cache.start_on_device(cache_device) cache.stop() cache = Cache.load_from_device(cache_device)
def test_neg_set_ioclass_name(pyocf_ctx): """ Test whether it is possible to add ioclass with invaild name :param pyocf_ctx: basic pyocf context fixture :return: """ invalid_chars = [ chr(c) for c in range(256) if chr(c) not in string.printable ] invalid_chars += [",", '"'] # Start cache device cache_device = RamVolume(S.from_MiB(50)) cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WT, cache_line_size=CacheLineSize.LINE_4KiB) # Set invalid name and check if failed for name in RandomStringGenerator(len_range=Range(0, 1024), count=10000, extra_chars=invalid_chars): if not any(c for c in invalid_chars if c in name): continue with pytest.raises(OcfError, match="Error adding partition to cache"): cache.configure_partition(part_id=1, name=name, max_size=100, priority=1) print(f"\n{name}")
def test_neg_set_ioclass_cache_mode(pyocf_ctx, cm, cls): """ Test whether it is possible to add ioclass with invaild cache mode :param pyocf_ctx: basic pyocf context fixture :param cm: cache mode we start with :param cls: cache line size we start with :return: """ # Start cache device cache_device = RamVolume(S.from_MiB(50)) cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls) # Set invalid cache mode and check if failed for i in RandomGenerator(DefaultRanges.INT): if i in list(CacheMode) + [CACHE_MODE_NONE]: continue with pytest.raises(OcfError, match="Error adding partition to cache"): cache.configure_partition(part_id=1, name="unclassified", max_size=100, priority=1, cache_mode=i) print(f"\n{i}")
def test_surprise_shutdown_set_io_class_config(pyocf_ctx): core_device = RamVolume(S.from_MiB(10)) core = Core(device=core_device) class_range = range(0, IoClassesInfo.MAX_IO_CLASSES) old_ioclass = [ { "_class_id": i, "_name": f"old_{i}" if i > 0 else "unclassified", "_max_size": i, "_priority": i, "_cache_mode": int(CacheMode.WB), } for i in range(IoClassesInfo.MAX_IO_CLASSES) ] new_ioclass = [ { "_class_id": i, "_name": f"new_{i}" if i > 0 else "unclassified", "_max_size": 2 * i, "_priority": 2 * i, "_cache_mode": int(CacheMode.WT), } for i in range(IoClassesInfo.MAX_IO_CLASSES) ] keys = old_ioclass[0].keys() def set_io_class_info(cache, desc): ioclasses_info = IoClassesInfo() for i in range(IoClassesInfo.MAX_IO_CLASSES): ioclasses_info._config[i]._class_id = i ioclasses_info._config[i]._name = desc[i]["_name"].encode("utf-8") ioclasses_info._config[i]._priority = desc[i]["_priority"] ioclasses_info._config[i]._cache_mode = desc[i]["_cache_mode"] ioclasses_info._config[i]._max_size = desc[i]["_max_size"] OcfLib.getInstance().ocf_mngt_cache_io_classes_configure( cache, byref(ioclasses_info) ) def prepare(cache): cache.add_core(core) set_io_class_info(cache, old_ioclass) cache.save() def test(cache): set_io_class_info(cache, new_ioclass) cache.save() def check(cache, error_triggered): curr_ioclass = [ {k: info[k] for k in keys} for info in [cache.get_partition_info(i) for i in class_range] ] assert curr_ioclass == old_ioclass or curr_ioclass == new_ioclass mngmt_op_surprise_shutdown_test(pyocf_ctx, test, prepare, check)
def test_30add_remove(pyocf_ctx): # Start cache device cache_device = RamVolume(S.from_MiB(50)) cache = Cache.start_on_device(cache_device) # Create core device core_device = RamVolume(S.from_MiB(10)) core = Core.using_device(core_device) # Add and remove core device in a loop 100 times # Check statistics after every operation for i in range(0, 30): cache.add_core(core) stats = cache.get_stats() assert stats["conf"]["core_count"] == 1 cache.remove_core(core) stats = cache.get_stats() assert stats["conf"]["core_count"] == 0
def test_start_check_default(pyocf_ctx): """Test if default values are correct after start. """ cache_device = RamVolume(Size.from_MiB(50)) core_device = RamVolume(Size.from_MiB(10)) cache = Cache.start_on_device(cache_device) core = Core.using_device(core_device) cache.add_core(core) # Check if values are default stats = cache.get_stats() assert stats["conf"]["cleaning_policy"] == CleaningPolicy.DEFAULT assert stats["conf"]["cache_mode"] == CacheMode.DEFAULT assert stats["conf"]["cache_line_size"] == CacheLineSize.DEFAULT core_stats = core.get_stats() assert core_stats["seq_cutoff_policy"] == SeqCutOffPolicy.DEFAULT
def test_load_cache_with_cores(pyocf_ctx, open_cores): cache_device = RamVolume(S.from_MiB(40)) core_device = RamVolume(S.from_MiB(40)) cache = Cache.start_on_device(cache_device) core = Core.using_device(core_device, name="test_core") cache.add_core(core) vol = CoreVolume(core, open=True) write_data = Data.from_string("This is test data") io = vol.new_io(cache.get_default_queue(), S.from_sector(3).B, write_data.size, IoDir.WRITE, 0, 0) io.set_data(write_data) cmpl = OcfCompletion([("err", c_int)]) io.callback = cmpl.callback io.submit() cmpl.wait() cache.stop() cache = Cache.load_from_device(cache_device, open_cores=open_cores) if not open_cores: cache.add_core(core, try_add=True) else: core = cache.get_core_by_name("test_core") vol = CoreVolume(core, open=True) read_data = Data(write_data.size) io = vol.new_io(cache.get_default_queue(), S.from_sector(3).B, read_data.size, IoDir.READ, 0, 0) io.set_data(read_data) cmpl = OcfCompletion([("err", c_int)]) io.callback = cmpl.callback io.submit() cmpl.wait() assert read_data.md5() == write_data.md5() assert vol.md5() == core_device.md5()