Home | History | Annotate | Download | only in server2
      1 # Copyright 2013 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 from compiled_file_system import CompiledFileSystem
      6 from file_system import FileNotFoundError
      7 
      8 class ChainedCompiledFileSystem(object):
      9   ''' A CompiledFileSystem implementation that fetches data from a chain of
     10   CompiledFileSystems that have different file systems and separate cache
     11   namespaces.
     12 
     13   The rules for the compiled file system chain are:
     14     - Versions are fetched from the first compiled file system's underlying
     15       file system.
     16     - Each compiled file system is read in the reverse order (the last one is
     17       read first). If the version matches, return the data. Otherwise, read
     18       from the previous compiled file system until the first one is read.
     19 
     20   It is used to chain compiled file systems whose underlying file systems are
     21   slightly different. This makes it possible to reuse cached compiled data in
     22   one of them without recompiling everything that is shared by them.
     23   '''
     24   class Factory(CompiledFileSystem.Factory):
     25     def __init__(self,
     26                  factory_and_fs_chain):
     27       self._factory_and_fs_chain = factory_and_fs_chain
     28 
     29     def Create(self, populate_function, cls, category=None):
     30       return ChainedCompiledFileSystem(
     31           [(factory.Create(populate_function, cls, category), fs)
     32            for factory, fs in self._factory_and_fs_chain])
     33 
     34   def __init__(self, compiled_fs_chain):
     35     assert len(compiled_fs_chain) > 0
     36     self._compiled_fs_chain = compiled_fs_chain
     37 
     38   def GetFromFile(self, path, binary=False):
     39     # It's possible that a new file is added in the first compiled file system
     40     # and it doesn't exist in other compiled file systems.
     41     try:
     42       first_compiled_fs, first_file_system = self._compiled_fs_chain[0]
     43       # The first file system contains both files of a newer version and files
     44       # shared with other compiled file systems. We are going to try each
     45       # compiled file system in the reverse order and return the data when
     46       # version matches. Data cached in other compiled file system will be
     47       # reused whenever possible so that we don't need to recompile things that
     48       # are not changed across these file systems.
     49       version = first_file_system.Stat(path).version
     50       for compiled_fs, _ in reversed(self._compiled_fs_chain):
     51         if compiled_fs.StatFile(path) == version:
     52           return compiled_fs.GetFromFile(path, binary)
     53     except FileNotFoundError:
     54       pass
     55     # Try first operation again to generate the correct stack trace
     56     return first_compiled_fs.GetFromFile(path, binary)
     57 
     58   def GetFromFileListing(self, path):
     59     if not path.endswith('/'):
     60       path += '/'
     61     try:
     62       first_compiled_fs, first_file_system = self._compiled_fs_chain[0]
     63       version = first_file_system.Stat(path).version
     64       for compiled_fs, _ in reversed(self._compiled_fs_chain):
     65         if compiled_fs.StatFileListing(path) == version:
     66           return compiled_fs.GetFromFileListing(path)
     67     except FileNotFoundError:
     68       pass
     69     # Try first operation again to generate the correct stack trace
     70     return first_compiled_fs.GetFromFileListing(path)
     71