Use inode number in addition to mtime (#632)

* Use inode number in addition to mtime

* Changelog
This commit is contained in:
Markus Unterwaditzer 2017-05-18 20:42:08 +02:00 committed by GitHub
parent 6851ceede0
commit d2127030c2
3 changed files with 12 additions and 9 deletions

View file

@ -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
==============

View file

@ -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):

View file

@ -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):