Esempio n. 1
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 = Volume(Size.from_MiB(35))
    core_device = Volume(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)

    cache.configure_partition(
        part_id=1, name="test_part", min_size=0, 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(core, 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 = Volume(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(core, 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
Esempio n. 2
0
def test_start_stop_incrementally(pyocf_ctx):
    """Starting/stopping multiple caches incrementally.
    Check whether OCF behaves correctly when few caches at a time are in turns added and removed (#added > #removed)
    until their number reaches limit, and then proportions are reversed and number of caches gradually falls to 0.
    """

    caches = []
    caches_limit = 10
    add = True
    run = True
    increase = True
    while run:
        if add:
            for i in range(0,
                           randrange(3, 5) if increase else randrange(1, 3)):
                cache_device = Volume(Size.from_MiB(20))
                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,
                                              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_id"] == len(caches), "Cache id"
                if len(caches) == caches_limit:
                    increase = False
        else:
            for i in range(0,
                           randrange(1, 3) if increase else randrange(3, 5)):
                if len(caches) == 0:
                    run = False
                    break
                cache = caches.pop()
                logger.info("Getting stats before stopping cache")
                stats = cache.get_stats()
                cache_id = stats["conf"]["cache_id"]
                cache.stop()
                assert get_cache_by_id(
                    pyocf_ctx,
                    cache_id) != 0, "Try getting cache after stopping it"
        add = not add
Esempio n. 3
0
def test_start_read_first_and_check_mode(pyocf_ctx, mode: CacheMode,
                                         cls: CacheLineSize):
    """Starting cache in different modes with different cache line sizes.
    After start check proper cache mode behaviour, starting with read operation.
    """

    cache_device = RamVolume(Size.from_MiB(50))
    core_device = RamVolume(Size.from_MiB(5))
    cache = Cache.start_on_device(cache_device,
                                  cache_mode=mode,
                                  cache_line_size=cls)
    core = Core.using_device(core_device)

    cache.add_core(core)
    front_vol = CoreVolume(core, open=True)
    bottom_vol = core.get_volume()
    queue = cache.get_default_queue()

    logger.info("[STAGE] Initial write to core device")
    test_data = Data.from_string("This is test data")
    io_to_core(bottom_vol, queue, test_data, Size.from_sector(1).B)

    cache_device.reset_stats()
    core_device.reset_stats()

    logger.info("[STAGE] Initial read from exported object")
    io_from_exported_object(front_vol, queue, test_data.size,
                            Size.from_sector(1).B)
    check_stats_read_empty(core, mode, cls)

    logger.info("[STAGE] Write to exported object after initial read")
    cache_device.reset_stats()
    core_device.reset_stats()

    test_data = Data.from_string("Changed test data")

    io_to_core(front_vol, queue, test_data, Size.from_sector(1).B)

    check_stats_write_after_read(core, mode, cls, True)

    logger.info("[STAGE] Read from exported object after write")
    io_from_exported_object(front_vol, queue, test_data.size,
                            Size.from_sector(1).B)
    check_stats_read_after_write(core, mode, cls)

    check_md5_sums(core, mode)
Esempio n. 4
0
def test_neg_change_cache_mode(pyocf_ctx, cm, cls):
    """
    Test whether it is possible to change cache mode 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
    """
    # Start cache device
    cache_device = Volume(S.from_MiB(30))
    cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)

    # Change cache mode to invalid one and check if failed
    for i in RandomGenerator(DefaultRanges.UINT32):
        if i in [item.value for item in CacheMode]:
            continue
        with pytest.raises(OcfError, match="Error changing cache mode"):
            cache.change_cache_mode(i)
Esempio n. 5
0
def test_start_stop_noqueue(pyocf_ctx):
    # cache object just to construct cfg conveniently
    _cache = Cache(pyocf_ctx.ctx_handle)

    cache_handle = c_void_p()
    status = pyocf_ctx.lib.ocf_mngt_cache_start(
        pyocf_ctx.ctx_handle, byref(cache_handle), byref(_cache.cfg)
    )
    assert not status, "Failed to start cache: {}".format(status)

    # stop without creating mngmt queue
    c = OcfCompletion(
        [("cache", c_void_p), ("priv", c_void_p), ("error", c_int)]
    )
    pyocf_ctx.lib.ocf_mngt_cache_stop(cache_handle, c, None)
    c.wait()
    assert not c.results["error"], "Failed to stop cache: {}".format(c.results["error"])
Esempio n. 6
0
def test_flush_after_mngmt(pyocf_ctx):
    """
    Check whether underlying volumes volatile caches (VC) are flushed after management operation
    """
    block_size = 4096

    data = bytes(block_size)

    cache_device = FlushValVolume(Size.from_MiB(30))
    core_device = FlushValVolume(Size.from_MiB(30))

    # after start cache VC must be cleared
    cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WT)
    assert cache_device.flush_last

    # adding core must flush VC
    core = Core.using_device(core_device)
    cache.add_core(core)
    assert cache_device.flush_last

    # WT I/O to write data to core and cache VC
    io_to_exp_obj(core, block_size * 0, block_size, data, 0, IoDir.WRITE, 0)

    # WB I/O to produce dirty cachelines in CAS
    cache.change_cache_mode(CacheMode.WB)
    io_to_exp_obj(core, block_size * 1, block_size, data, 0, IoDir.WRITE, 0)

    # after cache flush VCs are expected to be cleared
    cache.flush()
    assert cache_device.flush_last
    assert core_device.flush_last

    # I/O to write data to cache device VC
    io_to_exp_obj(core, block_size * 0, block_size, data, 0, IoDir.WRITE, 0)

    # cache save must flush VC
    cache.save()
    assert cache_device.flush_last

    # I/O to write data to cache device VC
    io_to_exp_obj(core, block_size * 0, block_size, data, 0, IoDir.WRITE, 0)

    # cache stop must flush VC
    cache.stop()
    assert cache_device.flush_last
Esempio n. 7
0
def test_neg_set_promotion_policy(pyocf_ctx, cm, cls):
    """
    Test whether it is possible to set invalid param for 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 = Volume(S.from_MiB(30))
    cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)

    # Change to invalid promotion policy and check if failed
    for i in RandomGenerator(DefaultRanges.UINT32):
        if i in [item.value for item in PromotionPolicy]:
            continue
        with pytest.raises(OcfError, match="Error setting promotion policy"):
            cache.set_promotion_policy(i)
Esempio n. 8
0
def test_neg_set_acp_param(pyocf_ctx, cm, cls):
    """
    Test whether it is possible to set invalid param for acp cleaning 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 = Volume(S.from_MiB(30))
    cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)

    # Change invalid acp param and check if failed
    for i in RandomGenerator(DefaultRanges.UINT32):
        if i in [item.value for item in AcpParams]:
            continue
        with pytest.raises(OcfError, match="Error setting cleaning policy param"):
            cache.set_cleaning_policy_param(CleaningPolicy.ALRU, i, 1)
Esempio n. 9
0
def test_init_nhit(pyocf_ctx, promotion_policy):
    """
    Check if starting cache with promotion policy is reflected in stats

    1. Create core/cache pair with parametrized promotion policy
    2. Get cache statistics
        * verify that promotion policy type is properly reflected in stats
    """

    cache_device = Volume(Size.from_MiB(30))
    core_device = Volume(Size.from_MiB(30))

    cache = Cache.start_on_device(cache_device, promotion_policy=promotion_policy)
    core = Core.using_device(core_device)

    cache.add_core(core)

    assert cache.get_stats()["conf"]["promotion_policy"] == promotion_policy
Esempio n. 10
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
Esempio n. 11
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 = Volume(
        Size.from_MiB(20))  # this gives about 1.375 MiB actual caching space

    core_device = Volume(Size.from_MiB(5))
    cache = Cache.start_on_device(cache_device,
                                  cache_mode=mode,
                                  cache_line_size=cls)
    core_exported = Core.using_device(core_device)
    cache.add_core(core_exported)
    cache.set_seq_cut_off_policy(SeqCutOffPolicy.NEVER)

    valid_io_size = Size.from_KiB(512)
    test_data = Data(valid_io_size)
    send_io(core_exported, test_data)

    stats = core_exported.cache.get_stats()
    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 5 MiB is a valid size (less than core device size)
    # Writing over 1.375 MiB in this case should go directly to core and shouldn't trigger eviction
    io_size_bigger_than_cache = Size.from_MiB(2)
    test_data = Data(io_size_bigger_than_cache)
    send_io(core_exported, test_data)

    stats = core_exported.cache.get_stats()

    # Writes from IO greater than cache size should go directly to core
    # Writes to core should equal the following:
    # Previous writes to core + size written + size cleaned (reads from cache)
    assert stats["block"]["core_volume_wr"]["value"] == \
        stats["block"]["cache_volume_rd"]["value"] + \
        prev_writes_to_core + io_size_bigger_than_cache.B / Size.from_KiB(4).B, \
        "Writes to core after second IO"

    # Occupancy shouldn't change (no eviction)
    assert stats["usage"]["occupancy"]["value"] == (valid_io_size.B / Size.from_KiB(4).B),\
        "Occupancy after second IO"
Esempio n. 12
0
def test_30add_remove(pyocf_ctx):
    # Start cache device
    cache_device = Volume(S.from_MiB(30))
    cache = Cache.start_on_device(cache_device)

    # Create core device
    core_device = Volume(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
Esempio n. 13
0
def test_remove_dirty_no_flush(pyocf_ctx, cache_mode, cls):
    # Start cache device
    cache_device = Volume(S.from_MiB(30))
    cache = Cache.start_on_device(cache_device,
                                  cache_mode=cache_mode,
                                  cache_line_size=cls)

    # Create core device
    core_device = Volume(S.from_MiB(10))
    core = Core.using_device(core_device)
    cache.add_core(core)

    # Prepare data
    core_size = core.get_stats()["size"]
    data = Data(core_size.B)

    _io_to_core(core, data)

    # Remove core from cache
    cache.remove_core(core)
Esempio n. 14
0
def test_neg_set_cleaning_policy(pyocf_ctx, cm, cls):
    """
    Test whether it is possible to change cleaning 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 = Volume(S.from_MiB(30))
    cache = Cache.start_on_device(
        cache_device, cache_mode=cm, cache_line_size=cls
    )

    # Set cleaning policy to invalid one and check if failed
    for i in generate_random_numbers(c_uint32):
        if i in [item.value for item in CleaningPolicy]:
            continue
        with pytest.raises(OcfError, match="Error changing cleaning policy"):
            cache.set_cleaning_policy(i)
Esempio n. 15
0
def test_removing_core(pyocf_ctx, cache_mode, cls):
    # Start cache device
    cache_device = Volume(S.from_MiB(30))
    cache = Cache.start_on_device(cache_device,
                                  cache_mode=cache_mode,
                                  cache_line_size=cls)

    # Create core device
    core_device = Volume(S.from_MiB(10))
    core = Core.using_device(core_device)

    # Add core to cache
    cache.add_core(core)

    # Remove core from cache
    cache.remove_core(core)

    # Check statistics after removing core
    stats = cache.get_stats()
    assert stats["conf"]["core_count"] == 0
Esempio n. 16
0
def test_add_remove_incrementally(pyocf_ctx, cache_mode, cls):
    # Start cache device
    cache_device = Volume(S.from_MiB(30))
    cache = Cache.start_on_device(cache_device,
                                  cache_mode=cache_mode,
                                  cache_line_size=cls)
    core_devices = []
    core_amount = 5

    # Create 5 core devices and add to cache
    for i in range(0, core_amount):
        core_device = Volume(S.from_MiB(10))
        core = Core.using_device(core_device)
        core_devices.append(core)
        cache.add_core(core)

    # Check that core count is as expected
    stats = cache.get_stats()
    assert stats["conf"]["core_count"] == core_amount

    # Remove 3 cores
    cache.remove_core(core_devices[0])
    cache.remove_core(core_devices[1])
    cache.remove_core(core_devices[2])

    # Add 2 cores and check if core count is as expected
    cache.add_core(core_devices[0])
    cache.add_core(core_devices[1])
    stats = cache.get_stats()
    assert stats["conf"]["core_count"] == core_amount - 1

    # Remove 1 core and check if core count is as expected
    cache.remove_core(core_devices[1])
    stats = cache.get_stats()
    assert stats["conf"]["core_count"] == core_amount - 2

    # Add 2 cores and check if core count is as expected
    cache.add_core(core_devices[1])
    cache.add_core(core_devices[2])
    stats = cache.get_stats()
    assert stats["conf"]["core_count"] == core_amount
Esempio n. 17
0
def test_change_cleaning_policy(pyocf_ctx, cm, cls):
    # Start cache device
    cache_device = Volume(S.from_MiB(30))
    cache = Cache.start_on_device(
        cache_device, cache_mode=cm, cache_line_size=cls
    )

    # Check all possible cleaning policy switches
    for cp_from in CleaningPolicy:
        for cp_to in CleaningPolicy:
            cache.set_cleaning_policy(cp_from.value)

            # Check if cleaning policy is correct
            stats = cache.get_stats()
            assert stats["conf"]["cleaning_policy"] == cp_from.value

            cache.set_cleaning_policy(cp_to.value)

            # Check if cleaning policy is correct
            stats = cache.get_stats()
            assert stats["conf"]["cleaning_policy"] == cp_to.value
Esempio n. 18
0
def test_start_cache_huge_device(pyocf_ctx_log_buffer, cls):
    """
    Test whether we can start cache which would overflow ocf_cache_line_t type.
    pass_criteria:
      - Starting cache on device too big to handle should fail
    """
    class HugeDevice(Volume):
        def get_length(self):
            return Size.from_B((cls * c_uint32(-1).value))

        def submit_io(self, io):
            io.contents._end(io, 0)

    cache_device = HugeDevice(Size.from_MiB(20))

    with pytest.raises(OcfError, match="OCF_ERR_START_CACHE_FAIL"):
        cache = Cache.start_on_device(cache_device, cache_line_size=cls, metadata_volatile=True)

    assert any(
        [line.find("exceeds maximum") > 0 for line in pyocf_ctx_log_buffer.get_lines()]
    ), "Expected to find log notifying that max size was exceeded"
Esempio n. 19
0
def test_100_start_stop(pyocf_ctx):
    """Starting/stopping stress test.
    Check OCF behaviour when cache is started and stopped continuously
    """

    for i in range(1, 101):
        cache_device = Volume(Size.from_MiB(20))
        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,
            cache_mode=cache_mode,
            cache_line_size=cache_line_size)
        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_id"] == 1, "Cache id"
        cache.stop()
        assert get_cache_by_id(pyocf_ctx, 1) != 0, "Try getting cache after stopping it"
Esempio n. 20
0
def test_adding_core_twice(pyocf_ctx, cache_mode, cls):
    # Start cache device
    cache_device = Volume(S.from_MiB(30))
    cache = Cache.start_on_device(cache_device,
                                  cache_mode=cache_mode,
                                  cache_line_size=cls)

    # Create core device
    core_device = Volume(S.from_MiB(10))
    core = Core.using_device(core_device)

    # Add core
    cache.add_core(core)

    # Check that it is not possible to add the same core again
    with pytest.raises(OcfError):
        cache.add_core(core)

    # Check that core count is still equal to one
    stats = cache.get_stats()
    assert stats["conf"]["core_count"] == 1
Esempio n. 21
0
def test_core_change_seq_cut_off_policy(pyocf_ctx, cm, cls):
    # Start cache device
    cache_device = Volume(S.from_MiB(30))
    cache = Cache.start_on_device(
        cache_device, cache_mode=cm, cache_line_size=cls
    )

    # Create 2 core devices
    core_device1 = Volume(S.from_MiB(10))
    core1 = Core.using_device(core_device1, name="core1")
    core_device2 = Volume(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 first core
    for seq_from in SeqCutOffPolicy:
        for seq_to in SeqCutOffPolicy:
            core1.set_seq_cut_off_policy(seq_from.value)

            # Check if seq cut off policy of the first core is correct
            stats = core1.get_stats()
            assert stats["seq_cutoff_policy"] == seq_from.value

            # Check if seq cut off policy of the second core did not change
            stats = core2.get_stats()
            assert stats["seq_cutoff_policy"] == SeqCutOffPolicy.DEFAULT

            core1.set_seq_cut_off_policy(seq_to.value)

            # Check if seq cut off policy of the first core is correct
            stats = core1.get_stats()
            assert stats["seq_cutoff_policy"] == seq_to.value

            # Check if seq cut off policy of the second core did not change
            stats = core2.get_stats()
            assert stats["seq_cutoff_policy"] == SeqCutOffPolicy.DEFAULT
Esempio n. 22
0
def test_neg_set_ioclass_name_len(pyocf_ctx):
    """
    Test whether it is possible to add ioclass with too long name
    :param pyocf_ctx: basic pyocf context fixture
    :return:
    """

    # Start cache device
    cache_device = Volume(S.from_MiB(30))
    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(1025, 4096),
                                      count=10000):
        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}")
Esempio n. 23
0
def test_start_write_first_and_check_mode(pyocf_ctx, mode: CacheMode,
                                          cls: CacheLineSize):
    """Test starting cache in different modes with different cache line sizes.
    After start check proper cache mode behaviour, starting with write operation.
    """

    cache_device = Volume(Size.from_MiB(40))
    core_device = Volume(Size.from_MiB(10))
    cache = Cache.start_on_device(cache_device,
                                  cache_mode=mode,
                                  cache_line_size=cls)
    core_exported = Core.using_device(core_device)

    cache.add_core(core_exported)

    logger.info("[STAGE] Initial write to exported object")
    cache_device.reset_stats()
    core_device.reset_stats()

    test_data = Data.from_string("This is test data")
    io_to_core(core_exported, test_data, Size.from_sector(1).B)
    check_stats_write_empty(core_exported, mode, cls)

    logger.info("[STAGE] Read from exported object after initial write")
    io_from_exported_object(core_exported, test_data.size,
                            Size.from_sector(1).B)
    check_stats_read_after_write(core_exported, mode, cls, True)

    logger.info("[STAGE] Write to exported object after read")
    cache_device.reset_stats()
    core_device.reset_stats()

    test_data = Data.from_string("Changed test data")

    io_to_core(core_exported, test_data, Size.from_sector(1).B)
    check_stats_write_after_read(core_exported, mode, cls)

    check_md5_sums(core_exported, mode)
Esempio n. 24
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 = Volume(S.from_MiB(30))
    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)
Esempio n. 25
0
def test_stop(pyocf_ctx, mode: CacheMode, cls: CacheLineSize,
              with_flush: bool):
    """Stopping cache.
    Check if cache is stopped properly in different modes with or without preceding flush operation.
    """

    cache_device = RamVolume(Size.from_MiB(50))
    core_device = RamVolume(Size.from_MiB(5))
    cache = Cache.start_on_device(cache_device,
                                  cache_mode=mode,
                                  cache_line_size=cls)
    core = Core.using_device(core_device)

    cache.add_core(core)
    front_vol = CoreVolume(core, open=True)
    queue = cache.get_default_queue()

    cls_no = 10

    run_io_and_cache_data_if_possible(core, mode, cls, cls_no)

    stats = cache.get_stats()
    assert int(stats["conf"]["dirty"]) == (cls_no if mode.lazy_write() else 0),\
        "Dirty data before MD5"

    md5_exported_core = front_vol.md5()

    if with_flush:
        cache.flush()
    cache.stop()

    if mode.lazy_write() and not with_flush:
        assert core_device.md5() != md5_exported_core, \
            "MD5 check: core device vs exported object with dirty data"
    else:
        assert core_device.md5() == md5_exported_core, \
            "MD5 check: core device vs exported object with clean data"
Esempio n. 26
0
def test_simple_wt_write(pyocf_ctx):
    cache_device = RamVolume(S.from_MiB(50))
    core_device = RamVolume(S.from_MiB(50))

    cache = Cache.start_on_device(cache_device)
    core = Core.using_device(core_device)
    queue = cache.get_default_queue()

    cache.add_core(core)
    vol = CoreVolume(core, open=True)

    cache_device.reset_stats()
    core_device.reset_stats()

    r = Rio().target(vol).readwrite(ReadWrite.WRITE).size(
        S.from_sector(1)).run([queue])
    assert cache_device.get_stats()[IoDir.WRITE] == 1
    cache.settle()
    stats = cache.get_stats()
    assert stats["req"]["wr_full_misses"]["value"] == 1
    assert stats["usage"]["occupancy"]["value"] == 1

    assert vol.md5() == core_device.md5()
    cache.stop()
Esempio n. 27
0
def test_neg_attach_cls(pyocf_ctx, cm, cls):
    """
    Test whether it is possible to change cache line size to
    invalid value while attaching cache device
    :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 = Volume(S.from_MiB(30))
    cache = Cache(owner=cache_device.owner, cache_mode=cm, cache_line_size=cls)
    cache.start_cache()

    # Check whether it is possible to attach cache device with invalid cache line size
    for i in RandomGenerator(DefaultRanges.UINT64):
        if i in [item.value for item in CacheLineSize]:
            continue
        with pytest.raises(OcfError, match="Attaching cache device failed"):
            cache.attach_device(cache_device, cache_line_size=i)
def try_start_cache(**config):
    cache_device = Volume(Size.from_MiB(30))
    cache = Cache.start_on_device(cache_device, **config)
    cache.stop()
Esempio n. 29
0
def test_change_to_nhit_and_back_io_in_flight(pyocf_ctx):
    """
    Try switching promotion policy during io, no io's should return with error

    1. Create core/cache pair with promotion policy ALWAYS
    2. Issue IOs without waiting for completion
    3. Change promotion policy to NHIT
    4. Wait for IO completions
        * no IOs should fail
    5. Issue IOs without waiting for completion
    6. Change promotion policy to ALWAYS
    7. Wait for IO completions
        * no IOs should fail
    """

    # Step 1
    cache_device = Volume(Size.from_MiB(30))
    core_device = Volume(Size.from_MiB(30))

    cache = Cache.start_on_device(cache_device)
    core = Core.using_device(core_device)

    cache.add_core(core)

    # Step 2
    completions = []
    for i in range(2000):
        comp = OcfCompletion([("error", c_int)])
        write_data = Data(4096)
        io = core.new_io(cache.get_default_queue(), i * 4096, write_data.size,
                         IoDir.WRITE, 0, 0)
        completions += [comp]
        io.set_data(write_data)
        io.callback = comp.callback
        io.submit()

    # Step 3
    cache.set_promotion_policy(PromotionPolicy.NHIT)

    # Step 4
    for c in completions:
        c.wait()
        assert not c.results[
            "error"], "No IO's should fail when turning NHIT policy on"

    # Step 5
    completions = []
    for i in range(2000):
        comp = OcfCompletion([("error", c_int)])
        write_data = Data(4096)
        io = core.new_io(cache.get_default_queue(), i * 4096, write_data.size,
                         IoDir.WRITE, 0, 0)
        completions += [comp]
        io.set_data(write_data)
        io.callback = comp.callback
        io.submit()

    # Step 6
    cache.set_promotion_policy(PromotionPolicy.ALWAYS)

    # Step 7
    for c in completions:
        c.wait()
        assert not c.results[
            "error"], "No IO's should fail when turning NHIT policy off"
Esempio n. 30
0
def test_promoted_after_hits_various_thresholds(pyocf_ctx, insertion_threshold,
                                                fill_percentage):
    """
    Check promotion policy behavior with various set thresholds

    1. Create core/cache pair with promotion policy NHIT
    2. Set TRIGGER_THRESHOLD/INSERTION_THRESHOLD to predefined values
    3. Fill cache from the beggining until occupancy reaches TRIGGER_THRESHOLD%
    4. Issue INSERTION_THRESHOLD - 1 requests to core line not inserted to cache
        * occupancy should not change
    5. Issue one request to LBA from step 4
        * occupancy should rise by one cache line
    """

    # Step 1
    cache_device = Volume(Size.from_MiB(30))
    core_device = Volume(Size.from_MiB(30))

    cache = Cache.start_on_device(cache_device,
                                  promotion_policy=PromotionPolicy.NHIT)
    core = Core.using_device(core_device)
    cache.add_core(core)

    # Step 2
    cache.set_promotion_policy_param(PromotionPolicy.NHIT,
                                     NhitParams.TRIGGER_THRESHOLD,
                                     fill_percentage)
    cache.set_promotion_policy_param(PromotionPolicy.NHIT,
                                     NhitParams.INSERTION_THRESHOLD,
                                     insertion_threshold)
    # Step 3
    fill_cache(cache, fill_percentage / 100)

    stats = cache.get_stats()
    cache_lines = stats["conf"]["size"]
    assert stats["usage"]["occupancy"]["fraction"] // 10 == fill_percentage * 10
    filled_occupancy = stats["usage"]["occupancy"]["value"]

    # Step 4
    last_core_line = int(core_device.size) - cache_lines.line_size
    completions = []
    for i in range(insertion_threshold - 1):
        comp = OcfCompletion([("error", c_int)])
        write_data = Data(cache_lines.line_size)
        io = core.new_io(
            cache.get_default_queue(),
            last_core_line,
            write_data.size,
            IoDir.WRITE,
            0,
            0,
        )
        completions += [comp]
        io.set_data(write_data)
        io.callback = comp.callback
        io.submit()

    for c in completions:
        c.wait()

    stats = cache.get_stats()
    threshold_reached_occupancy = stats["usage"]["occupancy"]["value"]
    assert threshold_reached_occupancy == filled_occupancy, (
        "No insertion should occur while NHIT is triggered and core line ",
        "didn't reach INSERTION_THRESHOLD",
    )

    # Step 5
    comp = OcfCompletion([("error", c_int)])
    write_data = Data(cache_lines.line_size)
    io = core.new_io(cache.get_default_queue(), last_core_line,
                     write_data.size, IoDir.WRITE, 0, 0)
    io.set_data(write_data)
    io.callback = comp.callback
    io.submit()

    comp.wait()

    assert (threshold_reached_occupancy ==
            cache.get_stats()["usage"]["occupancy"]["value"] -
            1), "Previous request should be promoted and occupancy should rise"