objectstore: add Object.read_at method

Implement a new `read_at` method that will bind mount the tree of the
object to a specified location, instead of a temporary directory as
it done in the `read` method. Implement the latter via `read_at`.
Implement the corresponding methods for `Store{Client,Server}`. Since
the `ObjectStore.read_at` method will fail if the target directory
does not exist (or is of the wrong type), catch any exceptions in
the `StoreServer` and send those to the `StoreClient` via an `error`
entry.
This one is for David: also fix a missing blank line.
This commit is contained in:
Christian Kellner 2021-06-01 11:53:35 +02:00 committed by Tom Gundersen
parent c9327a7a79
commit f8428e56e2

View file

@ -111,16 +111,22 @@ class Object:
@contextlib.contextmanager
def read(self) -> str:
with self.tempdir("reader") as target:
with self.read_at(target) as path:
yield path
@contextlib.contextmanager
def read_at(self, target: PathLike) -> str:
self._check_writable()
self._check_writer()
with self.tempdir("reader") as target:
mount(self._path, target)
try:
self._readers += 1
yield target
finally:
umount(target)
self._readers -= 1
mount(self._path, target)
try:
self._readers += 1
yield target
finally:
umount(target)
self._readers -= 1
def store_tree(self, destination: str):
"""Store the tree at destination and reset itself
@ -219,6 +225,7 @@ class HostTree:
`objectstore.Object` that can be used to read
the host file-system.
"""
def __init__(self, store):
self.store = store
@ -390,6 +397,25 @@ class StoreServer(api.BaseAPI):
path = self._stack.enter_context(reader)
sock.send({"path": path})
def _read_tree_at(self, msg, sock):
object_id = msg["object-id"]
target = msg["target"]
obj = self.store.get(object_id)
if not obj:
sock.send({"path": None})
return
try:
reader = obj.read_at(target)
path = self._stack.enter_context(reader)
# pylint: disable=broad-except
except Exception as e:
sock.send({"error": str(e)})
return
sock.send({"path": path})
def _mkdtemp(self, msg, sock):
args = {
"suffix": msg.get("suffix"),
@ -409,6 +435,8 @@ class StoreServer(api.BaseAPI):
def _message(self, msg, _fds, sock):
if msg["method"] == "read-tree":
self._read_tree(msg, sock)
elif msg["method"] == "read-tree-at":
self._read_tree_at(msg, sock)
elif msg["method"] == "mkdtemp":
self._mkdtemp(msg, sock)
elif msg["method"] == "source":
@ -448,6 +476,22 @@ class StoreClient:
return msg["path"]
def read_tree_at(self, object_id: str, target: str):
msg = {
"method": "read-tree-at",
"object-id": object_id,
"target": os.fspath(target)
}
self.client.send(msg)
msg, _, _ = self.client.recv()
err = msg.get("error")
if err:
raise RuntimeError(err)
return msg["path"]
def source(self, name: str) -> str:
msg = {
"method": "source",