Source code for swh.objstorage.backends.mosaic
# Copyright (C) 2026 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
"""
Implementation of the ObjStorage API based on a single MOSAIC file.
This is suitable for small objects collections (less than 100 million objects) that
can benefit from the efficiency of :ref:`swh-mosaic` without setting up a complete
:ref:`swh-objstorage-winery`.
"""
from typing import Iterable, Iterator
from swh.model.hashutil import HashDict
from swh.mosaic import IdxDescription, MosaicReader
from swh.objstorage.constants import LiteralPrimaryHash
from swh.objstorage.exc import ObjNotFoundError, ReadOnlyObjStorageError
from swh.objstorage.interface import ObjId
from swh.objstorage.objstorage import ObjStorage, timed
HashToIDX: dict[LiteralPrimaryHash, IdxDescription] = {
"sha1": IdxDescription.SHA1FMPHGO,
"sha1_git": IdxDescription.SHA1GITFMPHGO,
"sha256": IdxDescription.SHA256FMPHGO,
}
[docs]
class MosaicObjStorage(ObjStorage):
"""Readonly objstorage backed by a single MOSAIC file."""
name: str = "mosaic"
def __init__(
self, path: str, primary_hash: LiteralPrimaryHash = "sha1_git", **kwargs
):
super().__init__(**kwargs)
self.mosaic_path = path
self.primary_hash: LiteralPrimaryHash = primary_hash
self.mosaic = MosaicReader(path, HashToIDX[primary_hash])
def __del__(self):
self.mosaic.close()
[docs]
def check_config(self, *, check_write):
return not check_write
@timed
def __contains__(self, obj_id: ObjId) -> bool:
key = obj_id[self.primary_hash]
res = True
try:
self.mosaic.lookup(key)
except KeyError:
res = False
return res
[docs]
@timed
def add(self, content: bytes, obj_id: ObjId, check_presence: bool = True) -> None:
raise ReadOnlyObjStorageError("add")
[docs]
@timed
def get(self, obj_id: ObjId) -> bytes:
try:
key = obj_id[self.primary_hash]
return self.mosaic.lookup(key)
except KeyError:
raise ObjNotFoundError(obj_id)
[docs]
def get_batch(self, obj_ids: Iterable[HashDict]) -> Iterator[bytes | None]:
keys = [obj_id[self.primary_hash] for obj_id in obj_ids]
return iter(self.mosaic.get_batch(keys))
[docs]
def delete(self, obj_id: ObjId):
raise ReadOnlyObjStorageError("delete")