mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-04-15 12:25:52 +00:00
Use inode number in addition to mtime (#632)
* Use inode number in addition to mtime * Changelog
This commit is contained in:
parent
6851ceede0
commit
d2127030c2
3 changed files with 12 additions and 9 deletions
|
|
@ -26,6 +26,9 @@ Version 0.16.0
|
|||
- **Vdirsyncer is now licensed under the 3-clause BSD license**, see :gh:`610`.
|
||||
- Vdirsyncer now includes experimental support for `EteSync
|
||||
<https://www.etesync.com/>`_, see :ghpr:`614`.
|
||||
- Vdirsyncer now uses more filesystem metadata for determining whether an item
|
||||
changed. You will notice a **possibly heavy CPU/IO spike on the first sync
|
||||
after upgrading**.
|
||||
|
||||
Version 0.15.0
|
||||
==============
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ from atomicwrites import atomic_write
|
|||
|
||||
from .base import Storage
|
||||
from .. import exceptions
|
||||
from ..utils import checkfile, expand_path
|
||||
from ..utils import checkfile, expand_path, get_etag_from_file
|
||||
from ..vobject import Item, join_collection, split_collection
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -88,7 +88,7 @@ class SingleFileStorage(Storage):
|
|||
_read_mode = 'rb'
|
||||
|
||||
_items = None
|
||||
_last_mtime = None
|
||||
_last_etag = None
|
||||
|
||||
def __init__(self, path, encoding='utf-8', **kwargs):
|
||||
super(SingleFileStorage, self).__init__(**kwargs)
|
||||
|
|
@ -149,7 +149,7 @@ class SingleFileStorage(Storage):
|
|||
self._items = collections.OrderedDict()
|
||||
|
||||
try:
|
||||
self._last_mtime = os.path.getmtime(self.path)
|
||||
self._last_etag = get_etag_from_file(self.path)
|
||||
with open(self.path, self._read_mode) as f:
|
||||
text = f.read().decode(self.encoding)
|
||||
except OSError as e:
|
||||
|
|
@ -210,8 +210,8 @@ class SingleFileStorage(Storage):
|
|||
del self._items[href]
|
||||
|
||||
def _write(self):
|
||||
if self._last_mtime is not None and \
|
||||
self._last_mtime != os.path.getmtime(self.path):
|
||||
if self._last_etag is not None and \
|
||||
self._last_etag != get_etag_from_file(self.path):
|
||||
raise exceptions.PreconditionFailed(
|
||||
'Some other program modified the file {r!}. Re-run the '
|
||||
'synchronization and make sure absolutely no other program is '
|
||||
|
|
@ -224,7 +224,7 @@ class SingleFileStorage(Storage):
|
|||
f.write(text.encode(self.encoding))
|
||||
finally:
|
||||
self._items = None
|
||||
self._last_mtime = None
|
||||
self._last_etag = None
|
||||
|
||||
@contextlib.contextmanager
|
||||
def at_once(self):
|
||||
|
|
|
|||
|
|
@ -59,10 +59,10 @@ def uniq(s):
|
|||
|
||||
|
||||
def get_etag_from_file(f):
|
||||
'''Get mtime-based etag from a filepath or file-like object.
|
||||
'''Get etag from a filepath or file-like object.
|
||||
|
||||
This function will flush/sync the file as much as necessary to obtain a
|
||||
correct mtime.
|
||||
correct value.
|
||||
'''
|
||||
if hasattr(f, 'read'):
|
||||
f.flush() # Only this is necessary on Linux
|
||||
|
|
@ -75,7 +75,7 @@ def get_etag_from_file(f):
|
|||
mtime = getattr(stat, 'st_mtime_ns', None)
|
||||
if mtime is None:
|
||||
mtime = stat.st_mtime
|
||||
return '{:.9f}'.format(mtime)
|
||||
return '{:.9f};{}'.format(mtime, stat.st_ino)
|
||||
|
||||
|
||||
def get_storage_init_specs(cls, stop_at=object):
|
||||
|
|
|
|||
Loading…
Reference in a new issue