Example #1
0
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
Example #2
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
Example #3
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}")
Example #4
0
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}")
Example #5
0
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
Example #6
0
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
Example #7
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)
Example #9
0
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)
Example #10
0
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
Example #11
0
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
Example #13
0
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)
Example #14
0
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
    )
Example #15
0
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
Example #16
0
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
Example #17
0
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)
Example #19
0
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"
Example #20
0
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()
Example #22
0
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}")
Example #23
0
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"
Example #24
0
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)
Example #25
0
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}")
Example #26
0
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)
Example #28
0
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
Example #29
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
Example #30
0
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()