objectstore: implicit clone based on object ids

If the object's id does not match with the one supplied for the
commit, we create a clone. Otherwise we store the tree.
The code path is arranged in a way that we always go through
`Object.store_tree` so we always call `Object.finalize` as a
prepration for the future, where we might actually do something
meaningful in the finalizer, like reset the *times or count the
tree size.
This commit is contained in:
Christian Kellner 2022-08-22 17:00:06 +00:00
parent 5346025031
commit 28b8252a04
3 changed files with 15 additions and 9 deletions

View file

@ -279,7 +279,7 @@ class ObjectStore(contextlib.AbstractContextManager):
return obj
def commit(self, obj: Object, object_id: str, clone: bool = False) -> str:
def commit(self, obj: Object, object_id: str) -> str:
"""Commits a Object to the object store
Move the contents of the obj (Object) to object directory
@ -288,16 +288,22 @@ class ObjectStore(contextlib.AbstractContextManager):
directory with the object_id as the name ('refs/{object_id}).
If the link already exists, it will be atomically replaced.
If object_id is different from the id of the object, a copy
of the object will be stored.
Returns: The name of the object
"""
# The supplied object_id is not the object's final id, so
# we have to make a copy first
if obj.id != object_id:
tmp = self.new(object_id)
tmp.init(obj)
obj = tmp
# The object is stored in the objects directory using its unique
# name. This means that each commit will always result in a new
# object in the store, even if an identical one exists.
if clone:
object_name = str(uuid.uuid4())
obj.clone(os.path.join(self.objects, object_name))
else:
object_name = obj.store_tree()
# symlink the object_id (config hash) in the refs directory to the

View file

@ -354,7 +354,7 @@ class Pipeline:
return results
if stage.checkpoint:
object_store.commit(tree, stage.id, clone=bool(todo))
object_store.commit(tree, stage.id)
tree.finalize()

View file

@ -113,7 +113,7 @@ class TestObjectStore(unittest.TestCase):
data_inode = st.st_ino
# commit the object as "x", making a copy
store.commit(tree, "x", clone=True)
store.commit(tree, "x")
# check that "data" got indeed copied
tree = store.get("x")
@ -191,7 +191,7 @@ class TestObjectStore(unittest.TestCase):
p.touch()
assert not store.contains("a")
store.commit(tree, "a", clone=True)
store.commit(tree, "a") # store via "a", creates a clone
assert store.contains("a")
with tree.write() as path: