diff --git a/CHANGELOG.md b/CHANGELOG.md index f9e2a473..23f73485 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Add: option [auth] type oauth2 by code migration from https://gitlab.mim-libre.fr/alphabet/radicale_oauth/-/blob/dev/oauth2/ * Fix: catch OS errors on PUT MKCOL MKCALENDAR MOVE PROPPATCH (insufficient storage, access denied, internal server error) * Test: skip bcrypt related tests if module is missing +* Improve: relax mtime check on storage filesystem ## 3.4.1 * Add: option [auth] dovecot_connection_type / dovecot_host / dovecot_port diff --git a/radicale/storage/multifilesystem/__init__.py b/radicale/storage/multifilesystem/__init__.py index 3bf9202f..1a933d14 100644 --- a/radicale/storage/multifilesystem/__init__.py +++ b/radicale/storage/multifilesystem/__init__.py @@ -2,7 +2,7 @@ # Copyright © 2014 Jean-Marc Martins # Copyright © 2012-2017 Guillaume Ayoub # Copyright © 2017-2021 Unrud -# Copyright © 2024-2024 Peter Bieringer +# Copyright © 2024-2025 Peter Bieringer # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -95,15 +95,21 @@ class Storage( def _analyse_mtime(self): # calculate and display mtime resolution path = os.path.join(self._filesystem_folder, ".Radicale.mtime_test") + logger.debug("Storage item mtime resolution test with file: %r", path) try: with open(path, "w") as f: f.write("mtime_test") f.close except Exception as e: - logger.error("Storage item mtime resolution test not possible, cannot write file: %r (%s)", path, e) + logger.warning("Storage item mtime resolution test not possible, cannot write file: %r (%s)", path, e) raise # set mtime_ns for tests - os.utime(path, times=None, ns=(MTIME_NS_TEST, MTIME_NS_TEST)) + try: + os.utime(path, times=None, ns=(MTIME_NS_TEST, MTIME_NS_TEST)) + except Exception as e: + logger.warning("Storage item mtime resolution test not possible, cannot set utime on file: %r (%s)", path, e) + os.remove(path) + raise logger.debug("Storage item mtime resoultion test set: %d" % MTIME_NS_TEST) mtime_ns = os.stat(path).st_mtime_ns logger.debug("Storage item mtime resoultion test get: %d" % mtime_ns) @@ -147,17 +153,20 @@ def __init__(self, configuration: config.Configuration) -> None: logger.info("Storage cache subfolder usage for 'history': %s", self._use_cache_subfolder_for_history) logger.info("Storage cache subfolder usage for 'sync-token': %s", self._use_cache_subfolder_for_synctoken) logger.info("Storage cache use mtime and size for 'item': %s", self._use_mtime_and_size_for_item_cache) - (precision, precision_unit, unit) = self._analyse_mtime() - if precision >= 100000000: - # >= 100 ms - logger.warning("Storage item mtime resolution test result: %d %s (VERY RISKY ON PRODUCTION SYSTEMS)" % (precision_unit, unit)) - elif precision >= 10000000: - # >= 10 ms - logger.warning("Storage item mtime resolution test result: %d %s (RISKY ON PRODUCTION SYSTEMS)" % (precision_unit, unit)) - else: - logger.info("Storage item mtime resolution test result: %d %s" % (precision_unit, unit)) - if self._use_mtime_and_size_for_item_cache is False: - logger.info("Storage cache using mtime and size for 'item' may be an option in case of performance issues") + try: + (precision, precision_unit, unit) = self._analyse_mtime() + if precision >= 100000000: + # >= 100 ms + logger.warning("Storage item mtime resolution test result: %d %s (VERY RISKY ON PRODUCTION SYSTEMS)" % (precision_unit, unit)) + elif precision >= 10000000: + # >= 10 ms + logger.warning("Storage item mtime resolution test result: %d %s (RISKY ON PRODUCTION SYSTEMS)" % (precision_unit, unit)) + else: + logger.info("Storage item mtime resolution test result: %d %s" % (precision_unit, unit)) + if self._use_mtime_and_size_for_item_cache is False: + logger.info("Storage cache using mtime and size for 'item' may be an option in case of performance issues") + except Exception: + logger.warning("Storage item mtime resolution test result not successful") logger.debug("Storage cache action logging: %s", self._debug_cache_actions) if self._use_cache_subfolder_for_item is True or self._use_cache_subfolder_for_history is True or self._use_cache_subfolder_for_synctoken is True: logger.info("Storage cache subfolder: %r", self._get_collection_cache_folder())