|
@@ -13,7 +13,7 @@ from .xattr import _listxattr_inner, _getxattr_inner, _setxattr_inner, split_str
|
|
|
from libc cimport errno
|
|
|
from libc.stdint cimport int64_t
|
|
|
|
|
|
-API_VERSION = '1.2_02'
|
|
|
+API_VERSION = '1.2_03'
|
|
|
|
|
|
cdef extern from "sys/xattr.h":
|
|
|
ssize_t c_listxattr "listxattr" (const char *path, char *list, size_t size)
|
|
@@ -315,39 +315,60 @@ cdef _sync_file_range(fd, offset, length, flags):
|
|
|
raise OSError(errno.errno, os.strerror(errno.errno))
|
|
|
safe_fadvise(fd, offset, length, 'DONTNEED')
|
|
|
|
|
|
-cdef unsigned PAGE_MASK = sysconf(_SC_PAGESIZE) - 1
|
|
|
|
|
|
+cdef unsigned PAGE_MASK = sysconf(_SC_PAGESIZE) - 1
|
|
|
|
|
|
-class SyncFile(BaseSyncFile):
|
|
|
- """
|
|
|
- Implemented using sync_file_range for asynchronous write-out and fdatasync for actual durability.
|
|
|
|
|
|
- "write-out" means that dirty pages (= data that was written) are submitted to an I/O queue and will be send to
|
|
|
- disk in the immediate future.
|
|
|
- """
|
|
|
-
|
|
|
- def __init__(self, path, binary=False):
|
|
|
- super().__init__(path, binary)
|
|
|
- self.offset = 0
|
|
|
- self.write_window = (16 * 1024 ** 2) & ~PAGE_MASK
|
|
|
- self.last_sync = 0
|
|
|
- self.pending_sync = None
|
|
|
-
|
|
|
- def write(self, data):
|
|
|
- self.offset += self.fd.write(data)
|
|
|
- offset = self.offset & ~PAGE_MASK
|
|
|
- if offset >= self.last_sync + self.write_window:
|
|
|
+def _is_WSL():
|
|
|
+ """detect Windows Subsystem for Linux"""
|
|
|
+ try:
|
|
|
+ with open('/proc/version') as fd:
|
|
|
+ linux_version = fd.read()
|
|
|
+ # hopefully no non-WSL Linux will ever mention 'Microsoft' in the kernel version:
|
|
|
+ return 'Microsoft' in linux_version
|
|
|
+ except: # noqa
|
|
|
+ # make sure to never ever crash due to this check.
|
|
|
+ return False
|
|
|
+
|
|
|
+
|
|
|
+if _is_WSL():
|
|
|
+ class SyncFile(BaseSyncFile):
|
|
|
+ # if we are on Microsoft's "Windows Subsytem for Linux", use the
|
|
|
+ # more generic BaseSyncFile to avoid issues like seen there:
|
|
|
+ # https://github.com/borgbackup/borg/issues/1961
|
|
|
+ pass
|
|
|
+else:
|
|
|
+ # a real Linux, so we can do better. :)
|
|
|
+ class SyncFile(BaseSyncFile):
|
|
|
+ """
|
|
|
+ Implemented using sync_file_range for asynchronous write-out and fdatasync for actual durability.
|
|
|
+
|
|
|
+ "write-out" means that dirty pages (= data that was written) are submitted to an I/O queue and will be send to
|
|
|
+ disk in the immediate future.
|
|
|
+ """
|
|
|
+
|
|
|
+ def __init__(self, path, binary=False):
|
|
|
+ super().__init__(path, binary)
|
|
|
+ self.offset = 0
|
|
|
+ self.write_window = (16 * 1024 ** 2) & ~PAGE_MASK
|
|
|
+ self.last_sync = 0
|
|
|
+ self.pending_sync = None
|
|
|
+
|
|
|
+ def write(self, data):
|
|
|
+ self.offset += self.fd.write(data)
|
|
|
+ offset = self.offset & ~PAGE_MASK
|
|
|
+ if offset >= self.last_sync + self.write_window:
|
|
|
+ self.fd.flush()
|
|
|
+ _sync_file_range(self.fileno, self.last_sync, offset - self.last_sync, SYNC_FILE_RANGE_WRITE)
|
|
|
+ if self.pending_sync is not None:
|
|
|
+ _sync_file_range(self.fileno, self.pending_sync, self.last_sync - self.pending_sync,
|
|
|
+ SYNC_FILE_RANGE_WRITE | SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WAIT_AFTER)
|
|
|
+ self.pending_sync = self.last_sync
|
|
|
+ self.last_sync = offset
|
|
|
+
|
|
|
+ def sync(self):
|
|
|
self.fd.flush()
|
|
|
- _sync_file_range(self.fileno, self.last_sync, offset - self.last_sync, SYNC_FILE_RANGE_WRITE)
|
|
|
- if self.pending_sync is not None:
|
|
|
- _sync_file_range(self.fileno, self.pending_sync, self.last_sync - self.pending_sync,
|
|
|
- SYNC_FILE_RANGE_WRITE | SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WAIT_AFTER)
|
|
|
- self.pending_sync = self.last_sync
|
|
|
- self.last_sync = offset
|
|
|
-
|
|
|
- def sync(self):
|
|
|
- self.fd.flush()
|
|
|
- os.fdatasync(self.fileno)
|
|
|
- # tell the OS that it does not need to cache what we just wrote,
|
|
|
- # avoids spoiling the cache for the OS and other processes.
|
|
|
- safe_fadvise(self.fileno, 0, 0, 'DONTNEED')
|
|
|
+ os.fdatasync(self.fileno)
|
|
|
+ # tell the OS that it does not need to cache what we just wrote,
|
|
|
+ # avoids spoiling the cache for the OS and other processes.
|
|
|
+ safe_fadvise(self.fileno, 0, 0, 'DONTNEED')
|