Don't keep files open when uploading whole collection
This commit is contained in:
parent
59eded976b
commit
1821b872d2
@ -729,7 +729,7 @@ class Collection(BaseCollection):
|
|||||||
return os.path.join(filesystem_folder, "collection-root")
|
return os.path.join(filesystem_folder, "collection-root")
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def _atomic_write(self, path, mode="w", newline=None):
|
def _atomic_write(self, path, mode="w", newline=None, sync_directory=True):
|
||||||
directory = os.path.dirname(path)
|
directory = os.path.dirname(path)
|
||||||
tmp = NamedTemporaryFile(
|
tmp = NamedTemporaryFile(
|
||||||
mode=mode, dir=directory, delete=False, prefix=".Radicale.tmp-",
|
mode=mode, dir=directory, delete=False, prefix=".Radicale.tmp-",
|
||||||
@ -747,7 +747,8 @@ class Collection(BaseCollection):
|
|||||||
tmp.close()
|
tmp.close()
|
||||||
os.remove(tmp.name)
|
os.remove(tmp.name)
|
||||||
raise
|
raise
|
||||||
self._sync_directory(directory)
|
if sync_directory:
|
||||||
|
self._sync_directory(directory)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _find_available_file_name(exists_fn, suffix=""):
|
def _find_available_file_name(exists_fn, suffix=""):
|
||||||
@ -931,36 +932,26 @@ class Collection(BaseCollection):
|
|||||||
uploads them nonatomic and without existence checks.
|
uploads them nonatomic and without existence checks.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
with contextlib.ExitStack() as stack:
|
cache_folder = os.path.join(self._filesystem_path,
|
||||||
cache_folder = os.path.join(self._filesystem_path,
|
".Radicale.cache", "item")
|
||||||
".Radicale.cache", "item")
|
self._makedirs_synced(cache_folder)
|
||||||
self._makedirs_synced(cache_folder)
|
for href, vobject_item in vobject_items.items():
|
||||||
fs = []
|
if not is_safe_filesystem_path_component(href):
|
||||||
for href, vobject_item in vobject_items.items():
|
raise UnsafePathError(href)
|
||||||
if not is_safe_filesystem_path_component(href):
|
try:
|
||||||
raise UnsafePathError(href)
|
cache_content = self._item_cache_content(href, vobject_item)
|
||||||
try:
|
_, _, _, text, _, _, _ = cache_content
|
||||||
cache_content = self._item_cache_content(href,
|
except Exception as e:
|
||||||
vobject_item)
|
raise ValueError(
|
||||||
_, _, _, text, _, _, _ = cache_content
|
"Failed to store item %r in temporary collection %r: %s" %
|
||||||
except Exception as e:
|
(href, self.path, e)) from e
|
||||||
raise ValueError(
|
with self._atomic_write(os.path.join(cache_folder, href), "wb",
|
||||||
"Failed to store item %r in temporary collection %r: "
|
sync_directory=False) as f:
|
||||||
"%s" % (href, self.path, e)) from e
|
pickle.dump(cache_content, f)
|
||||||
fs.append(stack.enter_context(
|
path = path_to_filesystem(self._filesystem_path, href)
|
||||||
open(os.path.join(cache_folder, href), "wb")))
|
with self._atomic_write(
|
||||||
pickle.dump(cache_content, fs[-1])
|
path, newline="", sync_directory=False) as f:
|
||||||
path = path_to_filesystem(self._filesystem_path, href)
|
f.write(text)
|
||||||
fs.append(stack.enter_context(
|
|
||||||
open(path, "w", encoding=self._encoding, newline="")))
|
|
||||||
fs[-1].write(text)
|
|
||||||
# sync everything at once because it's slightly faster.
|
|
||||||
for f in fs:
|
|
||||||
try:
|
|
||||||
self._fsync(f.fileno())
|
|
||||||
except OSError as e:
|
|
||||||
raise RuntimeError("Fsync'ing file %r failed: %s" %
|
|
||||||
(f.name, e)) from e
|
|
||||||
self._sync_directory(self._filesystem_path)
|
self._sync_directory(self._filesystem_path)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
Loading…
Reference in New Issue
Block a user