Source code for swh.objstorage.backends.winery.settings
# Copyright (C) 2025 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
from typing import Literal, NotRequired, Optional, Tuple, TypedDict
# This would be used for image features that are not supported by the kernel RBD
# driver, e.g. exclusive-lock, object-map and fast-diff for kernels < 5.3
DEFAULT_IMAGE_FEATURES_UNSUPPORTED: Tuple[str, ...] = ()
[docs]
class Packer(TypedDict):
"""Settings for the packer process, either external or internal"""
create_images: NotRequired[bool]
"""Whether to create the images"""
pack_immediately: NotRequired[bool]
"""Immediately pack shards (in a separate thread) when overflowing"""
clean_immediately: NotRequired[bool]
"""Immediately clean shards when packing is complete"""
[docs]
def packer_settings_with_defaults(values: Packer) -> Packer:
"""Hydrate Packer settings with default values"""
return {
"create_images": True,
"pack_immediately": True,
"clean_immediately": True,
**values,
}
[docs]
class Shards(TypedDict):
"""Settings for shard management"""
max_size: int
"""Maximum cumulative size of objects in a shard"""
rw_idle_timeout: NotRequired[float]
"""Timeout (seconds) after which write shards get released when idle"""
[docs]
def shards_settings_with_defaults(values: Shards) -> Shards:
"""Hydrate Shards settings with default values"""
return {"rw_idle_timeout": 300, **values}
[docs]
class ShardsPool(TypedDict):
"""Settings for the Shards pool"""
type: Literal["rbd", "directory"]
[docs]
class RbdShardsPool(ShardsPool, TypedDict):
"""Settings for the Ceph RBD-based Shards pool"""
use_sudo: NotRequired[bool]
map_options: NotRequired[str]
pool_name: NotRequired[str]
data_pool_name: NotRequired[Optional[str]]
image_features_unsupported: NotRequired[Tuple[str, ...]]
[docs]
def rbd_shards_pool_settings_with_defaults(
values: ShardsPool,
) -> RbdShardsPool:
"""Hydrate RbdShards settings with default values"""
return {
"type": "rbd",
"use_sudo": True,
"pool_name": "shards",
"data_pool_name": None,
"image_features_unsupported": DEFAULT_IMAGE_FEATURES_UNSUPPORTED,
"map_options": "",
**values,
}
[docs]
class DirectoryShardsPool(ShardsPool, TypedDict):
"""Settings for the File-based Shards pool"""
base_directory: str
pool_name: NotRequired[str]
[docs]
def directory_shards_pool_settings_with_defaults(
values: ShardsPool,
) -> DirectoryShardsPool:
"""Hydrate RbdShards settings with default values"""
if values["type"] != "directory":
raise ValueError(
f"Instantiating a directory shards pool with the wrong type: {values['type']}"
)
if "base_directory" not in values:
raise ValueError(
"Missing base_directory setting for Directory-based shards pool"
)
return {
"type": "directory",
"pool_name": values.get("pool_name", "shards"), # type: ignore[typeddict-item]
"base_directory": values["base_directory"], # type: ignore[typeddict-item]
}
[docs]
class Throttler(TypedDict):
"""Settings for the winery throttler"""
db: NotRequired[str]
"""Throttler database connection string"""
max_read_bps: int
"""Max read bytes per second"""
max_write_bps: int
"""Max write bytes per second"""
[docs]
class Database(TypedDict):
"""Settings for the winery database"""
db: str
"""Database connection string"""
application_name: NotRequired[Optional[str]]
"""Application name for the database connection"""
[docs]
def database_settings_with_defaults(values: Database) -> Database:
"""Hydrate Database settings with defaults"""
return {"application_name": None, **values}
[docs]
class Winery(TypedDict, total=False):
"""A representation of all available winery settings"""
database: Database
shards: Shards
shards_pool: ShardsPool
throttler: Optional[Throttler]
packer: Packer
SETTINGS = frozenset({"database", "shards", "shards_pool", "throttler", "packer"})
[docs]
def populate_default_settings(
database: Optional[Database] = None,
shards: Optional[Shards] = None,
shards_pool: Optional[ShardsPool] = None,
throttler: Optional[Throttler] = None,
packer: Optional[Packer] = None,
) -> Winery:
"""Given some settings for a Winery objstorage, add all the appropriate
default settings."""
settings: Winery = {}
if database is not None:
database = database_settings_with_defaults(database)
settings["database"] = database
if shards is not None:
shards = shards_settings_with_defaults(shards)
settings["shards"] = shards
if shards_pool is not None:
if shards_pool["type"] == "rbd":
shards_pool = rbd_shards_pool_settings_with_defaults(shards_pool)
settings["shards_pool"] = shards_pool
elif shards_pool["type"] == "directory":
shards_pool = directory_shards_pool_settings_with_defaults(shards_pool)
settings["shards_pool"] = shards_pool
else:
raise ValueError(f"Unknown shards pool type: {shards_pool['type']}")
if throttler is not None:
if "db" not in throttler:
settings["throttler"] = {"db": settings["database"]["db"], **throttler}
else:
settings["throttler"] = throttler
if packer is not None:
packer = packer_settings_with_defaults(packer)
settings["packer"] = packer
return settings