2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source path is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the path LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
29 #include <folly/Executor.h>
30 #include <folly/SharedMutex.h>
31 #include <folly/Synchronized.h>
32 #include <folly/futures/Future.h>
33 #include <folly/futures/FutureSplitter.h>
34 #include "hphp/runtime/ext/facts/attribute-map.h"
35 #include "hphp/runtime/ext/facts/autoload-db.h"
36 #include "hphp/runtime/ext/facts/file-facts.h"
37 #include "hphp/runtime/ext/facts/inheritance-info.h"
38 #include "hphp/runtime/ext/facts/lazy-two-way-map.h"
39 #include "hphp/runtime/ext/facts/path-symbols-map.h"
40 #include "hphp/runtime/ext/facts/path-versions.h"
41 #include "hphp/runtime/ext/facts/string-ptr.h"
42 #include "hphp/runtime/ext/facts/symbol-types.h"
43 #include "hphp/util/assertions.h"
44 #include "hphp/util/hash-map.h"
45 #include "hphp/util/hash-set.h"
46 #include "hphp/util/sha1.h"
47 #include "hphp/util/sqlite-wrapper.h"
55 struct UpdateDBWorkItem
{
58 std::vector
<std::filesystem::path
> m_alteredPaths
;
59 std::vector
<std::filesystem::path
> m_deletedPaths
;
60 std::vector
<FileFacts
> m_alteredPathFacts
;
64 * Stores a map from thread to AutoloadDB.
66 struct AutoloadDBVault
{
67 explicit AutoloadDBVault(AutoloadDB::Opener
);
70 * Get the AutoloadDB associated with the thread that calls this method.
72 * Logically this is `const`, but it creates an AutoloadDB on first access.
74 std::shared_ptr
<AutoloadDB
> get() const;
77 AutoloadDB::Opener m_dbOpener
;
78 // Holds one AutoloadDB per thread. Creates an AutoloadDB on the first access.
79 mutable folly::Synchronized
<
80 hphp_hash_map
<std::thread::id
, std::shared_ptr
<AutoloadDB
>>>
85 * Stores and updates one PathToSymbolsMap for each kind of symbol.
87 * Multiple readers can run concurrently with one writer, but only one
88 * call to SymbolMap::update should happen at any given time.
90 * Queries the SQLite AutoloadDB when the DB has information
91 * we don't, and updates the AutoloadDB when we have
92 * information the DB doesn't have.
96 std::filesystem::path root
,
97 AutoloadDB::Opener dbOpener
,
98 hphp_vector_set
<Symbol
<SymKind::Type
>> indexedMethodAttributes
,
99 bool enableBlockingDbWait
,
100 bool useSymbolMapForGetFilesWithAttrAndAnyVal
,
101 std::chrono::milliseconds blockingDbWaitTimeout
);
102 SymbolMap() = delete;
103 SymbolMap(const SymbolMap
&) = delete;
104 SymbolMap(SymbolMap
&&) noexcept
= delete;
105 SymbolMap
& operator=(const SymbolMap
&) = delete;
106 SymbolMap
& operator=(SymbolMap
&&) noexcept
= delete;
110 * Resolve a type's name to its canonical, correctly-capitalized name.
112 * Return nullptr if the type is not defined, or if the type is defined in
113 * more than one file.
115 Optional
<Symbol
<SymKind::Type
>> getTypeName(const StringData
& type
);
118 * Return the one and only definition for the given symbol.
120 * If the symbol is defined in no files, or in more than one file,
123 * These methods may fill the map with information from the SQLite
124 * DB, and as such may throw SQLite exceptions.
126 Path
getTypeOrTypeAliasFile(Symbol
<SymKind::Type
> type
);
127 Path
getTypeOrTypeAliasFile(const StringData
& type
);
128 Path
getTypeFile(Symbol
<SymKind::Type
> type
);
129 Path
getTypeFile(const StringData
& type
);
130 Path
getFunctionFile(Symbol
<SymKind::Function
> function
);
131 Path
getFunctionFile(const StringData
& function
);
132 Path
getConstantFile(Symbol
<SymKind::Constant
> constant
);
133 Path
getConstantFile(const StringData
& constant
);
134 // Returns the file containing the module definition.
135 Path
getModuleFile(Symbol
<SymKind::Module
> module
);
136 // Returns the file containing the module definition.
137 Path
getModuleFile(const StringData
& module
);
138 Path
getTypeAliasFile(Symbol
<SymKind::Type
> typeAlias
);
139 Path
getTypeAliasFile(const StringData
& typeAlias
);
142 * Return all symbols of a given kind declared in the given path.
144 * These methods may fill the map with information from the SQLite
145 * DB, and as such may throw SQLite exceptions.
147 std::vector
<Symbol
<SymKind::Type
>> getFileTypes(Path path
);
148 std::vector
<Symbol
<SymKind::Type
>> getFileTypes(const std::filesystem::path
&);
150 std::vector
<Symbol
<SymKind::Function
>> getFileFunctions(Path path
);
151 std::vector
<Symbol
<SymKind::Function
>> getFileFunctions(
152 const std::filesystem::path
& path
);
154 std::vector
<Symbol
<SymKind::Constant
>> getFileConstants(Path path
);
155 std::vector
<Symbol
<SymKind::Constant
>> getFileConstants(
156 const std::filesystem::path
& path
);
158 // Returns the set of Modules defined in the given file.
159 std::vector
<Symbol
<SymKind::Module
>> getFileModules(Path path
);
160 std::vector
<Symbol
<SymKind::Module
>> getFileModules(
161 const std::filesystem::path
& path
);
163 // Returns the module the file is contained in, if any.
164 std::optional
<Symbol
<SymKind::ModuleMembership
>> getFileModuleMembership(
166 std::optional
<Symbol
<SymKind::ModuleMembership
>> getFileModuleMembership(
167 const std::filesystem::path
& path
);
169 std::vector
<Symbol
<SymKind::Type
>> getFileTypeAliases(Path path
);
170 std::vector
<Symbol
<SymKind::Type
>> getFileTypeAliases(
171 const std::filesystem::path
& path
);
174 * Return inheritance data about the given type
176 std::vector
<Symbol
<SymKind::Type
>> getBaseTypes(
177 Symbol
<SymKind::Type
> derivedType
,
179 std::vector
<Symbol
<SymKind::Type
>> getBaseTypes(
180 const StringData
& derivedType
,
183 std::vector
<Symbol
<SymKind::Type
>> getDerivedTypes(
184 Symbol
<SymKind::Type
> baseType
,
186 std::vector
<Symbol
<SymKind::Type
>> getDerivedTypes(
187 const StringData
& baseType
,
191 * Return the attributes of a type
193 std::vector
<Symbol
<SymKind::Type
>> getAttributesOfType(
194 Symbol
<SymKind::Type
> type
);
195 std::vector
<Symbol
<SymKind::Type
>> getAttributesOfType(
196 const StringData
& type
);
199 * Return the attributes decorating a type alias
201 std::vector
<Symbol
<SymKind::Type
>> getAttributesOfTypeAlias(
202 Symbol
<SymKind::Type
> typeAlias
);
203 std::vector
<Symbol
<SymKind::Type
>> getAttributesOfTypeAlias(
204 const StringData
& typeAlias
);
207 * Return the types decorated with a given attribute
209 std::vector
<Symbol
<SymKind::Type
>> getTypesWithAttribute(
210 Symbol
<SymKind::Type
> attr
);
211 std::vector
<Symbol
<SymKind::Type
>> getTypesWithAttribute(
212 const StringData
& attr
);
215 * Return the type aliases decorated with a given attribute
217 std::vector
<Symbol
<SymKind::Type
>> getTypeAliasesWithAttribute(
218 Symbol
<SymKind::Type
> attr
);
219 std::vector
<Symbol
<SymKind::Type
>> getTypeAliasesWithAttribute(
220 const StringData
& attr
);
223 * Return the attributes of a method
225 std::vector
<Symbol
<SymKind::Type
>> getAttributesOfMethod(
226 Symbol
<SymKind::Type
> type
,
227 Symbol
<SymKind::Method
> method
);
228 std::vector
<Symbol
<SymKind::Type
>> getAttributesOfMethod(
229 const StringData
& type
,
230 const StringData
& method
);
233 * Return the methods with a given attribute
235 std::vector
<MethodDecl
> getMethodsWithAttribute(Symbol
<SymKind::Type
> attr
);
236 std::vector
<MethodDecl
> getMethodsWithAttribute(const StringData
& attr
);
239 * Return the attributes of a file
241 std::vector
<Symbol
<SymKind::Type
>> getAttributesOfFile(Path path
);
244 * Return the files with a given attribute
246 std::vector
<Path
> getFilesWithAttribute(Symbol
<SymKind::Type
> attr
);
247 std::vector
<Path
> getFilesWithAttribute(const StringData
& attr
);
250 * Return the files with a given attribute and value
252 std::vector
<Path
> getFilesWithAttributeAndAnyValue(
253 Symbol
<SymKind::Type
> attr
,
254 const folly::dynamic
& value
);
255 std::vector
<Path
> getFilesWithAttributeAndAnyValue(
256 const StringData
& attr
,
257 const folly::dynamic
& value
);
259 std::vector
<FileAttrVal
> getFilesAndAttrValsWithAttribute(
260 Symbol
<SymKind::Type
> attr
);
262 std::vector
<FileAttrVal
> getFilesAndAttrValsWithAttribute(
263 const StringData
& attr
);
266 * Return the argument at the given position of a given type with a given
269 * So if a type were defined with an attribute like this:
271 * <<Oncalls('hhvm')>>
274 * You'd expect to be able to extract that "hhvm" argument this way:
276 * getAttributeArg("Foo", "Oncalls").at(0) == "hhvm"
278 * If this function returns an empty vector, it could be because:
280 * - The type is not defined.
281 * - The type is defined in more than one file, violating the One Definition
283 * - The type doesn't have the given attribute.
284 * - The attribute doesn't have any arguments.
286 * You can check that the type is defined with `getTypeFile()`, and you can
287 * check that the type has the given attribute with `getAttributesOfType()`.
289 std::vector
<folly::dynamic
> getTypeAttributeArgs(
290 Symbol
<SymKind::Type
> type
,
291 Symbol
<SymKind::Type
> attribute
);
292 std::vector
<folly::dynamic
> getTypeAttributeArgs(
293 const StringData
& type
,
294 const StringData
& attribute
);
296 std::vector
<folly::dynamic
> getTypeAliasAttributeArgs(
297 Symbol
<SymKind::Type
> type
,
298 Symbol
<SymKind::Type
> attribute
);
299 std::vector
<folly::dynamic
> getTypeAliasAttributeArgs(
300 const StringData
& type
,
301 const StringData
& attribute
);
303 std::vector
<folly::dynamic
> getMethodAttributeArgs(
304 Symbol
<SymKind::Type
> type
,
305 Symbol
<SymKind::Method
> method
,
306 Symbol
<SymKind::Type
> attribute
);
307 std::vector
<folly::dynamic
> getMethodAttributeArgs(
308 const StringData
& type
,
309 const StringData
& method
,
310 const StringData
& attribute
);
312 std::vector
<folly::dynamic
> getFileAttributeArgs(
314 Symbol
<SymKind::Type
> attribute
);
315 std::vector
<folly::dynamic
> getFileAttributeArgs(
317 const StringData
& attribute
);
320 * Return whether the given type is, for example, a class or interface.
322 * Return `TypeKind::Unknown` if the given type does not have a unique
323 * definition or is not an autoloadable type at all.
325 TypeKind
getKind(Symbol
<SymKind::Type
> type
);
326 TypeKind
getKind(const StringData
& type
);
328 bool isTypeAbstract(Symbol
<SymKind::Type
> type
);
329 bool isTypeAbstract(const StringData
& type
);
331 bool isTypeFinal(Symbol
<SymKind::Type
> type
);
332 bool isTypeFinal(const StringData
& type
);
334 bool isAttrIndexed(const StringData
& attr
) const;
335 std::string
debugIndexedAttrs() const;
338 * Return a hash representing the given path's last-known checksum.
340 Optional
<SHA1
> getSha1Hash(Path path
) const;
343 * For each file, update the SymbolMap with the given file facts.
345 * On success set m_clock to the given clock, and schedule a thread
346 * to update the DB with the new information.
348 * If the `since` token is nonempty and does not correspond to
349 * either our in-memory clock or the clock in the DB, throw an
350 * UpdateExc and do not perform any writes. The caller should
351 * initiate a fresh Watchman query with a `since` token
352 * corresponding to the clock in the map.
354 * since: An opaque token originating from Watchman representing the
355 * beginning of this update's time interval. `since` should either
356 * be empty (if we're initializing the map from scratch) or should
357 * be the timestamp currently in either the map or the DB (if we're
358 * incrementally updating the map).
360 * clock: An opaque token originating from Watchman representing the
361 * end of this update's time interval. After updating, this clock
362 * will be stored in the SymbolMap and DB.
364 * alteredPaths: A list of all paths which have changed between the
365 * last two queries to Watchman (represented by `since` and
366 * `clock`). This vector must have the same number of elements as
369 * deletedPaths: A list of all paths which have been deleted between
370 * the last two queries to Watchman (represented by `since` and
373 * alteredPathFacts: A list of all symbols found in the
374 * `alteredPaths`. Must be the same size as `alteredPaths`, and
375 * elements must be in the same order.
380 std::vector
<std::filesystem::path
> alteredPaths
,
381 std::vector
<std::filesystem::path
> deletedPaths
,
382 std::vector
<FileFacts
> alteredPathFacts
); // throws(SQLiteExc)
385 * Return an opaque token representing how up to date this map is.
387 * This token originated from Watchman.
389 Clock
getClock() const noexcept
;
392 * Throws an exception if facts sqlite database is corrupted/invalid.
394 * Currently only checks the sql DB for validation, not anything in map.
396 void validate(const std::set
<std::string
>& types_to_ignore
);
399 * Return an opaque token representing how up to date the SQLite DB is.
401 * This token originated from Watchman.
403 Clock
dbClock() const; // throws(SQLiteExc)
406 * Return the one and only path where `symbol` is defined.
408 * If `symbol` is not defined, return nullptr.
410 * If `symbol` is defined in more than one path, return either one of the
411 * paths that defines `symbol`, or return `nullptr`. In Hack, it's a bug to
412 * define the same symbol in multiple paths, so we leave this behavior
415 * Query the DB if there is no data about `symbol` in the given
416 * symbolMap, and add any information found to the corresponding symbolMap if
420 Path
getSymbolPath(Symbol
<k
> symbol
); // throws(SQLiteExc)
423 * Return all the symbols of the kind corresponding to symbolMap
424 * defined in the given path.
426 * Query the DB if there is no data about `path` in the given
427 * symbolMap, and add any information found to the corresponding symbolMap if
431 typename PathToSymbolsMap
<k
>::PathSymbolMap::Values
getPathSymbols(Path path
);
433 void waitForDBUpdate();
434 void waitForDBUpdate(std::chrono::milliseconds timeoutMs
);
437 * Return a map from path to hash for every path we know about.
439 hphp_hash_map
<Path
, SHA1
> getAllPathsWithHashes() const;
441 std::unique_ptr
<folly::Executor
> m_exec
;
447 * A Watchman clock representing how up-to-date this map is.
449 * If its `m_clock` string is empty, then this map has not yet updated.
454 * Version numbers which get bumped each time a path changes. We filter out
455 * the facts in our data structures which have version numbers older than
456 * the ones in this map.
458 std::shared_ptr
<PathVersions
> m_versions
;
461 * Maps between symbols and the paths defining them.
463 PathToSymbolsMap
<SymKind::Type
> m_typePath
;
464 PathToSymbolsMap
<SymKind::Function
> m_functionPath
;
465 PathToSymbolsMap
<SymKind::Constant
> m_constantPath
;
466 PathToSymbolsMap
<SymKind::Module
> m_modulePath
;
467 PathToSymbolsMap
<SymKind::ModuleMembership
> m_moduleMembershipPath
;
470 * Future chain and queue holding the work that needs to be done before the
471 * DB is considered up to date.
473 std::queue
<UpdateDBWorkItem
> m_updateDBWork
;
474 folly::FutureSplitter
<folly::Unit
> m_updateDBFuture
{folly::makeFuture()};
477 using KindAndFlags
= std::pair
<TypeKind
, int>;
479 void setKindAndFlags(
480 Symbol
<SymKind::Type
> type
,
484 auto& defs
= m_map
[type
];
485 for (auto& [existingPath
, existingInfo
] : defs
) {
486 if (existingPath
== path
) {
487 existingInfo
= {kind
, flags
};
491 defs
.push_back({path
, {kind
, flags
}});
494 Optional
<std::pair
<TypeKind
, int>> getKindAndFlags(
495 Symbol
<SymKind::Type
> type
,
497 auto const it
= m_map
.find(type
);
498 if (it
== m_map
.end()) {
501 for (auto& [existingPath
, info
] : it
->second
) {
502 if (existingPath
== path
) {
509 // {type: (path, (kind, flags))}
511 Symbol
<SymKind::Type
>,
512 std::vector
<std::pair
<Path
, KindAndFlags
>>>
517 * True if the file exists, false if the file is deleted.
519 hphp_hash_map
<Path
, bool> m_fileExistsMap
;
522 * Maps between types and their subtypes/supertypes.
524 InheritanceInfo m_inheritanceInfo
;
527 * Maps between types and the attributes that decorate them.
529 AttributeMap
<TypeDecl
> m_typeAttrs
;
532 * Maps between type aliases and the attributes that decorate them.
534 AttributeMap
<TypeDecl
> m_typeAliasAttrs
;
537 * Maps between methods and the attributes that decorate them.
539 AttributeMap
<MethodDecl
> m_methodAttrs
;
542 * Maps between files and the attributes that decorate them.
544 AttributeMap
<Path
> m_fileAttrs
;
547 * 40-byte hex strings representing the last-known SHA1 checksums of
548 * each file we've seen
550 hphp_hash_map
<Path
, SHA1
> m_sha1Hashes
;
553 * Parse the given path and store all its data in the map.
558 const hphp_vector_set
<Symbol
<SymKind::Type
>>& indexedMethodAttrs
);
561 * Remove the given path from the map, along with all data associated with
564 void removePath(Path path
);
568 void waitForDBUpdateImpl(HPHP::Optional
<std::chrono::milliseconds
> timeoutMs
);
570 * Update the DB on the time interval beginning at `since` and
573 * We throw an UpdateExc if the `since` token does not match the clock
574 * in the DB, and we don't catch SQLiteExc from the underlying SQLite layer.
579 const std::vector
<std::filesystem::path
>& alteredPaths
,
580 const std::vector
<std::filesystem::path
>& deletedPaths
,
581 const std::vector
<FileFacts
>& alteredPathFacts
) const; // throws
584 * Replace all facts in the DB with in-memory facts about the given path.
588 const std::filesystem::path
& path
,
589 const FileFacts
& facts
) const;
592 * Mark `derivedType` as inheriting from each of the `baseTypes`.
596 Symbol
<SymKind::Type
> derivedType
,
597 rust::Vec
<rust::String
> baseTypes
);
600 * Load information from the DB about who the given `derivedType` inherits.
602 void loadBaseTypesFromDB(
605 Symbol
<SymKind::Type
> derivedType
);
608 * Helper function to read from and write to m_synchronizedData.
610 * readFn: ((const Data&) -> Optional<Ret>)
611 * GetFromDBFn: ((AutoloadDB&) -> DataFromDB)
612 * writeFn: ((Data&, DataFromDB) -> Ret)
617 typename GetFromDBFn
,
619 Ret
readOrUpdate(ReadFn readFn
, GetFromDBFn getFromDBFn
, WriteFn writeFn
);
622 * Return a thread-local connection to the DB associated with this map.
624 std::shared_ptr
<AutoloadDB
> getDB() const;
627 * Return the type's kind (class/interface/enum) along with an
628 * abstract/final bitmask.
630 std::pair
<TypeKind
, TypeFlagMask
> getKindAndFlags(Symbol
<SymKind::Type
> type
);
631 std::pair
<TypeKind
, TypeFlagMask
> getKindAndFlags(
632 Symbol
<SymKind::Type
> type
,
635 std::atomic
<bool> m_useDB
= false;
636 // Used to prioritize updates over caching. Pending updates increment this
637 // count, while caching only occurs if this count is at 0.
638 std::atomic
<size_t> m_updatesInFlight
= 0;
640 folly::Synchronized
<Data
, folly::SharedMutexWritePriority
> m_syncedData
;
642 const std::filesystem::path m_root
;
643 const std::string m_schemaHash
;
644 AutoloadDBVault m_dbVault
;
645 const hphp_vector_set
<Symbol
<SymKind::Type
>> m_indexedMethodAttrs
;
646 const bool m_enableBlockingDbWait
;
647 const std::chrono::milliseconds m_blockingDbWaitTimeout
;
648 const bool m_useSymbolMapForGetFilesWithAttrAndAnyVal
;