2 # Copyright(c) 2019 Intel Corporation
3 # SPDX-License-Identifier: BSD-3-Clause-Clear
20 from enum
import IntEnum
21 from datetime
import timedelta
23 from ..ocf
import OcfLib
32 from ..utils
import Size
, struct_to_dict
33 from .core
import Core
34 from .queue
import Queue
35 from .stats
.cache
import CacheInfo
36 from .stats
.shared
import UsageStats
, RequestsStats
, BlocksStats
, ErrorsStats
39 class Backfill(Structure
):
40 _fields_
= [("_max_queue_size", c_uint32
), ("_queue_unblock_size", c_uint32
)]
43 class CacheConfig(Structure
):
47 ("_cache_mode", c_uint32
),
48 ("_eviction_policy", c_uint32
),
49 ("_cache_line_size", c_uint64
),
50 ("_metadata_layout", c_uint32
),
51 ("_metadata_volatile", c_bool
),
52 ("_backfill", Backfill
),
54 ("_pt_unaligned_io", c_bool
),
55 ("_use_submit_io_fast", c_bool
),
59 class CacheDeviceConfig(Structure
):
62 ("_volume_type", c_uint8
),
63 ("_cache_line_size", c_uint64
),
65 ("_min_free_ram", c_uint64
),
66 ("_perform_test", c_bool
),
67 ("_discard_on_start", c_bool
),
71 class CacheMode(IntEnum
):
80 class EvictionPolicy(IntEnum
):
85 class CleaningPolicy(IntEnum
):
92 class AlruParams(IntEnum
):
96 ACTIVITY_THRESHOLD
= 3
99 class AcpParams(IntEnum
):
101 FLUSH_MAX_BUFFERS
= 1
104 class MetadataLayout(IntEnum
):
112 DEFAULT_BACKFILL_QUEUE_SIZE
= 65536
113 DEFAULT_BACKFILL_UNBLOCK
= 60000
114 DEFAULT_PT_UNALIGNED_IO
= False
115 DEFAULT_USE_SUBMIT_FAST
= False
120 cache_id
: int = DEFAULT_ID
,
122 cache_mode
: CacheMode
= CacheMode
.DEFAULT
,
123 eviction_policy
: EvictionPolicy
= EvictionPolicy
.DEFAULT
,
124 cache_line_size
: CacheLineSize
= CacheLineSize
.DEFAULT
,
125 metadata_layout
: MetadataLayout
= MetadataLayout
.DEFAULT
,
126 metadata_volatile
: bool = False,
127 max_queue_size
: int = DEFAULT_BACKFILL_QUEUE_SIZE
,
128 queue_unblock_size
: int = DEFAULT_BACKFILL_UNBLOCK
,
129 locked
: bool = False,
130 pt_unaligned_io
: bool = DEFAULT_PT_UNALIGNED_IO
,
131 use_submit_fast
: bool = DEFAULT_USE_SUBMIT_FAST
,
136 self
.cache_line_size
= cache_line_size
138 self
.cfg
= CacheConfig(
140 _name
=name
.encode("ascii") if name
else None,
141 _cache_mode
=cache_mode
,
142 _eviction_policy
=eviction_policy
,
143 _cache_line_size
=cache_line_size
,
144 _metadata_layout
=metadata_layout
,
145 _metadata_volatile
=metadata_volatile
,
147 _max_queue_size
=max_queue_size
,
148 _queue_unblock_size
=queue_unblock_size
,
151 _pt_unaligned_io
=pt_unaligned_io
,
152 _use_submit_fast
=use_submit_fast
,
154 self
.cache_handle
= c_void_p()
155 self
._as
_parameter
_ = self
.cache_handle
161 self
, default_io_queue
: Queue
= None, mngt_queue
: Queue
= None
163 status
= self
.owner
.lib
.ocf_mngt_cache_start(
164 self
.owner
.ctx_handle
, byref(self
.cache_handle
), byref(self
.cfg
)
167 raise OcfError("Creating cache instance failed", status
)
168 self
.owner
.caches
.append(self
)
170 self
.mngt_queue
= mngt_queue
or Queue(
171 self
, "mgmt-{}".format(self
.get_name()), mngt_queue
=True
175 self
.io_queues
+= [default_io_queue
]
178 Queue(self
, "default-io-{}".format(self
.get_name()))
181 status
= self
.owner
.lib
.ocf_mngt_cache_set_mngt_queue(
182 self
, self
.mngt_queue
185 raise OcfError("Error setting management queue", status
)
189 def change_cache_mode(self
, cache_mode
: CacheMode
):
190 self
.get_and_write_lock()
191 status
= self
.owner
.lib
.ocf_mngt_cache_set_mode(
192 self
.cache_handle
, cache_mode
196 self
.put_and_write_unlock()
197 raise OcfError("Error changing cache mode", status
)
199 self
.put_and_write_unlock()
201 def set_cleaning_policy(self
, cleaning_policy
: CleaningPolicy
):
202 self
.get_and_write_lock()
204 status
= self
.owner
.lib
.ocf_mngt_cache_cleaning_set_policy(
205 self
.cache_handle
, cleaning_policy
208 self
.put_and_write_unlock()
209 raise OcfError("Error changing cleaning policy", status
)
211 self
.put_and_write_unlock()
213 def set_cleaning_policy_param(
214 self
, cleaning_policy
: CleaningPolicy
, param_id
, param_value
216 self
.get_and_write_lock()
218 status
= self
.owner
.lib
.ocf_mngt_cache_cleaning_set_param(
219 self
.cache_handle
, cleaning_policy
, param_id
, param_value
222 self
.put_and_write_unlock()
223 raise OcfError("Error setting cleaning policy param", status
)
225 self
.put_and_write_unlock()
227 def set_seq_cut_off_policy(self
, policy
: SeqCutOffPolicy
):
228 self
.get_and_write_lock()
230 status
= self
.owner
.lib
.ocf_mngt_core_set_seq_cutoff_policy_all(
231 self
.cache_handle
, policy
234 self
.put_and_write_unlock()
235 raise OcfError("Error setting cache seq cut off policy", status
)
237 self
.put_and_write_unlock()
239 def configure_device(
240 self
, device
, force
=False, perform_test
=False, cache_line_size
=None
243 self
.device_name
= device
.uuid
244 self
.dev_cfg
= CacheDeviceConfig(
247 create_string_buffer(self
.device_name
.encode("ascii")),
250 _size
=len(self
.device_name
) + 1,
252 _volume_type
=device
.type_id
,
253 _cache_line_size
=cache_line_size
255 else self
.cache_line_size
,
258 _perform_test
=perform_test
,
259 _discard_on_start
=False,
263 self
, device
, force
=False, perform_test
=False, cache_line_size
=None
265 self
.configure_device(device
, force
, perform_test
, cache_line_size
)
266 self
.get_and_write_lock()
269 [("cache", c_void_p
), ("priv", c_void_p
), ("error", c_int
)]
272 device
.owner
.lib
.ocf_mngt_cache_attach(
273 self
.cache_handle
, byref(self
.dev_cfg
), c
, None
277 if c
.results
["error"]:
278 self
.put_and_write_unlock()
279 raise OcfError("Attaching cache device failed", c
.results
["error"])
281 self
.put_and_write_unlock()
283 def load_cache(self
, device
):
284 self
.configure_device(device
)
286 [("cache", c_void_p
), ("priv", c_void_p
), ("error", c_int
)]
288 device
.owner
.lib
.ocf_mngt_cache_load(
289 self
.cache_handle
, byref(self
.dev_cfg
), c
, None
293 if c
.results
["error"]:
294 raise OcfError("Loading cache device failed", c
.results
["error"])
297 def load_from_device(cls
, device
, name
=""):
298 c
= cls(name
=name
, owner
=device
.owner
)
305 def start_on_device(cls
, device
, **kwargs
):
306 c
= cls(locked
=True, owner
=device
.owner
, **kwargs
)
310 c
.attach_device(device
, force
=True)
317 def _get_and_lock(self
, read
=True):
321 status
= self
.owner
.lib
.ocf_mngt_cache_read_lock(self
.cache_handle
)
323 status
= self
.owner
.lib
.ocf_mngt_cache_lock(self
.cache_handle
)
327 raise OcfError("Couldn't lock cache instance", status
)
329 def _put_and_unlock(self
, read
=True):
331 self
.owner
.lib
.ocf_mngt_cache_read_unlock(self
.cache_handle
)
333 self
.owner
.lib
.ocf_mngt_cache_unlock(self
.cache_handle
)
338 self
.owner
.lib
.ocf_mngt_cache_put(self
.cache_handle
)
341 status
= self
.owner
.lib
.ocf_mngt_cache_get(self
.cache_handle
)
343 raise OcfError("Couldn't get cache instance", status
)
345 def get_and_read_lock(self
):
346 self
._get
_and
_lock
(True)
348 def get_and_write_lock(self
):
349 self
._get
_and
_lock
(False)
351 def put_and_read_unlock(self
):
352 self
._put
_and
_unlock
(True)
354 def put_and_write_unlock(self
):
355 self
._put
_and
_unlock
(False)
357 def add_core(self
, core
: Core
):
358 self
.get_and_write_lock()
369 self
.owner
.lib
.ocf_mngt_cache_add_core(
370 self
.cache_handle
, byref(core
.get_cfg()), c
, None
374 if c
.results
["error"]:
375 self
.put_and_write_unlock()
376 raise OcfError("Failed adding core", c
.results
["error"])
379 core
.handle
= c
.results
["core"]
380 self
.cores
.append(core
)
382 self
.put_and_write_unlock()
384 def remove_core(self
, core
: Core
):
385 self
.get_and_write_lock()
387 c
= OcfCompletion([("priv", c_void_p
), ("error", c_int
)])
389 self
.owner
.lib
.ocf_mngt_cache_remove_core(core
.handle
, c
, None)
392 if c
.results
["error"]:
393 self
.put_and_write_unlock()
394 raise OcfError("Failed removing core", c
.results
["error"])
396 self
.cores
.remove(core
)
398 self
.put_and_write_unlock()
401 cache_info
= CacheInfo()
403 req
= RequestsStats()
404 block
= BlocksStats()
405 errors
= ErrorsStats()
407 self
.get_and_read_lock()
409 status
= self
.owner
.lib
.ocf_cache_get_info(
410 self
.cache_handle
, byref(cache_info
)
413 self
.put_and_read_unlock()
414 raise OcfError("Failed getting cache info", status
)
416 status
= self
.owner
.lib
.ocf_stats_collect_cache(
424 self
.put_and_read_unlock()
425 raise OcfError("Failed getting stats", status
)
427 line_size
= CacheLineSize(cache_info
.cache_line_size
)
429 self
.put_and_read_unlock()
432 "attached": cache_info
.attached
,
433 "volume_type": self
.owner
.volume_types
[cache_info
.volume_type
],
434 "size": CacheLines(cache_info
.size
, line_size
),
436 "occupancy": CacheLines(
437 cache_info
.inactive
.occupancy
, line_size
439 "dirty": CacheLines(cache_info
.inactive
.dirty
, line_size
),
441 "occupancy": CacheLines(cache_info
.occupancy
, line_size
),
442 "dirty": CacheLines(cache_info
.dirty
, line_size
),
443 "dirty_initial": CacheLines(cache_info
.dirty_initial
, line_size
),
444 "dirty_for": timedelta(seconds
=cache_info
.dirty_for
),
445 "cache_mode": CacheMode(cache_info
.cache_mode
),
447 "error_counter": cache_info
.fallback_pt
.error_counter
,
448 "status": cache_info
.fallback_pt
.status
,
450 "state": cache_info
.state
,
451 "eviction_policy": EvictionPolicy(cache_info
.eviction_policy
),
452 "cleaning_policy": CleaningPolicy(cache_info
.cleaning_policy
),
453 "cache_line_size": line_size
,
454 "flushed": CacheLines(cache_info
.flushed
, line_size
),
455 "core_count": cache_info
.core_count
,
456 "metadata_footprint": Size(cache_info
.metadata_footprint
),
457 "metadata_end_offset": Size(cache_info
.metadata_end_offset
),
459 "block": struct_to_dict(block
),
460 "req": struct_to_dict(req
),
461 "usage": struct_to_dict(usage
),
462 "errors": struct_to_dict(errors
),
465 def reset_stats(self
):
466 self
.owner
.lib
.ocf_core_stats_initialize_all(self
.cache_handle
)
468 def get_default_queue(self
):
469 if not self
.io_queues
:
470 raise Exception("No queues added for cache")
472 return self
.io_queues
[0]
476 raise Exception("Already stopped!")
478 self
.get_and_write_lock()
481 [("cache", c_void_p
), ("priv", c_void_p
), ("error", c_int
)]
484 self
.owner
.lib
.ocf_cache_wait_for_io_finish(self
.cache_handle
)
485 self
.owner
.lib
.ocf_mngt_cache_stop(self
.cache_handle
, c
, None)
488 if c
.results
["error"]:
489 self
.put_and_write_unlock()
490 raise OcfError("Failed stopping cache", c
.results
["error"])
492 self
.mngt_queue
.stop()
493 del self
.io_queues
[:]
496 self
.put_and_write_unlock()
499 self
.owner
.caches
.remove(self
)
502 self
.get_and_write_lock()
505 [("cache", c_void_p
), ("priv", c_void_p
), ("error", c_int
)]
507 self
.owner
.lib
.ocf_mngt_cache_flush(self
.cache_handle
, False, c
, None)
509 if c
.results
["error"]:
510 self
.put_and_write_unlock()
511 raise OcfError("Couldn't flush cache", c
.results
["error"])
513 self
.put_and_write_unlock()
516 self
.get_and_read_lock()
519 return str(self
.owner
.lib
.ocf_cache_get_name(self
), encoding
="ascii")
521 raise OcfError("Couldn't get cache name")
523 self
.put_and_read_unlock()
526 lib
= OcfLib
.getInstance()
527 lib
.ocf_mngt_cache_remove_core
.argtypes
= [c_void_p
, c_void_p
, c_void_p
]
528 lib
.ocf_mngt_cache_add_core
.argtypes
= [c_void_p
, c_void_p
, c_void_p
, c_void_p
]
529 lib
.ocf_cache_get_name
.argtypes
= [c_void_p
]
530 lib
.ocf_cache_get_name
.restype
= c_char_p
531 lib
.ocf_mngt_cache_cleaning_set_policy
.argtypes
= [c_void_p
, c_uint32
]
532 lib
.ocf_mngt_cache_cleaning_set_policy
.restype
= c_int
533 lib
.ocf_mngt_core_set_seq_cutoff_policy_all
.argtypes
= [c_void_p
, c_uint32
]
534 lib
.ocf_mngt_core_set_seq_cutoff_policy_all
.restype
= c_int
535 lib
.ocf_mngt_cache_cleaning_set_param
.argtypes
= [
541 lib
.ocf_mngt_cache_cleaning_set_param
.restype
= c_int