Pārlūkot izejas kodu

open files with O_NOATIME if possible

Carlo Teubner 10 gadi atpakaļ
vecāks
revīzija
f4804c07ca
1 mainītis faili ar 41 papildinājumiem un 2 dzēšanām
  1. 41 2
      attic/archive.py

+ 41 - 2
attic/archive.py

@@ -82,7 +82,7 @@ class ChunkBuffer:
         chunks = list(bytes(s) for s in self.chunker.chunkify(self.buffer))
         chunks = list(bytes(s) for s in self.chunker.chunkify(self.buffer))
         self.buffer.seek(0)
         self.buffer.seek(0)
         self.buffer.truncate(0)
         self.buffer.truncate(0)
-        # Leave the last parital chunk in the buffer unless flush is True
+        # Leave the last partial chunk in the buffer unless flush is True
         end = None if flush or len(chunks) == 1 else -1
         end = None if flush or len(chunks) == 1 else -1
         for chunk in chunks[:end]:
         for chunk in chunks[:end]:
             self.chunks.append(self.write_chunk(chunk))
             self.chunks.append(self.write_chunk(chunk))
@@ -399,7 +399,7 @@ class Archive:
                 chunks = [cache.chunk_incref(id_, self.stats) for id_ in ids]
                 chunks = [cache.chunk_incref(id_, self.stats) for id_ in ids]
         # Only chunkify the file if needed
         # Only chunkify the file if needed
         if chunks is None:
         if chunks is None:
-            with open(path, 'rb') as fd:
+            with Archive._open_rb(path, st) as fd:
                 chunks = []
                 chunks = []
                 for chunk in self.chunker.chunkify(fd):
                 for chunk in self.chunker.chunkify(fd):
                     chunks.append(cache.add_chunk(self.key.id_hash(chunk), chunk, self.stats))
                     chunks.append(cache.add_chunk(self.key.id_hash(chunk), chunk, self.stats))
@@ -414,6 +414,45 @@ class Archive:
         for name, info in manifest.archives.items():
         for name, info in manifest.archives.items():
             yield Archive(repository, key, manifest, name, cache=cache)
             yield Archive(repository, key, manifest, name, cache=cache)
 
 
+    @staticmethod
+    def _open_rb(path, st):
+        flags_noatime = None
+        euid = None
+
+        def open_simple(p, s):
+            return open(p, 'rb')
+
+        def open_noatime_if_owner(p, s):
+            if s.st_uid == euid:
+                return os.fdopen(os.open(p, flags_noatime), 'rb')
+            else:
+                return open(p, 'rb')
+
+        def open_noatime(p, s):
+            try:
+                fd = os.open(p, flags_noatime)
+            except PermissionError:
+                # Was this EPERM due to the O_NOATIME flag?
+                fo = open(p, 'rb')
+                # Yes, it was -- otherwise the above line would have thrown
+                # another exception.
+                euid = os.geteuid()
+                # So in future, let's check whether the file is owned by us
+                # before attempting to use O_NOATIME.
+                Archive._open_rb = open_noatime_if_owner
+                return fo
+            return os.fdopen(fd, 'rb')
+
+        o_noatime = getattr(os, 'O_NOATIME', None)
+        if o_noatime is not None:
+            flags_noatime = os.O_RDONLY | getattr(os, 'O_BINARY', 0) | o_noatime
+            # Always use O_NOATIME version.
+            Archive._open_rb = open_noatime
+        else:
+            # Always use non-O_NOATIME version.
+            Archive._open_rb = open_simple
+        return Archive._open_rb(path, st)
+
 
 
 class RobustUnpacker():
 class RobustUnpacker():
     """A restartable/robust version of the streaming msgpack unpacker
     """A restartable/robust version of the streaming msgpack unpacker