os-brick/os_brick/caches/__init__.py
Liang Fang abd97bb2eb Add volume local cache support to os-brick
Try to leverage cache software, such as Open CAS, use high performance
disk or persistent memory as the cache in compute node locally for low
performance volume that allocated by cinder from remote backend storage.

open-cas: https://open-cas.github.io/
Nova Spec: https://review.opendev.org/#/c/689070/
Cinder Spec: https://review.opendev.org/#/c/684556/

Change-Id: Ib120047a65ecbb4ae0f060640d59f3f759a1cade
Signed-off-by: Liang Fang <liang.a.fang@intel.com>
2020-08-26 14:37:15 +08:00

104 lines
3.3 KiB
Python

# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
import abc
from oslo_log import log as logging
from oslo_utils import importutils
from os_brick import exception
from os_brick.i18n import _
LOG = logging.getLogger(__name__)
CACHE_ENGINE_TO_CACHE_CLASS_MAP = {
"opencas": 'os_brick.caches.opencas.OpenCASEngine',
}
class CacheEngineBase(object, metaclass=abc.ABCMeta):
def __init__(self, **kwargs):
self._root_helper = kwargs.get('root_helper')
@abc.abstractmethod
def is_engine_ready(self, **kwargs):
return
@abc.abstractmethod
def attach_volume(self, **kwargs):
return
@abc.abstractmethod
def detach_volume(self, **kwargs):
return
class CacheManager():
"""Cache manager for volumes.
This CacheManager uses cache engines to do volume cache.
"""
def __init__(self, root_helper, connection_info,
*args, **kwargs):
data = connection_info['data']
if not data.get('device_path'):
volume_id = data.get('volume_id') or connection_info.get('serial')
raise exception.VolumeLocalCacheNotSupported(
volume_id=volume_id,
volume_type=connection_info.get('driver_volume_type'))
self.ori_device_path = data.get('device_path')
if not data.get('cacheable'):
self.cacheable = False
return
self.cacheable = True
self.root_helper = root_helper
self.engine_name = kwargs.get('cache_name')
self.args = args
self.kwargs = kwargs
self.kwargs["root_helper"] = root_helper
self.kwargs["dev_path"] = data.get('device_path')
self.engine = self._get_engine(self.engine_name, **self.kwargs)
def _get_engine(self, engine_name, **kwargs):
eng_cls_path = CACHE_ENGINE_TO_CACHE_CLASS_MAP.get(engine_name)
if eng_cls_path:
engine_cls = importutils.import_class(eng_cls_path)
eng = engine_cls(**kwargs)
if eng.is_engine_ready():
return eng
raise exception.Invalid(_("No valid cache engine"))
def attach_volume(self):
"""setup the cache when attaching volume."""
if not self.cacheable:
return self.ori_device_path
LOG.debug("volume before cached: %s", self.kwargs.get('dev_path'))
emulated_disk = self.engine.attach_volume(**self.kwargs)
LOG.debug("volume after cached: %s", emulated_disk)
return emulated_disk
def detach_volume(self):
"""Release the cache on detaching volume."""
if not self.cacheable:
return self.ori_device_path
LOG.debug("volume before detach: %s", self.kwargs.get('dev_path'))
ori_disk = self.engine.detach_volume(**self.kwargs)
LOG.debug("volume after detach: %s", ori_disk)
return ori_disk