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.
5 from compiled_file_system
import CompiledFileSystem
6 from docs_server_utils
import StringIdentity
7 from file_system
import FileNotFoundError
8 from future
import Future
9 from path_util
import ToDirectory
12 class ChainedCompiledFileSystem(object):
13 '''A CompiledFileSystem implementation that fetches data from a chain of
14 possible FileSystems. The chain consists of some number of FileSystems which
15 may have cached data for their CompiledFileSystem instances (injected on
16 Factory construction) + the main FileSystem (injected at Creation time).
18 The expected configuration is that the main FileSystem is a PatchedFileSystem
19 and the chain the FileSystem which it patches, but with file systems
20 constructed via the HostFileSystemIterator the main FileSystems could be
23 This slightly unusual configuration is primarily needed to avoid re-compiling
24 data for PatchedFileSystems, which are very similar to the FileSystem which
25 they patch. Re-compiling data is expensive and a waste of memory resources.
26 ChainedCompiledFileSystem shares the data.
28 class Factory(CompiledFileSystem
.Factory
):
29 def __init__(self
, file_system_chain
, object_store
):
30 self
._file
_system
_chain
= file_system_chain
31 self
._object
_store
= object_store
33 def Create(self
, file_system
, populate_function
, cls
, category
=None):
34 return ChainedCompiledFileSystem(
35 # Chain of CompiledFileSystem instances.
36 tuple(CompiledFileSystem
.Factory(self
._object
_store
).Create(
37 fs
, populate_function
, cls
, category
=category
)
38 for fs
in [file_system
] + self
._file
_system
_chain
),
39 # Identity, as computed by all file systems.
40 StringIdentity(*(fs
.GetIdentity() for fs
in self
._file
_system
_chain
)))
42 def __init__(self
, compiled_fs_chain
, identity
):
43 '''|compiled_fs_chain| is a list of tuples (compiled_fs, file_system).
45 assert len(compiled_fs_chain
) > 0
46 self
._compiled
_fs
_chain
= compiled_fs_chain
47 self
._identity
= identity
49 def GetFromFile(self
, path
, skip_not_found
=False):
52 lambda cfs
: cfs
.GetFromFile(path
, skip_not_found
=skip_not_found
),
53 lambda cfs
: cfs
._GetFileVersionFromCache
(path
))
55 def GetFromFileListing(self
, path
):
56 path
= ToDirectory(path
)
59 lambda compiled_fs
: compiled_fs
.GetFromFileListing(path
),
60 lambda compiled_fs
: compiled_fs
._GetFileListingVersionFromCache
(path
))
62 def _GetImpl(self
, path
, reader
, version_getter
):
63 # Strategy: Get the current version of |path| in main FileSystem, then run
64 # through |_compiled_fs_chain| in *reverse* to find the "oldest" FileSystem
65 # with an up-to-date version of that file.
67 # Obviously, if files have been added in the main FileSystem then none of
68 # the older FileSystems will be able to find it.
69 read_and_version_futures
= [(reader(fs
), version_getter(fs
), fs
)
70 for fs
in self
._compiled
_fs
_chain
]
74 # The first file system contains both files of a newer version and
75 # files shared with other compiled file systems. We are going to try
76 # each compiled file system in the reverse order and return the data
77 # when version matches. Data cached in other compiled file system will
78 # be reused whenever possible so that we don't need to recompile things
79 # that are not changed across these file systems.
80 first_version
= read_and_version_futures
[0][1].Get()
83 compiled_fs
) in reversed(read_and_version_futures
):
84 if version_future
.Get() == first_version
:
85 return read_future
.Get()
86 except FileNotFoundError
:
88 # Try an arbitrary operation again to generate a realistic stack trace.
89 return read_and_version_futures
[0][0].Get()
91 return Future(callback
=resolve
)
93 def GetIdentity(self
):