Start API refactor to remove separate Tree
We want trees to just be notes. We want to reference notes by Path instead of object ids. Stop thinking about the fs implementation and the fuse service with the same terms - they will be different backends.
This commit is contained in:
parent
abbef64bbc
commit
41480a39c9
5 changed files with 245 additions and 234 deletions
|
|
@ -20,7 +20,9 @@ import pyfuse3
|
|||
import trio
|
||||
from pyfuse3 import InodeT, FileHandleT
|
||||
|
||||
from trovedb.trove import Trove, Note, Tree as TroveTree, TreeNote, Blob as TroveBlob, ObjectId, TreeExists
|
||||
from trovedb.trove import Trove, Note, Tree as TroveTree, TreeNote, ObjectId, TreeExists
|
||||
|
||||
import trovedb.trove as tr
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -140,7 +142,7 @@ class TroveFuseOps(pyfuse3.Operations):
|
|||
raise pyfuse3.FUSEError(errno.ENOTDIR)
|
||||
try:
|
||||
note = parent.child(name.decode())
|
||||
except KeyError:
|
||||
except (KeyError, tr.ErrorNotFound):
|
||||
logger.debug("lookup failed: %d -> %s", parent_inode, name.decode())
|
||||
raise pyfuse3.FUSEError(errno.ENOENT) from None
|
||||
ent = self._create_get_ent_from_note(note)
|
||||
|
|
@ -184,8 +186,8 @@ class TroveFuseOps(pyfuse3.Operations):
|
|||
# Determine basic information
|
||||
is_tree = True
|
||||
size = 0
|
||||
if isinstance(note, TroveBlob):
|
||||
size = len(note.read())
|
||||
if not hasattr(note, 'mkdir'):
|
||||
size = len(note.read_content())
|
||||
is_tree = False
|
||||
|
||||
# Create and fill attr structure
|
||||
|
|
@ -239,13 +241,13 @@ class TroveFuseOps(pyfuse3.Operations):
|
|||
ent = self._get_ent_from_inode(inode)
|
||||
note = self._get_ent_note(ent)
|
||||
if fields.update_size:
|
||||
if isinstance(note, TroveBlob):
|
||||
current = note.read()
|
||||
if not hasattr(note, 'mkdir'):
|
||||
current = note.read_content()
|
||||
new_size = attr.st_size
|
||||
if new_size < len(current):
|
||||
note.write(current[:new_size])
|
||||
note.write_content(current[:new_size])
|
||||
elif new_size > len(current):
|
||||
note.write(current + b"\x00" * (new_size - len(current)))
|
||||
note.write_content(current + b"\x00" * (new_size - len(current)))
|
||||
else:
|
||||
raise pyfuse3.FUSEError(errno.EINVAL)
|
||||
return self._get_attr(ent, note)
|
||||
|
|
@ -278,13 +280,13 @@ class TroveFuseOps(pyfuse3.Operations):
|
|||
if not isinstance(note, TroveTree):
|
||||
logger.debug("attempted readdir on %d not a tree", fh)
|
||||
raise pyfuse3.FUSEError(errno.ENOTDIR)
|
||||
entries = list(note.list().items()) # [(name, object_id), ...]
|
||||
entries = list(note.entries()) # [(name, object_id), ...]
|
||||
|
||||
for idx, (name, child_id) in enumerate(entries):
|
||||
for idx, entry in enumerate(entries):
|
||||
if idx < start_id:
|
||||
continue
|
||||
|
||||
child = self._trove.get_raw_note(child_id)
|
||||
child = self._trove.get_raw_note(entry.object_id)
|
||||
if child is None:
|
||||
continue
|
||||
|
||||
|
|
@ -292,7 +294,7 @@ class TroveFuseOps(pyfuse3.Operations):
|
|||
attr = self._get_attr(child_ent, child)
|
||||
self._ref_entry(child_ent)
|
||||
|
||||
if not pyfuse3.readdir_reply(token, name.encode(), attr, idx + 1):
|
||||
if not pyfuse3.readdir_reply(token, entry.name.encode(), attr, idx + 1):
|
||||
break
|
||||
|
||||
async def releasedir(self, fh: FileHandleT) -> None:
|
||||
|
|
@ -302,19 +304,18 @@ class TroveFuseOps(pyfuse3.Operations):
|
|||
|
||||
async def mkdir(self, parent_inode: InodeT, name: bytes, mode: int, ctx) -> pyfuse3.EntryAttributes:
|
||||
logger.debug("mkdir inode:%d name:%s", parent_inode, name)
|
||||
# Grab parent note, verify is tree
|
||||
|
||||
parent = self._get_inode_note(parent_inode)
|
||||
if not isinstance(parent, TreeNote):
|
||||
raise pyfuse3.FUSEError(errno.ENOTDIR)
|
||||
# Create new directory in note
|
||||
# TODO: consider implications here, maybe look at ext on dir for mime?
|
||||
try:
|
||||
new_tree: TreeNote = parent.mkdir(name.decode())
|
||||
except TreeExists:
|
||||
raise pyfuse3.FUSEError(errno.EEXIST) from None
|
||||
note = tr.new_child(parent, name.decode(), mime='inode/directory')
|
||||
except tr.ErrorWithErrno as e:
|
||||
raise pyfuse3.FUSEError(e.errno) from None
|
||||
|
||||
# Grab entity for kernel
|
||||
ent = self._create_get_ent_from_note(new_tree)
|
||||
ent = self._create_get_ent_from_note(note)
|
||||
self._ref_entry(ent)
|
||||
return self._get_attr(ent, new_tree)
|
||||
return self._get_attr(ent, note)
|
||||
|
||||
async def rmdir(self, parent_inode: InodeT, name: bytes, ctx) -> None:
|
||||
logger.debug("rmdir inode:%d name:%s", parent_inode, name)
|
||||
|
|
@ -341,37 +342,35 @@ class TroveFuseOps(pyfuse3.Operations):
|
|||
async def create(self, parent_inode: InodeT, name: bytes, mode: int, flags, ctx) -> tuple:
|
||||
logger.debug("create inode:%d name:%s", parent_inode, name)
|
||||
parent = self._get_inode_note(parent_inode)
|
||||
if not isinstance(parent, TroveTree):
|
||||
raise pyfuse3.FUSEError(errno.ENOTDIR)
|
||||
name_str = name.decode()
|
||||
if name_str in parent.list():
|
||||
raise pyfuse3.FUSEError(errno.EEXIST)
|
||||
blob = self._trove.create_blob(b"")
|
||||
parent.link(name_str, blob)
|
||||
|
||||
ent = self._create_get_ent_from_note(blob)
|
||||
# TODO: handle mode
|
||||
# TODO: handle flags
|
||||
|
||||
name_str = name.decode()
|
||||
note = tr.new_child(parent, name_str)
|
||||
ent = self._create_get_ent_from_note(note)
|
||||
self._ref_entry(ent)
|
||||
|
||||
handle = self._open_handle(ent.sys_inode)
|
||||
attr = self._get_attr(ent, blob)
|
||||
attr = self._get_attr(ent, note)
|
||||
return pyfuse3.FileInfo(fh=handle.handle_id), attr
|
||||
|
||||
async def read(self, fh: FileHandleT, offset: int, length: int) -> bytes:
|
||||
logger.debug("read fh:%d offset:%d length:%d", fh, offset, length)
|
||||
handle = self._get_handle(fh)
|
||||
note = handle.note
|
||||
if isinstance(note, TroveBlob):
|
||||
return note.read()[offset:offset + length]
|
||||
if not hasattr(note, 'mkdir'):
|
||||
return note.read_content()[offset:offset + length]
|
||||
raise pyfuse3.FUSEError(errno.EBADF)
|
||||
|
||||
async def write(self, fh: FileHandleT, offset: int, data: bytes) -> int:
|
||||
handle = self._get_handle(fh)
|
||||
note = handle.note
|
||||
if isinstance(note, TroveBlob):
|
||||
existing = note.read()
|
||||
if not hasattr(note, 'mkdir'):
|
||||
existing = note.read_content()
|
||||
if offset > len(existing):
|
||||
existing = existing + b"\x00" * (offset - len(existing))
|
||||
note.write(existing[:offset] + data + existing[offset + len(data):])
|
||||
note.write_content(existing[:offset] + data + existing[offset + len(data):])
|
||||
return len(data)
|
||||
|
||||
async def release(self, fh: FileHandleT) -> None:
|
||||
|
|
@ -380,12 +379,8 @@ class TroveFuseOps(pyfuse3.Operations):
|
|||
|
||||
async def unlink(self, parent_inode: InodeT, name: bytes, ctx) -> None:
|
||||
parent_note = self._get_inode_note(parent_inode)
|
||||
if not isinstance(parent_note, TroveTree):
|
||||
raise pyfuse3.FUSEError(errno.ENOTDIR)
|
||||
name_str = name.decode()
|
||||
if name_str not in parent_note.list():
|
||||
raise pyfuse3.FUSEError(errno.ENOENT)
|
||||
parent_note.unlink(name.decode())
|
||||
parent_note.rm_child(name_str, False)
|
||||
|
||||
async def rename(self, parent_inode_old: InodeT, name_old: bytes, parent_inode_new: InodeT, name_new: bytes, flags, ctx):
|
||||
# Decode / validate names
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue