1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
5 from __future__ import absolute_import
12 from .fresh import FreshBase, convertTime
14 _logger = logging.getLogger('arvados.arvados_fuse')
16 class File(FreshBase):
17 """Base for file objects."""
19 __slots__ = ("inode", "parent_inode", "_mtime")
21 def __init__(self, parent_inode, _mtime=0):
22 super(File, self).__init__()
24 self.parent_inode = parent_inode
30 def readfrom(self, off, size, num_retries=0):
33 def writeto(self, off, size, num_retries=0):
34 raise Exception("Not writable")
49 class FuseArvadosFile(File):
50 """Wraps a ArvadosFile."""
52 __slots__ = ('arvfile',)
54 def __init__(self, parent_inode, arvfile, _mtime):
55 super(FuseArvadosFile, self).__init__(parent_inode, _mtime)
56 self.arvfile = arvfile
59 with llfuse.lock_released:
60 return self.arvfile.size()
62 def readfrom(self, off, size, num_retries=0):
63 with llfuse.lock_released:
64 return self.arvfile.readfrom(off, size, num_retries, exact=True)
66 def writeto(self, off, buf, num_retries=0):
67 with llfuse.lock_released:
68 return self.arvfile.writeto(off, buf, num_retries)
74 return self.arvfile.writable()
77 with llfuse.lock_released:
79 self.arvfile.parent.root_collection().save()
82 class StringFile(File):
83 """Wrap a simple string as a file"""
84 def __init__(self, parent_inode, contents, _mtime):
85 super(StringFile, self).__init__(parent_inode, _mtime)
86 self.contents = contents
89 return len(self.contents)
91 def readfrom(self, off, size, num_retries=0):
92 return self.contents[off:(off+size)]
95 class ObjectFile(StringFile):
96 """Wrap a dict as a serialized json object."""
98 def __init__(self, parent_inode, obj):
99 super(ObjectFile, self).__init__(parent_inode, "", 0)
100 self.object_uuid = obj['uuid']
104 return self.object_uuid
106 def update(self, obj=None):
108 # TODO: retrieve the current record for self.object_uuid
109 # from the server. For now, at least don't crash when
110 # someone tells us it's a good time to update but doesn't
111 # pass us a fresh obj. See #8345
113 self._mtime = convertTime(obj['modified_at']) if 'modified_at' in obj else 0
114 self.contents = json.dumps(obj, indent=4, sort_keys=True) + "\n"
120 class FuncToJSONFile(StringFile):
121 """File content is the return value of a given function, encoded as JSON.
123 The function is called at the time the file is read. The result is
124 cached until invalidate() is called.
126 def __init__(self, parent_inode, func):
127 super(FuncToJSONFile, self).__init__(parent_inode, "", 0)
130 # invalidate_inode() is asynchronous with no callback to wait for. In
131 # order to guarantee userspace programs don't get stale data that was
132 # generated before the last invalidate(), we must disallow inode
134 self.allow_attr_cache = False
138 return super(FuncToJSONFile, self).size()
140 def readfrom(self, *args, **kwargs):
142 return super(FuncToJSONFile, self).readfrom(*args, **kwargs)
147 self._mtime = time.time()
149 self.contents = json.dumps(obj, indent=4, sort_keys=True) + "\n"