| 
					
				 | 
			
			
				@@ -17,6 +17,7 @@ from .helpers import Error, ErrorWithTraceback, IntegrityError, Location, Progre 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .hashindex import NSIndex 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .locking import UpgradableLock, LockError, LockErrorT 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 from .lrucache import LRUCache 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from .platform import SyncFile, sync_dir 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 MAX_OBJECT_SIZE = 20 * 1024 * 1024 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 MAGIC = b'BORG_SEG' 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -32,7 +33,7 @@ class Repository: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     On disk layout: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     dir/README 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     dir/config 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    dir/data/<X / SEGMENTS_PER_DIR>/<X> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    dir/data/<X // SEGMENTS_PER_DIR>/<X> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     dir/index.X 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     dir/hints.X 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     """ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -507,7 +508,7 @@ class LoggedIO: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def __init__(self, path, limit, segments_per_dir, capacity=90): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.path = path 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.fds = LRUCache(capacity, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            dispose=lambda fd: fd.close()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            dispose=self.close_fd) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.segment = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.limit = limit 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.segments_per_dir = segments_per_dir 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -519,6 +520,11 @@ class LoggedIO: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.fds.clear() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.fds = None  # Just to make sure we're disabled 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def close_fd(self, fd): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if hasattr(os, 'posix_fadvise'):  # only on UNIX 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            os.posix_fadvise(fd.fileno(), 0, 0, os.POSIX_FADV_DONTNEED) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fd.close() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def segment_iterator(self, reverse=False): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         data_path = os.path.join(self.path, 'data') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         dirs = sorted((dir for dir in os.listdir(data_path) if dir.isdigit()), key=int, reverse=reverse) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -535,7 +541,7 @@ class LoggedIO: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def get_segments_transaction_id(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        """Verify that the transaction id is consistent with the index transaction id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        """Return the last committed segment. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         for segment, filename in self.segment_iterator(reverse=True): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if self.is_committed_segment(filename): 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -578,7 +584,8 @@ class LoggedIO: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 dirname = os.path.join(self.path, 'data', str(self.segment // self.segments_per_dir)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 if not os.path.exists(dirname): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     os.mkdir(dirname) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            self._write_fd = open(self.segment_filename(self.segment), 'ab') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    sync_dir(os.path.join(self.path, 'data')) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self._write_fd = SyncFile(self.segment_filename(self.segment)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             self._write_fd.write(MAGIC) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             self.offset = MAGIC_LEN 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         return self._write_fd 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -591,6 +598,13 @@ class LoggedIO: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             self.fds[segment] = fd 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return fd 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def close_segment(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if self._write_fd: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self.segment += 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self.offset = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self._write_fd.close() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self._write_fd = None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def delete_segment(self, segment): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if segment in self.fds: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             del self.fds[segment] 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -641,7 +655,7 @@ class LoggedIO: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def read(self, segment, offset, id): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if segment == self.segment and self._write_fd: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            self._write_fd.flush() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self._write_fd.sync() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         fd = self.get_fd(segment) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         fd.seek(offset) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         header = fd.read(self.put_header_fmt.size) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -703,20 +717,8 @@ class LoggedIO: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     def write_commit(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         fd = self.get_write_fd(no_new=True) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fd.sync() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         header = self.header_no_crc_fmt.pack(self.header_fmt.size, TAG_COMMIT) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         crc = self.crc_fmt.pack(crc32(header) & 0xffffffff) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         fd.write(b''.join((crc, header))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         self.close_segment() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    def close_segment(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if self._write_fd: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            self.segment += 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            self.offset = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            self._write_fd.flush() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            os.fsync(self._write_fd.fileno()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if hasattr(os, 'posix_fadvise'):  # only on UNIX 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                # tell the OS that it does not need to cache what we just wrote, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                # avoids spoiling the cache for the OS and other processes. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                os.posix_fadvise(self._write_fd.fileno(), 0, 0, os.POSIX_FADV_DONTNEED) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            self._write_fd.close() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            self._write_fd = None 
			 |