pyocf: simplify volume open/close API

Make Volumes usable by both pyocf and OCF with clear open/_open split
and clean-up of instance/uuid tracking on C interface only.

Signed-off-by: Jan Musial <jan.musial@intel.com>
This commit is contained in:
Jan Musial
2022-06-20 09:44:21 +02:00
parent b1b3e134cf
commit b3bd778a78
5 changed files with 74 additions and 55 deletions

View File

@@ -58,13 +58,20 @@ class CVolume(OcfInternalVolume):
def get_c_handle(self):
return self.cvol.value
def do_open(self):
ret = self.lib.ocf_volume_open(self.cvol, c_void_p())
if ret != 0:
raise OcfError("openning composite volume failed", ret)
def open(self):
ret = super().open()
if ret == 0:
ret = self.lib.ocf_volume_open(self.handle, c_void_p())
if ret:
raise OcfError("opening composite volume failed", ret)
return ret
def close(self):
self.lib.ocf_volume_close(self.handle)
super().close()
def do_close(self):
self.lib.ocf_volume_close(self.cvol)
lib = OcfLib.getInstance()

View File

@@ -23,6 +23,7 @@ from ctypes import (
from hashlib import md5
import weakref
from enum import IntEnum
import warnings
from .io import Io, IoOps, IoDir
from .queue import Queue
@@ -143,16 +144,25 @@ class Volume:
try:
volume = Volume.get_by_uuid(uuid)
except: # noqa E722 TODO:Investigate whether this really should be so broad
print("Tried to access unallocated volume {}".format(uuid))
print("{}".format(Volume._uuid_))
warnings.warn("Tried to access unallocated volume {}".format(uuid))
return -1
return Volume.s_open(ref, volume)
ret = volume.open()
if not ret:
Volume._instances_[ref] = volume
volume.handle = ref
return ret
@VolumeOps.CLOSE
def _close(ref):
volume = Volume.get_instance(ref)
Volume.s_close(volume)
del Volume._instances_[volume.handle]
volume.handle = None
volume.close()
@VolumeOps.GET_MAX_IO_SIZE
def _get_max_io_size(ref):
@@ -178,31 +188,19 @@ class Volume:
return Volume._ops_[cls]
@staticmethod
def s_open(ref, volume):
if volume.opened:
def open(self):
if self.opened:
return -OcfErrorCode.OCF_ERR_NOT_OPEN_EXC
volume.handle = ref
Volume._instances_[ref] = volume
volume.opened = True
self.opened = True
ret = volume.do_open()
if ret == 0:
volume.opened = True
return 0
return ret
@staticmethod
def s_close(volume):
if not volume.opened:
def close(self):
if not self.opened:
return
volume.do_close()
volume.opened = False
del Volume._instances_[volume.handle]
volume.handle = None
self.opened = False
@classmethod
def get_io_ops(cls):
@@ -230,7 +228,7 @@ class Volume:
@classmethod
def get_instance(cls, ref):
if ref not in cls._instances_:
print("tried to access {} but it's gone".format(ref))
warnings.warn(f"tried to access volume ref {ref} but it's gone")
return None
return cls._instances_[ref]
@@ -270,15 +268,6 @@ class Volume:
self.opened = False
self.handle = None
def do_open(self):
return 0
def do_close(self):
try:
del Volume._instances_[self.handle]
except AttributeError:
pass
def get_length(self):
raise NotImplementedError
@@ -444,7 +433,6 @@ class ErrorDevice(Volume):
uuid=None,
):
self.vol = vol
self.vol.open()
super().__init__(uuid)
self.error_sectors = error_sectors or set()
self.error_seq_no = error_seq_no or {IoDir.WRITE: -1, IoDir.READ: -1}
@@ -456,6 +444,16 @@ class ErrorDevice(Volume):
def set_mapping(self, error_sectors: set):
self.error_sectors = error_sectors
def open(self):
ret = self.vol.open()
if ret:
return ret
return super().open()
def close(self):
super().close()
self.vol.close()
def should_forward_io(self, io):
if not self.armed:
return True
@@ -540,6 +538,16 @@ class TraceDevice(Volume):
super().__init__(uuid)
self.trace_fcn = trace_fcn
def open(self):
ret = self.vol.open()
if ret:
return ret
return super().open()
def close(self):
super().close()
self.vol.close()
def _trace(self, io, io_type):
submit = True

View File

@@ -5,6 +5,7 @@
from threading import Lock
from .volume import Volume, VOLUME_POISON
from .shared import OcfErrorCode
from .io import Io, IoDir
from ctypes import cast, c_void_p, CFUNCTYPE, c_int, POINTER, memmove, sizeof, pointer
@@ -14,19 +15,24 @@ class ReplicatedVolume(Volume):
super().__init__(uuid)
self.primary = primary
self.secondary = secondary
def open(self):
ret = self.primary.open()
if ret:
raise Exception(f"Couldn't open primary volume. ({ret})")
return ret
ret = self.secondary.open()
if ret:
raise Exception(f"Couldn't open secondary volume. ({ret})")
return ret
if secondary.get_max_io_size() < primary.get_max_io_size():
if self.secondary.get_max_io_size() < self.primary.get_max_io_size():
raise Exception("secondary volume max io size too small")
if secondary.get_length() < primary.get_length():
return -OcfErrorCode.OCF_ERR_INVAL
if self.secondary.get_length() < self.primary.get_length():
raise Exception("secondary volume size too small")
return -OcfErrorCode.OCF_ERR_INVAL
def open(self):
return super().open()
def close(self):