Merge pull request #666 from arutk/pyocf_vol_cleaniup
pyocf: volume changes required for failover tests
This commit is contained in:
commit
a64fc61413
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright(c) 2019-2021 Intel Corporation
|
* Copyright(c) 2019-2022 Intel Corporation
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -260,11 +260,12 @@ int submit_io(ocf_core_t core, struct volume_data *data,
|
|||||||
uint64_t addr, uint64_t len, int dir, ocf_end_io_t cmpl)
|
uint64_t addr, uint64_t len, int dir, ocf_end_io_t cmpl)
|
||||||
{
|
{
|
||||||
ocf_cache_t cache = ocf_core_get_cache(core);
|
ocf_cache_t cache = ocf_core_get_cache(core);
|
||||||
|
ocf_volume_t core_vol = ocf_core_get_front_volume(core);
|
||||||
struct cache_priv *cache_priv = ocf_cache_get_priv(cache);
|
struct cache_priv *cache_priv = ocf_cache_get_priv(cache);
|
||||||
struct ocf_io *io;
|
struct ocf_io *io;
|
||||||
|
|
||||||
/* Allocate new io */
|
/* Allocate new io */
|
||||||
io = ocf_core_new_io(core, cache_priv->io_queue, addr, len, dir, 0, 0);
|
io = ocf_volume_new_io(core_vol, cache_priv->io_queue, addr, len, dir, 0, 0);
|
||||||
if (!io)
|
if (!io)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright(c) 2012-2021 Intel Corporation
|
* Copyright(c) 2012-2022 Intel Corporation
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -146,29 +146,6 @@ const char *ocf_core_get_name(ocf_core_t core);
|
|||||||
*/
|
*/
|
||||||
ocf_core_state_t ocf_core_get_state(ocf_core_t core);
|
ocf_core_state_t ocf_core_get_state(ocf_core_t core);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Allocate new ocf_io
|
|
||||||
*
|
|
||||||
* @param[in] core Core object
|
|
||||||
* @param[in] queue IO queue handle
|
|
||||||
* @param[in] addr OCF IO destination address
|
|
||||||
* @param[in] bytes OCF IO size in bytes
|
|
||||||
* @param[in] dir OCF IO direction
|
|
||||||
* @param[in] io_class OCF IO destination class
|
|
||||||
* @param[in] flags OCF IO flags
|
|
||||||
*
|
|
||||||
* @retval ocf_io object
|
|
||||||
*/
|
|
||||||
static inline struct ocf_io *ocf_core_new_io(ocf_core_t core, ocf_queue_t queue,
|
|
||||||
uint64_t addr, uint32_t bytes, uint32_t dir,
|
|
||||||
uint32_t io_class, uint64_t flags)
|
|
||||||
{
|
|
||||||
ocf_volume_t volume = ocf_core_get_front_volume(core);
|
|
||||||
|
|
||||||
return ocf_volume_new_io(volume, queue, addr, bytes, dir,
|
|
||||||
io_class, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Submit ocf_io
|
* @brief Submit ocf_io
|
||||||
*
|
*
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright(c) 2021 Intel Corporation
|
# Copyright(c) 2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -35,11 +35,11 @@ from ..utils import Size, struct_to_dict
|
|||||||
from .core import Core
|
from .core import Core
|
||||||
from .queue import Queue
|
from .queue import Queue
|
||||||
from .stats.cache import CacheInfo
|
from .stats.cache import CacheInfo
|
||||||
|
from .io import IoDir
|
||||||
from .ioclass import IoClassesInfo, IoClassInfo
|
from .ioclass import IoClassesInfo, IoClassInfo
|
||||||
from .stats.shared import UsageStats, RequestsStats, BlocksStats, ErrorsStats
|
from .stats.shared import UsageStats, RequestsStats, BlocksStats, ErrorsStats
|
||||||
from .ctx import OcfCtx
|
from .ctx import OcfCtx
|
||||||
from .volume import Volume
|
from .volume import RamVolume
|
||||||
|
|
||||||
|
|
||||||
class Backfill(Structure):
|
class Backfill(Structure):
|
||||||
_fields_ = [("_max_queue_size", c_uint32), ("_queue_unblock_size", c_uint32)]
|
_fields_ = [("_max_queue_size", c_uint32), ("_queue_unblock_size", c_uint32)]
|
||||||
@ -697,7 +697,7 @@ class Cache:
|
|||||||
raise OcfError("Failed getting core by name", result)
|
raise OcfError("Failed getting core by name", result)
|
||||||
|
|
||||||
uuid = self.owner.lib.ocf_core_get_uuid_wrapper(core_handle)
|
uuid = self.owner.lib.ocf_core_get_uuid_wrapper(core_handle)
|
||||||
device = Volume.get_by_uuid(uuid.contents._data.decode("ascii"))
|
device = RamVolume.get_by_uuid(uuid.contents._data.decode("ascii"))
|
||||||
core = Core(device)
|
core = Core(device)
|
||||||
core.cache = self
|
core.cache = self
|
||||||
core.handle = core_handle
|
core.handle = core_handle
|
||||||
@ -749,6 +749,12 @@ class Cache:
|
|||||||
|
|
||||||
self.cores.remove(core)
|
self.cores.remove(core)
|
||||||
|
|
||||||
|
def get_front_volume(self):
|
||||||
|
return Volume.get_instance(lib.ocf_cache_get_front_volume(self.cache_handle))
|
||||||
|
|
||||||
|
def get_volume(self):
|
||||||
|
return Volume.get_instance(lib.ocf_cache_get_volume(self.cache_handle))
|
||||||
|
|
||||||
def get_stats(self):
|
def get_stats(self):
|
||||||
cache_info = CacheInfo()
|
cache_info = CacheInfo()
|
||||||
usage = UsageStats()
|
usage = UsageStats()
|
||||||
@ -897,6 +903,10 @@ lib.ocf_mngt_cache_remove_core.argtypes = [c_void_p, c_void_p, c_void_p]
|
|||||||
lib.ocf_mngt_cache_add_core.argtypes = [c_void_p, c_void_p, c_void_p, c_void_p]
|
lib.ocf_mngt_cache_add_core.argtypes = [c_void_p, c_void_p, c_void_p, c_void_p]
|
||||||
lib.ocf_cache_get_name.argtypes = [c_void_p]
|
lib.ocf_cache_get_name.argtypes = [c_void_p]
|
||||||
lib.ocf_cache_get_name.restype = c_char_p
|
lib.ocf_cache_get_name.restype = c_char_p
|
||||||
|
lib.ocf_cache_get_front_volume.argtypes = [c_void_p]
|
||||||
|
lib.ocf_cache_get_front_volume.restype = c_void_p
|
||||||
|
lib.ocf_cache_get_volume.argtypes = [c_void_p]
|
||||||
|
lib.ocf_cache_get_volume.restype = c_void_p
|
||||||
lib.ocf_mngt_cache_cleaning_set_policy.argtypes = [
|
lib.ocf_mngt_cache_cleaning_set_policy.argtypes = [
|
||||||
c_void_p,
|
c_void_p,
|
||||||
c_uint32,
|
c_uint32,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright(c) 2019-2021 Intel Corporation
|
# Copyright(c) 2019-2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -99,30 +99,14 @@ class Core:
|
|||||||
def get_handle(self):
|
def get_handle(self):
|
||||||
return self.handle
|
return self.handle
|
||||||
|
|
||||||
def new_io(
|
def get_front_volume(self):
|
||||||
self, queue: Queue, addr: int, length: int, direction: IoDir,
|
return Volume.get_instance(lib.ocf_core_get_front_volume(self.handle))
|
||||||
io_class: int, flags: int
|
|
||||||
):
|
|
||||||
if not self.cache:
|
|
||||||
raise Exception("Core isn't attached to any cache")
|
|
||||||
|
|
||||||
io = OcfLib.getInstance().ocf_core_new_io_wrapper(
|
def get_volume(self):
|
||||||
self.handle, queue.handle, addr, length, direction, io_class, flags)
|
return Volume.get_instance(lib.ocf_core_get_volume(self.handle))
|
||||||
|
|
||||||
if io is None:
|
def get_default_queue(self):
|
||||||
raise Exception("Failed to create io!")
|
return self.cache.get_default_queue()
|
||||||
|
|
||||||
return Io.from_pointer(io)
|
|
||||||
|
|
||||||
def new_core_io(
|
|
||||||
self, queue: Queue, addr: int, length: int, direction: IoDir,
|
|
||||||
io_class: int, flags: int
|
|
||||||
):
|
|
||||||
lib = OcfLib.getInstance()
|
|
||||||
volume = lib.ocf_core_get_volume(self.handle)
|
|
||||||
io = lib.ocf_volume_new_io(
|
|
||||||
volume, queue.handle, addr, length, direction, io_class, flags)
|
|
||||||
return Io.from_pointer(io)
|
|
||||||
|
|
||||||
def get_stats(self):
|
def get_stats(self):
|
||||||
core_info = CoreInfo()
|
core_info = CoreInfo()
|
||||||
@ -191,52 +175,13 @@ class Core:
|
|||||||
def reset_stats(self):
|
def reset_stats(self):
|
||||||
self.cache.owner.lib.ocf_core_stats_initialize(self.handle)
|
self.cache.owner.lib.ocf_core_stats_initialize(self.handle)
|
||||||
|
|
||||||
def exp_obj_md5(self):
|
|
||||||
logging.getLogger("pyocf").warning(
|
|
||||||
"Reading whole exported object! This disturbs statistics values"
|
|
||||||
)
|
|
||||||
|
|
||||||
cache_line_size = int(self.cache.get_stats()['conf']['cache_line_size'])
|
|
||||||
read_buffer_all = Data(self.device.size)
|
|
||||||
|
|
||||||
read_buffer = Data(cache_line_size)
|
|
||||||
|
|
||||||
position = 0
|
|
||||||
while position < read_buffer_all.size:
|
|
||||||
io = self.new_io(self.cache.get_default_queue(), position,
|
|
||||||
cache_line_size, IoDir.READ, 0, 0)
|
|
||||||
io.set_data(read_buffer)
|
|
||||||
|
|
||||||
cmpl = OcfCompletion([("err", c_int)])
|
|
||||||
io.callback = cmpl.callback
|
|
||||||
io.submit()
|
|
||||||
cmpl.wait()
|
|
||||||
|
|
||||||
if cmpl.results["err"]:
|
|
||||||
raise Exception("Error reading whole exported object")
|
|
||||||
|
|
||||||
read_buffer_all.copy(read_buffer, position, 0, cache_line_size)
|
|
||||||
position += cache_line_size
|
|
||||||
|
|
||||||
return read_buffer_all.md5()
|
|
||||||
|
|
||||||
|
|
||||||
lib = OcfLib.getInstance()
|
lib = OcfLib.getInstance()
|
||||||
lib.ocf_core_get_uuid_wrapper.restype = POINTER(Uuid)
|
lib.ocf_core_get_uuid_wrapper.restype = POINTER(Uuid)
|
||||||
lib.ocf_core_get_uuid_wrapper.argtypes = [c_void_p]
|
lib.ocf_core_get_uuid_wrapper.argtypes = [c_void_p]
|
||||||
lib.ocf_core_get_volume.restype = c_void_p
|
|
||||||
lib.ocf_volume_new_io.argtypes = [
|
|
||||||
c_void_p,
|
|
||||||
c_void_p,
|
|
||||||
c_uint64,
|
|
||||||
c_uint32,
|
|
||||||
c_uint32,
|
|
||||||
c_uint32,
|
|
||||||
c_uint64,
|
|
||||||
]
|
|
||||||
lib.ocf_volume_new_io.restype = c_void_p
|
|
||||||
lib.ocf_core_get_volume.argtypes = [c_void_p]
|
lib.ocf_core_get_volume.argtypes = [c_void_p]
|
||||||
lib.ocf_core_get_volume.restype = c_void_p
|
lib.ocf_core_get_volume.restype = c_void_p
|
||||||
|
lib.ocf_core_get_front_volume.argtypes = [c_void_p]
|
||||||
|
lib.ocf_core_get_front_volume.restype = c_void_p
|
||||||
lib.ocf_mngt_core_set_seq_cutoff_policy.argtypes = [c_void_p, c_uint32]
|
lib.ocf_mngt_core_set_seq_cutoff_policy.argtypes = [c_void_p, c_uint32]
|
||||||
lib.ocf_mngt_core_set_seq_cutoff_policy.restype = c_int
|
lib.ocf_mngt_core_set_seq_cutoff_policy.restype = c_int
|
||||||
lib.ocf_mngt_core_set_seq_cutoff_threshold.argtypes = [c_void_p, c_uint32]
|
lib.ocf_mngt_core_set_seq_cutoff_threshold.argtypes = [c_void_p, c_uint32]
|
||||||
@ -247,13 +192,3 @@ lib.ocf_stats_collect_core.argtypes = [c_void_p, c_void_p, c_void_p, c_void_p, c
|
|||||||
lib.ocf_stats_collect_core.restype = c_int
|
lib.ocf_stats_collect_core.restype = c_int
|
||||||
lib.ocf_core_get_info.argtypes = [c_void_p, c_void_p]
|
lib.ocf_core_get_info.argtypes = [c_void_p, c_void_p]
|
||||||
lib.ocf_core_get_info.restype = c_int
|
lib.ocf_core_get_info.restype = c_int
|
||||||
lib.ocf_core_new_io_wrapper.argtypes = [
|
|
||||||
c_void_p,
|
|
||||||
c_void_p,
|
|
||||||
c_uint64,
|
|
||||||
c_uint32,
|
|
||||||
c_uint32,
|
|
||||||
c_uint32,
|
|
||||||
c_uint64,
|
|
||||||
]
|
|
||||||
lib.ocf_core_new_io_wrapper.restype = c_void_p
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright(c) 2019-2021 Intel Corporation
|
# Copyright(c) 2019-2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -12,8 +12,6 @@ from .cleaner import CleanerOps, Cleaner
|
|||||||
from .shared import OcfError
|
from .shared import OcfError
|
||||||
from ..ocf import OcfLib
|
from ..ocf import OcfLib
|
||||||
from .queue import Queue
|
from .queue import Queue
|
||||||
from .volume import Volume
|
|
||||||
|
|
||||||
|
|
||||||
class OcfCtxOps(Structure):
|
class OcfCtxOps(Structure):
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright(c) 2019-2021 Intel Corporation
|
# Copyright(c) 2019-2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -96,7 +96,13 @@ class Io(Structure):
|
|||||||
self.del_object()
|
self.del_object()
|
||||||
|
|
||||||
def submit(self):
|
def submit(self):
|
||||||
return OcfLib.getInstance().ocf_core_submit_io_wrapper(byref(self))
|
return OcfLib.getInstance().ocf_volume_submit_io(byref(self))
|
||||||
|
|
||||||
|
def submit_flush(self):
|
||||||
|
return OcfLib.getInstance().ocf_volume_submit_flush(byref(self))
|
||||||
|
|
||||||
|
def submit_discard(self):
|
||||||
|
return OcfLib.getInstance().ocf_volume_submit_discard(byref(self))
|
||||||
|
|
||||||
def set_data(self, data: Data, offset: int = 0):
|
def set_data(self, data: Data, offset: int = 0):
|
||||||
self.data = data
|
self.data = data
|
||||||
@ -111,8 +117,14 @@ IoOps._fields_ = [("_set_data", IoOps.SET_DATA), ("_get_data", IoOps.GET_DATA)]
|
|||||||
lib = OcfLib.getInstance()
|
lib = OcfLib.getInstance()
|
||||||
lib.ocf_io_set_cmpl_wrapper.argtypes = [POINTER(Io), c_void_p, c_void_p, Io.END]
|
lib.ocf_io_set_cmpl_wrapper.argtypes = [POINTER(Io), c_void_p, c_void_p, Io.END]
|
||||||
|
|
||||||
lib.ocf_core_new_io_wrapper.argtypes = [c_void_p]
|
|
||||||
lib.ocf_core_new_io_wrapper.restype = c_void_p
|
|
||||||
|
|
||||||
lib.ocf_io_set_data.argtypes = [POINTER(Io), c_void_p, c_uint32]
|
lib.ocf_io_set_data.argtypes = [POINTER(Io), c_void_p, c_uint32]
|
||||||
lib.ocf_io_set_data.restype = c_int
|
lib.ocf_io_set_data.restype = c_int
|
||||||
|
|
||||||
|
lib.ocf_volume_submit_io.argtypes = [POINTER(Io)]
|
||||||
|
lib.ocf_volume_submit_io.restype = None
|
||||||
|
|
||||||
|
lib.ocf_volume_submit_flush.argtypes = [POINTER(Io)]
|
||||||
|
lib.ocf_volume_submit_flush.restype = None
|
||||||
|
|
||||||
|
lib.ocf_volume_submit_discard.argtypes = [POINTER(Io)]
|
||||||
|
lib.ocf_volume_submit_discard.restype = None
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright(c) 2019-2021 Intel Corporation
|
# Copyright(c) 2019-2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -24,10 +24,12 @@ from hashlib import md5
|
|||||||
import weakref
|
import weakref
|
||||||
|
|
||||||
from .io import Io, IoOps, IoDir
|
from .io import Io, IoOps, IoDir
|
||||||
|
from .queue import Queue
|
||||||
from .shared import OcfErrorCode, Uuid
|
from .shared import OcfErrorCode, Uuid
|
||||||
from ..ocf import OcfLib
|
from ..ocf import OcfLib
|
||||||
from ..utils import print_buffer, Size as S
|
from ..utils import print_buffer, Size as S
|
||||||
from .data import Data
|
from .data import Data
|
||||||
|
from .queue import Queue
|
||||||
|
|
||||||
|
|
||||||
class VolumeCaps(Structure):
|
class VolumeCaps(Structure):
|
||||||
@ -66,89 +68,27 @@ class VolumeProperties(Structure):
|
|||||||
("_caps", VolumeCaps),
|
("_caps", VolumeCaps),
|
||||||
("_io_ops", IoOps),
|
("_io_ops", IoOps),
|
||||||
("_deinit", c_char_p),
|
("_deinit", c_char_p),
|
||||||
("_ops", VolumeOps),
|
("_ops_", VolumeOps),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class VolumeIoPriv(Structure):
|
class VolumeIoPriv(Structure):
|
||||||
_fields_ = [("_data", c_void_p), ("_offset", c_uint64)]
|
_fields_ = [("_data", c_void_p), ("_offset", c_uint64)]
|
||||||
|
|
||||||
|
|
||||||
class Volume(Structure):
|
VOLUME_POISON = 0x13
|
||||||
VOLUME_POISON = 0x13
|
|
||||||
|
|
||||||
_fields_ = [("_storage", c_void_p)]
|
|
||||||
|
class Volume:
|
||||||
_instances_ = weakref.WeakValueDictionary()
|
_instances_ = weakref.WeakValueDictionary()
|
||||||
_uuid_ = weakref.WeakValueDictionary()
|
_uuid_ = weakref.WeakValueDictionary()
|
||||||
|
_ops_ = {}
|
||||||
props = None
|
_props_ = {}
|
||||||
|
|
||||||
def __init__(self, size: S, uuid=None):
|
|
||||||
super().__init__()
|
|
||||||
self.size = size
|
|
||||||
if uuid:
|
|
||||||
if uuid in type(self)._uuid_:
|
|
||||||
raise Exception(
|
|
||||||
"Volume with uuid {} already created".format(uuid)
|
|
||||||
)
|
|
||||||
self.uuid = uuid
|
|
||||||
else:
|
|
||||||
self.uuid = str(id(self))
|
|
||||||
|
|
||||||
type(self)._uuid_[self.uuid] = self
|
|
||||||
|
|
||||||
self.data = create_string_buffer(int(self.size))
|
|
||||||
memset(self.data, self.VOLUME_POISON, self.size)
|
|
||||||
self._storage = cast(self.data, c_void_p)
|
|
||||||
|
|
||||||
self.reset_stats()
|
|
||||||
self.opened = False
|
|
||||||
|
|
||||||
def get_copy(self):
|
|
||||||
new_volume = Volume(self.size)
|
|
||||||
memmove(new_volume.data, self.data, self.size)
|
|
||||||
return new_volume
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_props(cls):
|
def get_ops(cls):
|
||||||
if not cls.props:
|
if cls in Volume._ops_:
|
||||||
cls.props = VolumeProperties(
|
return Volume._ops_[cls]
|
||||||
_name=str(cls.__name__).encode("ascii"),
|
|
||||||
_io_priv_size=sizeof(VolumeIoPriv),
|
|
||||||
_volume_priv_size=0,
|
|
||||||
_caps=VolumeCaps(_atomic_writes=0),
|
|
||||||
_ops=VolumeOps(
|
|
||||||
_submit_io=cls._submit_io,
|
|
||||||
_submit_flush=cls._submit_flush,
|
|
||||||
_submit_metadata=cls._submit_metadata,
|
|
||||||
_submit_discard=cls._submit_discard,
|
|
||||||
_submit_write_zeroes=cls._submit_write_zeroes,
|
|
||||||
_open=cls._open,
|
|
||||||
_close=cls._close,
|
|
||||||
_get_max_io_size=cls._get_max_io_size,
|
|
||||||
_get_length=cls._get_length,
|
|
||||||
),
|
|
||||||
_io_ops=IoOps(
|
|
||||||
_set_data=cls._io_set_data, _get_data=cls._io_get_data
|
|
||||||
),
|
|
||||||
_deinit=0,
|
|
||||||
)
|
|
||||||
|
|
||||||
return cls.props
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_instance(cls, ref):
|
|
||||||
instance = cls._instances_[ref]
|
|
||||||
if instance is None:
|
|
||||||
print("tried to access {} but it's gone".format(ref))
|
|
||||||
|
|
||||||
return instance
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_by_uuid(cls, uuid):
|
|
||||||
return cls._uuid_[uuid]
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
@VolumeOps.SUBMIT_IO
|
@VolumeOps.SUBMIT_IO
|
||||||
def _submit_io(io):
|
def _submit_io(io):
|
||||||
io_structure = cast(io, POINTER(Io))
|
io_structure = cast(io, POINTER(Io))
|
||||||
@ -158,7 +98,6 @@ class Volume(Structure):
|
|||||||
|
|
||||||
volume.submit_io(io_structure)
|
volume.submit_io(io_structure)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
@VolumeOps.SUBMIT_FLUSH
|
@VolumeOps.SUBMIT_FLUSH
|
||||||
def _submit_flush(flush):
|
def _submit_flush(flush):
|
||||||
io_structure = cast(flush, POINTER(Io))
|
io_structure = cast(flush, POINTER(Io))
|
||||||
@ -168,12 +107,10 @@ class Volume(Structure):
|
|||||||
|
|
||||||
volume.submit_flush(io_structure)
|
volume.submit_flush(io_structure)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
@VolumeOps.SUBMIT_METADATA
|
@VolumeOps.SUBMIT_METADATA
|
||||||
def _submit_metadata(meta):
|
def _submit_metadata(meta):
|
||||||
pass
|
raise NotImplementedError
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
@VolumeOps.SUBMIT_DISCARD
|
@VolumeOps.SUBMIT_DISCARD
|
||||||
def _submit_discard(discard):
|
def _submit_discard(discard):
|
||||||
io_structure = cast(discard, POINTER(Io))
|
io_structure = cast(discard, POINTER(Io))
|
||||||
@ -183,13 +120,11 @@ class Volume(Structure):
|
|||||||
|
|
||||||
volume.submit_discard(io_structure)
|
volume.submit_discard(io_structure)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
@VolumeOps.SUBMIT_WRITE_ZEROES
|
@VolumeOps.SUBMIT_WRITE_ZEROES
|
||||||
def _submit_write_zeroes(write_zeroes):
|
def _submit_write_zeroes(write_zeroes):
|
||||||
pass
|
raise NotImplementedError
|
||||||
|
|
||||||
@staticmethod
|
@VolumeOps.OPEN
|
||||||
@CFUNCTYPE(c_int, c_void_p)
|
|
||||||
def _open(ref):
|
def _open(ref):
|
||||||
uuid_ptr = cast(
|
uuid_ptr = cast(
|
||||||
OcfLib.getInstance().ocf_volume_get_uuid(ref), POINTER(Uuid)
|
OcfLib.getInstance().ocf_volume_get_uuid(ref), POINTER(Uuid)
|
||||||
@ -202,30 +137,81 @@ class Volume(Structure):
|
|||||||
print("{}".format(Volume._uuid_))
|
print("{}".format(Volume._uuid_))
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
if volume.opened:
|
return Volume.open(ref, volume)
|
||||||
return -OcfErrorCode.OCF_ERR_NOT_OPEN_EXC
|
|
||||||
|
|
||||||
Volume._instances_[ref] = volume
|
|
||||||
|
|
||||||
return volume.open()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
@VolumeOps.CLOSE
|
@VolumeOps.CLOSE
|
||||||
def _close(ref):
|
def _close(ref):
|
||||||
volume = Volume.get_instance(ref)
|
volume = Volume.get_instance(ref)
|
||||||
volume.close()
|
volume.close()
|
||||||
volume.opened = False
|
volume.opened = False
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
@VolumeOps.GET_MAX_IO_SIZE
|
@VolumeOps.GET_MAX_IO_SIZE
|
||||||
def _get_max_io_size(ref):
|
def _get_max_io_size(ref):
|
||||||
return Volume.get_instance(ref).get_max_io_size()
|
return Volume.get_instance(ref).get_max_io_size()
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
@VolumeOps.GET_LENGTH
|
@VolumeOps.GET_LENGTH
|
||||||
def _get_length(ref):
|
def _get_length(ref):
|
||||||
return Volume.get_instance(ref).get_length()
|
return Volume.get_instance(ref).get_length()
|
||||||
|
|
||||||
|
Volume._ops_[cls] = VolumeOps(
|
||||||
|
_submit_io=_submit_io,
|
||||||
|
_submit_flush=_submit_flush,
|
||||||
|
_submit_metadata=_submit_metadata,
|
||||||
|
_submit_discard=_submit_discard,
|
||||||
|
_submit_write_zeroes=_submit_write_zeroes,
|
||||||
|
_open=_open,
|
||||||
|
_close=_close,
|
||||||
|
_get_max_io_size=_get_max_io_size,
|
||||||
|
_get_length=_get_length,
|
||||||
|
)
|
||||||
|
|
||||||
|
return Volume._ops_[cls]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def open(ref, volume):
|
||||||
|
if volume.opened:
|
||||||
|
return -OcfErrorCode.OCF_ERR_NOT_OPEN_EXC
|
||||||
|
|
||||||
|
Volume._instances_[ref] = volume
|
||||||
|
volume.handle = ref
|
||||||
|
|
||||||
|
return volume.do_open()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_io_ops(cls):
|
||||||
|
return IoOps(_set_data=cls._io_set_data, _get_data=cls._io_get_data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_props(cls):
|
||||||
|
if cls in Volume._props_:
|
||||||
|
return Volume._props_[cls]
|
||||||
|
|
||||||
|
Volume._props_[cls] = VolumeProperties(
|
||||||
|
_name=str(cls.__name__).encode("ascii"),
|
||||||
|
_io_priv_size=sizeof(VolumeIoPriv),
|
||||||
|
_volume_priv_size=0,
|
||||||
|
_caps=VolumeCaps(_atomic_writes=0),
|
||||||
|
_ops_=cls.get_ops(),
|
||||||
|
_io_ops=cls.get_io_ops(),
|
||||||
|
_deinit=0,
|
||||||
|
)
|
||||||
|
return Volume._props_[cls]
|
||||||
|
|
||||||
|
def get_copy(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_instance(cls, ref):
|
||||||
|
instance = cls._instances_[ref]
|
||||||
|
if instance is None:
|
||||||
|
print("tried to access {} but it's gone".format(ref))
|
||||||
|
|
||||||
|
return instance
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_by_uuid(cls, uuid):
|
||||||
|
return cls._uuid_[uuid]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@IoOps.SET_DATA
|
@IoOps.SET_DATA
|
||||||
def _io_set_data(io, data, offset):
|
def _io_set_data(io, data, offset):
|
||||||
@ -246,36 +232,40 @@ class Volume(Structure):
|
|||||||
)
|
)
|
||||||
return io_priv.contents._data
|
return io_priv.contents._data
|
||||||
|
|
||||||
def open(self):
|
def __init__(self, uuid=None):
|
||||||
|
if uuid:
|
||||||
|
if uuid in type(self)._uuid_:
|
||||||
|
raise Exception(
|
||||||
|
"Volume with uuid {} already created".format(uuid)
|
||||||
|
)
|
||||||
|
self.uuid = uuid
|
||||||
|
else:
|
||||||
|
self.uuid = str(id(self))
|
||||||
|
|
||||||
|
type(self)._uuid_[self.uuid] = self
|
||||||
|
|
||||||
|
self.reset_stats()
|
||||||
|
self.is_online = True
|
||||||
|
self.opened = False
|
||||||
|
|
||||||
|
def do_open(self):
|
||||||
self.opened = True
|
self.opened = True
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
pass
|
self.opened = False
|
||||||
|
|
||||||
def get_length(self):
|
def get_length(self):
|
||||||
return self.size
|
raise NotImplementedError
|
||||||
|
|
||||||
def resize(self, size):
|
|
||||||
self.size = size
|
|
||||||
self.data = create_string_buffer(int(self.size))
|
|
||||||
memset(self.data, self.VOLUME_POISON, self.size)
|
|
||||||
self._storage = cast(self.data, c_void_p)
|
|
||||||
|
|
||||||
def get_max_io_size(self):
|
def get_max_io_size(self):
|
||||||
return S.from_KiB(128)
|
raise NotImplementedError
|
||||||
|
|
||||||
def submit_flush(self, flush):
|
def do_submit_flush(self, flush):
|
||||||
flush.contents._end(flush, 0)
|
raise NotImplementedError
|
||||||
|
|
||||||
def submit_discard(self, discard):
|
def do_submit_discard(self, discard):
|
||||||
try:
|
raise NotImplementedError
|
||||||
dst = self._storage + discard.contents._addr
|
|
||||||
memset(dst, 0, discard.contents._bytes)
|
|
||||||
|
|
||||||
discard.contents._end(discard, 0)
|
|
||||||
except: # noqa E722
|
|
||||||
discard.contents._end(discard, -OcfErrorCode.OCF_ERR_NOT_SUPP)
|
|
||||||
|
|
||||||
def get_stats(self):
|
def get_stats(self):
|
||||||
return self.stats
|
return self.stats
|
||||||
@ -283,10 +273,103 @@ class Volume(Structure):
|
|||||||
def reset_stats(self):
|
def reset_stats(self):
|
||||||
self.stats = {IoDir.WRITE: 0, IoDir.READ: 0}
|
self.stats = {IoDir.WRITE: 0, IoDir.READ: 0}
|
||||||
|
|
||||||
def submit_io(self, io):
|
def inc_stats(self, _dir):
|
||||||
try:
|
self.stats[_dir] += 1
|
||||||
self.stats[IoDir(io.contents._dir)] += 1
|
|
||||||
|
|
||||||
|
def do_submit_io(self, io):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def dump(self, offset=0, size=0, ignore=VOLUME_POISON, **kwargs):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def md5(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def offline(self):
|
||||||
|
self.is_online = False
|
||||||
|
|
||||||
|
def online(self):
|
||||||
|
self.is_online = True
|
||||||
|
|
||||||
|
def _reject_io(self, io):
|
||||||
|
cast(io, POINTER(Io)).contents._end(io, -OcfErrorCode.OCF_ERR_IO)
|
||||||
|
|
||||||
|
def submit_flush(self, io):
|
||||||
|
if self.is_online:
|
||||||
|
self.do_submit_flush(io)
|
||||||
|
else:
|
||||||
|
self._reject_io(io)
|
||||||
|
|
||||||
|
def submit_io(self, io):
|
||||||
|
if self.is_online:
|
||||||
|
self.inc_stats(IoDir(io.contents._dir))
|
||||||
|
self.do_submit_io(io)
|
||||||
|
else:
|
||||||
|
self._reject_io(io)
|
||||||
|
|
||||||
|
def submit_discard(self, io):
|
||||||
|
if self.is_online:
|
||||||
|
self.do_submit_discard(io)
|
||||||
|
else:
|
||||||
|
self._reject_io(io)
|
||||||
|
|
||||||
|
def new_io(
|
||||||
|
self,
|
||||||
|
queue: Queue,
|
||||||
|
addr: int,
|
||||||
|
length: int,
|
||||||
|
direction: IoDir,
|
||||||
|
io_class: int,
|
||||||
|
flags: int,
|
||||||
|
):
|
||||||
|
lib = OcfLib.getInstance()
|
||||||
|
io = lib.ocf_volume_new_io(
|
||||||
|
self.handle, queue.handle, addr, length, direction, io_class, flags
|
||||||
|
)
|
||||||
|
return Io.from_pointer(io)
|
||||||
|
|
||||||
|
|
||||||
|
class RamVolume(Volume):
|
||||||
|
props = None
|
||||||
|
|
||||||
|
def __init__(self, size: S, uuid=None):
|
||||||
|
super().__init__(uuid)
|
||||||
|
self.size = size
|
||||||
|
self.data = create_string_buffer(int(self.size))
|
||||||
|
memset(self.data, VOLUME_POISON, self.size)
|
||||||
|
self.data_ptr = cast(self.data, c_void_p).value
|
||||||
|
|
||||||
|
def get_copy(self):
|
||||||
|
new_volume = RamVolume(self.size)
|
||||||
|
memmove(new_volume.data, self.data, self.size)
|
||||||
|
return new_volume
|
||||||
|
|
||||||
|
def get_length(self):
|
||||||
|
return self.size
|
||||||
|
|
||||||
|
def resize(self, size):
|
||||||
|
self.size = size
|
||||||
|
self.data = create_string_buffer(int(self.size))
|
||||||
|
memset(self.data, VOLUME_POISON, self.size)
|
||||||
|
self.data_ptr = cast(self.data, c_void_p).value
|
||||||
|
|
||||||
|
def get_max_io_size(self):
|
||||||
|
return S.from_KiB(128)
|
||||||
|
|
||||||
|
def do_submit_flush(self, flush):
|
||||||
|
flush.contents._end(flush, 0)
|
||||||
|
|
||||||
|
def do_submit_discard(self, discard):
|
||||||
|
try:
|
||||||
|
dst = self.data_ptr + discard.contents._addr
|
||||||
|
memset(dst, 0, discard.contents._bytes)
|
||||||
|
|
||||||
|
discard.contents._end(discard, 0)
|
||||||
|
except: # noqa E722
|
||||||
|
discard.contents._end(discard, -OcfErrorCode.OCF_ERR_NOT_SUPP)
|
||||||
|
|
||||||
|
def do_submit_io(self, io):
|
||||||
|
try:
|
||||||
io_priv = cast(
|
io_priv = cast(
|
||||||
OcfLib.getInstance().ocf_io_get_priv(io), POINTER(VolumeIoPriv))
|
OcfLib.getInstance().ocf_io_get_priv(io), POINTER(VolumeIoPriv))
|
||||||
offset = io_priv.contents._offset
|
offset = io_priv.contents._offset
|
||||||
@ -294,11 +377,11 @@ class Volume(Structure):
|
|||||||
if io.contents._dir == IoDir.WRITE:
|
if io.contents._dir == IoDir.WRITE:
|
||||||
src_ptr = cast(OcfLib.getInstance().ocf_io_get_data(io), c_void_p)
|
src_ptr = cast(OcfLib.getInstance().ocf_io_get_data(io), c_void_p)
|
||||||
src = Data.get_instance(src_ptr.value).handle.value + offset
|
src = Data.get_instance(src_ptr.value).handle.value + offset
|
||||||
dst = self._storage + io.contents._addr
|
dst = self.data_ptr + io.contents._addr
|
||||||
elif io.contents._dir == IoDir.READ:
|
elif io.contents._dir == IoDir.READ:
|
||||||
dst_ptr = cast(OcfLib.getInstance().ocf_io_get_data(io), c_void_p)
|
dst_ptr = cast(OcfLib.getInstance().ocf_io_get_data(io), c_void_p)
|
||||||
dst = Data.get_instance(dst_ptr.value).handle.value + offset
|
dst = Data.get_instance(dst_ptr.value).handle.value + offset
|
||||||
src = self._storage + io.contents._addr
|
src = self.data_ptr + io.contents._addr
|
||||||
|
|
||||||
memmove(dst, src, io.contents._bytes)
|
memmove(dst, src, io.contents._bytes)
|
||||||
io_priv.contents._offset += io.contents._bytes
|
io_priv.contents._offset += io.contents._bytes
|
||||||
@ -311,18 +394,18 @@ class Volume(Structure):
|
|||||||
if size == 0:
|
if size == 0:
|
||||||
size = int(self.size) - int(offset)
|
size = int(self.size) - int(offset)
|
||||||
|
|
||||||
print_buffer(self._storage, size, ignore=ignore, **kwargs)
|
print_buffer(self.data_ptr, size, ignore=ignore, **kwargs)
|
||||||
|
|
||||||
def md5(self):
|
def md5(self):
|
||||||
m = md5()
|
m = md5()
|
||||||
m.update(string_at(self._storage, self.size))
|
m.update(string_at(self.data_ptr, self.size))
|
||||||
return m.hexdigest()
|
return m.hexdigest()
|
||||||
|
|
||||||
def get_bytes(self):
|
def get_bytes(self):
|
||||||
return string_at(self._storage, self.size)
|
return string_at(self.data_ptr, self.size)
|
||||||
|
|
||||||
|
|
||||||
class ErrorDevice(Volume):
|
class ErrorDevice(RamVolume):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
size,
|
size,
|
||||||
@ -341,9 +424,9 @@ class ErrorDevice(Volume):
|
|||||||
def set_mapping(self, error_sectors: set):
|
def set_mapping(self, error_sectors: set):
|
||||||
self.error_sectors = error_sectors
|
self.error_sectors = error_sectors
|
||||||
|
|
||||||
def submit_io(self, io):
|
def do_submit_io(self, io):
|
||||||
if not self.armed:
|
if not self.armed:
|
||||||
super().submit_io(io)
|
super().do_submit_io(io)
|
||||||
return
|
return
|
||||||
|
|
||||||
direction = IoDir(io.contents._dir)
|
direction = IoDir(io.contents._dir)
|
||||||
@ -368,7 +451,7 @@ class ErrorDevice(Volume):
|
|||||||
io.contents._end(io, -OcfErrorCode.OCF_ERR_IO)
|
io.contents._end(io, -OcfErrorCode.OCF_ERR_IO)
|
||||||
self.stats["errors"][direction] += 1
|
self.stats["errors"][direction] += 1
|
||||||
else:
|
else:
|
||||||
super().submit_io(io)
|
super().do_submit_io(io)
|
||||||
|
|
||||||
def arm(self):
|
def arm(self):
|
||||||
self.armed = True
|
self.armed = True
|
||||||
@ -384,24 +467,19 @@ class ErrorDevice(Volume):
|
|||||||
self.stats["errors"] = {IoDir.WRITE: 0, IoDir.READ: 0}
|
self.stats["errors"] = {IoDir.WRITE: 0, IoDir.READ: 0}
|
||||||
|
|
||||||
|
|
||||||
class TraceDevice(Volume):
|
|
||||||
def __init__(self, size, trace_fcn=None, uuid=None):
|
|
||||||
super().__init__(size, uuid)
|
|
||||||
self.trace_fcn = trace_fcn
|
|
||||||
|
|
||||||
def submit_io(self, io):
|
|
||||||
submit = True
|
|
||||||
|
|
||||||
if self.trace_fcn:
|
|
||||||
submit = self.trace_fcn(self, io)
|
|
||||||
|
|
||||||
if submit:
|
|
||||||
super().submit_io(io)
|
|
||||||
|
|
||||||
|
|
||||||
lib = OcfLib.getInstance()
|
lib = OcfLib.getInstance()
|
||||||
lib.ocf_io_get_priv.restype = POINTER(VolumeIoPriv)
|
lib.ocf_io_get_priv.restype = POINTER(VolumeIoPriv)
|
||||||
lib.ocf_io_get_volume.argtypes = [c_void_p]
|
lib.ocf_io_get_volume.argtypes = [c_void_p]
|
||||||
lib.ocf_io_get_volume.restype = c_void_p
|
lib.ocf_io_get_volume.restype = c_void_p
|
||||||
lib.ocf_io_get_data.argtypes = [c_void_p]
|
lib.ocf_io_get_data.argtypes = [c_void_p]
|
||||||
lib.ocf_io_get_data.restype = c_void_p
|
lib.ocf_io_get_data.restype = c_void_p
|
||||||
|
lib.ocf_volume_new_io.argtypes = [
|
||||||
|
c_void_p,
|
||||||
|
c_void_p,
|
||||||
|
c_uint64,
|
||||||
|
c_uint32,
|
||||||
|
c_uint32,
|
||||||
|
c_uint32,
|
||||||
|
c_uint64,
|
||||||
|
]
|
||||||
|
lib.ocf_volume_new_io.restype = c_void_p
|
||||||
|
31
tests/functional/pyocf/types/volume_cache.py
Normal file
31
tests/functional/pyocf/types/volume_cache.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#
|
||||||
|
# Copyright(c) 2022 Intel Corporation
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
#
|
||||||
|
|
||||||
|
from ctypes import cast, POINTER
|
||||||
|
|
||||||
|
from .cache import Cache
|
||||||
|
from .io import Io
|
||||||
|
from .io import IoDir
|
||||||
|
from .volume_exp_obj import ExpObjVolume
|
||||||
|
from .volume import Volume
|
||||||
|
|
||||||
|
|
||||||
|
class CacheVolume(ExpObjVolume):
|
||||||
|
def __init__(self, cache, open=False, uuid=None):
|
||||||
|
super().__init__(cache, uuid)
|
||||||
|
self.cache = cache
|
||||||
|
self.lib = cache.owner.lib
|
||||||
|
if open:
|
||||||
|
self.open()
|
||||||
|
|
||||||
|
def open(self):
|
||||||
|
return Volume.open(
|
||||||
|
self.lib.ocf_cache_get_front_volume(self.cache.handle),
|
||||||
|
self
|
||||||
|
)
|
||||||
|
|
||||||
|
def md5(self):
|
||||||
|
cache_line_size = int(self.cache.get_stats()['conf']['cache_line_size'])
|
||||||
|
return self._exp_obj_md5(cache_line_size)
|
27
tests/functional/pyocf/types/volume_core.py
Normal file
27
tests/functional/pyocf/types/volume_core.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#
|
||||||
|
# Copyright(c) 2022 Intel Corporation
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
#
|
||||||
|
|
||||||
|
from .core import Core
|
||||||
|
from .volume_exp_obj import ExpObjVolume
|
||||||
|
from .io import IoDir
|
||||||
|
from .volume import Volume
|
||||||
|
|
||||||
|
|
||||||
|
class CoreVolume(ExpObjVolume):
|
||||||
|
def __init__(self, core, open=False, uuid=None):
|
||||||
|
super().__init__(core, uuid)
|
||||||
|
self.core = core
|
||||||
|
self.lib = core.cache.owner.lib
|
||||||
|
if open:
|
||||||
|
self.open()
|
||||||
|
|
||||||
|
def open(self):
|
||||||
|
return Volume.open(
|
||||||
|
self.lib.ocf_core_get_front_volume(self.core.handle),
|
||||||
|
self
|
||||||
|
)
|
||||||
|
|
||||||
|
def md5(self):
|
||||||
|
return self._exp_obj_md5(4096)
|
126
tests/functional/pyocf/types/volume_exp_obj.py
Normal file
126
tests/functional/pyocf/types/volume_exp_obj.py
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
#
|
||||||
|
# Copyright(c) 2022 Intel Corporation
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
#
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from ctypes import c_int, c_void_p, CFUNCTYPE, byref, c_uint32, c_uint64, cast, POINTER
|
||||||
|
|
||||||
|
from ..ocf import OcfLib
|
||||||
|
from .volume import Volume, VOLUME_POISON
|
||||||
|
from pyocf.utils import Size
|
||||||
|
from pyocf.types.data import Data
|
||||||
|
from pyocf.types.io import IoDir, Io
|
||||||
|
from pyocf.types.shared import OcfCompletion
|
||||||
|
|
||||||
|
|
||||||
|
class ExpObjVolume(Volume):
|
||||||
|
def __init__(self, parent, uuid=None):
|
||||||
|
super().__init__(uuid)
|
||||||
|
self.parent = parent
|
||||||
|
|
||||||
|
def __alloc_io(self, addr, _bytes, _dir, _class, _flags):
|
||||||
|
vol = self.parent.get_front_volume()
|
||||||
|
queue = self.parent.get_default_queue() # TODO multiple queues?
|
||||||
|
return vol.new_io(
|
||||||
|
queue, addr, _bytes, _dir, _class, _flags
|
||||||
|
)
|
||||||
|
|
||||||
|
def _alloc_io(self, io):
|
||||||
|
exp_obj_io = self.__alloc_io(
|
||||||
|
io.contents._addr,
|
||||||
|
io.contents._bytes,
|
||||||
|
io.contents._dir,
|
||||||
|
io.contents._class,
|
||||||
|
io.contents._flags,
|
||||||
|
)
|
||||||
|
|
||||||
|
lib = OcfLib.getInstance()
|
||||||
|
cdata = OcfLib.getInstance().ocf_io_get_data(io)
|
||||||
|
OcfLib.getInstance().ocf_io_set_data(byref(exp_obj_io), cdata, 0)
|
||||||
|
|
||||||
|
def cb(error):
|
||||||
|
nonlocal io
|
||||||
|
io = cast(io, POINTER(Io))
|
||||||
|
io.contents._end(io, error)
|
||||||
|
|
||||||
|
exp_obj_io.callback = cb
|
||||||
|
|
||||||
|
return exp_obj_io
|
||||||
|
|
||||||
|
def get_length(self):
|
||||||
|
return Size.from_B(OcfLib.getInstance().ocf_volume_get_length(self.c_vol))
|
||||||
|
|
||||||
|
def get_max_io_size(self):
|
||||||
|
return Size.from_B(OcfLib.getInstance().ocf_volume_get_max_io_size(self.c_vol))
|
||||||
|
|
||||||
|
def do_submit_io(self, io):
|
||||||
|
io = self._alloc_io(io)
|
||||||
|
io.submit()
|
||||||
|
|
||||||
|
def do_submit_flush(self, flush):
|
||||||
|
io = self._alloc_io(flush)
|
||||||
|
io.submit_flush()
|
||||||
|
|
||||||
|
def do_submit_discard(self, discard):
|
||||||
|
io = self._alloc_io(discard)
|
||||||
|
io.submit_discard()
|
||||||
|
|
||||||
|
def _read(self, offset=0, size=0):
|
||||||
|
if size == 0:
|
||||||
|
size = self.get_length().B - offset
|
||||||
|
exp_obj_io = self.__alloc_io(offset, size, IoDir.READ, 0, 0)
|
||||||
|
completion = OcfCompletion([("err", c_int)])
|
||||||
|
exp_obj_io.callback = completion
|
||||||
|
data = Data.from_bytes(bytes(size))
|
||||||
|
exp_obj_io.set_data(data)
|
||||||
|
exp_obj_io.submit()
|
||||||
|
completion.wait()
|
||||||
|
error = completion.results["err"]
|
||||||
|
if error:
|
||||||
|
raise Exception("error reading exported object for dump")
|
||||||
|
return data
|
||||||
|
|
||||||
|
def dump(self, offset=0, size=0, ignore=VOLUME_POISON, **kwargs):
|
||||||
|
data = self._read(offset, size)
|
||||||
|
data.dump(ignore=ifnore, **kwargs)
|
||||||
|
|
||||||
|
def md5(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def _exp_obj_md5(self, read_size):
|
||||||
|
logging.getLogger("pyocf").warning(
|
||||||
|
"Reading whole exported object! This disturbs statistics values"
|
||||||
|
)
|
||||||
|
|
||||||
|
read_buffer_all = Data(self.parent.device.size)
|
||||||
|
|
||||||
|
read_buffer = Data(read_size)
|
||||||
|
|
||||||
|
position = 0
|
||||||
|
while position < read_buffer_all.size:
|
||||||
|
io = self.new_io(self.parent.get_default_queue(), position,
|
||||||
|
read_size, IoDir.READ, 0, 0)
|
||||||
|
io.set_data(read_buffer)
|
||||||
|
|
||||||
|
cmpl = OcfCompletion([("err", c_int)])
|
||||||
|
io.callback = cmpl.callback
|
||||||
|
io.submit()
|
||||||
|
cmpl.wait()
|
||||||
|
|
||||||
|
if cmpl.results["err"]:
|
||||||
|
raise Exception("Error reading whole exported object")
|
||||||
|
|
||||||
|
read_buffer_all.copy(read_buffer, position, 0, read_size)
|
||||||
|
position += read_size
|
||||||
|
|
||||||
|
return read_buffer_all.md5()
|
||||||
|
|
||||||
|
|
||||||
|
lib = OcfLib.getInstance()
|
||||||
|
lib.ocf_volume_get_max_io_size.argtypes = [c_void_p]
|
||||||
|
lib.ocf_volume_get_max_io_size.restype = c_uint32
|
||||||
|
lib.ocf_volume_get_length.argtypes = [c_void_p]
|
||||||
|
lib.ocf_volume_get_length.restype = c_uint64
|
||||||
|
lib.ocf_io_get_data.argtypes = [POINTER(Io)]
|
||||||
|
lib.ocf_io_get_data.restype = c_void_p
|
92
tests/functional/pyocf/types/volume_replicated.py
Normal file
92
tests/functional/pyocf/types/volume_replicated.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#
|
||||||
|
# Copyright(c) 2022 Intel Corporation
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
#
|
||||||
|
|
||||||
|
from threading import Lock
|
||||||
|
from .volume import Volume, VOLUME_POISON
|
||||||
|
from .io import Io, IoDir
|
||||||
|
from ctypes import cast, c_void_p, CFUNCTYPE, c_int, POINTER, memmove, sizeof, pointer
|
||||||
|
|
||||||
|
|
||||||
|
class ReplicatedVolume(Volume):
|
||||||
|
def __init__(self, primary: Volume, secondary: Volume, uuid=None):
|
||||||
|
super().__init__(uuid)
|
||||||
|
self.primary = primary
|
||||||
|
self.secondary = secondary
|
||||||
|
|
||||||
|
if secondary.get_max_io_size() < primary.get_max_io_size():
|
||||||
|
raise Exception("secondary volume max io size too small")
|
||||||
|
if secondary.get_length() < primary.get_length():
|
||||||
|
raise Exception("secondary volume size too small")
|
||||||
|
|
||||||
|
def do_open(self):
|
||||||
|
ret = self.primary.do_open()
|
||||||
|
if ret:
|
||||||
|
return ret
|
||||||
|
ret = self.secondary.do_open()
|
||||||
|
if ret:
|
||||||
|
self.primary.close()
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self.primary.close()
|
||||||
|
self.secondary.close()
|
||||||
|
|
||||||
|
def get_length(self):
|
||||||
|
return self.primary.get_length()
|
||||||
|
|
||||||
|
def get_max_io_size(self):
|
||||||
|
return self.primary.get_max_io_size()
|
||||||
|
|
||||||
|
def _prepare_io(self, io):
|
||||||
|
original_cb = Io.END()
|
||||||
|
pointer(original_cb)[0] = io.contents._end
|
||||||
|
lock = Lock()
|
||||||
|
error = 0
|
||||||
|
io_remaining = 2
|
||||||
|
|
||||||
|
@CFUNCTYPE(None, c_void_p, c_int)
|
||||||
|
def cb(io, err):
|
||||||
|
nonlocal io_remaining
|
||||||
|
nonlocal error
|
||||||
|
nonlocal original_cb
|
||||||
|
nonlocal lock
|
||||||
|
io = cast(io, POINTER(Io))
|
||||||
|
|
||||||
|
with lock:
|
||||||
|
if err:
|
||||||
|
error = err
|
||||||
|
io_remaining -= 1
|
||||||
|
finished = True if io_remaining == 0 else False
|
||||||
|
if finished:
|
||||||
|
io.contents._end = original_cb
|
||||||
|
original_cb(io, error)
|
||||||
|
|
||||||
|
io.contents._end = cb
|
||||||
|
|
||||||
|
def do_submit_io(self, io):
|
||||||
|
if io.contents._dir == IoDir.WRITE:
|
||||||
|
self._prepare_io(io)
|
||||||
|
self.primary.submit_io(io)
|
||||||
|
self.secondary.submit_io(io)
|
||||||
|
else:
|
||||||
|
# for read just pass through down to primary
|
||||||
|
# with original completion
|
||||||
|
self.primary.submit_io(io)
|
||||||
|
|
||||||
|
def do_submit_flush(self, flush):
|
||||||
|
self._prepare_io(flush)
|
||||||
|
self.primary.submit_flush(flush)
|
||||||
|
self.secondary.submit_flush(flush)
|
||||||
|
|
||||||
|
def do_submit_discard(self, discard):
|
||||||
|
self._prepare_io(discard)
|
||||||
|
self.primary.submit_discard(discard)
|
||||||
|
self.secondary.submit_discard(discard)
|
||||||
|
|
||||||
|
def dump(self, offset=0, size=0, ignore=VOLUME_POISON, **kwargs):
|
||||||
|
self.primary.dump()
|
||||||
|
|
||||||
|
def md5(self):
|
||||||
|
return self.primary.md5()
|
@ -1,18 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright(c) 2012-2021 Intel Corporation
|
* Copyright(c) 2012-2022 Intel Corporation
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ocf/ocf_io.h"
|
#include "ocf/ocf_io.h"
|
||||||
#include "ocf/ocf_core.h"
|
#include "ocf/ocf_core.h"
|
||||||
|
|
||||||
struct ocf_io *ocf_core_new_io_wrapper(ocf_core_t core, ocf_queue_t queue,
|
|
||||||
uint64_t addr, uint32_t bytes, uint32_t dir,
|
|
||||||
uint32_t io_class, uint64_t flags)
|
|
||||||
{
|
|
||||||
return ocf_core_new_io(core, queue, addr, bytes, dir, io_class, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ocf_io_set_cmpl_wrapper(struct ocf_io *io, void *context,
|
void ocf_io_set_cmpl_wrapper(struct ocf_io *io, void *context,
|
||||||
void *context2, ocf_end_io_t fn)
|
void *context2, ocf_end_io_t fn)
|
||||||
{
|
{
|
||||||
@ -34,3 +27,13 @@ void ocf_core_submit_io_wrapper(struct ocf_io *io)
|
|||||||
ocf_core_submit_io(io);
|
ocf_core_submit_io(io);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ocf_core_submit_flush_wrapper(struct ocf_io *io)
|
||||||
|
{
|
||||||
|
ocf_core_submit_flush(io);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ocf_core_submit_discard_wrapper(struct ocf_io *io)
|
||||||
|
{
|
||||||
|
ocf_core_submit_discard(io);
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright(c) 2019-2021 Intel Corporation
|
# Copyright(c) 2019-2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -8,7 +8,8 @@ from ctypes import c_int
|
|||||||
|
|
||||||
from pyocf.types.cache import Cache
|
from pyocf.types.cache import Cache
|
||||||
from pyocf.types.core import Core
|
from pyocf.types.core import Core
|
||||||
from pyocf.types.volume import Volume, ErrorDevice
|
from pyocf.types.volume import RamVolume, ErrorDevice
|
||||||
|
from pyocf.types.volume_core import CoreVolume
|
||||||
from pyocf.types.data import Data
|
from pyocf.types.data import Data
|
||||||
from pyocf.types.io import IoDir
|
from pyocf.types.io import IoDir
|
||||||
from pyocf.utils import Size as S
|
from pyocf.utils import Size as S
|
||||||
@ -21,25 +22,27 @@ def test_ctx_fixture(pyocf_ctx):
|
|||||||
|
|
||||||
|
|
||||||
def test_simple_wt_write(pyocf_ctx):
|
def test_simple_wt_write(pyocf_ctx):
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
core_device = Volume(S.from_MiB(50))
|
core_device = RamVolume(S.from_MiB(50))
|
||||||
|
|
||||||
cache = Cache.start_on_device(cache_device)
|
cache = Cache.start_on_device(cache_device)
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
|
queue = cache.get_default_queue()
|
||||||
|
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
|
|
||||||
cache_device.reset_stats()
|
cache_device.reset_stats()
|
||||||
core_device.reset_stats()
|
core_device.reset_stats()
|
||||||
|
|
||||||
r = Rio().target(core).readwrite(ReadWrite.WRITE).size(S.from_sector(1)).run()
|
r = Rio().target(vol).readwrite(ReadWrite.WRITE).size(S.from_sector(1)).run([queue])
|
||||||
assert cache_device.get_stats()[IoDir.WRITE] == 1
|
assert cache_device.get_stats()[IoDir.WRITE] == 1
|
||||||
cache.settle()
|
cache.settle()
|
||||||
stats = cache.get_stats()
|
stats = cache.get_stats()
|
||||||
assert stats["req"]["wr_full_misses"]["value"] == 1
|
assert stats["req"]["wr_full_misses"]["value"] == 1
|
||||||
assert stats["usage"]["occupancy"]["value"] == 1
|
assert stats["usage"]["occupancy"]["value"] == 1
|
||||||
|
|
||||||
assert core.exp_obj_md5() == core_device.md5()
|
assert vol.md5() == core_device.md5()
|
||||||
cache.stop()
|
cache.stop()
|
||||||
|
|
||||||
|
|
||||||
@ -51,14 +54,14 @@ def test_start_corrupted_metadata_lba(pyocf_ctx):
|
|||||||
|
|
||||||
|
|
||||||
def test_load_cache_no_preexisting_data(pyocf_ctx):
|
def test_load_cache_no_preexisting_data(pyocf_ctx):
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
|
|
||||||
with pytest.raises(OcfError, match="OCF_ERR_NO_METADATA"):
|
with pytest.raises(OcfError, match="OCF_ERR_NO_METADATA"):
|
||||||
cache = Cache.load_from_device(cache_device)
|
cache = Cache.load_from_device(cache_device)
|
||||||
|
|
||||||
|
|
||||||
def test_load_cache(pyocf_ctx):
|
def test_load_cache(pyocf_ctx):
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
|
|
||||||
cache = Cache.start_on_device(cache_device)
|
cache = Cache.start_on_device(cache_device)
|
||||||
cache.stop()
|
cache.stop()
|
||||||
@ -67,7 +70,7 @@ def test_load_cache(pyocf_ctx):
|
|||||||
|
|
||||||
|
|
||||||
def test_load_cache_recovery(pyocf_ctx):
|
def test_load_cache_recovery(pyocf_ctx):
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
|
|
||||||
cache = Cache.start_on_device(cache_device)
|
cache = Cache.start_on_device(cache_device)
|
||||||
|
|
||||||
@ -80,16 +83,17 @@ def test_load_cache_recovery(pyocf_ctx):
|
|||||||
|
|
||||||
@pytest.mark.parametrize("open_cores", [True, False])
|
@pytest.mark.parametrize("open_cores", [True, False])
|
||||||
def test_load_cache_with_cores(pyocf_ctx, open_cores):
|
def test_load_cache_with_cores(pyocf_ctx, open_cores):
|
||||||
cache_device = Volume(S.from_MiB(40))
|
cache_device = RamVolume(S.from_MiB(40))
|
||||||
core_device = Volume(S.from_MiB(40))
|
core_device = RamVolume(S.from_MiB(40))
|
||||||
|
|
||||||
cache = Cache.start_on_device(cache_device)
|
cache = Cache.start_on_device(cache_device)
|
||||||
core = Core.using_device(core_device, name="test_core")
|
core = Core.using_device(core_device, name="test_core")
|
||||||
|
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
|
|
||||||
write_data = Data.from_string("This is test data")
|
write_data = Data.from_string("This is test data")
|
||||||
io = core.new_io(cache.get_default_queue(), S.from_sector(3).B,
|
io = vol.new_io(cache.get_default_queue(), S.from_sector(3).B,
|
||||||
write_data.size, IoDir.WRITE, 0, 0)
|
write_data.size, IoDir.WRITE, 0, 0)
|
||||||
io.set_data(write_data)
|
io.set_data(write_data)
|
||||||
|
|
||||||
@ -106,8 +110,10 @@ def test_load_cache_with_cores(pyocf_ctx, open_cores):
|
|||||||
else:
|
else:
|
||||||
core = cache.get_core_by_name("test_core")
|
core = cache.get_core_by_name("test_core")
|
||||||
|
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
|
|
||||||
read_data = Data(write_data.size)
|
read_data = Data(write_data.size)
|
||||||
io = core.new_io(cache.get_default_queue(), S.from_sector(3).B,
|
io = vol.new_io(cache.get_default_queue(), S.from_sector(3).B,
|
||||||
read_data.size, IoDir.READ, 0, 0)
|
read_data.size, IoDir.READ, 0, 0)
|
||||||
io.set_data(read_data)
|
io.set_data(read_data)
|
||||||
|
|
||||||
@ -117,4 +123,4 @@ def test_load_cache_with_cores(pyocf_ctx, open_cores):
|
|||||||
cmpl.wait()
|
cmpl.wait()
|
||||||
|
|
||||||
assert read_data.md5() == write_data.md5()
|
assert read_data.md5() == write_data.md5()
|
||||||
assert core.exp_obj_md5() == core_device.md5()
|
assert vol.md5() == core_device.md5()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright(c) 2019-2021 Intel Corporation
|
# Copyright(c) 2019-2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -10,7 +10,10 @@ import gc
|
|||||||
|
|
||||||
sys.path.append(os.path.join(os.path.dirname(__file__), os.path.pardir))
|
sys.path.append(os.path.join(os.path.dirname(__file__), os.path.pardir))
|
||||||
from pyocf.types.logger import LogLevel, DefaultLogger, BufferLogger
|
from pyocf.types.logger import LogLevel, DefaultLogger, BufferLogger
|
||||||
from pyocf.types.volume import Volume, ErrorDevice
|
from pyocf.types.volume import RamVolume, ErrorDevice
|
||||||
|
from pyocf.types.volume_cache import CacheVolume
|
||||||
|
from pyocf.types.volume_core import CoreVolume
|
||||||
|
from pyocf.types.volume_replicated import ReplicatedVolume
|
||||||
from pyocf.types.ctx import OcfCtx
|
from pyocf.types.ctx import OcfCtx
|
||||||
|
|
||||||
|
|
||||||
@ -21,8 +24,11 @@ def pytest_configure(config):
|
|||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def pyocf_ctx():
|
def pyocf_ctx():
|
||||||
c = OcfCtx.with_defaults(DefaultLogger(LogLevel.WARN))
|
c = OcfCtx.with_defaults(DefaultLogger(LogLevel.WARN))
|
||||||
c.register_volume_type(Volume)
|
c.register_volume_type(RamVolume)
|
||||||
c.register_volume_type(ErrorDevice)
|
c.register_volume_type(ErrorDevice)
|
||||||
|
c.register_volume_type(CacheVolume)
|
||||||
|
c.register_volume_type(CoreVolume)
|
||||||
|
c.register_volume_type(ReplicatedVolume)
|
||||||
yield c
|
yield c
|
||||||
c.exit()
|
c.exit()
|
||||||
gc.collect()
|
gc.collect()
|
||||||
@ -32,8 +38,11 @@ def pyocf_ctx():
|
|||||||
def pyocf_ctx_log_buffer():
|
def pyocf_ctx_log_buffer():
|
||||||
logger = BufferLogger(LogLevel.DEBUG)
|
logger = BufferLogger(LogLevel.DEBUG)
|
||||||
c = OcfCtx.with_defaults(logger)
|
c = OcfCtx.with_defaults(logger)
|
||||||
c.register_volume_type(Volume)
|
c.register_volume_type(RamVolume)
|
||||||
c.register_volume_type(ErrorDevice)
|
c.register_volume_type(ErrorDevice)
|
||||||
|
c.register_volume_type(CacheVolume)
|
||||||
|
c.register_volume_type(CoreVolume)
|
||||||
|
c.register_volume_type(ReplicatedVolume)
|
||||||
yield logger
|
yield logger
|
||||||
c.exit()
|
c.exit()
|
||||||
gc.collect()
|
gc.collect()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright(c) 2020-2021 Intel Corporation
|
# Copyright(c) 2020-2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -12,7 +12,8 @@ import pytest
|
|||||||
|
|
||||||
from pyocf.types.cache import Cache, CacheMode
|
from pyocf.types.cache import Cache, CacheMode
|
||||||
from pyocf.types.core import Core
|
from pyocf.types.core import Core
|
||||||
from pyocf.types.volume import Volume
|
from pyocf.types.volume import RamVolume
|
||||||
|
from pyocf.types.volume_core import CoreVolume
|
||||||
from pyocf.types.data import Data
|
from pyocf.types.data import Data
|
||||||
from pyocf.types.io import IoDir
|
from pyocf.types.io import IoDir
|
||||||
from pyocf.utils import Size
|
from pyocf.utils import Size
|
||||||
@ -28,8 +29,10 @@ def __io(io, queue, address, size, data, direction):
|
|||||||
return int(completion.results["err"])
|
return int(completion.results["err"])
|
||||||
|
|
||||||
|
|
||||||
def _io(new_io, queue, address, size, data, offset, direction, flags):
|
def io_to_exp_obj(core, address, size, data, offset, direction, flags):
|
||||||
io = new_io(queue, address, size, direction, 0, flags)
|
vol = core.get_front_volume()
|
||||||
|
queue = core.cache.get_default_queue()
|
||||||
|
io = vol.new_io(queue, address, size, direction, 0, flags)
|
||||||
if direction == IoDir.READ:
|
if direction == IoDir.READ:
|
||||||
_data = Data.from_bytes(bytes(size))
|
_data = Data.from_bytes(bytes(size))
|
||||||
else:
|
else:
|
||||||
@ -40,20 +43,7 @@ def _io(new_io, queue, address, size, data, offset, direction, flags):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def io_to_exp_obj(core, address, size, data, offset, direction, flags):
|
class FlagsValVolume(RamVolume):
|
||||||
return _io(
|
|
||||||
core.new_io,
|
|
||||||
core.cache.get_default_queue(),
|
|
||||||
address,
|
|
||||||
size,
|
|
||||||
data,
|
|
||||||
offset,
|
|
||||||
direction,
|
|
||||||
flags,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class FlagsValVolume(Volume):
|
|
||||||
def __init__(self, size, flags):
|
def __init__(self, size, flags):
|
||||||
self.flags = flags
|
self.flags = flags
|
||||||
self.check = False
|
self.check = False
|
||||||
@ -91,6 +81,7 @@ def test_io_flags(pyocf_ctx, cache_mode):
|
|||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
|
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
|
|
||||||
cache_device.set_check(True)
|
cache_device.set_check(True)
|
||||||
core_device.set_check(True)
|
core_device.set_check(True)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright(c) 2019-2021 Intel Corporation
|
# Copyright(c) 2019-2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -10,7 +10,8 @@ from datetime import timedelta
|
|||||||
|
|
||||||
from pyocf.types.cache import Cache, PromotionPolicy, NhitParams
|
from pyocf.types.cache import Cache, PromotionPolicy, NhitParams
|
||||||
from pyocf.types.core import Core
|
from pyocf.types.core import Core
|
||||||
from pyocf.types.volume import Volume
|
from pyocf.types.volume import RamVolume
|
||||||
|
from pyocf.types.volume_core import CoreVolume
|
||||||
from pyocf.types.data import Data
|
from pyocf.types.data import Data
|
||||||
from pyocf.types.io import IoDir
|
from pyocf.types.io import IoDir
|
||||||
from pyocf.utils import Size
|
from pyocf.utils import Size
|
||||||
@ -28,8 +29,8 @@ def test_init_nhit(pyocf_ctx, promotion_policy):
|
|||||||
* verify that promotion policy type is properly reflected in stats
|
* verify that promotion policy type is properly reflected in stats
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
core_device = Volume(Size.from_MiB(50))
|
core_device = RamVolume(Size.from_MiB(50))
|
||||||
|
|
||||||
cache = Cache.start_on_device(cache_device, promotion_policy=promotion_policy)
|
cache = Cache.start_on_device(cache_device, promotion_policy=promotion_policy)
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
@ -55,18 +56,20 @@ def test_change_to_nhit_and_back_io_in_flight(pyocf_ctx):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Step 1
|
# Step 1
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
core_device = Volume(Size.from_MiB(50))
|
core_device = RamVolume(Size.from_MiB(50))
|
||||||
|
|
||||||
cache = Cache.start_on_device(cache_device)
|
cache = Cache.start_on_device(cache_device)
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
|
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
|
queue = cache.get_default_queue()
|
||||||
|
|
||||||
# Step 2
|
# Step 2
|
||||||
r = (
|
r = (
|
||||||
Rio()
|
Rio()
|
||||||
.target(core)
|
.target(vol)
|
||||||
.njobs(10)
|
.njobs(10)
|
||||||
.bs(Size.from_KiB(4))
|
.bs(Size.from_KiB(4))
|
||||||
.readwrite(ReadWrite.RANDWRITE)
|
.readwrite(ReadWrite.RANDWRITE)
|
||||||
@ -74,7 +77,7 @@ def test_change_to_nhit_and_back_io_in_flight(pyocf_ctx):
|
|||||||
.time_based()
|
.time_based()
|
||||||
.time(timedelta(minutes=1))
|
.time(timedelta(minutes=1))
|
||||||
.qd(10)
|
.qd(10)
|
||||||
.run_async()
|
.run_async([queue])
|
||||||
)
|
)
|
||||||
|
|
||||||
# Step 3
|
# Step 3
|
||||||
@ -85,7 +88,7 @@ def test_change_to_nhit_and_back_io_in_flight(pyocf_ctx):
|
|||||||
assert r.error_count == 0, "No IO's should fail when turning NHIT policy on"
|
assert r.error_count == 0, "No IO's should fail when turning NHIT policy on"
|
||||||
|
|
||||||
# Step 5
|
# Step 5
|
||||||
r.run_async()
|
r.run_async([queue])
|
||||||
|
|
||||||
# Step 6
|
# Step 6
|
||||||
cache.set_promotion_policy(PromotionPolicy.ALWAYS)
|
cache.set_promotion_policy(PromotionPolicy.ALWAYS)
|
||||||
@ -107,15 +110,17 @@ def fill_cache(cache, fill_ratio):
|
|||||||
bytes_to_fill = Size(round(cache_lines.bytes * fill_ratio))
|
bytes_to_fill = Size(round(cache_lines.bytes * fill_ratio))
|
||||||
|
|
||||||
core = cache.cores[0]
|
core = cache.cores[0]
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
|
queue = cache.get_default_queue()
|
||||||
|
|
||||||
r = (
|
r = (
|
||||||
Rio()
|
Rio()
|
||||||
.target(core)
|
.target(vol)
|
||||||
.readwrite(ReadWrite.RANDWRITE)
|
.readwrite(ReadWrite.RANDWRITE)
|
||||||
.size(bytes_to_fill)
|
.size(bytes_to_fill)
|
||||||
.bs(Size(512))
|
.bs(Size(512))
|
||||||
.qd(10)
|
.qd(10)
|
||||||
.run()
|
.run([queue])
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -137,12 +142,14 @@ def test_promoted_after_hits_various_thresholds(
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Step 1
|
# Step 1
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
core_device = Volume(Size.from_MiB(50))
|
core_device = RamVolume(Size.from_MiB(50))
|
||||||
|
|
||||||
cache = Cache.start_on_device(cache_device, promotion_policy=PromotionPolicy.NHIT)
|
cache = Cache.start_on_device(cache_device, promotion_policy=PromotionPolicy.NHIT)
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
|
queue = cache.get_default_queue()
|
||||||
|
|
||||||
# Step 2
|
# Step 2
|
||||||
cache.set_promotion_policy_param(
|
cache.set_promotion_policy_param(
|
||||||
@ -167,12 +174,12 @@ def test_promoted_after_hits_various_thresholds(
|
|||||||
.readwrite(ReadWrite.WRITE)
|
.readwrite(ReadWrite.WRITE)
|
||||||
.bs(Size(4096))
|
.bs(Size(4096))
|
||||||
.offset(last_core_line)
|
.offset(last_core_line)
|
||||||
.target(core)
|
.target(vol)
|
||||||
.size(Size(4096) + last_core_line)
|
.size(Size(4096) + last_core_line)
|
||||||
)
|
)
|
||||||
|
|
||||||
for i in range(insertion_threshold - 1):
|
for i in range(insertion_threshold - 1):
|
||||||
r.run()
|
r.run([queue])
|
||||||
|
|
||||||
cache.settle()
|
cache.settle()
|
||||||
stats = cache.get_stats()
|
stats = cache.get_stats()
|
||||||
@ -183,7 +190,7 @@ def test_promoted_after_hits_various_thresholds(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Step 5
|
# Step 5
|
||||||
r.run()
|
r.run([queue])
|
||||||
|
|
||||||
cache.settle()
|
cache.settle()
|
||||||
stats = cache.get_stats()
|
stats = cache.get_stats()
|
||||||
@ -207,15 +214,17 @@ def test_partial_hit_promotion(pyocf_ctx):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Step 1
|
# Step 1
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
core_device = Volume(Size.from_MiB(50))
|
core_device = RamVolume(Size.from_MiB(50))
|
||||||
|
|
||||||
cache = Cache.start_on_device(cache_device)
|
cache = Cache.start_on_device(cache_device)
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
|
queue = cache.get_default_queue()
|
||||||
|
|
||||||
# Step 2
|
# Step 2
|
||||||
r = Rio().readwrite(ReadWrite.READ).bs(Size(512)).size(Size(512)).target(core).run()
|
r = Rio().readwrite(ReadWrite.READ).bs(Size(512)).size(Size(512)).target(vol).run([queue])
|
||||||
|
|
||||||
stats = cache.get_stats()
|
stats = cache.get_stats()
|
||||||
cache_lines = stats["conf"]["size"]
|
cache_lines = stats["conf"]["size"]
|
||||||
@ -232,7 +241,7 @@ def test_partial_hit_promotion(pyocf_ctx):
|
|||||||
|
|
||||||
# Step 4
|
# Step 4
|
||||||
req_size = Size(2 * cache_lines.line_size)
|
req_size = Size(2 * cache_lines.line_size)
|
||||||
r.size(req_size).bs(req_size).readwrite(ReadWrite.WRITE).run()
|
r.size(req_size).bs(req_size).readwrite(ReadWrite.WRITE).run([queue])
|
||||||
|
|
||||||
cache.settle()
|
cache.settle()
|
||||||
stats = cache.get_stats()
|
stats = cache.get_stats()
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# Copyright(c) 2019-2021 Intel Corporation
|
#
|
||||||
|
# Copyright(c) 2019-2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -13,7 +14,8 @@ from datetime import datetime
|
|||||||
|
|
||||||
from pyocf.types.cache import Cache, CacheMode
|
from pyocf.types.cache import Cache, CacheMode
|
||||||
from pyocf.types.core import Core
|
from pyocf.types.core import Core
|
||||||
from pyocf.types.volume import Volume
|
from pyocf.types.volume import RamVolume
|
||||||
|
from pyocf.types.volume_core import CoreVolume
|
||||||
from pyocf.types.data import Data
|
from pyocf.types.data import Data
|
||||||
from pyocf.types.io import IoDir
|
from pyocf.types.io import IoDir
|
||||||
from pyocf.utils import Size
|
from pyocf.utils import Size
|
||||||
@ -37,8 +39,8 @@ def __io(io, queue, address, size, data, direction):
|
|||||||
return int(completion.results["err"])
|
return int(completion.results["err"])
|
||||||
|
|
||||||
|
|
||||||
def _io(new_io, queue, address, size, data, offset, direction):
|
def io_to_exp_obj(vol, queue, address, size, data, offset, direction):
|
||||||
io = new_io(queue, address, size, direction, 0, 0)
|
io = vol.new_io(queue, address, size, direction, 0, 0)
|
||||||
if direction == IoDir.READ:
|
if direction == IoDir.READ:
|
||||||
_data = Data.from_bytes(bytes(size))
|
_data = Data.from_bytes(bytes(size))
|
||||||
else:
|
else:
|
||||||
@ -49,30 +51,6 @@ def _io(new_io, queue, address, size, data, offset, direction):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def io_to_core(core, address, size, data, offset, direction):
|
|
||||||
return _io(
|
|
||||||
core.new_core_io,
|
|
||||||
core.cache.get_default_queue(),
|
|
||||||
address,
|
|
||||||
size,
|
|
||||||
data,
|
|
||||||
offset,
|
|
||||||
direction,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def io_to_exp_obj(core, address, size, data, offset, direction):
|
|
||||||
return _io(
|
|
||||||
core.new_io,
|
|
||||||
core.cache.get_default_queue(),
|
|
||||||
address,
|
|
||||||
size,
|
|
||||||
data,
|
|
||||||
offset,
|
|
||||||
direction,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def sector_to_region(sector, region_start):
|
def sector_to_region(sector, region_start):
|
||||||
num_regions = len(region_start)
|
num_regions = len(region_start)
|
||||||
i = 0
|
i = 0
|
||||||
@ -259,15 +237,17 @@ def test_read_data_consistency(pyocf_ctx, cacheline_size, cache_mode, rand_seed)
|
|||||||
|
|
||||||
result_b = bytes(WORKSET_SIZE)
|
result_b = bytes(WORKSET_SIZE)
|
||||||
|
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
core_device = Volume(Size.from_MiB(50))
|
core_device = RamVolume(Size.from_MiB(50))
|
||||||
|
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device, cache_mode=CacheMode.WO, cache_line_size=cacheline_size
|
cache_device, cache_mode=CacheMode.WO, cache_line_size=cacheline_size
|
||||||
)
|
)
|
||||||
core = Core.using_device(core_device)
|
|
||||||
|
|
||||||
|
core = Core.using_device(core_device)
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
|
queue = cache.get_default_queue()
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
|
|
||||||
insert_order = list(range(CACHELINE_COUNT))
|
insert_order = list(range(CACHELINE_COUNT))
|
||||||
|
|
||||||
@ -310,7 +290,8 @@ def test_read_data_consistency(pyocf_ctx, cacheline_size, cache_mode, rand_seed)
|
|||||||
# write data to core and invalidate all CL and write data pattern to core
|
# write data to core and invalidate all CL and write data pattern to core
|
||||||
cache.change_cache_mode(cache_mode=CacheMode.PT)
|
cache.change_cache_mode(cache_mode=CacheMode.PT)
|
||||||
io_to_exp_obj(
|
io_to_exp_obj(
|
||||||
core,
|
vol,
|
||||||
|
queue,
|
||||||
WORKSET_OFFSET,
|
WORKSET_OFFSET,
|
||||||
len(data[SectorStatus.INVALID]),
|
len(data[SectorStatus.INVALID]),
|
||||||
data[SectorStatus.INVALID],
|
data[SectorStatus.INVALID],
|
||||||
@ -331,7 +312,8 @@ def test_read_data_consistency(pyocf_ctx, cacheline_size, cache_mode, rand_seed)
|
|||||||
region = sector_to_region(sec, region_start)
|
region = sector_to_region(sec, region_start)
|
||||||
if region_state[region] != SectorStatus.INVALID:
|
if region_state[region] != SectorStatus.INVALID:
|
||||||
io_to_exp_obj(
|
io_to_exp_obj(
|
||||||
core,
|
vol,
|
||||||
|
queue,
|
||||||
WORKSET_OFFSET + SECTOR_SIZE * sec,
|
WORKSET_OFFSET + SECTOR_SIZE * sec,
|
||||||
SECTOR_SIZE,
|
SECTOR_SIZE,
|
||||||
data[SectorStatus.CLEAN],
|
data[SectorStatus.CLEAN],
|
||||||
@ -345,7 +327,8 @@ def test_read_data_consistency(pyocf_ctx, cacheline_size, cache_mode, rand_seed)
|
|||||||
region = sector_to_region(sec, region_start)
|
region = sector_to_region(sec, region_start)
|
||||||
if region_state[region] == SectorStatus.DIRTY:
|
if region_state[region] == SectorStatus.DIRTY:
|
||||||
io_to_exp_obj(
|
io_to_exp_obj(
|
||||||
core,
|
vol,
|
||||||
|
queue,
|
||||||
WORKSET_OFFSET + SECTOR_SIZE * sec,
|
WORKSET_OFFSET + SECTOR_SIZE * sec,
|
||||||
SECTOR_SIZE,
|
SECTOR_SIZE,
|
||||||
data[SectorStatus.DIRTY],
|
data[SectorStatus.DIRTY],
|
||||||
@ -372,7 +355,7 @@ def test_read_data_consistency(pyocf_ctx, cacheline_size, cache_mode, rand_seed)
|
|||||||
END = end * SECTOR_SIZE
|
END = end * SECTOR_SIZE
|
||||||
size = (end - start + 1) * SECTOR_SIZE
|
size = (end - start + 1) * SECTOR_SIZE
|
||||||
assert 0 == io_to_exp_obj(
|
assert 0 == io_to_exp_obj(
|
||||||
core, WORKSET_OFFSET + START, size, result_b, START, IoDir.READ
|
vol, queue, WORKSET_OFFSET + START, size, result_b, START, IoDir.READ
|
||||||
), "error reading in {}: region_state={}, start={}, end={}, insert_order={}".format(
|
), "error reading in {}: region_state={}, start={}, end={}, insert_order={}".format(
|
||||||
cache_mode, region_state, start, end, insert_order
|
cache_mode, region_state, start, end, insert_order
|
||||||
)
|
)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright(c) 2020-2021 Intel Corporation
|
# Copyright(c) 2020-2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -10,7 +10,8 @@ import pytest
|
|||||||
|
|
||||||
from pyocf.types.cache import Cache, CacheMode
|
from pyocf.types.cache import Cache, CacheMode
|
||||||
from pyocf.types.core import Core
|
from pyocf.types.core import Core
|
||||||
from pyocf.types.volume import Volume
|
from pyocf.types.volume import RamVolume
|
||||||
|
from pyocf.types.volume_core import CoreVolume
|
||||||
from pyocf.types.data import Data
|
from pyocf.types.data import Data
|
||||||
from pyocf.types.io import IoDir
|
from pyocf.types.io import IoDir
|
||||||
from pyocf.utils import Size
|
from pyocf.utils import Size
|
||||||
@ -27,11 +28,11 @@ class Stream:
|
|||||||
return f"{self.last} {self.length} {self.direction}"
|
return f"{self.last} {self.length} {self.direction}"
|
||||||
|
|
||||||
|
|
||||||
def _io(core, addr, size, direction, context):
|
def _io(vol, queue, addr, size, direction, context):
|
||||||
comp = OcfCompletion([("error", c_int)], context=context)
|
comp = OcfCompletion([("error", c_int)], context=context)
|
||||||
data = Data(size)
|
data = Data(size)
|
||||||
|
|
||||||
io = core.new_io(core.cache.get_default_queue(), addr, size, direction, 0, 0)
|
io = vol.new_io(queue, addr, size, direction, 0, 0)
|
||||||
io.set_data(data)
|
io.set_data(data)
|
||||||
io.callback = comp.callback
|
io.callback = comp.callback
|
||||||
io.submit()
|
io.submit()
|
||||||
@ -39,11 +40,11 @@ def _io(core, addr, size, direction, context):
|
|||||||
return comp
|
return comp
|
||||||
|
|
||||||
|
|
||||||
def io_to_streams(core, streams, io_size):
|
def io_to_streams(vol, queue, streams, io_size):
|
||||||
completions = []
|
completions = []
|
||||||
for stream in streams:
|
for stream in streams:
|
||||||
completions.append(
|
completions.append(
|
||||||
_io(core, stream.last, io_size, stream.direction, context=(io_size, stream))
|
_io(vol, queue, stream.last, io_size, stream.direction, context=(io_size, stream))
|
||||||
)
|
)
|
||||||
|
|
||||||
for c in completions:
|
for c in completions:
|
||||||
@ -90,10 +91,12 @@ def test_seq_cutoff_max_streams(pyocf_ctx):
|
|||||||
non_active_stream = choice(streams)
|
non_active_stream = choice(streams)
|
||||||
streams.remove(non_active_stream)
|
streams.remove(non_active_stream)
|
||||||
|
|
||||||
cache = Cache.start_on_device(Volume(Size.from_MiB(200)), cache_mode=CacheMode.WT)
|
cache = Cache.start_on_device(RamVolume(Size.from_MiB(200)), cache_mode=CacheMode.WT)
|
||||||
core = Core.using_device(Volume(core_size), seq_cutoff_promotion_count=1)
|
core = Core.using_device(RamVolume(core_size), seq_cutoff_promotion_count=1)
|
||||||
|
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
|
queue = cache.get_default_queue()
|
||||||
|
|
||||||
cache.set_seq_cut_off_policy(SeqCutOffPolicy.ALWAYS)
|
cache.set_seq_cut_off_policy(SeqCutOffPolicy.ALWAYS)
|
||||||
cache.set_seq_cut_off_threshold(threshold)
|
cache.set_seq_cut_off_threshold(threshold)
|
||||||
@ -101,7 +104,7 @@ def test_seq_cutoff_max_streams(pyocf_ctx):
|
|||||||
# STEP 1
|
# STEP 1
|
||||||
shuffle(streams)
|
shuffle(streams)
|
||||||
io_size = threshold - Size.from_sector(1)
|
io_size = threshold - Size.from_sector(1)
|
||||||
io_to_streams(core, streams, io_size)
|
io_to_streams(vol, queue, streams, io_size)
|
||||||
|
|
||||||
stats = cache.get_stats()
|
stats = cache.get_stats()
|
||||||
assert (
|
assert (
|
||||||
@ -115,7 +118,7 @@ def test_seq_cutoff_max_streams(pyocf_ctx):
|
|||||||
streams.remove(lru_stream)
|
streams.remove(lru_stream)
|
||||||
|
|
||||||
shuffle(streams)
|
shuffle(streams)
|
||||||
io_to_streams(core, streams, Size.from_sector(1))
|
io_to_streams(vol, queue, streams, Size.from_sector(1))
|
||||||
|
|
||||||
stats = cache.get_stats()
|
stats = cache.get_stats()
|
||||||
assert (
|
assert (
|
||||||
@ -126,7 +129,7 @@ def test_seq_cutoff_max_streams(pyocf_ctx):
|
|||||||
), "All streams should be handled in PT - cutoff engaged for all streams"
|
), "All streams should be handled in PT - cutoff engaged for all streams"
|
||||||
|
|
||||||
# STEP 3
|
# STEP 3
|
||||||
io_to_streams(core, [non_active_stream], Size.from_sector(1))
|
io_to_streams(vol, queue, [non_active_stream], Size.from_sector(1))
|
||||||
|
|
||||||
stats = cache.get_stats()
|
stats = cache.get_stats()
|
||||||
assert (
|
assert (
|
||||||
@ -134,7 +137,7 @@ def test_seq_cutoff_max_streams(pyocf_ctx):
|
|||||||
), "This request should be serviced by cache - no cutoff for inactive stream"
|
), "This request should be serviced by cache - no cutoff for inactive stream"
|
||||||
|
|
||||||
# STEP 4
|
# STEP 4
|
||||||
io_to_streams(core, [lru_stream], Size.from_sector(1))
|
io_to_streams(vol, queue, [lru_stream], Size.from_sector(1))
|
||||||
|
|
||||||
stats = cache.get_stats()
|
stats = cache.get_stats()
|
||||||
assert (
|
assert (
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright(c) 2019-2021 Intel Corporation
|
# Copyright(c) 2019-2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -14,7 +14,8 @@ from pyocf.types.core import Core
|
|||||||
from pyocf.types.data import Data
|
from pyocf.types.data import Data
|
||||||
from pyocf.types.io import IoDir
|
from pyocf.types.io import IoDir
|
||||||
from pyocf.types.shared import OcfCompletion, CacheLineSize, SeqCutOffPolicy, CacheLines
|
from pyocf.types.shared import OcfCompletion, CacheLineSize, SeqCutOffPolicy, CacheLines
|
||||||
from pyocf.types.volume import Volume
|
from pyocf.types.volume import RamVolume
|
||||||
|
from pyocf.types.volume_core import CoreVolume
|
||||||
from pyocf.utils import Size
|
from pyocf.utils import Size
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -24,25 +25,27 @@ logger = logging.getLogger(__name__)
|
|||||||
@pytest.mark.parametrize("mode", [CacheMode.WT])
|
@pytest.mark.parametrize("mode", [CacheMode.WT])
|
||||||
def test_eviction_two_cores(pyocf_ctx, mode: CacheMode, cls: CacheLineSize):
|
def test_eviction_two_cores(pyocf_ctx, mode: CacheMode, cls: CacheLineSize):
|
||||||
"""Test if eviction works correctly when remapping cachelines between distinct cores."""
|
"""Test if eviction works correctly when remapping cachelines between distinct cores."""
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
|
|
||||||
core_device1 = Volume(Size.from_MiB(40))
|
core_device1 = RamVolume(Size.from_MiB(40))
|
||||||
core_device2 = Volume(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 = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls)
|
||||||
cache.set_seq_cut_off_policy(SeqCutOffPolicy.NEVER)
|
cache.set_seq_cut_off_policy(SeqCutOffPolicy.NEVER)
|
||||||
cache_size = cache.get_stats()["conf"]["size"]
|
cache_size = cache.get_stats()["conf"]["size"]
|
||||||
core_exported1 = Core.using_device(core_device1, name="core1")
|
core1 = Core.using_device(core_device1, name="core1")
|
||||||
core_exported2 = Core.using_device(core_device2, name="core2")
|
core2 = Core.using_device(core_device2, name="core2")
|
||||||
cache.add_core(core_exported1)
|
cache.add_core(core1)
|
||||||
cache.add_core(core_exported2)
|
vol1 = CoreVolume(core1, open=True)
|
||||||
|
cache.add_core(core2)
|
||||||
|
vol2 = CoreVolume(core2, open=True)
|
||||||
|
|
||||||
valid_io_size = Size.from_B(cache_size.B)
|
valid_io_size = Size.from_B(cache_size.B)
|
||||||
test_data = Data(valid_io_size)
|
test_data = Data(valid_io_size)
|
||||||
send_io(core_exported1, test_data)
|
send_io(core1, test_data)
|
||||||
send_io(core_exported2, test_data)
|
send_io(core2, test_data)
|
||||||
|
|
||||||
stats1 = core_exported1.get_stats()
|
stats1 = core1.get_stats()
|
||||||
stats2 = core_exported2.get_stats()
|
stats2 = core2.get_stats()
|
||||||
# IO to the second core should evict all the data from the first core
|
# IO to the second core should evict all the data from the first core
|
||||||
assert stats1["usage"]["occupancy"]["value"] == 0
|
assert stats1["usage"]["occupancy"]["value"] == 0
|
||||||
assert stats2["usage"]["occupancy"]["value"] == valid_io_size.blocks_4k
|
assert stats2["usage"]["occupancy"]["value"] == valid_io_size.blocks_4k
|
||||||
@ -52,20 +55,21 @@ def test_eviction_two_cores(pyocf_ctx, mode: CacheMode, cls: CacheLineSize):
|
|||||||
@pytest.mark.parametrize("mode", [CacheMode.WT, CacheMode.WB, CacheMode.WO])
|
@pytest.mark.parametrize("mode", [CacheMode.WT, CacheMode.WB, CacheMode.WO])
|
||||||
def test_write_size_greater_than_cache(pyocf_ctx, mode: CacheMode, cls: CacheLineSize):
|
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."""
|
"""Test if eviction does not occur when IO greater than cache size is submitted."""
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
|
|
||||||
core_device = Volume(Size.from_MiB(200))
|
core_device = RamVolume(Size.from_MiB(200))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls)
|
||||||
cache_size = cache.get_stats()["conf"]["size"]
|
cache_size = cache.get_stats()["conf"]["size"]
|
||||||
core_exported = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
cache.add_core(core_exported)
|
cache.add_core(core)
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
cache.set_seq_cut_off_policy(SeqCutOffPolicy.NEVER)
|
cache.set_seq_cut_off_policy(SeqCutOffPolicy.NEVER)
|
||||||
|
|
||||||
valid_io_size = Size.from_B(cache_size.B // 2)
|
valid_io_size = Size.from_B(cache_size.B // 2)
|
||||||
test_data = Data(valid_io_size)
|
test_data = Data(valid_io_size)
|
||||||
send_io(core_exported, test_data)
|
send_io(core, test_data)
|
||||||
|
|
||||||
stats = core_exported.cache.get_stats()
|
stats = core.cache.get_stats()
|
||||||
first_block_sts = stats["block"]
|
first_block_sts = stats["block"]
|
||||||
first_usage_sts = stats["usage"]
|
first_usage_sts = stats["usage"]
|
||||||
pt_writes_first = stats["req"]["wr_pt"]
|
pt_writes_first = stats["req"]["wr_pt"]
|
||||||
@ -80,12 +84,12 @@ def test_write_size_greater_than_cache(pyocf_ctx, mode: CacheMode, cls: CacheLin
|
|||||||
io_size_bigger_than_cache = Size.from_MiB(100)
|
io_size_bigger_than_cache = Size.from_MiB(100)
|
||||||
io_offset = valid_io_size
|
io_offset = valid_io_size
|
||||||
test_data = Data(io_size_bigger_than_cache)
|
test_data = Data(io_size_bigger_than_cache)
|
||||||
send_io(core_exported, test_data, io_offset)
|
send_io(core, test_data, io_offset)
|
||||||
|
|
||||||
if mode is not CacheMode.WT:
|
if mode is not CacheMode.WT:
|
||||||
# Flush first write
|
# Flush first write
|
||||||
cache.flush()
|
cache.flush()
|
||||||
stats = core_exported.cache.get_stats()
|
stats = core.cache.get_stats()
|
||||||
second_block_sts = stats["block"]
|
second_block_sts = stats["block"]
|
||||||
second_usage_sts = stats["usage"]
|
second_usage_sts = stats["usage"]
|
||||||
pt_writes_second = stats["req"]["wr_pt"]
|
pt_writes_second = stats["req"]["wr_pt"]
|
||||||
@ -106,13 +110,14 @@ def test_write_size_greater_than_cache(pyocf_ctx, mode: CacheMode, cls: CacheLin
|
|||||||
@pytest.mark.parametrize("cls", CacheLineSize)
|
@pytest.mark.parametrize("cls", CacheLineSize)
|
||||||
def test_evict_overflown_pinned(pyocf_ctx, cls: CacheLineSize):
|
def test_evict_overflown_pinned(pyocf_ctx, cls: CacheLineSize):
|
||||||
""" Verify if overflown pinned ioclass is evicted """
|
""" Verify if overflown pinned ioclass is evicted """
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
core_device = Volume(Size.from_MiB(100))
|
core_device = RamVolume(Size.from_MiB(100))
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device, cache_mode=CacheMode.WT, cache_line_size=cls
|
cache_device, cache_mode=CacheMode.WT, cache_line_size=cls
|
||||||
)
|
)
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
|
|
||||||
test_ioclass_id = 1
|
test_ioclass_id = 1
|
||||||
pinned_ioclass_id = 2
|
pinned_ioclass_id = 2
|
||||||
@ -176,9 +181,10 @@ def test_evict_overflown_pinned(pyocf_ctx, cls: CacheLineSize):
|
|||||||
), "Overflown part has not been evicted"
|
), "Overflown part has not been evicted"
|
||||||
|
|
||||||
|
|
||||||
def send_io(exported_obj: Core, data: Data, addr: int = 0, target_ioclass: int = 0):
|
def send_io(core: Core, data: Data, addr: int = 0, target_ioclass: int = 0):
|
||||||
io = exported_obj.new_io(
|
vol = core.get_front_volume()
|
||||||
exported_obj.cache.get_default_queue(),
|
io = vol.new_io(
|
||||||
|
core.cache.get_default_queue(),
|
||||||
addr,
|
addr,
|
||||||
data.size,
|
data.size,
|
||||||
IoDir.WRITE,
|
IoDir.WRITE,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright(c) 2020-2021 Intel Corporation
|
# Copyright(c) 2020-2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -12,7 +12,8 @@ import pytest
|
|||||||
|
|
||||||
from pyocf.types.cache import Cache, CacheMode
|
from pyocf.types.cache import Cache, CacheMode
|
||||||
from pyocf.types.core import Core
|
from pyocf.types.core import Core
|
||||||
from pyocf.types.volume import Volume
|
from pyocf.types.volume import RamVolume
|
||||||
|
from pyocf.types.volume_core import CoreVolume
|
||||||
from pyocf.types.data import Data
|
from pyocf.types.data import Data
|
||||||
from pyocf.types.io import IoDir
|
from pyocf.types.io import IoDir
|
||||||
from pyocf.utils import Size
|
from pyocf.utils import Size
|
||||||
@ -28,8 +29,8 @@ def __io(io, queue, address, size, data, direction):
|
|||||||
return int(completion.results["err"])
|
return int(completion.results["err"])
|
||||||
|
|
||||||
|
|
||||||
def _io(new_io, queue, address, size, data, offset, direction, flags):
|
def io_to_exp_obj(vol, queue, address, size, data, offset, direction, flags):
|
||||||
io = new_io(queue, address, size, direction, 0, flags)
|
io = vol.new_io(queue, address, size, direction, 0, flags)
|
||||||
if direction == IoDir.READ:
|
if direction == IoDir.READ:
|
||||||
_data = Data.from_bytes(bytes(size))
|
_data = Data.from_bytes(bytes(size))
|
||||||
else:
|
else:
|
||||||
@ -40,20 +41,7 @@ def _io(new_io, queue, address, size, data, offset, direction, flags):
|
|||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def io_to_exp_obj(core, address, size, data, offset, direction, flags):
|
class FlushValVolume(RamVolume):
|
||||||
return _io(
|
|
||||||
core.new_io,
|
|
||||||
core.cache.get_default_queue(),
|
|
||||||
address,
|
|
||||||
size,
|
|
||||||
data,
|
|
||||||
offset,
|
|
||||||
direction,
|
|
||||||
flags,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class FlushValVolume(Volume):
|
|
||||||
def __init__(self, size):
|
def __init__(self, size):
|
||||||
self.flush_last = False
|
self.flush_last = False
|
||||||
super().__init__(size)
|
super().__init__(size)
|
||||||
@ -87,12 +75,15 @@ def test_flush_after_mngmt(pyocf_ctx):
|
|||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
assert cache_device.flush_last
|
assert cache_device.flush_last
|
||||||
|
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
|
queue = cache.get_default_queue()
|
||||||
|
|
||||||
# WT I/O to write data to core and cache VC
|
# 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)
|
io_to_exp_obj(vol, queue, block_size * 0, block_size, data, 0, IoDir.WRITE, 0)
|
||||||
|
|
||||||
# WB I/O to produce dirty cachelines in CAS
|
# WB I/O to produce dirty cachelines in CAS
|
||||||
cache.change_cache_mode(CacheMode.WB)
|
cache.change_cache_mode(CacheMode.WB)
|
||||||
io_to_exp_obj(core, block_size * 1, block_size, data, 0, IoDir.WRITE, 0)
|
io_to_exp_obj(vol, queue, block_size * 1, block_size, data, 0, IoDir.WRITE, 0)
|
||||||
|
|
||||||
# after cache flush VCs are expected to be cleared
|
# after cache flush VCs are expected to be cleared
|
||||||
cache.flush()
|
cache.flush()
|
||||||
@ -100,14 +91,14 @@ def test_flush_after_mngmt(pyocf_ctx):
|
|||||||
assert core_device.flush_last
|
assert core_device.flush_last
|
||||||
|
|
||||||
# I/O to write data to cache device VC
|
# I/O to write data to cache device VC
|
||||||
io_to_exp_obj(core, block_size * 0, block_size, data, 0, IoDir.WRITE, 0)
|
io_to_exp_obj(vol, queue, block_size * 0, block_size, data, 0, IoDir.WRITE, 0)
|
||||||
|
|
||||||
# cache save must flush VC
|
# cache save must flush VC
|
||||||
cache.save()
|
cache.save()
|
||||||
assert cache_device.flush_last
|
assert cache_device.flush_last
|
||||||
|
|
||||||
# I/O to write data to cache device VC
|
# I/O to write data to cache device VC
|
||||||
io_to_exp_obj(core, block_size * 0, block_size, data, 0, IoDir.WRITE, 0)
|
io_to_exp_obj(vol, queue, block_size * 0, block_size, data, 0, IoDir.WRITE, 0)
|
||||||
|
|
||||||
# cache stop must flush VC
|
# cache stop must flush VC
|
||||||
cache.stop()
|
cache.stop()
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# Copyright(c) 2019-2021 Intel Corporation
|
#
|
||||||
|
# Copyright(c) 2019-2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -8,9 +9,11 @@ from ctypes import c_int
|
|||||||
from random import randint
|
from random import randint
|
||||||
from pyocf.types.cache import Cache, CacheMode
|
from pyocf.types.cache import Cache, CacheMode
|
||||||
from pyocf.types.core import Core
|
from pyocf.types.core import Core
|
||||||
from pyocf.types.volume import Volume
|
from pyocf.types.volume import RamVolume, Volume
|
||||||
|
from pyocf.types.volume_core import CoreVolume
|
||||||
from pyocf.types.data import Data
|
from pyocf.types.data import Data
|
||||||
from pyocf.types.io import IoDir
|
from pyocf.types.io import IoDir
|
||||||
|
from pyocf.types.queue import Queue
|
||||||
from pyocf.utils import Size as S
|
from pyocf.utils import Size as S
|
||||||
from pyocf.types.shared import OcfError, OcfCompletion, CacheLineSize
|
from pyocf.types.shared import OcfError, OcfCompletion, CacheLineSize
|
||||||
|
|
||||||
@ -19,13 +22,13 @@ from pyocf.types.shared import OcfError, OcfCompletion, CacheLineSize
|
|||||||
@pytest.mark.parametrize("cls", CacheLineSize)
|
@pytest.mark.parametrize("cls", CacheLineSize)
|
||||||
def test_adding_core(pyocf_ctx, cache_mode, cls):
|
def test_adding_core(pyocf_ctx, cache_mode, cls):
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device, cache_mode=cache_mode, cache_line_size=cls
|
cache_device, cache_mode=cache_mode, cache_line_size=cls
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create core device
|
# Create core device
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
|
|
||||||
# Check statistics before adding core
|
# Check statistics before adding core
|
||||||
@ -44,13 +47,13 @@ def test_adding_core(pyocf_ctx, cache_mode, cls):
|
|||||||
@pytest.mark.parametrize("cls", CacheLineSize)
|
@pytest.mark.parametrize("cls", CacheLineSize)
|
||||||
def test_removing_core(pyocf_ctx, cache_mode, cls):
|
def test_removing_core(pyocf_ctx, cache_mode, cls):
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device, cache_mode=cache_mode, cache_line_size=cls
|
cache_device, cache_mode=cache_mode, cache_line_size=cls
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create core device
|
# Create core device
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
|
|
||||||
# Add core to cache
|
# Add core to cache
|
||||||
@ -68,21 +71,24 @@ def test_removing_core(pyocf_ctx, cache_mode, cls):
|
|||||||
@pytest.mark.parametrize("cls", CacheLineSize)
|
@pytest.mark.parametrize("cls", CacheLineSize)
|
||||||
def test_remove_dirty_no_flush(pyocf_ctx, cache_mode, cls):
|
def test_remove_dirty_no_flush(pyocf_ctx, cache_mode, cls):
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device, cache_mode=cache_mode, cache_line_size=cls
|
cache_device, cache_mode=cache_mode, cache_line_size=cls
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create core device
|
# Create core device
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
|
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
|
queue = core.cache.get_default_queue()
|
||||||
|
|
||||||
# Prepare data
|
# Prepare data
|
||||||
core_size = core.get_stats()["size"]
|
core_size = core.get_stats()["size"]
|
||||||
data = Data(core_size.B)
|
data = Data(core_size.B)
|
||||||
|
|
||||||
_io_to_core(core, data)
|
_io_to_core(vol, queue, data)
|
||||||
|
|
||||||
# Remove core from cache
|
# Remove core from cache
|
||||||
cache.remove_core(core)
|
cache.remove_core(core)
|
||||||
@ -90,11 +96,11 @@ def test_remove_dirty_no_flush(pyocf_ctx, cache_mode, cls):
|
|||||||
|
|
||||||
def test_30add_remove(pyocf_ctx):
|
def test_30add_remove(pyocf_ctx):
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device)
|
cache = Cache.start_on_device(cache_device)
|
||||||
|
|
||||||
# Create core device
|
# Create core device
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
|
|
||||||
# Add and remove core device in a loop 100 times
|
# Add and remove core device in a loop 100 times
|
||||||
@ -111,21 +117,22 @@ def test_30add_remove(pyocf_ctx):
|
|||||||
|
|
||||||
def test_10add_remove_with_io(pyocf_ctx):
|
def test_10add_remove_with_io(pyocf_ctx):
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device)
|
cache = Cache.start_on_device(cache_device)
|
||||||
|
|
||||||
# Create core device
|
# Create core device
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
|
|
||||||
# Add and remove core 10 times in a loop with io in between
|
# Add and remove core 10 times in a loop with io in between
|
||||||
for i in range(0, 10):
|
for i in range(0, 10):
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
stats = cache.get_stats()
|
stats = cache.get_stats()
|
||||||
assert stats["conf"]["core_count"] == 1
|
assert stats["conf"]["core_count"] == 1
|
||||||
|
|
||||||
write_data = Data.from_string("Test data")
|
write_data = Data.from_string("Test data")
|
||||||
io = core.new_io(
|
io = vol.new_io(
|
||||||
cache.get_default_queue(), S.from_sector(1).B, write_data.size,
|
cache.get_default_queue(), S.from_sector(1).B, write_data.size,
|
||||||
IoDir.WRITE, 0, 0
|
IoDir.WRITE, 0, 0
|
||||||
)
|
)
|
||||||
@ -143,7 +150,7 @@ def test_10add_remove_with_io(pyocf_ctx):
|
|||||||
|
|
||||||
def test_add_remove_30core(pyocf_ctx):
|
def test_add_remove_30core(pyocf_ctx):
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device)
|
cache = Cache.start_on_device(cache_device)
|
||||||
core_devices = []
|
core_devices = []
|
||||||
core_amount = 30
|
core_amount = 30
|
||||||
@ -152,7 +159,7 @@ def test_add_remove_30core(pyocf_ctx):
|
|||||||
for i in range(0, core_amount):
|
for i in range(0, core_amount):
|
||||||
stats = cache.get_stats()
|
stats = cache.get_stats()
|
||||||
assert stats["conf"]["core_count"] == i
|
assert stats["conf"]["core_count"] == i
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core.using_device(core_device, name=f"core{i}")
|
core = Core.using_device(core_device, name=f"core{i}")
|
||||||
core_devices.append(core)
|
core_devices.append(core)
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
@ -176,13 +183,13 @@ def test_adding_to_random_cache(pyocf_ctx):
|
|||||||
|
|
||||||
# Create 5 cache devices
|
# Create 5 cache devices
|
||||||
for i in range(0, cache_amount):
|
for i in range(0, cache_amount):
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, name=f"cache{i}")
|
cache = Cache.start_on_device(cache_device, name=f"cache{i}")
|
||||||
cache_devices.append(cache)
|
cache_devices.append(cache)
|
||||||
|
|
||||||
# Create 50 core devices and add to random cache
|
# Create 50 core devices and add to random cache
|
||||||
for i in range(0, core_amount):
|
for i in range(0, core_amount):
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core.using_device(core_device, name=f"core{i}")
|
core = Core.using_device(core_device, name=f"core{i}")
|
||||||
core_devices[core] = randint(0, cache_amount - 1)
|
core_devices[core] = randint(0, cache_amount - 1)
|
||||||
cache_devices[core_devices[core]].add_core(core)
|
cache_devices[core_devices[core]].add_core(core)
|
||||||
@ -202,13 +209,13 @@ def test_adding_to_random_cache(pyocf_ctx):
|
|||||||
@pytest.mark.parametrize("cls", CacheLineSize)
|
@pytest.mark.parametrize("cls", CacheLineSize)
|
||||||
def test_adding_core_twice(pyocf_ctx, cache_mode, cls):
|
def test_adding_core_twice(pyocf_ctx, cache_mode, cls):
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device, cache_mode=cache_mode, cache_line_size=cls
|
cache_device, cache_mode=cache_mode, cache_line_size=cls
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create core device
|
# Create core device
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
|
|
||||||
# Add core
|
# Add core
|
||||||
@ -227,19 +234,19 @@ def test_adding_core_twice(pyocf_ctx, cache_mode, cls):
|
|||||||
@pytest.mark.parametrize("cls", CacheLineSize)
|
@pytest.mark.parametrize("cls", CacheLineSize)
|
||||||
def test_adding_core_already_used(pyocf_ctx, cache_mode, cls):
|
def test_adding_core_already_used(pyocf_ctx, cache_mode, cls):
|
||||||
# Start first cache device
|
# Start first cache device
|
||||||
cache_device1 = Volume(S.from_MiB(50))
|
cache_device1 = RamVolume(S.from_MiB(50))
|
||||||
cache1 = Cache.start_on_device(
|
cache1 = Cache.start_on_device(
|
||||||
cache_device1, cache_mode=cache_mode, cache_line_size=cls, name="cache1"
|
cache_device1, cache_mode=cache_mode, cache_line_size=cls, name="cache1"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Start second cache device
|
# Start second cache device
|
||||||
cache_device2 = Volume(S.from_MiB(50))
|
cache_device2 = RamVolume(S.from_MiB(50))
|
||||||
cache2 = Cache.start_on_device(
|
cache2 = Cache.start_on_device(
|
||||||
cache_device2, cache_mode=cache_mode, cache_line_size=cls, name="cache2"
|
cache_device2, cache_mode=cache_mode, cache_line_size=cls, name="cache2"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create core device
|
# Create core device
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
|
|
||||||
# Add core to first cache
|
# Add core to first cache
|
||||||
@ -261,7 +268,7 @@ def test_adding_core_already_used(pyocf_ctx, cache_mode, cls):
|
|||||||
@pytest.mark.parametrize("cls", CacheLineSize)
|
@pytest.mark.parametrize("cls", CacheLineSize)
|
||||||
def test_add_remove_incrementally(pyocf_ctx, cache_mode, cls):
|
def test_add_remove_incrementally(pyocf_ctx, cache_mode, cls):
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device, cache_mode=cache_mode, cache_line_size=cls
|
cache_device, cache_mode=cache_mode, cache_line_size=cls
|
||||||
)
|
)
|
||||||
@ -270,7 +277,7 @@ def test_add_remove_incrementally(pyocf_ctx, cache_mode, cls):
|
|||||||
|
|
||||||
# Create 5 core devices and add to cache
|
# Create 5 core devices and add to cache
|
||||||
for i in range(0, core_amount):
|
for i in range(0, core_amount):
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core.using_device(core_device, name=f"core{i}")
|
core = Core.using_device(core_device, name=f"core{i}")
|
||||||
core_devices.append(core)
|
core_devices.append(core)
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
@ -302,8 +309,8 @@ def test_add_remove_incrementally(pyocf_ctx, cache_mode, cls):
|
|||||||
assert stats["conf"]["core_count"] == core_amount
|
assert stats["conf"]["core_count"] == core_amount
|
||||||
|
|
||||||
|
|
||||||
def _io_to_core(exported_obj: Core, data: Data):
|
def _io_to_core(vol: Volume, queue: Queue, data: Data):
|
||||||
io = exported_obj.new_io(exported_obj.cache.get_default_queue(), 0, data.size,
|
io = vol.new_io(queue, 0, data.size,
|
||||||
IoDir.WRITE, 0, 0)
|
IoDir.WRITE, 0, 0)
|
||||||
io.set_data(data)
|
io.set_data(data)
|
||||||
|
|
||||||
@ -325,13 +332,13 @@ def test_try_add_core_with_changed_size(pyocf_ctx, cache_mode, cls):
|
|||||||
:param cls: cache line size we start with
|
:param cls: cache line size we start with
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device, cache_mode=cache_mode, cache_line_size=cls
|
cache_device, cache_mode=cache_mode, cache_line_size=cls
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add core to cache
|
# Add core to cache
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
|
|
||||||
@ -359,13 +366,13 @@ def test_load_with_changed_core_size(pyocf_ctx, cache_mode, cls):
|
|||||||
:param cls: cache line size we start with
|
:param cls: cache line size we start with
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device, cache_mode=cache_mode, cache_line_size=cls
|
cache_device, cache_mode=cache_mode, cache_line_size=cls
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add core to cache
|
# Add core to cache
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright(c) 2019-2021 Intel Corporation
|
# Copyright(c) 2019-2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -27,7 +27,8 @@ from pyocf.types.shared import (
|
|||||||
CacheLineSize,
|
CacheLineSize,
|
||||||
SeqCutOffPolicy,
|
SeqCutOffPolicy,
|
||||||
)
|
)
|
||||||
from pyocf.types.volume import Volume
|
from pyocf.types.volume import RamVolume
|
||||||
|
from pyocf.types.volume_core import CoreVolume
|
||||||
from pyocf.utils import Size
|
from pyocf.utils import Size
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -43,12 +44,15 @@ def test_attach_different_size(
|
|||||||
attach cache with different size and trigger IO. Verify if occupancy thresold is
|
attach cache with different size and trigger IO. Verify if occupancy thresold is
|
||||||
respected with both original and new cache device.
|
respected with both original and new cache device.
|
||||||
"""
|
"""
|
||||||
cache_device = Volume(Size.from_MiB(100))
|
cache_device = RamVolume(Size.from_MiB(100))
|
||||||
core_device = Volume(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)
|
cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls)
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
|
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
|
queue = cache.get_default_queue()
|
||||||
|
|
||||||
cache.configure_partition(
|
cache.configure_partition(
|
||||||
part_id=1, name="test_part", max_size=50, priority=1
|
part_id=1, name="test_part", max_size=50, priority=1
|
||||||
)
|
)
|
||||||
@ -61,7 +65,7 @@ def test_attach_different_size(
|
|||||||
data = bytes(block_size)
|
data = bytes(block_size)
|
||||||
|
|
||||||
for i in range(cache_size.blocks_4k):
|
for i in range(cache_size.blocks_4k):
|
||||||
io_to_exp_obj(core, block_size * i, block_size, data, 0, IoDir.WRITE, 1, 0)
|
io_to_exp_obj(vol, queue, block_size * i, block_size, data, 0, IoDir.WRITE, 1, 0)
|
||||||
|
|
||||||
part_current_size = CacheLines(
|
part_current_size = CacheLines(
|
||||||
cache.get_partition_info(part_id=1)["_curr_size"], cls
|
cache.get_partition_info(part_id=1)["_curr_size"], cls
|
||||||
@ -70,13 +74,13 @@ def test_attach_different_size(
|
|||||||
assert part_current_size.blocks_4k == cache_size.blocks_4k * 0.5
|
assert part_current_size.blocks_4k == cache_size.blocks_4k * 0.5
|
||||||
|
|
||||||
cache.detach_device()
|
cache.detach_device()
|
||||||
new_cache_device = Volume(Size.from_MiB(new_cache_size))
|
new_cache_device = RamVolume(Size.from_MiB(new_cache_size))
|
||||||
cache.attach_device(new_cache_device, force=True)
|
cache.attach_device(new_cache_device, force=True)
|
||||||
|
|
||||||
cache_size = cache.get_stats()["conf"]["size"]
|
cache_size = cache.get_stats()["conf"]["size"]
|
||||||
|
|
||||||
for i in range(cache_size.blocks_4k):
|
for i in range(cache_size.blocks_4k):
|
||||||
io_to_exp_obj(core, block_size * i, block_size, data, 0, IoDir.WRITE, 1, 0)
|
io_to_exp_obj(vol, queue, block_size * i, block_size, data, 0, IoDir.WRITE, 1, 0)
|
||||||
|
|
||||||
part_current_size = CacheLines(
|
part_current_size = CacheLines(
|
||||||
cache.get_partition_info(part_id=1)["_curr_size"], cls
|
cache.get_partition_info(part_id=1)["_curr_size"], cls
|
||||||
@ -85,22 +89,8 @@ def test_attach_different_size(
|
|||||||
assert part_current_size.blocks_4k == cache_size.blocks_4k * 0.5
|
assert part_current_size.blocks_4k == cache_size.blocks_4k * 0.5
|
||||||
|
|
||||||
|
|
||||||
def io_to_exp_obj(core, address, size, data, offset, direction, target_ioclass, flags):
|
def io_to_exp_obj(vol, queue, address, size, data, offset, direction, target_ioclass, flags):
|
||||||
return _io(
|
io = vol.new_io(queue, address, size, direction, target_ioclass, flags)
|
||||||
core.new_io,
|
|
||||||
core.cache.get_default_queue(),
|
|
||||||
address,
|
|
||||||
size,
|
|
||||||
data,
|
|
||||||
offset,
|
|
||||||
direction,
|
|
||||||
target_ioclass,
|
|
||||||
flags,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def _io(new_io, queue, address, size, data, offset, direction, target_ioclass, flags):
|
|
||||||
io = new_io(queue, address, size, direction, target_ioclass, flags)
|
|
||||||
if direction == IoDir.READ:
|
if direction == IoDir.READ:
|
||||||
_data = Data.from_bytes(bytes(size))
|
_data = Data.from_bytes(bytes(size))
|
||||||
else:
|
else:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright(c) 2019-2021 Intel Corporation
|
# Copyright(c) 2019-2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -7,7 +7,7 @@ import pytest
|
|||||||
|
|
||||||
from pyocf.types.cache import Cache, CacheMode, CleaningPolicy, SeqCutOffPolicy
|
from pyocf.types.cache import Cache, CacheMode, CleaningPolicy, SeqCutOffPolicy
|
||||||
from pyocf.types.core import Core
|
from pyocf.types.core import Core
|
||||||
from pyocf.types.volume import Volume
|
from pyocf.types.volume import RamVolume
|
||||||
from pyocf.utils import Size as S
|
from pyocf.utils import Size as S
|
||||||
from pyocf.types.shared import CacheLineSize
|
from pyocf.types.shared import CacheLineSize
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ from pyocf.types.shared import CacheLineSize
|
|||||||
@pytest.mark.parametrize("cls", CacheLineSize)
|
@pytest.mark.parametrize("cls", CacheLineSize)
|
||||||
def test_change_cache_mode(pyocf_ctx, from_cm, to_cm, cls):
|
def test_change_cache_mode(pyocf_ctx, from_cm, to_cm, cls):
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device, cache_mode=from_cm, cache_line_size=cls
|
cache_device, cache_mode=from_cm, cache_line_size=cls
|
||||||
)
|
)
|
||||||
@ -32,7 +32,7 @@ def test_change_cache_mode(pyocf_ctx, from_cm, to_cm, cls):
|
|||||||
@pytest.mark.parametrize("cls", CacheLineSize)
|
@pytest.mark.parametrize("cls", CacheLineSize)
|
||||||
def test_change_cleaning_policy(pyocf_ctx, cm, cls):
|
def test_change_cleaning_policy(pyocf_ctx, cm, cls):
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device, cache_mode=cm, cache_line_size=cls
|
cache_device, cache_mode=cm, cache_line_size=cls
|
||||||
)
|
)
|
||||||
@ -57,15 +57,15 @@ def test_change_cleaning_policy(pyocf_ctx, cm, cls):
|
|||||||
@pytest.mark.parametrize("cls", CacheLineSize)
|
@pytest.mark.parametrize("cls", CacheLineSize)
|
||||||
def test_cache_change_seq_cut_off_policy(pyocf_ctx, cm, cls):
|
def test_cache_change_seq_cut_off_policy(pyocf_ctx, cm, cls):
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device, cache_mode=cm, cache_line_size=cls
|
cache_device, cache_mode=cm, cache_line_size=cls
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create 2 core devices
|
# Create 2 core devices
|
||||||
core_device1 = Volume(S.from_MiB(10))
|
core_device1 = RamVolume(S.from_MiB(10))
|
||||||
core1 = Core.using_device(core_device1, name="core1")
|
core1 = Core.using_device(core_device1, name="core1")
|
||||||
core_device2 = Volume(S.from_MiB(10))
|
core_device2 = RamVolume(S.from_MiB(10))
|
||||||
core2 = Core.using_device(core_device2, name="core2")
|
core2 = Core.using_device(core_device2, name="core2")
|
||||||
|
|
||||||
# Add cores
|
# Add cores
|
||||||
@ -96,15 +96,15 @@ def test_cache_change_seq_cut_off_policy(pyocf_ctx, cm, cls):
|
|||||||
@pytest.mark.parametrize("cls", CacheLineSize)
|
@pytest.mark.parametrize("cls", CacheLineSize)
|
||||||
def test_core_change_seq_cut_off_policy(pyocf_ctx, cm, cls):
|
def test_core_change_seq_cut_off_policy(pyocf_ctx, cm, cls):
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device, cache_mode=cm, cache_line_size=cls
|
cache_device, cache_mode=cm, cache_line_size=cls
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create 2 core devices
|
# Create 2 core devices
|
||||||
core_device1 = Volume(S.from_MiB(10))
|
core_device1 = RamVolume(S.from_MiB(10))
|
||||||
core1 = Core.using_device(core_device1, name="core1")
|
core1 = Core.using_device(core_device1, name="core1")
|
||||||
core_device2 = Volume(S.from_MiB(10))
|
core_device2 = RamVolume(S.from_MiB(10))
|
||||||
core2 = Core.using_device(core_device2, name="core2")
|
core2 = Core.using_device(core_device2, name="core2")
|
||||||
|
|
||||||
# Add cores
|
# Add cores
|
||||||
|
@ -21,10 +21,13 @@ from pyocf.types.cache import (
|
|||||||
Backfill
|
Backfill
|
||||||
)
|
)
|
||||||
from pyocf.types.core import Core
|
from pyocf.types.core import Core
|
||||||
|
from pyocf.types.ctx import OcfCtx
|
||||||
from pyocf.types.data import Data
|
from pyocf.types.data import Data
|
||||||
from pyocf.types.io import IoDir
|
from pyocf.types.io import IoDir
|
||||||
|
from pyocf.types.queue import Queue
|
||||||
from pyocf.types.shared import OcfError, OcfCompletion, CacheLineSize, SeqCutOffPolicy
|
from pyocf.types.shared import OcfError, OcfCompletion, CacheLineSize, SeqCutOffPolicy
|
||||||
from pyocf.types.volume import Volume
|
from pyocf.types.volume import Volume, RamVolume
|
||||||
|
from pyocf.types.volume_core import CoreVolume
|
||||||
from pyocf.utils import Size
|
from pyocf.utils import Size
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -34,8 +37,8 @@ def test_start_check_default(pyocf_ctx):
|
|||||||
"""Test if default values are correct after start.
|
"""Test if default values are correct after start.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
core_device = Volume(Size.from_MiB(10))
|
core_device = RamVolume(Size.from_MiB(10))
|
||||||
cache = Cache.start_on_device(cache_device)
|
cache = Cache.start_on_device(cache_device)
|
||||||
|
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
@ -58,24 +61,26 @@ def test_start_write_first_and_check_mode(pyocf_ctx, mode: CacheMode, cls: Cache
|
|||||||
After start check proper cache mode behaviour, starting with write operation.
|
After start check proper cache mode behaviour, starting with write operation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
core_device = Volume(Size.from_MiB(10))
|
core_device = RamVolume(Size.from_MiB(10))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls)
|
||||||
core_exported = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
|
|
||||||
cache.add_core(core_exported)
|
cache.add_core(core)
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
|
queue = cache.get_default_queue()
|
||||||
|
|
||||||
logger.info("[STAGE] Initial write to exported object")
|
logger.info("[STAGE] Initial write to exported object")
|
||||||
cache_device.reset_stats()
|
cache_device.reset_stats()
|
||||||
core_device.reset_stats()
|
core_device.reset_stats()
|
||||||
|
|
||||||
test_data = Data.from_string("This is test data")
|
test_data = Data.from_string("This is test data")
|
||||||
io_to_core(core_exported, test_data, Size.from_sector(1).B)
|
io_to_core(vol, queue, test_data, Size.from_sector(1).B)
|
||||||
check_stats_write_empty(core_exported, mode, cls)
|
check_stats_write_empty(core, mode, cls)
|
||||||
|
|
||||||
logger.info("[STAGE] Read from exported object after initial write")
|
logger.info("[STAGE] Read from exported object after initial write")
|
||||||
io_from_exported_object(core_exported, test_data.size, Size.from_sector(1).B)
|
io_from_exported_object(vol, queue, test_data.size, Size.from_sector(1).B)
|
||||||
check_stats_read_after_write(core_exported, mode, cls, True)
|
check_stats_read_after_write(core, mode, cls, True)
|
||||||
|
|
||||||
logger.info("[STAGE] Write to exported object after read")
|
logger.info("[STAGE] Write to exported object after read")
|
||||||
cache_device.reset_stats()
|
cache_device.reset_stats()
|
||||||
@ -83,10 +88,10 @@ def test_start_write_first_and_check_mode(pyocf_ctx, mode: CacheMode, cls: Cache
|
|||||||
|
|
||||||
test_data = Data.from_string("Changed test data")
|
test_data = Data.from_string("Changed test data")
|
||||||
|
|
||||||
io_to_core(core_exported, test_data, Size.from_sector(1).B)
|
io_to_core(vol, queue, test_data, Size.from_sector(1).B)
|
||||||
check_stats_write_after_read(core_exported, mode, cls)
|
check_stats_write_after_read(core, mode, cls)
|
||||||
|
|
||||||
check_md5_sums(core_exported, mode)
|
check_md5_sums(core, mode)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("cls", CacheLineSize)
|
@pytest.mark.parametrize("cls", CacheLineSize)
|
||||||
@ -96,23 +101,26 @@ def test_start_read_first_and_check_mode(pyocf_ctx, mode: CacheMode, cls: CacheL
|
|||||||
After start check proper cache mode behaviour, starting with read operation.
|
After start check proper cache mode behaviour, starting with read operation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
core_device = Volume(Size.from_MiB(5))
|
core_device = RamVolume(Size.from_MiB(5))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls)
|
||||||
core_exported = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
|
|
||||||
cache.add_core(core_exported)
|
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")
|
logger.info("[STAGE] Initial write to core device")
|
||||||
test_data = Data.from_string("This is test data")
|
test_data = Data.from_string("This is test data")
|
||||||
io_to_core(core_exported, test_data, Size.from_sector(1).B, True)
|
io_to_core(bottom_vol, queue, test_data, Size.from_sector(1).B)
|
||||||
|
|
||||||
cache_device.reset_stats()
|
cache_device.reset_stats()
|
||||||
core_device.reset_stats()
|
core_device.reset_stats()
|
||||||
|
|
||||||
logger.info("[STAGE] Initial read from exported object")
|
logger.info("[STAGE] Initial read from exported object")
|
||||||
io_from_exported_object(core_exported, test_data.size, Size.from_sector(1).B)
|
io_from_exported_object(front_vol, queue, test_data.size, Size.from_sector(1).B)
|
||||||
check_stats_read_empty(core_exported, mode, cls)
|
check_stats_read_empty(core, mode, cls)
|
||||||
|
|
||||||
logger.info("[STAGE] Write to exported object after initial read")
|
logger.info("[STAGE] Write to exported object after initial read")
|
||||||
cache_device.reset_stats()
|
cache_device.reset_stats()
|
||||||
@ -120,15 +128,15 @@ def test_start_read_first_and_check_mode(pyocf_ctx, mode: CacheMode, cls: CacheL
|
|||||||
|
|
||||||
test_data = Data.from_string("Changed test data")
|
test_data = Data.from_string("Changed test data")
|
||||||
|
|
||||||
io_to_core(core_exported, test_data, Size.from_sector(1).B)
|
io_to_core(front_vol, queue, test_data, Size.from_sector(1).B)
|
||||||
|
|
||||||
check_stats_write_after_read(core_exported, mode, cls, True)
|
check_stats_write_after_read(core, mode, cls, True)
|
||||||
|
|
||||||
logger.info("[STAGE] Read from exported object after write")
|
logger.info("[STAGE] Read from exported object after write")
|
||||||
io_from_exported_object(core_exported, test_data.size, Size.from_sector(1).B)
|
io_from_exported_object(front_vol, queue, test_data.size, Size.from_sector(1).B)
|
||||||
check_stats_read_after_write(core_exported, mode, cls)
|
check_stats_read_after_write(core, mode, cls)
|
||||||
|
|
||||||
check_md5_sums(core_exported, mode)
|
check_md5_sums(core, mode)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("cls", CacheLineSize)
|
@pytest.mark.parametrize("cls", CacheLineSize)
|
||||||
@ -139,7 +147,7 @@ def test_start_params(pyocf_ctx, mode: CacheMode, cls: CacheLineSize, layout: Me
|
|||||||
Check if cache starts without errors.
|
Check if cache starts without errors.
|
||||||
If possible check whether cache reports properly set parameters.
|
If possible check whether cache reports properly set parameters.
|
||||||
"""
|
"""
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
queue_size = randrange(60000, 2**32)
|
queue_size = randrange(60000, 2**32)
|
||||||
unblock_size = randrange(1, queue_size)
|
unblock_size = randrange(1, queue_size)
|
||||||
volatile_metadata = randrange(2) == 1
|
volatile_metadata = randrange(2) == 1
|
||||||
@ -176,20 +184,24 @@ def test_stop(pyocf_ctx, mode: CacheMode, cls: CacheLineSize, with_flush: bool):
|
|||||||
Check if cache is stopped properly in different modes with or without preceding flush operation.
|
Check if cache is stopped properly in different modes with or without preceding flush operation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
core_device = Volume(Size.from_MiB(5))
|
core_device = RamVolume(Size.from_MiB(5))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls)
|
||||||
core_exported = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
cache.add_core(core_exported)
|
|
||||||
|
cache.add_core(core)
|
||||||
|
front_vol = CoreVolume(core, open=True)
|
||||||
|
queue = cache.get_default_queue()
|
||||||
|
|
||||||
cls_no = 10
|
cls_no = 10
|
||||||
|
|
||||||
run_io_and_cache_data_if_possible(core_exported, mode, cls, cls_no)
|
run_io_and_cache_data_if_possible(core, mode, cls, cls_no)
|
||||||
|
|
||||||
stats = cache.get_stats()
|
stats = cache.get_stats()
|
||||||
assert int(stats["conf"]["dirty"]) == (cls_no if mode.lazy_write() else 0),\
|
assert int(stats["conf"]["dirty"]) == (cls_no if mode.lazy_write() else 0),\
|
||||||
"Dirty data before MD5"
|
"Dirty data before MD5"
|
||||||
|
|
||||||
md5_exported_core = core_exported.exp_obj_md5()
|
md5_exported_core = front_vol.md5()
|
||||||
|
|
||||||
if with_flush:
|
if with_flush:
|
||||||
cache.flush()
|
cache.flush()
|
||||||
@ -211,7 +223,7 @@ def test_start_stop_multiple(pyocf_ctx):
|
|||||||
caches = []
|
caches = []
|
||||||
caches_no = randrange(6, 11)
|
caches_no = randrange(6, 11)
|
||||||
for i in range(1, caches_no):
|
for i in range(1, caches_no):
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
cache_name = f"cache{i}"
|
cache_name = f"cache{i}"
|
||||||
cache_mode = CacheMode(randrange(0, len(CacheMode)))
|
cache_mode = CacheMode(randrange(0, len(CacheMode)))
|
||||||
size = 4096 * 2**randrange(0, len(CacheLineSize))
|
size = 4096 * 2**randrange(0, len(CacheLineSize))
|
||||||
@ -243,7 +255,7 @@ def test_100_start_stop(pyocf_ctx):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
for i in range(1, 101):
|
for i in range(1, 101):
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
cache_name = f"cache{i}"
|
cache_name = f"cache{i}"
|
||||||
cache_mode = CacheMode(randrange(0, len(CacheMode)))
|
cache_mode = CacheMode(randrange(0, len(CacheMode)))
|
||||||
size = 4096 * 2**randrange(0, len(CacheLineSize))
|
size = 4096 * 2**randrange(0, len(CacheLineSize))
|
||||||
@ -278,7 +290,7 @@ def test_start_stop_incrementally(pyocf_ctx):
|
|||||||
while run:
|
while run:
|
||||||
if add:
|
if add:
|
||||||
for i in range(0, randrange(3, 5) if increase else randrange(1, 3)):
|
for i in range(0, randrange(3, 5) if increase else randrange(1, 3)):
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
cache_name = f"cache{next(counter)}"
|
cache_name = f"cache{next(counter)}"
|
||||||
cache_mode = CacheMode(randrange(0, len(CacheMode)))
|
cache_mode = CacheMode(randrange(0, len(CacheMode)))
|
||||||
size = 4096 * 2**randrange(0, len(CacheLineSize))
|
size = 4096 * 2**randrange(0, len(CacheLineSize))
|
||||||
@ -318,8 +330,8 @@ def test_start_cache_same_id(pyocf_ctx, mode, cls):
|
|||||||
Check that OCF does not allow for 2 caches to be started with the same cache_name
|
Check that OCF does not allow for 2 caches to be started with the same cache_name
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cache_device1 = Volume(Size.from_MiB(50))
|
cache_device1 = RamVolume(Size.from_MiB(50))
|
||||||
cache_device2 = Volume(Size.from_MiB(50))
|
cache_device2 = RamVolume(Size.from_MiB(50))
|
||||||
cache_name = "cache"
|
cache_name = "cache"
|
||||||
cache = Cache.start_on_device(cache_device1,
|
cache = Cache.start_on_device(cache_device1,
|
||||||
cache_mode=mode,
|
cache_mode=mode,
|
||||||
@ -349,7 +361,9 @@ def test_start_cache_huge_device(pyocf_ctx_log_buffer, cls):
|
|||||||
def submit_io(self, io):
|
def submit_io(self, io):
|
||||||
io.contents._end(io, 0)
|
io.contents._end(io, 0)
|
||||||
|
|
||||||
cache_device = HugeDevice(Size.from_MiB(50))
|
OcfCtx.get_default().register_volume_type(HugeDevice)
|
||||||
|
|
||||||
|
cache_device = HugeDevice()
|
||||||
|
|
||||||
with pytest.raises(OcfError, match="OCF_ERR_INVAL_CACHE_DEV"):
|
with pytest.raises(OcfError, match="OCF_ERR_INVAL_CACHE_DEV"):
|
||||||
cache = Cache.start_on_device(cache_device, cache_line_size=cls, metadata_volatile=True)
|
cache = Cache.start_on_device(cache_device, cache_line_size=cls, metadata_volatile=True)
|
||||||
@ -367,7 +381,7 @@ def test_start_cache_same_device(pyocf_ctx, mode, cls):
|
|||||||
Check that OCF does not allow for 2 caches using the same cache device to be started
|
Check that OCF does not allow for 2 caches using the same cache device to be started
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device, cache_mode=mode, cache_line_size=cls, name="cache1"
|
cache_device, cache_mode=mode, cache_line_size=cls, name="cache1"
|
||||||
)
|
)
|
||||||
@ -387,7 +401,7 @@ def test_start_too_small_device(pyocf_ctx, mode, cls):
|
|||||||
Check if starting cache with device below minimum size is blocked
|
Check if starting cache with device below minimum size is blocked
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cache_device = Volume(Size.from_B(20 * 1024 * 1024 - 1))
|
cache_device = RamVolume(Size.from_B(20 * 1024 * 1024 - 1))
|
||||||
|
|
||||||
with pytest.raises(OcfError, match="OCF_ERR_INVAL_CACHE_DEV"):
|
with pytest.raises(OcfError, match="OCF_ERR_INVAL_CACHE_DEV"):
|
||||||
Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls)
|
Cache.start_on_device(cache_device, cache_mode=mode, cache_line_size=cls)
|
||||||
@ -414,27 +428,29 @@ def test_start_stop_noqueue(pyocf_ctx):
|
|||||||
assert not c.results["error"], "Failed to stop cache: {}".format(c.results["error"])
|
assert not c.results["error"], "Failed to stop cache: {}".format(c.results["error"])
|
||||||
|
|
||||||
|
|
||||||
def run_io_and_cache_data_if_possible(exported_obj, mode, cls, cls_no):
|
def run_io_and_cache_data_if_possible(core, mode, cls, cls_no):
|
||||||
|
front_vol = core.get_front_volume()
|
||||||
|
bottom_vol = core.get_volume()
|
||||||
|
queue = core.cache.get_default_queue()
|
||||||
|
|
||||||
test_data = Data(cls_no * cls)
|
test_data = Data(cls_no * cls)
|
||||||
|
|
||||||
if mode in {CacheMode.WI, CacheMode.WA}:
|
if mode in {CacheMode.WI, CacheMode.WA}:
|
||||||
logger.info("[STAGE] Write to core device")
|
logger.info("[STAGE] Write to core device")
|
||||||
io_to_core(exported_obj, test_data, 0, True)
|
io_to_core(bottom_vol, queue, test_data, 0)
|
||||||
logger.info("[STAGE] Read from exported object")
|
logger.info("[STAGE] Read from exported object")
|
||||||
io_from_exported_object(exported_obj, test_data.size, 0)
|
io_from_exported_object(front_vol, queue, test_data.size, 0)
|
||||||
else:
|
else:
|
||||||
logger.info("[STAGE] Write to exported object")
|
logger.info("[STAGE] Write to exported object")
|
||||||
io_to_core(exported_obj, test_data, 0)
|
io_to_core(front_vol, queue, test_data, 0)
|
||||||
|
|
||||||
stats = exported_obj.cache.get_stats()
|
stats = core.cache.get_stats()
|
||||||
assert stats["usage"]["occupancy"]["value"] == \
|
assert stats["usage"]["occupancy"]["value"] == \
|
||||||
((cls_no * cls / CacheLineSize.LINE_4KiB) if mode != CacheMode.PT else 0), "Occupancy"
|
((cls_no * cls / CacheLineSize.LINE_4KiB) if mode != CacheMode.PT else 0), "Occupancy"
|
||||||
|
|
||||||
|
|
||||||
def io_to_core(exported_obj: Core, data: Data, offset: int, to_core_device=False):
|
def io_to_core(vol: Volume, queue: Queue, data: Data, offset: int):
|
||||||
new_io = exported_obj.new_core_io if to_core_device else exported_obj.new_io
|
io = vol.new_io(queue, offset, data.size, IoDir.WRITE, 0, 0)
|
||||||
io = new_io(exported_obj.cache.get_default_queue(), offset, data.size,
|
|
||||||
IoDir.WRITE, 0, 0)
|
|
||||||
io.set_data(data)
|
io.set_data(data)
|
||||||
|
|
||||||
completion = OcfCompletion([("err", c_int)])
|
completion = OcfCompletion([("err", c_int)])
|
||||||
@ -445,10 +461,9 @@ def io_to_core(exported_obj: Core, data: Data, offset: int, to_core_device=False
|
|||||||
assert completion.results["err"] == 0, "IO to exported object completion"
|
assert completion.results["err"] == 0, "IO to exported object completion"
|
||||||
|
|
||||||
|
|
||||||
def io_from_exported_object(exported_obj: Core, buffer_size: int, offset: int):
|
def io_from_exported_object(vol: Volume, queue: Queue, buffer_size: int, offset: int):
|
||||||
read_buffer = Data(buffer_size)
|
read_buffer = Data(buffer_size)
|
||||||
io = exported_obj.new_io(exported_obj.cache.get_default_queue(), offset,
|
io = vol.new_io(queue, offset, read_buffer.size, IoDir.READ, 0, 0)
|
||||||
read_buffer.size, IoDir.READ, 0, 0)
|
|
||||||
io.set_data(read_buffer)
|
io.set_data(read_buffer)
|
||||||
|
|
||||||
completion = OcfCompletion([("err", c_int)])
|
completion = OcfCompletion([("err", c_int)])
|
||||||
@ -460,28 +475,28 @@ def io_from_exported_object(exported_obj: Core, buffer_size: int, offset: int):
|
|||||||
return read_buffer
|
return read_buffer
|
||||||
|
|
||||||
|
|
||||||
def check_stats_read_empty(exported_obj: Core, mode: CacheMode, cls: CacheLineSize):
|
def check_stats_read_empty(core: Core, mode: CacheMode, cls: CacheLineSize):
|
||||||
exported_obj.cache.settle()
|
core.cache.settle()
|
||||||
stats = exported_obj.cache.get_stats()
|
stats = core.cache.get_stats()
|
||||||
assert stats["conf"]["cache_mode"] == mode, "Cache mode"
|
assert stats["conf"]["cache_mode"] == mode, "Cache mode"
|
||||||
assert exported_obj.cache.device.get_stats()[IoDir.WRITE] == (1 if mode.read_insert() else 0), \
|
assert core.cache.device.get_stats()[IoDir.WRITE] == (1 if mode.read_insert() else 0), \
|
||||||
"Writes to cache device"
|
"Writes to cache device"
|
||||||
assert exported_obj.device.get_stats()[IoDir.READ] == 1, "Reads from core device"
|
assert core.device.get_stats()[IoDir.READ] == 1, "Reads from core device"
|
||||||
assert stats["req"]["rd_full_misses"]["value"] == (0 if mode == CacheMode.PT else 1), \
|
assert stats["req"]["rd_full_misses"]["value"] == (0 if mode == CacheMode.PT else 1), \
|
||||||
"Read full misses"
|
"Read full misses"
|
||||||
assert stats["usage"]["occupancy"]["value"] == \
|
assert stats["usage"]["occupancy"]["value"] == \
|
||||||
((cls / CacheLineSize.LINE_4KiB) if mode.read_insert() else 0), "Occupancy"
|
((cls / CacheLineSize.LINE_4KiB) if mode.read_insert() else 0), "Occupancy"
|
||||||
|
|
||||||
|
|
||||||
def check_stats_write_empty(exported_obj: Core, mode: CacheMode, cls: CacheLineSize):
|
def check_stats_write_empty(core: Core, mode: CacheMode, cls: CacheLineSize):
|
||||||
exported_obj.cache.settle()
|
core.cache.settle()
|
||||||
stats = exported_obj.cache.get_stats()
|
stats = core.cache.get_stats()
|
||||||
assert stats["conf"]["cache_mode"] == mode, "Cache mode"
|
assert stats["conf"]["cache_mode"] == mode, "Cache mode"
|
||||||
# TODO(ajrutkow): why 1 for WT ??
|
# TODO(ajrutkow): why 1 for WT ??
|
||||||
assert exported_obj.cache.device.get_stats()[IoDir.WRITE] == \
|
assert core.cache.device.get_stats()[IoDir.WRITE] == \
|
||||||
(2 if mode.lazy_write() else (1 if mode == CacheMode.WT else 0)), \
|
(2 if mode.lazy_write() else (1 if mode == CacheMode.WT else 0)), \
|
||||||
"Writes to cache device"
|
"Writes to cache device"
|
||||||
assert exported_obj.device.get_stats()[IoDir.WRITE] == (0 if mode.lazy_write() else 1), \
|
assert core.device.get_stats()[IoDir.WRITE] == (0 if mode.lazy_write() else 1), \
|
||||||
"Writes to core device"
|
"Writes to core device"
|
||||||
assert stats["req"]["wr_full_misses"]["value"] == (1 if mode.write_insert() else 0), \
|
assert stats["req"]["wr_full_misses"]["value"] == (1 if mode.write_insert() else 0), \
|
||||||
"Write full misses"
|
"Write full misses"
|
||||||
@ -490,17 +505,17 @@ def check_stats_write_empty(exported_obj: Core, mode: CacheMode, cls: CacheLineS
|
|||||||
"Occupancy"
|
"Occupancy"
|
||||||
|
|
||||||
|
|
||||||
def check_stats_write_after_read(exported_obj: Core,
|
def check_stats_write_after_read(core: Core,
|
||||||
mode: CacheMode,
|
mode: CacheMode,
|
||||||
cls: CacheLineSize,
|
cls: CacheLineSize,
|
||||||
read_from_empty=False):
|
read_from_empty=False):
|
||||||
exported_obj.cache.settle()
|
core.cache.settle()
|
||||||
stats = exported_obj.cache.get_stats()
|
stats = core.cache.get_stats()
|
||||||
assert exported_obj.cache.device.get_stats()[IoDir.WRITE] == \
|
assert core.cache.device.get_stats()[IoDir.WRITE] == \
|
||||||
(0 if mode in {CacheMode.WI, CacheMode.PT} else
|
(0 if mode in {CacheMode.WI, CacheMode.PT} else
|
||||||
(2 if read_from_empty and mode.lazy_write() else 1)), \
|
(2 if read_from_empty and mode.lazy_write() else 1)), \
|
||||||
"Writes to cache device"
|
"Writes to cache device"
|
||||||
assert exported_obj.device.get_stats()[IoDir.WRITE] == (0 if mode.lazy_write() else 1), \
|
assert core.device.get_stats()[IoDir.WRITE] == (0 if mode.lazy_write() else 1), \
|
||||||
"Writes to core device"
|
"Writes to core device"
|
||||||
assert stats["req"]["wr_hits"]["value"] == \
|
assert stats["req"]["wr_hits"]["value"] == \
|
||||||
(1 if (mode.read_insert() and mode != CacheMode.WI)
|
(1 if (mode.read_insert() and mode != CacheMode.WI)
|
||||||
@ -511,17 +526,17 @@ def check_stats_write_after_read(exported_obj: Core,
|
|||||||
"Occupancy"
|
"Occupancy"
|
||||||
|
|
||||||
|
|
||||||
def check_stats_read_after_write(exported_obj, mode, cls, write_to_empty=False):
|
def check_stats_read_after_write(core, mode, cls, write_to_empty=False):
|
||||||
exported_obj.cache.settle()
|
core.cache.settle()
|
||||||
stats = exported_obj.cache.get_stats()
|
stats = core.cache.get_stats()
|
||||||
assert exported_obj.cache.device.get_stats()[IoDir.WRITE] == \
|
assert core.cache.device.get_stats()[IoDir.WRITE] == \
|
||||||
(2 if mode.lazy_write() else (0 if mode == CacheMode.PT else 1)), \
|
(2 if mode.lazy_write() else (0 if mode == CacheMode.PT else 1)), \
|
||||||
"Writes to cache device"
|
"Writes to cache device"
|
||||||
assert exported_obj.cache.device.get_stats()[IoDir.READ] == \
|
assert core.cache.device.get_stats()[IoDir.READ] == \
|
||||||
(1 if mode in {CacheMode.WT, CacheMode.WB, CacheMode.WO}
|
(1 if mode in {CacheMode.WT, CacheMode.WB, CacheMode.WO}
|
||||||
or (mode == CacheMode.WA and not write_to_empty) else 0), \
|
or (mode == CacheMode.WA and not write_to_empty) else 0), \
|
||||||
"Reads from cache device"
|
"Reads from cache device"
|
||||||
assert exported_obj.device.get_stats()[IoDir.READ] == \
|
assert core.device.get_stats()[IoDir.READ] == \
|
||||||
(0 if mode in {CacheMode.WB, CacheMode.WO, CacheMode.WT}
|
(0 if mode in {CacheMode.WB, CacheMode.WO, CacheMode.WT}
|
||||||
or (mode == CacheMode.WA and not write_to_empty) else 1), \
|
or (mode == CacheMode.WA and not write_to_empty) else 1), \
|
||||||
"Reads from core device"
|
"Reads from core device"
|
||||||
@ -537,15 +552,15 @@ def check_stats_read_after_write(exported_obj, mode, cls, write_to_empty=False):
|
|||||||
(0 if mode == CacheMode.PT else (cls / CacheLineSize.LINE_4KiB)), "Occupancy"
|
(0 if mode == CacheMode.PT else (cls / CacheLineSize.LINE_4KiB)), "Occupancy"
|
||||||
|
|
||||||
|
|
||||||
def check_md5_sums(exported_obj: Core, mode: CacheMode):
|
def check_md5_sums(core: Core, mode: CacheMode):
|
||||||
if mode.lazy_write():
|
if mode.lazy_write():
|
||||||
assert exported_obj.device.md5() != exported_obj.exp_obj_md5(), \
|
assert core.device.md5() != core.get_front_volume().md5(), \
|
||||||
"MD5 check: core device vs exported object without flush"
|
"MD5 check: core device vs exported object without flush"
|
||||||
exported_obj.cache.flush()
|
core.cache.flush()
|
||||||
assert exported_obj.device.md5() == exported_obj.exp_obj_md5(), \
|
assert core.device.md5() == core.get_front_volume().md5(), \
|
||||||
"MD5 check: core device vs exported object after flush"
|
"MD5 check: core device vs exported object after flush"
|
||||||
else:
|
else:
|
||||||
assert exported_obj.device.md5() == exported_obj.exp_obj_md5(), \
|
assert core.device.md5() == core.get_front_volume().md5(), \
|
||||||
"MD5 check: core device vs exported object"
|
"MD5 check: core device vs exported object"
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright(c) 2019-2021 Intel Corporation
|
# Copyright(c) 2019-2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ from pyocf.types.cache import (
|
|||||||
ConfValidValues,
|
ConfValidValues,
|
||||||
)
|
)
|
||||||
from pyocf.types.core import Core
|
from pyocf.types.core import Core
|
||||||
from pyocf.types.volume import Volume
|
from pyocf.types.volume import RamVolume
|
||||||
from pyocf.utils import Size as S
|
from pyocf.utils import Size as S
|
||||||
from tests.utils.random import (
|
from tests.utils.random import (
|
||||||
Range,
|
Range,
|
||||||
@ -41,7 +41,7 @@ def test_neg_change_cache_mode(pyocf_ctx, cm, cls):
|
|||||||
:param cls: cache line size we start with
|
:param cls: cache line size we start with
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
||||||
|
|
||||||
# Change cache mode to invalid one and check if failed
|
# Change cache mode to invalid one and check if failed
|
||||||
@ -65,7 +65,7 @@ def test_neg_set_cleaning_policy(pyocf_ctx, cm, cls):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
||||||
|
|
||||||
# Set cleaning policy to invalid one and check if failed
|
# Set cleaning policy to invalid one and check if failed
|
||||||
@ -90,7 +90,7 @@ def test_neg_attach_cls(pyocf_ctx, cm, cls):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache(owner=cache_device.owner, cache_mode=cm, cache_line_size=cls)
|
cache = Cache(owner=cache_device.owner, cache_mode=cm, cache_line_size=cls)
|
||||||
cache.start_cache()
|
cache.start_cache()
|
||||||
|
|
||||||
@ -115,13 +115,13 @@ def test_neg_cache_set_seq_cut_off_policy(pyocf_ctx, cm, cls):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
||||||
|
|
||||||
# Create 2 core devices
|
# Create 2 core devices
|
||||||
core_device1 = Volume(S.from_MiB(10))
|
core_device1 = RamVolume(S.from_MiB(10))
|
||||||
core1 = Core.using_device(core_device1, name="core1")
|
core1 = Core.using_device(core_device1, name="core1")
|
||||||
core_device2 = Volume(S.from_MiB(10))
|
core_device2 = RamVolume(S.from_MiB(10))
|
||||||
core2 = Core.using_device(core_device2, name="core2")
|
core2 = Core.using_device(core_device2, name="core2")
|
||||||
|
|
||||||
# Add cores
|
# Add cores
|
||||||
@ -149,13 +149,13 @@ def test_neg_cache_set_seq_cut_off_promotion(pyocf_ctx, cm, cls):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
||||||
|
|
||||||
# Create 2 core devices
|
# Create 2 core devices
|
||||||
core_device1 = Volume(S.from_MiB(10))
|
core_device1 = RamVolume(S.from_MiB(10))
|
||||||
core1 = Core.using_device(core_device1, name="core1")
|
core1 = Core.using_device(core_device1, name="core1")
|
||||||
core_device2 = Volume(S.from_MiB(10))
|
core_device2 = RamVolume(S.from_MiB(10))
|
||||||
core2 = Core.using_device(core_device2, name="core2")
|
core2 = Core.using_device(core_device2, name="core2")
|
||||||
|
|
||||||
# Add cores
|
# Add cores
|
||||||
@ -185,11 +185,11 @@ def test_neg_core_set_seq_cut_off_promotion(pyocf_ctx, cm, cls):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
||||||
|
|
||||||
# Create core device
|
# Create core device
|
||||||
core_device1 = Volume(S.from_MiB(10))
|
core_device1 = RamVolume(S.from_MiB(10))
|
||||||
core1 = Core.using_device(core_device1, name="core1")
|
core1 = Core.using_device(core_device1, name="core1")
|
||||||
|
|
||||||
# Add core
|
# Add core
|
||||||
@ -218,13 +218,13 @@ def test_neg_cache_set_seq_cut_off_threshold(pyocf_ctx, cm, cls):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
||||||
|
|
||||||
# Create 2 core devices
|
# Create 2 core devices
|
||||||
core_device1 = Volume(S.from_MiB(10))
|
core_device1 = RamVolume(S.from_MiB(10))
|
||||||
core1 = Core.using_device(core_device1, name="core1")
|
core1 = Core.using_device(core_device1, name="core1")
|
||||||
core_device2 = Volume(S.from_MiB(10))
|
core_device2 = RamVolume(S.from_MiB(10))
|
||||||
core2 = Core.using_device(core_device2, name="core2")
|
core2 = Core.using_device(core_device2, name="core2")
|
||||||
|
|
||||||
# Add cores
|
# Add cores
|
||||||
@ -254,11 +254,11 @@ def test_neg_core_set_seq_cut_off_threshold(pyocf_ctx, cm, cls):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
||||||
|
|
||||||
# Create core device
|
# Create core device
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core.using_device(core_device, name="core")
|
core = Core.using_device(core_device, name="core")
|
||||||
|
|
||||||
# Add core
|
# Add core
|
||||||
@ -287,11 +287,11 @@ def test_neg_core_set_seq_cut_off_policy(pyocf_ctx, cm, cls):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
||||||
|
|
||||||
# Create core device
|
# Create core device
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
|
|
||||||
# Add core
|
# Add core
|
||||||
@ -318,7 +318,7 @@ def test_neg_set_alru_param(pyocf_ctx, cm, cls):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
||||||
|
|
||||||
# Change invalid alru param and check if failed
|
# Change invalid alru param and check if failed
|
||||||
@ -355,7 +355,7 @@ def test_neg_set_alru_param_value(pyocf_ctx, cm, cls, param):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
||||||
|
|
||||||
cache.set_cleaning_policy(CleaningPolicy.ALRU)
|
cache.set_cleaning_policy(CleaningPolicy.ALRU)
|
||||||
@ -382,7 +382,7 @@ def test_neg_set_acp_param(pyocf_ctx, cm, cls):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
||||||
|
|
||||||
# Change invalid acp param and check if failed
|
# Change invalid acp param and check if failed
|
||||||
@ -415,7 +415,7 @@ def test_neg_set_acp_param_value(pyocf_ctx, cm, cls, param):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
||||||
|
|
||||||
cache.set_cleaning_policy(CleaningPolicy.ACP)
|
cache.set_cleaning_policy(CleaningPolicy.ACP)
|
||||||
@ -442,7 +442,7 @@ def test_neg_set_promotion_policy(pyocf_ctx, cm, cls):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
||||||
|
|
||||||
# Change to invalid promotion policy and check if failed
|
# Change to invalid promotion policy and check if failed
|
||||||
@ -466,7 +466,7 @@ def test_neg_set_nhit_promotion_policy_param(pyocf_ctx, cm, cls):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device,
|
cache_device,
|
||||||
cache_mode=cm,
|
cache_mode=cm,
|
||||||
@ -496,7 +496,7 @@ def test_neg_set_nhit_promotion_policy_param_trigger(pyocf_ctx, cm, cls):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device,
|
cache_device,
|
||||||
cache_mode=cm,
|
cache_mode=cm,
|
||||||
@ -528,7 +528,7 @@ def test_neg_set_nhit_promotion_policy_param_threshold(pyocf_ctx, cm, cls):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device,
|
cache_device,
|
||||||
cache_mode=cm,
|
cache_mode=cm,
|
||||||
@ -559,7 +559,7 @@ def test_neg_set_ioclass_max_size(pyocf_ctx, cm, cls):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
||||||
|
|
||||||
# Set invalid max size and check if failed
|
# Set invalid max size and check if failed
|
||||||
@ -589,7 +589,7 @@ def test_neg_set_ioclass_priority(pyocf_ctx, cm, cls):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
||||||
|
|
||||||
# Set invalid priority and check if failed
|
# Set invalid priority and check if failed
|
||||||
@ -619,7 +619,7 @@ def test_neg_set_ioclass_cache_mode(pyocf_ctx, cm, cls):
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
cache = Cache.start_on_device(cache_device, cache_mode=cm, cache_line_size=cls)
|
||||||
|
|
||||||
# Set invalid cache mode and check if failed
|
# Set invalid cache mode and check if failed
|
||||||
@ -644,7 +644,7 @@ def test_neg_set_ioclass_name(pyocf_ctx):
|
|||||||
invalid_chars += [",", '"']
|
invalid_chars += [",", '"']
|
||||||
|
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device, cache_mode=CacheMode.WT, cache_line_size=CacheLineSize.LINE_4KiB
|
cache_device, cache_mode=CacheMode.WT, cache_line_size=CacheLineSize.LINE_4KiB
|
||||||
)
|
)
|
||||||
@ -669,7 +669,7 @@ def test_neg_set_ioclass_name_len(pyocf_ctx):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Start cache device
|
# Start cache device
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(
|
cache = Cache.start_on_device(
|
||||||
cache_device, cache_mode=CacheMode.WT, cache_line_size=CacheLineSize.LINE_4KiB
|
cache_device, cache_mode=CacheMode.WT, cache_line_size=CacheLineSize.LINE_4KiB
|
||||||
)
|
)
|
||||||
|
@ -9,7 +9,7 @@ import pytest
|
|||||||
|
|
||||||
from pyocf.types.cache import Cache, CacheMode, MetadataLayout, PromotionPolicy
|
from pyocf.types.cache import Cache, CacheMode, MetadataLayout, PromotionPolicy
|
||||||
from pyocf.types.shared import OcfError, CacheLineSize
|
from pyocf.types.shared import OcfError, CacheLineSize
|
||||||
from pyocf.types.volume import Volume
|
from pyocf.types.volume import RamVolume
|
||||||
from pyocf.utils import Size
|
from pyocf.utils import Size
|
||||||
from tests.utils.random import RandomGenerator, DefaultRanges, Range
|
from tests.utils.random import RandomGenerator, DefaultRanges, Range
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
def try_start_cache(**config):
|
def try_start_cache(**config):
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, **config)
|
cache = Cache.start_on_device(cache_device, **config)
|
||||||
cache.stop()
|
cache.stop()
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ def test_fuzzy_start_name(pyocf_ctx, string_randomize, cm, cls):
|
|||||||
:param cm: cache mode value to start cache with
|
:param cm: cache mode value to start cache with
|
||||||
:param cls: cache line size value to start cache with
|
:param cls: cache line size value to start cache with
|
||||||
"""
|
"""
|
||||||
cache_device = Volume(Size.from_MiB(50))
|
cache_device = RamVolume(Size.from_MiB(50))
|
||||||
incorrect_values = ['']
|
incorrect_values = ['']
|
||||||
try:
|
try:
|
||||||
cache = Cache.start_on_device(cache_device, name=string_randomize, cache_mode=cm,
|
cache = Cache.start_on_device(cache_device, name=string_randomize, cache_mode=cm,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright(c) 2019-2021 Intel Corporation
|
# Copyright(c) 2019-2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -11,8 +11,10 @@ import pytest
|
|||||||
from pyocf.types.cache import Cache, Core
|
from pyocf.types.cache import Cache, Core
|
||||||
from pyocf.types.data import Data
|
from pyocf.types.data import Data
|
||||||
from pyocf.types.io import IoDir
|
from pyocf.types.io import IoDir
|
||||||
|
from pyocf.types.queue import Queue
|
||||||
from pyocf.types.shared import OcfCompletion
|
from pyocf.types.shared import OcfCompletion
|
||||||
from pyocf.types.volume import Volume
|
from pyocf.types.volume import Volume, RamVolume
|
||||||
|
from pyocf.types.volume_core import CoreVolume
|
||||||
from pyocf.utils import Size
|
from pyocf.utils import Size
|
||||||
|
|
||||||
|
|
||||||
@ -22,9 +24,9 @@ def test_neg_write_too_long_data(pyocf_ctx, c_uint16_randomize):
|
|||||||
Check if writing data larger than exported object size is properly blocked
|
Check if writing data larger than exported object size is properly blocked
|
||||||
"""
|
"""
|
||||||
|
|
||||||
core = prepare_cache_and_core(Size.from_MiB(1))
|
vol, queue = prepare_cache_and_core(Size.from_MiB(1))
|
||||||
data = Data(int(Size.from_KiB(c_uint16_randomize)))
|
data = Data(int(Size.from_KiB(c_uint16_randomize)))
|
||||||
completion = io_operation(core, data, IoDir.WRITE)
|
completion = io_operation(vol, queue, data, IoDir.WRITE)
|
||||||
|
|
||||||
if c_uint16_randomize > 1024:
|
if c_uint16_randomize > 1024:
|
||||||
assert completion.results["err"] != 0
|
assert completion.results["err"] != 0
|
||||||
@ -38,9 +40,9 @@ def test_neg_read_too_long_data(pyocf_ctx, c_uint16_randomize):
|
|||||||
Check if reading data larger than exported object size is properly blocked
|
Check if reading data larger than exported object size is properly blocked
|
||||||
"""
|
"""
|
||||||
|
|
||||||
core = prepare_cache_and_core(Size.from_MiB(1))
|
vol, queue = prepare_cache_and_core(Size.from_MiB(1))
|
||||||
data = Data(int(Size.from_KiB(c_uint16_randomize)))
|
data = Data(int(Size.from_KiB(c_uint16_randomize)))
|
||||||
completion = io_operation(core, data, IoDir.READ)
|
completion = io_operation(vol, queue, data, IoDir.READ)
|
||||||
|
|
||||||
if c_uint16_randomize > 1024:
|
if c_uint16_randomize > 1024:
|
||||||
assert completion.results["err"] != 0
|
assert completion.results["err"] != 0
|
||||||
@ -56,9 +58,9 @@ def test_neg_write_too_far(pyocf_ctx, c_uint16_randomize):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
limited_size = c_uint16_randomize % (int(Size.from_KiB(4)) + 1)
|
limited_size = c_uint16_randomize % (int(Size.from_KiB(4)) + 1)
|
||||||
core = prepare_cache_and_core(Size.from_MiB(4))
|
vol, queue = prepare_cache_and_core(Size.from_MiB(4))
|
||||||
data = Data(int(Size.from_KiB(limited_size)))
|
data = Data(int(Size.from_KiB(limited_size)))
|
||||||
completion = io_operation(core, data, IoDir.WRITE, int(Size.from_MiB(3)))
|
completion = io_operation(vol, queue, data, IoDir.WRITE, int(Size.from_MiB(3)))
|
||||||
|
|
||||||
if limited_size > 1024:
|
if limited_size > 1024:
|
||||||
assert completion.results["err"] != 0
|
assert completion.results["err"] != 0
|
||||||
@ -74,9 +76,9 @@ def test_neg_read_too_far(pyocf_ctx, c_uint16_randomize):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
limited_size = c_uint16_randomize % (int(Size.from_KiB(4)) + 1)
|
limited_size = c_uint16_randomize % (int(Size.from_KiB(4)) + 1)
|
||||||
core = prepare_cache_and_core(Size.from_MiB(4))
|
vol, queue = prepare_cache_and_core(Size.from_MiB(4))
|
||||||
data = Data(int(Size.from_KiB(limited_size)))
|
data = Data(int(Size.from_KiB(limited_size)))
|
||||||
completion = io_operation(core, data, IoDir.READ, offset=(Size.from_MiB(3)))
|
completion = io_operation(vol, queue, data, IoDir.READ, offset=(Size.from_MiB(3)))
|
||||||
|
|
||||||
if limited_size > 1024:
|
if limited_size > 1024:
|
||||||
assert completion.results["err"] != 0
|
assert completion.results["err"] != 0
|
||||||
@ -91,9 +93,9 @@ def test_neg_write_offset_outside_of_device(pyocf_ctx, c_int_sector_randomize):
|
|||||||
IO offset is located outside of device range
|
IO offset is located outside of device range
|
||||||
"""
|
"""
|
||||||
|
|
||||||
core = prepare_cache_and_core(Size.from_MiB(2))
|
vol, queue = prepare_cache_and_core(Size.from_MiB(2))
|
||||||
data = Data(int(Size.from_KiB(1)))
|
data = Data(int(Size.from_KiB(1)))
|
||||||
completion = io_operation(core, data, IoDir.WRITE, offset=c_int_sector_randomize)
|
completion = io_operation(vol, queue, data, IoDir.WRITE, offset=c_int_sector_randomize)
|
||||||
|
|
||||||
if 0 <= c_int_sector_randomize <= int(Size.from_MiB(2)) - int(Size.from_KiB(1)):
|
if 0 <= c_int_sector_randomize <= int(Size.from_MiB(2)) - int(Size.from_KiB(1)):
|
||||||
assert completion.results["err"] == 0
|
assert completion.results["err"] == 0
|
||||||
@ -108,9 +110,9 @@ def test_neg_read_offset_outside_of_device(pyocf_ctx, c_int_sector_randomize):
|
|||||||
IO offset is located outside of device range
|
IO offset is located outside of device range
|
||||||
"""
|
"""
|
||||||
|
|
||||||
core = prepare_cache_and_core(Size.from_MiB(2))
|
vol, queue = prepare_cache_and_core(Size.from_MiB(2))
|
||||||
data = Data(int(Size.from_KiB(1)))
|
data = Data(int(Size.from_KiB(1)))
|
||||||
completion = io_operation(core, data, IoDir.READ, offset=c_int_sector_randomize)
|
completion = io_operation(vol, queue, data, IoDir.READ, offset=c_int_sector_randomize)
|
||||||
|
|
||||||
if 0 <= c_int_sector_randomize <= int(Size.from_MiB(2)) - int(Size.from_KiB(1)):
|
if 0 <= c_int_sector_randomize <= int(Size.from_MiB(2)) - int(Size.from_KiB(1)):
|
||||||
assert completion.results["err"] == 0
|
assert completion.results["err"] == 0
|
||||||
@ -125,11 +127,11 @@ def test_neg_offset_unaligned(pyocf_ctx, c_int_randomize):
|
|||||||
IO offset is not aligned
|
IO offset is not aligned
|
||||||
"""
|
"""
|
||||||
|
|
||||||
core = prepare_cache_and_core(Size.from_MiB(2))
|
vol, queue = prepare_cache_and_core(Size.from_MiB(2))
|
||||||
data = Data(int(Size.from_KiB(1)))
|
data = Data(int(Size.from_KiB(1)))
|
||||||
if c_int_randomize % 512 != 0:
|
if c_int_randomize % 512 != 0:
|
||||||
with pytest.raises(Exception, match="Failed to create io!"):
|
with pytest.raises(Exception, match="Failed to create io!"):
|
||||||
core.new_io(core.cache.get_default_queue(), c_int_randomize, data.size,
|
vol.new_io(queue, c_int_randomize, data.size,
|
||||||
IoDir.WRITE, 0, 0)
|
IoDir.WRITE, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
@ -140,11 +142,11 @@ def test_neg_size_unaligned(pyocf_ctx, c_uint16_randomize):
|
|||||||
IO size is not aligned
|
IO size is not aligned
|
||||||
"""
|
"""
|
||||||
|
|
||||||
core = prepare_cache_and_core(Size.from_MiB(2))
|
vol, queue = prepare_cache_and_core(Size.from_MiB(2))
|
||||||
data = Data(int(Size.from_B(c_uint16_randomize)))
|
data = Data(int(Size.from_B(c_uint16_randomize)))
|
||||||
if c_uint16_randomize % 512 != 0:
|
if c_uint16_randomize % 512 != 0:
|
||||||
with pytest.raises(Exception, match="Failed to create io!"):
|
with pytest.raises(Exception, match="Failed to create io!"):
|
||||||
core.new_io(core.cache.get_default_queue(), 0, data.size,
|
vol.new_io(queue, 0, data.size,
|
||||||
IoDir.WRITE, 0, 0)
|
IoDir.WRITE, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
@ -155,9 +157,9 @@ def test_neg_io_class(pyocf_ctx, c_int_randomize):
|
|||||||
number is not in allowed values {0, ..., 32}
|
number is not in allowed values {0, ..., 32}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
core = prepare_cache_and_core(Size.from_MiB(2))
|
vol, queue = prepare_cache_and_core(Size.from_MiB(2))
|
||||||
data = Data(int(Size.from_MiB(1)))
|
data = Data(int(Size.from_MiB(1)))
|
||||||
completion = io_operation(core, data, randrange(0, 2), io_class=c_int_randomize)
|
completion = io_operation(vol, queue, data, randrange(0, 2), io_class=c_int_randomize)
|
||||||
|
|
||||||
if 0 <= c_int_randomize <= 32:
|
if 0 <= c_int_randomize <= 32:
|
||||||
assert completion.results["err"] == 0
|
assert completion.results["err"] == 0
|
||||||
@ -172,9 +174,9 @@ def test_neg_io_direction(pyocf_ctx, c_int_randomize):
|
|||||||
that is when IO direction value is not in allowed values {0, 1}
|
that is when IO direction value is not in allowed values {0, 1}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
core = prepare_cache_and_core(Size.from_MiB(2))
|
vol, queue = prepare_cache_and_core(Size.from_MiB(2))
|
||||||
data = Data(int(Size.from_MiB(1)))
|
data = Data(int(Size.from_MiB(1)))
|
||||||
completion = io_operation(core, data, c_int_randomize)
|
completion = io_operation(vol, queue, data, c_int_randomize)
|
||||||
|
|
||||||
if c_int_randomize in [0, 1]:
|
if c_int_randomize in [0, 1]:
|
||||||
assert completion.results["err"] == 0
|
assert completion.results["err"] == 0
|
||||||
@ -183,19 +185,28 @@ def test_neg_io_direction(pyocf_ctx, c_int_randomize):
|
|||||||
|
|
||||||
|
|
||||||
def prepare_cache_and_core(core_size: Size, cache_size: Size = Size.from_MiB(50)):
|
def prepare_cache_and_core(core_size: Size, cache_size: Size = Size.from_MiB(50)):
|
||||||
cache_device = Volume(cache_size)
|
cache_device = RamVolume(cache_size)
|
||||||
core_device = Volume(core_size)
|
core_device = RamVolume(core_size)
|
||||||
|
|
||||||
cache = Cache.start_on_device(cache_device)
|
cache = Cache.start_on_device(cache_device)
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
|
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
return core
|
vol = CoreVolume(core, open=True)
|
||||||
|
queue = cache.get_default_queue()
|
||||||
|
|
||||||
|
return vol, queue
|
||||||
|
|
||||||
|
|
||||||
def io_operation(core: Core, data: Data, io_direction: int, offset: int = 0, io_class: int = 0):
|
def io_operation(
|
||||||
io = core.new_io(core.cache.get_default_queue(), offset, data.size,
|
vol: Volume,
|
||||||
io_direction, io_class, 0)
|
queue: Queue,
|
||||||
|
data: Data,
|
||||||
|
io_direction: int,
|
||||||
|
offset: int = 0,
|
||||||
|
io_class: int = 0,
|
||||||
|
):
|
||||||
|
io = vol.new_io(queue, offset, data.size, io_direction, io_class, 0)
|
||||||
io.set_data(data)
|
io.set_data(data)
|
||||||
|
|
||||||
completion = OcfCompletion([("err", c_int)])
|
completion = OcfCompletion([("err", c_int)])
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright(c) 2019-2021 Intel Corporation
|
# Copyright(c) 2019-2022 Intel Corporation
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -8,7 +8,8 @@ from ctypes import c_int
|
|||||||
|
|
||||||
from pyocf.types.cache import Cache, CacheMode
|
from pyocf.types.cache import Cache, CacheMode
|
||||||
from pyocf.types.core import Core
|
from pyocf.types.core import Core
|
||||||
from pyocf.types.volume import Volume
|
from pyocf.types.volume import Volume, RamVolume
|
||||||
|
from pyocf.types.volume_core import CoreVolume
|
||||||
from pyocf.utils import Size as S
|
from pyocf.utils import Size as S
|
||||||
from pyocf.types.data import Data, DataOps
|
from pyocf.types.data import Data, DataOps
|
||||||
from pyocf.types.ctx import OcfCtx
|
from pyocf.types.ctx import OcfCtx
|
||||||
@ -75,18 +76,20 @@ def test_secure_erase_simple_io_read_misses(cache_mode):
|
|||||||
Cleaner,
|
Cleaner,
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx.register_volume_type(Volume)
|
ctx.register_volume_type(RamVolume)
|
||||||
|
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=cache_mode)
|
cache = Cache.start_on_device(cache_device, cache_mode=cache_mode)
|
||||||
|
|
||||||
core_device = Volume(S.from_MiB(50))
|
core_device = RamVolume(S.from_MiB(50))
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
|
queue = cache.get_default_queue()
|
||||||
|
|
||||||
write_data = DataCopyTracer(S.from_sector(1))
|
write_data = DataCopyTracer(S.from_sector(1))
|
||||||
io = core.new_io(
|
io = vol.new_io(
|
||||||
cache.get_default_queue(),
|
queue,
|
||||||
S.from_sector(1).B,
|
S.from_sector(1).B,
|
||||||
write_data.size,
|
write_data.size,
|
||||||
IoDir.WRITE,
|
IoDir.WRITE,
|
||||||
@ -103,8 +106,8 @@ def test_secure_erase_simple_io_read_misses(cache_mode):
|
|||||||
cmpls = []
|
cmpls = []
|
||||||
for i in range(100):
|
for i in range(100):
|
||||||
read_data = DataCopyTracer(S.from_sector(1))
|
read_data = DataCopyTracer(S.from_sector(1))
|
||||||
io = core.new_io(
|
io = vol.new_io(
|
||||||
cache.get_default_queue(),
|
queue,
|
||||||
i * S.from_sector(1).B,
|
i * S.from_sector(1).B,
|
||||||
read_data.size,
|
read_data.size,
|
||||||
IoDir.READ,
|
IoDir.READ,
|
||||||
@ -122,9 +125,7 @@ def test_secure_erase_simple_io_read_misses(cache_mode):
|
|||||||
c.wait()
|
c.wait()
|
||||||
|
|
||||||
write_data = DataCopyTracer.from_string("TEST DATA" * 100)
|
write_data = DataCopyTracer.from_string("TEST DATA" * 100)
|
||||||
io = core.new_io(
|
io = vol.new_io(queue, S.from_sector(1), write_data.size, IoDir.WRITE, 0, 0)
|
||||||
cache.get_default_queue(), S.from_sector(1), write_data.size, IoDir.WRITE, 0, 0
|
|
||||||
)
|
|
||||||
io.set_data(write_data)
|
io.set_data(write_data)
|
||||||
|
|
||||||
cmpl = OcfCompletion([("err", c_int)])
|
cmpl = OcfCompletion([("err", c_int)])
|
||||||
@ -147,7 +148,6 @@ def test_secure_erase_simple_io_read_misses(cache_mode):
|
|||||||
+ stats["req"]["rd_full_misses"]["value"]
|
+ stats["req"]["rd_full_misses"]["value"]
|
||||||
) > 0
|
) > 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.security
|
@pytest.mark.security
|
||||||
def test_secure_erase_simple_io_cleaning():
|
def test_secure_erase_simple_io_cleaning():
|
||||||
"""
|
"""
|
||||||
@ -168,19 +168,19 @@ def test_secure_erase_simple_io_cleaning():
|
|||||||
Cleaner,
|
Cleaner,
|
||||||
)
|
)
|
||||||
|
|
||||||
ctx.register_volume_type(Volume)
|
ctx.register_volume_type(RamVolume)
|
||||||
|
|
||||||
cache_device = Volume(S.from_MiB(50))
|
cache_device = RamVolume(S.from_MiB(50))
|
||||||
cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WB)
|
cache = Cache.start_on_device(cache_device, cache_mode=CacheMode.WB)
|
||||||
|
|
||||||
core_device = Volume(S.from_MiB(100))
|
core_device = RamVolume(S.from_MiB(100))
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
|
queue = cache.get_default_queue()
|
||||||
|
|
||||||
read_data = Data(S.from_sector(1).B)
|
read_data = Data(S.from_sector(1).B)
|
||||||
io = core.new_io(
|
io = vol.new_io(queue, S.from_sector(1).B, read_data.size, IoDir.WRITE, 0, 0)
|
||||||
cache.get_default_queue(), S.from_sector(1).B, read_data.size, IoDir.WRITE, 0, 0
|
|
||||||
)
|
|
||||||
io.set_data(read_data)
|
io.set_data(read_data)
|
||||||
|
|
||||||
cmpl = OcfCompletion([("err", c_int)])
|
cmpl = OcfCompletion([("err", c_int)])
|
||||||
@ -189,9 +189,7 @@ def test_secure_erase_simple_io_cleaning():
|
|||||||
cmpl.wait()
|
cmpl.wait()
|
||||||
|
|
||||||
read_data = Data(S.from_sector(8).B)
|
read_data = Data(S.from_sector(8).B)
|
||||||
io = core.new_io(
|
io = vol.new_io(queue, S.from_sector(1).B, read_data.size, IoDir.READ, 0, 0)
|
||||||
cache.get_default_queue(), S.from_sector(1).B, read_data.size, IoDir.READ, 0, 0
|
|
||||||
)
|
|
||||||
io.set_data(read_data)
|
io.set_data(read_data)
|
||||||
|
|
||||||
cmpl = OcfCompletion([("err", c_int)])
|
cmpl = OcfCompletion([("err", c_int)])
|
||||||
|
@ -17,7 +17,8 @@ from pyocf.types.cache import (
|
|||||||
)
|
)
|
||||||
from pyocf.types.data import Data
|
from pyocf.types.data import Data
|
||||||
from pyocf.types.core import Core
|
from pyocf.types.core import Core
|
||||||
from pyocf.types.volume import ErrorDevice, Volume
|
from pyocf.types.volume import ErrorDevice, RamVolume, VOLUME_POISON
|
||||||
|
from pyocf.types.volume_core import CoreVolume
|
||||||
from pyocf.types.io import IoDir
|
from pyocf.types.io import IoDir
|
||||||
from pyocf.types.ioclass import IoClassesInfo, IoClassInfo
|
from pyocf.types.ioclass import IoClassesInfo, IoClassInfo
|
||||||
from pyocf.utils import Size as S
|
from pyocf.utils import Size as S
|
||||||
@ -34,20 +35,20 @@ mngmt_op_surprise_shutdown_test_cache_size = S.from_MiB(40)
|
|||||||
mngmt_op_surprise_shutdown_test_io_offset = S.from_MiB(4).B
|
mngmt_op_surprise_shutdown_test_io_offset = S.from_MiB(4).B
|
||||||
|
|
||||||
|
|
||||||
def ocf_write(cache, core, val, offset):
|
def ocf_write(vol, queue, val, offset):
|
||||||
data = Data.from_bytes(bytes([val] * 512))
|
data = Data.from_bytes(bytes([val] * 512))
|
||||||
comp = OcfCompletion([("error", c_int)])
|
comp = OcfCompletion([("error", c_int)])
|
||||||
io = core.new_io(cache.get_default_queue(), offset, 512, IoDir.WRITE, 0, 0)
|
io = vol.new_io(queue, offset, 512, IoDir.WRITE, 0, 0)
|
||||||
io.set_data(data)
|
io.set_data(data)
|
||||||
io.callback = comp.callback
|
io.callback = comp.callback
|
||||||
io.submit()
|
io.submit()
|
||||||
comp.wait()
|
comp.wait()
|
||||||
|
|
||||||
|
|
||||||
def ocf_read(cache, core, offset):
|
def ocf_read(vol, queue, offset):
|
||||||
data = Data(byte_count=512)
|
data = Data(byte_count=512)
|
||||||
comp = OcfCompletion([("error", c_int)])
|
comp = OcfCompletion([("error", c_int)])
|
||||||
io = core.new_io(cache.get_default_queue(), offset, 512, IoDir.READ, 0, 0)
|
io = vol.new_io(queue, offset, 512, IoDir.READ, 0, 0)
|
||||||
io.set_data(data)
|
io.set_data(data)
|
||||||
io.callback = comp.callback
|
io.callback = comp.callback
|
||||||
io.submit()
|
io.submit()
|
||||||
@ -118,7 +119,7 @@ def mngmt_op_surprise_shutdown_test(
|
|||||||
# power failure during core insert
|
# power failure during core insert
|
||||||
@pytest.mark.security
|
@pytest.mark.security
|
||||||
def test_surprise_shutdown_add_core(pyocf_ctx):
|
def test_surprise_shutdown_add_core(pyocf_ctx):
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
|
|
||||||
def check_core(cache, error_triggered):
|
def check_core(cache, error_triggered):
|
||||||
stats = cache.get_stats()
|
stats = cache.get_stats()
|
||||||
@ -138,7 +139,7 @@ def test_surprise_shutdown_add_core(pyocf_ctx):
|
|||||||
@pytest.mark.security
|
@pytest.mark.security
|
||||||
@pytest.mark.long
|
@pytest.mark.long
|
||||||
def test_surprise_shutdown_remove_core(pyocf_ctx):
|
def test_surprise_shutdown_remove_core(pyocf_ctx):
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core.using_device(core_device)
|
core = Core.using_device(core_device)
|
||||||
|
|
||||||
def prepare_func(cache):
|
def prepare_func(cache):
|
||||||
@ -158,12 +159,13 @@ def test_surprise_shutdown_remove_core(pyocf_ctx):
|
|||||||
@pytest.mark.long
|
@pytest.mark.long
|
||||||
def test_surprise_shutdown_remove_core_with_data(pyocf_ctx):
|
def test_surprise_shutdown_remove_core_with_data(pyocf_ctx):
|
||||||
io_offset = mngmt_op_surprise_shutdown_test_io_offset
|
io_offset = mngmt_op_surprise_shutdown_test_io_offset
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core.using_device(core_device, name="core1")
|
core = Core.using_device(core_device, name="core1")
|
||||||
|
|
||||||
def prepare_func(cache):
|
def prepare_func(cache):
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
ocf_write(cache, core, 0xAA, io_offset)
|
vol = CoreVolume(core, open=True)
|
||||||
|
ocf_write(vol, cache.get_default_queue(), 0xAA, io_offset)
|
||||||
|
|
||||||
def tested_func(cache):
|
def tested_func(cache):
|
||||||
cache.flush()
|
cache.flush()
|
||||||
@ -175,7 +177,8 @@ def test_surprise_shutdown_remove_core_with_data(pyocf_ctx):
|
|||||||
assert core_device.get_bytes()[io_offset] == 0xAA
|
assert core_device.get_bytes()[io_offset] == 0xAA
|
||||||
else:
|
else:
|
||||||
core = cache.get_core_by_name("core1")
|
core = cache.get_core_by_name("core1")
|
||||||
assert ocf_read(cache, core, io_offset) == 0xAA
|
vol = CoreVolume(core, open=True)
|
||||||
|
assert ocf_read(vol, cache.get_default_queue(), io_offset) == 0xAA
|
||||||
|
|
||||||
mngmt_op_surprise_shutdown_test(pyocf_ctx, tested_func, prepare_func, check_func)
|
mngmt_op_surprise_shutdown_test(pyocf_ctx, tested_func, prepare_func, check_func)
|
||||||
|
|
||||||
@ -184,8 +187,8 @@ def test_surprise_shutdown_remove_core_with_data(pyocf_ctx):
|
|||||||
@pytest.mark.security
|
@pytest.mark.security
|
||||||
@pytest.mark.long
|
@pytest.mark.long
|
||||||
def test_surprise_shutdown_swap_core(pyocf_ctx):
|
def test_surprise_shutdown_swap_core(pyocf_ctx):
|
||||||
core_device_1 = Volume(S.from_MiB(10), uuid="dev1")
|
core_device_1 = RamVolume(S.from_MiB(10), uuid="dev1")
|
||||||
core_device_2 = Volume(S.from_MiB(10), uuid="dev2")
|
core_device_2 = RamVolume(S.from_MiB(10), uuid="dev2")
|
||||||
core1 = Core.using_device(core_device_1, name="core1")
|
core1 = Core.using_device(core_device_1, name="core1")
|
||||||
core2 = Core.using_device(core_device_2, name="core2")
|
core2 = Core.using_device(core_device_2, name="core2")
|
||||||
|
|
||||||
@ -219,15 +222,16 @@ def test_surprise_shutdown_swap_core(pyocf_ctx):
|
|||||||
@pytest.mark.security
|
@pytest.mark.security
|
||||||
@pytest.mark.long
|
@pytest.mark.long
|
||||||
def test_surprise_shutdown_swap_core_with_data(pyocf_ctx):
|
def test_surprise_shutdown_swap_core_with_data(pyocf_ctx):
|
||||||
core_device_1 = Volume(S.from_MiB(10), uuid="dev1")
|
core_device_1 = RamVolume(S.from_MiB(10), uuid="dev1")
|
||||||
core_device_2 = Volume(S.from_MiB(10), uuid="dev2")
|
core_device_2 = RamVolume(S.from_MiB(10), uuid="dev2")
|
||||||
core1 = Core.using_device(core_device_1, name="core1")
|
core1 = Core.using_device(core_device_1, name="core1")
|
||||||
core2 = Core.using_device(core_device_2, name="core2")
|
core2 = Core.using_device(core_device_2, name="core2")
|
||||||
|
|
||||||
def prepare(cache):
|
def prepare(cache):
|
||||||
cache.add_core(core1)
|
cache.add_core(core1)
|
||||||
|
vol = CoreVolume(core1, open=True)
|
||||||
cache.save()
|
cache.save()
|
||||||
ocf_write(cache, core1, 0xAA, mngmt_op_surprise_shutdown_test_io_offset)
|
ocf_write(vol, cache.get_default_queue(), 0xAA, mngmt_op_surprise_shutdown_test_io_offset)
|
||||||
cache.remove_core(core1)
|
cache.remove_core(core1)
|
||||||
cache.save()
|
cache.save()
|
||||||
|
|
||||||
@ -249,10 +253,11 @@ def test_surprise_shutdown_swap_core_with_data(pyocf_ctx):
|
|||||||
core2 = cache.get_core_by_name("core2")
|
core2 = cache.get_core_by_name("core2")
|
||||||
|
|
||||||
if core2 is not None:
|
if core2 is not None:
|
||||||
|
vol2 = CoreVolume(core2, open=True)
|
||||||
assert core2.device.uuid == "dev2"
|
assert core2.device.uuid == "dev2"
|
||||||
assert (
|
assert (
|
||||||
ocf_read(cache, core2, mngmt_op_surprise_shutdown_test_io_offset)
|
ocf_read(vol2, cache.get_default_queue(), mngmt_op_surprise_shutdown_test_io_offset)
|
||||||
== Volume.VOLUME_POISON
|
== VOLUME_POISON
|
||||||
)
|
)
|
||||||
|
|
||||||
mngmt_op_surprise_shutdown_test(pyocf_ctx, tested_func, prepare, check_func)
|
mngmt_op_surprise_shutdown_test(pyocf_ctx, tested_func, prepare, check_func)
|
||||||
@ -312,7 +317,7 @@ def test_surprise_shutdown_start_cache(pyocf_ctx):
|
|||||||
@pytest.mark.security
|
@pytest.mark.security
|
||||||
@pytest.mark.long
|
@pytest.mark.long
|
||||||
def test_surprise_shutdown_stop_cache(pyocf_ctx):
|
def test_surprise_shutdown_stop_cache(pyocf_ctx):
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
error_triggered = True
|
error_triggered = True
|
||||||
error_io_seq_no = 0
|
error_io_seq_no = 0
|
||||||
io_offset = mngmt_op_surprise_shutdown_test_io_offset
|
io_offset = mngmt_op_surprise_shutdown_test_io_offset
|
||||||
@ -328,7 +333,8 @@ def test_surprise_shutdown_stop_cache(pyocf_ctx):
|
|||||||
cache = Cache.start_on_device(device, cache_mode=CacheMode.WB)
|
cache = Cache.start_on_device(device, cache_mode=CacheMode.WB)
|
||||||
core = Core(device=core_device)
|
core = Core(device=core_device)
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
ocf_write(cache, core, 0xAA, io_offset)
|
vol = CoreVolume(core, open=True)
|
||||||
|
ocf_write(vol, cache.get_default_queue(), 0xAA, io_offset)
|
||||||
|
|
||||||
# start error injection
|
# start error injection
|
||||||
device.arm()
|
device.arm()
|
||||||
@ -353,7 +359,7 @@ def test_surprise_shutdown_stop_cache(pyocf_ctx):
|
|||||||
device.disarm()
|
device.disarm()
|
||||||
cache = None
|
cache = None
|
||||||
|
|
||||||
assert core_device.get_bytes()[io_offset] == Volume.VOLUME_POISON
|
assert core_device.get_bytes()[io_offset] == VOLUME_POISON
|
||||||
|
|
||||||
cache = Cache.load_from_device(device, open_cores=False)
|
cache = Cache.load_from_device(device, open_cores=False)
|
||||||
stats = cache.get_stats()
|
stats = cache.get_stats()
|
||||||
@ -361,7 +367,8 @@ def test_surprise_shutdown_stop_cache(pyocf_ctx):
|
|||||||
assert stats["usage"]["occupancy"]["value"] == 1
|
assert stats["usage"]["occupancy"]["value"] == 1
|
||||||
core = Core(device=core_device)
|
core = Core(device=core_device)
|
||||||
cache.add_core(core, try_add=True)
|
cache.add_core(core, try_add=True)
|
||||||
assert ocf_read(cache, core, io_offset) == 0xAA
|
vol = CoreVolume(core, open=True)
|
||||||
|
assert ocf_read(vol, cache.get_default_queue(), io_offset) == 0xAA
|
||||||
|
|
||||||
cache.stop()
|
cache.stop()
|
||||||
|
|
||||||
@ -371,7 +378,7 @@ def test_surprise_shutdown_stop_cache(pyocf_ctx):
|
|||||||
|
|
||||||
@pytest.mark.security
|
@pytest.mark.security
|
||||||
def test_surprise_shutdown_cache_reinit(pyocf_ctx):
|
def test_surprise_shutdown_cache_reinit(pyocf_ctx):
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
|
|
||||||
error_io = {IoDir.WRITE: 0}
|
error_io = {IoDir.WRITE: 0}
|
||||||
|
|
||||||
@ -388,13 +395,15 @@ def test_surprise_shutdown_cache_reinit(pyocf_ctx):
|
|||||||
cache = Cache.start_on_device(device, cache_mode=CacheMode.WB)
|
cache = Cache.start_on_device(device, cache_mode=CacheMode.WB)
|
||||||
core = Core(device=core_device)
|
core = Core(device=core_device)
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
|
vol = CoreVolume(core, open=True)
|
||||||
|
queue = cache.get_default_queue()
|
||||||
|
|
||||||
# insert dirty cacheline
|
# insert dirty cacheline
|
||||||
ocf_write(cache, core, 0xAA, io_offset)
|
ocf_write(vol, queue, 0xAA, io_offset)
|
||||||
|
|
||||||
cache.stop()
|
cache.stop()
|
||||||
|
|
||||||
assert core_device.get_bytes()[io_offset] == Volume.VOLUME_POISON
|
assert core_device.get_bytes()[io_offset] == VOLUME_POISON
|
||||||
|
|
||||||
# start error injection
|
# start error injection
|
||||||
device.arm()
|
device.arm()
|
||||||
@ -432,7 +441,8 @@ def test_surprise_shutdown_cache_reinit(pyocf_ctx):
|
|||||||
if stats["conf"]["core_count"] == 0:
|
if stats["conf"]["core_count"] == 0:
|
||||||
assert stats["usage"]["occupancy"]["value"] == 0
|
assert stats["usage"]["occupancy"]["value"] == 0
|
||||||
cache.add_core(core)
|
cache.add_core(core)
|
||||||
assert ocf_read(cache, core, io_offset) == Volume.VOLUME_POISON
|
vol = CoreVolume(core, open=True)
|
||||||
|
assert ocf_read(vol, cache.get_default_queue(), io_offset) == VOLUME_POISON
|
||||||
|
|
||||||
cache.stop()
|
cache.stop()
|
||||||
|
|
||||||
@ -440,7 +450,7 @@ def test_surprise_shutdown_cache_reinit(pyocf_ctx):
|
|||||||
|
|
||||||
|
|
||||||
def _test_surprise_shutdown_mngmt_generic(pyocf_ctx, func):
|
def _test_surprise_shutdown_mngmt_generic(pyocf_ctx, func):
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core(device=core_device)
|
core = Core(device=core_device)
|
||||||
|
|
||||||
def prepare(cache):
|
def prepare(cache):
|
||||||
@ -464,7 +474,7 @@ def test_surprise_shutdown_change_cache_mode(pyocf_ctx):
|
|||||||
@pytest.mark.security
|
@pytest.mark.security
|
||||||
@pytest.mark.long
|
@pytest.mark.long
|
||||||
def test_surprise_shutdown_set_cleaning_policy(pyocf_ctx):
|
def test_surprise_shutdown_set_cleaning_policy(pyocf_ctx):
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core(device=core_device)
|
core = Core(device=core_device)
|
||||||
|
|
||||||
for c1 in CleaningPolicy:
|
for c1 in CleaningPolicy:
|
||||||
@ -485,7 +495,7 @@ def test_surprise_shutdown_set_cleaning_policy(pyocf_ctx):
|
|||||||
@pytest.mark.security
|
@pytest.mark.security
|
||||||
@pytest.mark.long
|
@pytest.mark.long
|
||||||
def test_surprise_shutdown_set_seq_cut_off_policy(pyocf_ctx):
|
def test_surprise_shutdown_set_seq_cut_off_policy(pyocf_ctx):
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core(device=core_device)
|
core = Core(device=core_device)
|
||||||
|
|
||||||
for s1 in SeqCutOffPolicy:
|
for s1 in SeqCutOffPolicy:
|
||||||
@ -522,7 +532,7 @@ def test_surprise_shutdown_set_seq_cut_off_threshold(pyocf_ctx):
|
|||||||
@pytest.mark.security
|
@pytest.mark.security
|
||||||
@pytest.mark.long
|
@pytest.mark.long
|
||||||
def test_surprise_shutdown_set_cleaning_policy_param(pyocf_ctx):
|
def test_surprise_shutdown_set_cleaning_policy_param(pyocf_ctx):
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core(device=core_device)
|
core = Core(device=core_device)
|
||||||
|
|
||||||
for pol in CleaningPolicy:
|
for pol in CleaningPolicy:
|
||||||
@ -574,7 +584,7 @@ def test_surprise_shutdown_set_cleaning_policy_param(pyocf_ctx):
|
|||||||
@pytest.mark.security
|
@pytest.mark.security
|
||||||
@pytest.mark.long
|
@pytest.mark.long
|
||||||
def test_surprise_shutdown_set_promotion_policy(pyocf_ctx):
|
def test_surprise_shutdown_set_promotion_policy(pyocf_ctx):
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core(device=core_device)
|
core = Core(device=core_device)
|
||||||
|
|
||||||
for pp1 in PromotionPolicy:
|
for pp1 in PromotionPolicy:
|
||||||
@ -595,7 +605,7 @@ def test_surprise_shutdown_set_promotion_policy(pyocf_ctx):
|
|||||||
@pytest.mark.security
|
@pytest.mark.security
|
||||||
@pytest.mark.long
|
@pytest.mark.long
|
||||||
def test_surprise_shutdown_set_promotion_policy_param(pyocf_ctx):
|
def test_surprise_shutdown_set_promotion_policy_param(pyocf_ctx):
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core(device=core_device)
|
core = Core(device=core_device)
|
||||||
|
|
||||||
for pp in PromotionPolicy:
|
for pp in PromotionPolicy:
|
||||||
@ -633,7 +643,7 @@ def test_surprise_shutdown_set_promotion_policy_param(pyocf_ctx):
|
|||||||
@pytest.mark.security
|
@pytest.mark.security
|
||||||
@pytest.mark.long
|
@pytest.mark.long
|
||||||
def test_surprise_shutdown_set_io_class_config(pyocf_ctx):
|
def test_surprise_shutdown_set_io_class_config(pyocf_ctx):
|
||||||
core_device = Volume(S.from_MiB(10))
|
core_device = RamVolume(S.from_MiB(10))
|
||||||
core = Core(device=core_device)
|
core = Core(device=core_device)
|
||||||
|
|
||||||
class_range = range(0, IoClassesInfo.MAX_IO_CLASSES)
|
class_range = range(0, IoClassesInfo.MAX_IO_CLASSES)
|
||||||
|
Loading…
Reference in New Issue
Block a user