| 
														
															@@ -3,6 +3,7 @@ import mmap 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 import os 
														 | 
														
														 | 
														
															 import os 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 import shutil 
														 | 
														
														 | 
														
															 import shutil 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 import struct 
														 | 
														
														 | 
														
															 import struct 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+import time 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 from binascii import hexlify, unhexlify 
														 | 
														
														 | 
														
															 from binascii import hexlify, unhexlify 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 from collections import defaultdict 
														 | 
														
														 | 
														
															 from collections import defaultdict 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 from configparser import ConfigParser 
														 | 
														
														 | 
														
															 from configparser import ConfigParser 
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -1135,8 +1136,7 @@ class LoggedIO: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															     def __init__(self, path, limit, segments_per_dir, capacity=90): 
														 | 
														
														 | 
														
															     def __init__(self, path, limit, segments_per_dir, capacity=90): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         self.path = path 
														 | 
														
														 | 
														
															         self.path = path 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-        self.fds = LRUCache(capacity, 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-                            dispose=self.close_fd) 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        self.fds = LRUCache(capacity, dispose=self._close_fd) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         self.segment = 0 
														 | 
														
														 | 
														
															         self.segment = 0 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         self.limit = limit 
														 | 
														
														 | 
														
															         self.limit = limit 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         self.segments_per_dir = segments_per_dir 
														 | 
														
														 | 
														
															         self.segments_per_dir = segments_per_dir 
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -1148,7 +1148,8 @@ class LoggedIO: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         self.fds.clear() 
														 | 
														
														 | 
														
															         self.fds.clear() 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         self.fds = None  # Just to make sure we're disabled 
														 | 
														
														 | 
														
															         self.fds = None  # Just to make sure we're disabled 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															-    def close_fd(self, fd): 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+    def _close_fd(self, ts_fd): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        ts, fd = ts_fd 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         safe_fadvise(fd.fileno(), 0, 0, 'DONTNEED') 
														 | 
														
														 | 
														
															         safe_fadvise(fd.fileno(), 0, 0, 'DONTNEED') 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         fd.close() 
														 | 
														
														 | 
														
															         fd.close() 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -1262,13 +1263,31 @@ class LoggedIO: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         return self._write_fd 
														 | 
														
														 | 
														
															         return self._write_fd 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															     def get_fd(self, segment): 
														 | 
														
														 | 
														
															     def get_fd(self, segment): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-        try: 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-            return self.fds[segment] 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-        except KeyError: 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        # note: get_fd() returns a fd with undefined file pointer position, 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        # so callers must always seek() to desired position afterwards. 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        now = time.monotonic() 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+ 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        def open_fd(): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															             fd = open(self.segment_filename(segment), 'rb') 
														 | 
														
														 | 
														
															             fd = open(self.segment_filename(segment), 'rb') 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-            self.fds[segment] = fd 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+            self.fds[segment] = (now, fd) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															             return fd 
														 | 
														
														 | 
														
															             return fd 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        try: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+            ts, fd = self.fds[segment] 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        except KeyError: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+            fd = open_fd() 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        else: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+            if now - ts > FD_MAX_AGE: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+                # we do not want to touch long-unused file handles to 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+                # avoid ESTALE issues (e.g. on network filesystems). 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+                del self.fds[segment] 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+                fd = open_fd() 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+            else: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+                # fd is fresh enough, so we use it. 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+                # also, we update the timestamp of the lru cache entry. 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+                self.fds.upd(segment, (now, fd)) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+        return fd 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+ 
														 | 
													
												
											
												
													
														| 
														 | 
														
															     def close_segment(self): 
														 | 
														
														 | 
														
															     def close_segment(self): 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         # set self._write_fd to None early to guard against reentry from error handling code paths: 
														 | 
														
														 | 
														
															         # set self._write_fd to None early to guard against reentry from error handling code paths: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															         fd, self._write_fd = self._write_fd, None 
														 | 
														
														 | 
														
															         fd, self._write_fd = self._write_fd, None 
														 |