Changeset View
Changeset View
Standalone View
Standalone View
swh/objstorage/backends/winery/roshard.py
- This file was added.
# Copyright (C) 2021 The Software Heritage developers | |||||
# See the AUTHORS file at the top-level directory of this distribution | |||||
# License: GNU General Public License version 3, or any later version | |||||
# See top-level LICENSE file for more information | |||||
import logging | |||||
import sh | |||||
from swh.perfecthash import Shard | |||||
LOGGER = logging.getLogger(__name__) | |||||
class Pool(object): | |||||
name = "shards" | |||||
def __init__(self, **kwargs): | |||||
self.args = kwargs | |||||
def init(self): | |||||
self.rbd = sh.sudo.bake("rbd", f"--pool={self.name}") | |||||
self.ceph = sh.sudo.bake("ceph") | |||||
self.image_size = self.args["shard_max_size"] * 2 | |||||
olasd: Doesn't look like `init` has any side effect, so all calls can probably go to the `__init__`… | |||||
dacharyAuthorUnsubmitted Done Inline ActionsDone. dachary: Done. | |||||
def uninit(self): | |||||
pass | |||||
def image_list(self): | |||||
try: | |||||
self.rbd.ls() | |||||
except sh.ErrorReturnCode_2 as e: | |||||
if "No such file or directory" in e.args[0]: | |||||
vlorentzUnsubmitted Not Done Inline ActionsI don't think this work when $LANG is not an English locale. You should force the locale when calling it. vlorentz: I don't think this work when `$LANG` is not an English locale. You should force the locale when… | |||||
return [] | |||||
else: | |||||
raise | |||||
return [image.strip() for image in self.rbd.ls()] | |||||
def image_path(self, image): | |||||
return f"/dev/rbd/{self.name}/{image}" | |||||
def image_create(self, image): | |||||
LOGGER.info(f"rdb --pool {self.name} create --size={self.image_size} {image}") | |||||
self.rbd.create( | |||||
f"--size={self.image_size}", f"--data-pool={self.name}-data", image | |||||
) | |||||
self.rbd.feature.disable( | |||||
f"{self.name}/{image}", "object-map", "fast-diff", "deep-flatten" | |||||
) | |||||
self.image_map(image, "rw") | |||||
def image_map(self, image, options): | |||||
self.rbd.device("map", "-o", options, image) | |||||
sh.sudo("chmod", "777", self.image_path(image)) | |||||
def image_remap_ro(self, image): | |||||
self.image_unmap(image) | |||||
self.image_map(image, "ro") | |||||
def image_unmap(self, image): | |||||
self.rbd.device.unmap(f"{self.name}/{image}", _ok_code=(0, 22)) | |||||
def image_delete(self, image): | |||||
self.image_unmap(image) | |||||
LOGGER.info(f"rdb --pool {self.name} remove {image}") | |||||
self.rbd.remove(image) | |||||
def images_clobber(self): | |||||
for image in self.image_list(): | |||||
image = image.strip() | |||||
self.image_unmap(image) | |||||
def clobber(self): | |||||
self.images_clobber() | |||||
self.pool_clobber() | |||||
def pool_clobber(self): | |||||
LOGGER.info(f"ceph osd pool delete {self.name}") | |||||
self.ceph.osd.pool.delete(self.name, self.name, "--yes-i-really-really-mean-it") | |||||
data = f"{self.name}-data" | |||||
LOGGER.info(f"ceph osd pool delete {data}") | |||||
self.ceph.osd.pool.delete(data, data, "--yes-i-really-really-mean-it") | |||||
def pool_create(self): | |||||
data = f"{self.name}-data" | |||||
LOGGER.info(f"ceph osd pool create {data}") | |||||
self.ceph.osd( | |||||
"erasure-code-profile", | |||||
"set", | |||||
"--force", | |||||
data, | |||||
"k=4", | |||||
"m=2", | |||||
"crush-failure-domain=host", | |||||
) | |||||
self.ceph.osd.pool.create(data, "200", "erasure", data) | |||||
self.ceph.osd.pool.set(data, "allow_ec_overwrites", "true") | |||||
self.ceph.osd.pool.set(data, "pg_autoscale_mode", "off") | |||||
LOGGER.info(f"ceph osd pool create {self.name}") | |||||
self.ceph.osd.pool.create(self.name) | |||||
olasdUnsubmitted Done Inline ActionsI would be (much) more comfortable if these functions were only in a Pool subclass defined and used by tests. olasd: I would be (much) more comfortable if these functions were only in a `Pool` subclass defined… | |||||
dacharyAuthorUnsubmitted Done Inline ActionsMoved to the PoolHelper class and to the test directory. Dangerous indeed... dachary: Moved to the PoolHelper class and to the test directory. Dangerous indeed... | |||||
class ROShard: | |||||
def __init__(self, name, **kwargs): | |||||
self.pool = Pool(shard_max_size=kwargs["shard_max_size"]) | |||||
self.pool.init() | |||||
self.name = name | |||||
def create(self, count): | |||||
self.pool.image_create(self.name) | |||||
self.shard = Shard(self.pool.image_path(self.name)) | |||||
return self.shard.create(count) | |||||
def load(self): | |||||
self.shard = Shard(self.pool.image_path(self.name)) | |||||
return self.shard.load() == self.shard | |||||
def get(self, key): | |||||
return self.shard.lookup(key) |
Doesn't look like init has any side effect, so all calls can probably go to the __init__ function