From 43a0cae32c16a93ea7a61ec9db184a3d374a3ac0 Mon Sep 17 00:00:00 2001 From: Emil Hesslow Date: Thu, 26 Mar 2020 12:16:55 -0700 Subject: [PATCH] Create Autoload map from repo Summary: - I need to look into why the tests fails but I want to make sure I'm going in the right direction - When HHVM starts up and running in repo mode I check a config and if that config is set to true then I build an autoload map from the repo at start up. - The autoload map contains Map and then we go from unitSn to path and then we load that path which looks up the unitSn from the path. - That was the easiest way to implement it without changing to much. - A followup optimization would be to never go to path. Just get the unitSn and then load it. Reviewed By: jano, jthemphill Differential Revision: D15329666 fbshipit-source-id: c86b981f5ef6e4091a7d12013cc77aa87db476d8 --- hphp/compiler/analysis/emitter.cpp | 2 +- hphp/hhbbc/main.cpp | 2 +- hphp/runtime/base/autoload-handler.cpp | 83 +++++++++------- hphp/runtime/base/autoload-handler.h | 1 - hphp/runtime/base/repo-autoload-map.cpp | 122 +++++++++++++++++++++++ hphp/runtime/base/repo-autoload-map.h | 94 ++++++++++++++++++ hphp/runtime/base/runtime-option.h | 2 - hphp/runtime/ext/hh/ext_hh.cpp | 10 ++ hphp/runtime/vm/repo-autoload-map-builder.cpp | 8 ++ hphp/runtime/vm/repo-autoload-map-builder.h | 19 ++++ hphp/runtime/vm/repo-global-data.h | 3 + hphp/runtime/vm/repo.cpp | 135 +++++++++++++++++++++++--- hphp/runtime/vm/repo.h | 17 +++- 13 files changed, 443 insertions(+), 55 deletions(-) create mode 100644 hphp/runtime/base/repo-autoload-map.cpp create mode 100644 hphp/runtime/base/repo-autoload-map.h diff --git a/hphp/compiler/analysis/emitter.cpp b/hphp/compiler/analysis/emitter.cpp index 4ac8d84f98d..4c2af7e3a2b 100644 --- a/hphp/compiler/analysis/emitter.cpp +++ b/hphp/compiler/analysis/emitter.cpp @@ -188,7 +188,7 @@ void commitGlobalData(std::unique_ptr arrTable) { gd.ConstantFunctions.push_back(elm); } if (arrTable) globalArrayTypeTable().repopulate(*arrTable); - Repo::get().saveGlobalData(gd); + Repo::get().saveGlobalData(std::move(gd)); } } diff --git a/hphp/hhbbc/main.cpp b/hphp/hhbbc/main.cpp index 4c69c23f32f..670c6b21a36 100644 --- a/hphp/hhbbc/main.cpp +++ b/hphp/hhbbc/main.cpp @@ -431,7 +431,7 @@ void write_global_data( globalArrayTypeTable().repopulate(*arrTable); // NOTE: There's no way to tell if saveGlobalData() fails for some reason. - Repo::get().saveGlobalData(gd); + Repo::get().saveGlobalData(std::move(gd)); } void compile_repo() { diff --git a/hphp/runtime/base/autoload-handler.cpp b/hphp/runtime/base/autoload-handler.cpp index 1a9326505b8..2f2e99aaa1e 100644 --- a/hphp/runtime/base/autoload-handler.cpp +++ b/hphp/runtime/base/autoload-handler.cpp @@ -27,7 +27,10 @@ #include "hphp/runtime/base/container-functions.h" #include "hphp/runtime/base/runtime-option.h" #include "hphp/runtime/base/stat-cache.h" +#include "hphp/runtime/base/repo-autoload-map.h" #include "hphp/runtime/base/unit-cache.h" +#include "hphp/runtime/vm/repo.h" +#include "hphp/runtime/vm/repo-global-data.h" #include "hphp/runtime/vm/unit.h" #include "hphp/runtime/vm/unit-util.h" #include "hphp/runtime/vm/vm-regs.h" @@ -120,6 +123,47 @@ void AutoloadMapFactory::setInstance(AutoloadMapFactory* instance) { ////////////////////////////////////////////////////////////////////// +static AutoloadMap* getAutoloadMapForRequest() { + if (RuntimeOption::RepoAuthoritative) { + auto map = Repo::get().global().AutoloadMap.get(); + if (map) { + return map; + } + } + + auto* factory = AutoloadMapFactory::getInstance(); + if (!factory) { + return nullptr; + } + + if (g_context.isNull()) { + return nullptr; + } + + auto* repoOptions = g_context->getRepoOptionsForRequest(); + if (!repoOptions) { + return nullptr; + } + + auto repoRoot = folly::fs::canonical(repoOptions->path()).parent_path(); + + auto* map = factory->getForRoot(repoRoot); + if (!map) { + return nullptr; + } + + try { + map->ensureUpdated(); + return map; + } catch (const std::exception& e) { + Logger::Error( + "Failed to update native autoloader, not natively autoloading %s. %s\n", + repoRoot.generic().c_str(), + e.what()); + } + return nullptr; +} + void AutoloadHandler::requestInit() { assertx(!m_map); assertx(!m_req_map); @@ -128,10 +172,7 @@ void AutoloadHandler::requestInit() { new (&m_handlers) req::deque(); m_handlers_valid = true; - auto* factory = AutoloadMapFactory::getInstance(); - if (factory) { - setAutoloadMapFromFactory(*factory); - } + m_map = getAutoloadMapForRequest(); } void AutoloadHandler::requestShutdown() { @@ -144,6 +185,10 @@ void AutoloadHandler::requestShutdown() { } bool AutoloadHandler::setMap(const Array& map, String root) { + assertx(!(RuntimeOption::RepoAuthoritative && + RuntimeOption::EvalUseRepoAutoloadMap && + Repo::get().global().AutoloadMap)); + m_req_map = req::make_unique( UserAutoloadMap::fromFullMap(map, std::move(root))); m_map = m_req_map.get(); @@ -341,36 +386,6 @@ AutoloadHandler::loadFromMap(const String& clsName, } } -void AutoloadHandler::setAutoloadMapFromFactory( - AutoloadMapFactory& factory) { - - if (g_context.isNull()) { - return; - } - - auto* repoOptions = g_context->getRepoOptionsForRequest(); - if (!repoOptions) { - return; - } - - auto repoRoot = folly::fs::canonical(repoOptions->path()).parent_path(); - - auto* map = factory.getForRoot(repoRoot); - if (!map) { - return; - } - - try { - map->ensureUpdated(); - m_map = map; - } catch (const std::exception& e) { - Logger::Error( - "Failed to update native autoloader, not natively autoloading %s. %s\n", - repoRoot.generic().c_str(), - e.what()); - } -} - bool AutoloadHandler::autoloadFunc(StringData* name) { return m_map && loadFromMap(String{name}, diff --git a/hphp/runtime/base/autoload-handler.h b/hphp/runtime/base/autoload-handler.h index dab81ec0664..015a23b7194 100644 --- a/hphp/runtime/base/autoload-handler.h +++ b/hphp/runtime/base/autoload-handler.h @@ -202,7 +202,6 @@ private: static String getSignature(const Variant& handler); private: - void setAutoloadMapFromFactory(AutoloadMapFactory& factory); // m_map points to either the request-scoped userland AutoloadMap or // a statically-scoped native AutoloadMap diff --git a/hphp/runtime/base/repo-autoload-map.cpp b/hphp/runtime/base/repo-autoload-map.cpp new file mode 100644 index 00000000000..52589210874 --- /dev/null +++ b/hphp/runtime/base/repo-autoload-map.cpp @@ -0,0 +1,122 @@ +/* + +----------------------------------------------------------------------+ + | HipHop for PHP | + +----------------------------------------------------------------------+ + | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ +*/ + +#include "hphp/runtime/base/repo-autoload-map.h" + +#include "hphp/runtime/base/builtin-functions.h" +#include "hphp/runtime/vm/repo.h" +#include "hphp/util/assertions.h" + +namespace HPHP { + +////////////////////////////////////////////////////////////////////// + +using UnitToPathMap = tbb::concurrent_hash_map; + +namespace { + UnitToPathMap unitToPathMap; +} + +template +static folly::Optional getPathFromSymbol( + const RepoAutoloadMap::Map& map, + const String& name) { + auto search = map.find(name.get()); + if (search == map.end()) { + return {}; + } + auto unitSn = search->second; + + UnitToPathMap::const_accessor acc; + if (unitToPathMap.find(acc, unitSn)) { + return {StrNR(acc->second).asString()}; + } + + String path; + auto res = Repo::get().findPath(unitSn, RuntimeOption::SourceRoot, path); + always_assert(res == RepoStatus::success); + auto spath = makeStaticString(path.get()); + unitToPathMap.insert(std::make_pair(unitSn, spath)); + return {StrNR(spath).asString()}; +} + +template +Array getSymbolFromPath( + const RepoAutoloadMap::Map& map, + const String& path) { + auto ret = Array::CreateVec(); + int64_t unitSn; + auto res = Repo::get().findUnit(path.c_str(), RuntimeOption::SourceRoot, unitSn); + if (res == RepoStatus::success) { + for (auto it = map.begin(); it != map.end(); ++it) { + if (it->second == unitSn) { + ret.append(StrNR(it->first).asString()); + } + } + } + return ret; +} + +folly::Optional RepoAutoloadMap::getTypeFile( + const String& typeName) { + return getPathFromSymbol(m_types, typeName); +} + +folly::Optional RepoAutoloadMap::getFunctionFile( + const String& funcName) { + return getPathFromSymbol(m_functions, funcName); +} + +folly::Optional RepoAutoloadMap::getConstantFile( + const String& constName) { + return getPathFromSymbol(m_constants, constName); +} + +folly::Optional RepoAutoloadMap::getTypeAliasFile( + const String& typeAliasName) { + return getPathFromSymbol(m_typeAliases, typeAliasName); +} + +Array RepoAutoloadMap::getFileTypes(const String& path) { + return getSymbolFromPath(m_types, path); +} + +Array RepoAutoloadMap::getFileFunctions(const String& path) { + return getSymbolFromPath(m_functions, path); +} + +Array RepoAutoloadMap::getFileConstants(const String& path) { + return getSymbolFromPath(m_constants, path); +} + +Array RepoAutoloadMap::getFileTypeAliases(const String& path) { + return getSymbolFromPath(m_typeAliases, path); +} + +AutoloadMap::Result RepoAutoloadMap::handleFailure( + KindOf kind, const String& className, const Variant& err) const { + return AutoloadMap::Result::Failure; +} + +Array RepoAutoloadMap::getAllFiles() const { + SystemLib::throwInvalidOperationExceptionObject( + "Repo Autoload Map does not support getAllFiles" + ); +} + +////////////////////////////////////////////////////////////////////// + +} // HPHP diff --git a/hphp/runtime/base/repo-autoload-map.h b/hphp/runtime/base/repo-autoload-map.h new file mode 100644 index 00000000000..484c880db6e --- /dev/null +++ b/hphp/runtime/base/repo-autoload-map.h @@ -0,0 +1,94 @@ +/* + +----------------------------------------------------------------------+ + | HipHop for PHP | + +----------------------------------------------------------------------+ + | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ +*/ + +#pragma once + +#include + +#include + +#include "hphp/runtime/base/array-init.h" +#include "hphp/runtime/base/autoload-map.h" +#include "hphp/runtime/base/type-string.h" +#include "hphp/runtime/base/type-variant.h" + +namespace HPHP { + +////////////////////////////////////////////////////////////////////// + +/** + * AutoloadMap using the info from the repo + */ + +struct RepoAutoloadMap final : AutoloadMap { + + template + using Map = hphp_fast_map< + const StringData*, + int64_t, + string_data_hash, + Compare + >; + + using CaseInsensitiveMap = Map; + using CaseSensitiveMap = Map; + + explicit RepoAutoloadMap( + CaseInsensitiveMap types, + CaseInsensitiveMap functions, + CaseSensitiveMap constants, + CaseInsensitiveMap typeAliases) + : m_types{std::move(types)}, + m_functions{std::move(functions)}, + m_constants{std::move(constants)}, + m_typeAliases{std::move(typeAliases)} {} + + virtual folly::Optional getTypeFile( + const String& typeName) override; + virtual folly::Optional getFunctionFile( + const String& functionName) override; + virtual folly::Optional getConstantFile( + const String& constantName) override; + virtual folly::Optional getTypeAliasFile( + const String& typeAliasName) override; + + virtual Array getFileTypes(const String& path) override; + virtual Array getFileFunctions(const String& path) override; + virtual Array getFileConstants(const String& path) override; + virtual Array getFileTypeAliases(const String& path) override; + + virtual bool canHandleFailure() const override { + return false; + } + + virtual bool isNative() const noexcept override { + return true; + } + + virtual AutoloadMap::Result handleFailure(KindOf kind, + const String& className, + const Variant& err) const override; + + virtual Array getAllFiles() const override; + +private: + CaseInsensitiveMap m_types; + CaseInsensitiveMap m_functions; + CaseSensitiveMap m_constants; + CaseInsensitiveMap m_typeAliases; +}; + +} // HPHP diff --git a/hphp/runtime/base/runtime-option.h b/hphp/runtime/base/runtime-option.h index 1da4bfe60cb..c11a414b277 100644 --- a/hphp/runtime/base/runtime-option.h +++ b/hphp/runtime/base/runtime-option.h @@ -1318,8 +1318,6 @@ struct RuntimeOption { F(bool, EnablePerFileCoverage, false) \ F(bool, NoUseMagicMethods, false) \ F(bool, NoAppendToMap, false) \ - /* Should build an autoload map when we build the repo */ \ - F(bool, BuildRepoAutoloadMap, false) \ /* Should we use the autoload map from the repo */ \ F(bool, UseRepoAutoloadMap, false) \ /* */ diff --git a/hphp/runtime/ext/hh/ext_hh.cpp b/hphp/runtime/ext/hh/ext_hh.cpp index 2d071aa4b3a..054eb703637 100644 --- a/hphp/runtime/ext/hh/ext_hh.cpp +++ b/hphp/runtime/ext/hh/ext_hh.cpp @@ -38,6 +38,8 @@ #include "hphp/runtime/vm/class-meth-data-ref.h" #include "hphp/runtime/vm/extern-compiler.h" #include "hphp/runtime/vm/memo-cache.h" +#include "hphp/runtime/vm/repo-global-data.h" +#include "hphp/runtime/vm/repo.h" #include "hphp/runtime/vm/runtime.h" #include "hphp/runtime/vm/vm-regs.h" #include "hphp/util/file.h" @@ -69,6 +71,14 @@ bool HHVM_FUNCTION(autoload_is_native) { bool HHVM_FUNCTION(autoload_set_paths, const Variant& map, const String& root) { + // If we are using a native autoload map you are not allowed to override it + // in repo mode + if (RuntimeOption::RepoAuthoritative && + RuntimeOption::EvalUseRepoAutoloadMap && + Repo::get().global().AutoloadMap.get()) { + return false; + } + if (map.isArray()) { return AutoloadHandler::s_instance->setMap(map.asCArrRef(), root); } diff --git a/hphp/runtime/vm/repo-autoload-map-builder.cpp b/hphp/runtime/vm/repo-autoload-map-builder.cpp index 587ccca798c..b8542a979af 100644 --- a/hphp/runtime/vm/repo-autoload-map-builder.cpp +++ b/hphp/runtime/vm/repo-autoload-map-builder.cpp @@ -76,6 +76,14 @@ void RepoAutoloadMapBuilder::BuilderCollect::serde(BlobEncoder& sd) { serdeMap(sd, m_constants); } +std::unique_ptr RepoAutoloadMapBuilder::serde(BlobDecoder& sd) { + RepoAutoloadMap::CaseInsensitiveMap classes = serdeMap(sd); + RepoAutoloadMap::CaseInsensitiveMap funcs = serdeMap(sd); + RepoAutoloadMap::CaseInsensitiveMap typeAliases = serdeMap(sd); + RepoAutoloadMap::CaseSensitiveMap constants = serdeMap(sd); + return std::make_unique(classes, funcs, constants, typeAliases); +} + ////////////////////////////////////////////////////////////////////// } diff --git a/hphp/runtime/vm/repo-autoload-map-builder.h b/hphp/runtime/vm/repo-autoload-map-builder.h index c89f8014d5d..fa3d989895c 100644 --- a/hphp/runtime/vm/repo-autoload-map-builder.h +++ b/hphp/runtime/vm/repo-autoload-map-builder.h @@ -16,6 +16,7 @@ #ifndef incl_HPHP_REPO_AUTOLOAD_MAP_BUILDER_H_ #define incl_HPHP_REPO_AUTOLOAD_MAP_BUILDER_H_ +#include "hphp/runtime/base/repo-autoload-map.h" #include "hphp/runtime/base/string-data.h" #include "hphp/runtime/base/string-functors.h" #include "hphp/runtime/vm/blob-helper.h" @@ -88,6 +89,8 @@ struct RepoAutoloadMapBuilder { CaseSensitiveMap m_constants; }; + static std::unique_ptr serde(BlobDecoder& sd); + static RepoAutoloadMapBuilder::BuilderBase& get(); template @@ -100,6 +103,22 @@ struct RepoAutoloadMapBuilder { } } + template + static Map serdeMap(BlobDecoder& sd) { + size_t size; + sd(size); + Map map(size); + for (size_t i = 0; i < size; i++) { + const StringData* str; + int64_t unitSn; + sd(str) + (unitSn) + ; + map[str] = unitSn; + } + return map; + } + static Guard collect() { return Guard(); } diff --git a/hphp/runtime/vm/repo-global-data.h b/hphp/runtime/vm/repo-global-data.h index 92bb353c4eb..2276cd7de36 100644 --- a/hphp/runtime/vm/repo-global-data.h +++ b/hphp/runtime/vm/repo-global-data.h @@ -18,6 +18,7 @@ #include "hphp/runtime/vm/repo.h" #include "hphp/runtime/base/repo-auth-type-array.h" +#include "hphp/runtime/base/repo-autoload-map.h" namespace HPHP { @@ -186,6 +187,8 @@ struct Repo::GlobalData { std::vector> ConstantFunctions; + std::unique_ptr AutoloadMap = nullptr; + template void serde(SerDe& sd) { sd(InitialNamedEntityTableSize) (InitialStaticStringTableSize) diff --git a/hphp/runtime/vm/repo.cpp b/hphp/runtime/vm/repo.cpp index c33cd56ec2d..3e79f8159d3 100644 --- a/hphp/runtime/vm/repo.cpp +++ b/hphp/runtime/vm/repo.cpp @@ -20,6 +20,7 @@ #include #include +#include "hphp/runtime/base/repo-autoload-map.h" #include "hphp/runtime/vm/blob-helper.h" #include "hphp/runtime/vm/repo-autoload-map-builder.h" #include "hphp/runtime/vm/repo-global-data.h" @@ -112,6 +113,8 @@ Repo::Repo() m_getFileHash{GetFileHashStmt(*this, 0), GetFileHashStmt(*this, 1)}, m_removeFileHash{RemoveFileHashStmt(*this, 0), RemoveFileHashStmt(*this, 1)}, + m_getUnitPath{GetUnitPathStmt(*this, 0), GetUnitPathStmt(*this, 1)}, + m_getUnit{GetUnitStmt(*this, 0), GetUnitStmt(*this, 1)}, m_dbc(nullptr), m_localReadable(false), m_localWritable(false), m_evalRepoId(-1), m_txDepth(0), m_rollback(false), m_beginStmt(*this), m_rollbackStmt(*this), m_commitStmt(*this), m_urp(*this), m_pcrp(*this), @@ -235,7 +238,8 @@ void Repo::loadGlobalData(bool readArrayTable /* = true */) { if (!query.row()) { throw RepoExc("Can't find key = 'autoloadmap' in %s", tbl.c_str()); } - query.getBlob(0, true); + BlobDecoder decoder = query.getBlob(0, true); + s_globalData.AutoloadMap = RepoAutoloadMapBuilder::serde(decoder); } } @@ -286,7 +290,6 @@ void Repo::loadGlobalData(bool readArrayTable /* = true */) { for (auto const& elm : s_globalData.ConstantFunctions) { RuntimeOption::ConstantFunctions.insert(elm); } - return; } @@ -308,8 +311,8 @@ void Repo::loadGlobalData(bool readArrayTable /* = true */) { exit(1); } -void Repo::saveGlobalData(GlobalData newData) { - s_globalData = newData; +void Repo::saveGlobalData(GlobalData&& newData) { + s_globalData = std::move(newData); auto const repoId = repoIdForNewUnit(UnitOrigin::File); RepoStmt stmt(*this); @@ -341,16 +344,14 @@ void Repo::saveGlobalData(GlobalData newData) { query.exec(); } - if (RuntimeOption::EvalBuildRepoAutoloadMap) { - { - RepoTxnQuery query(txn, stmt); - auto key = std::string("autoloadmap"); - query.bindStdString("@key", key); - BlobEncoder encoder{true}; - RepoAutoloadMapBuilder::get().serde(encoder); - query.bindBlob("@data", encoder, /* static */ true); - query.exec(); - } + { + RepoTxnQuery query(txn, stmt); + auto key = std::string("autoloadmap"); + query.bindStdString("@key", key); + BlobEncoder encoder{true}; + RepoAutoloadMapBuilder::get().serde(encoder); + query.bindBlob("@data", encoder, /* static */ true); + query.exec(); } // TODO(#3521039): we could just put the litstr table in the same @@ -475,7 +476,104 @@ void Repo::RemoveFileHashStmt::remove(RepoTxn& txn, const std::string& path) { query.exec(); } -RepoStatus Repo::findFile(const char *path, const std::string &root, +RepoStatus Repo::GetUnitPathStmt::get(int64_t unitSn, String& path) { + try { + auto txn = RepoTxn{m_repo.begin()}; + if (!prepared()) { + auto selectQuery = folly::sformat( + "SELECT f.path " + "FROM {} AS u, {} AS f " + "WHERE u.unitSn == @unitSn AND f.sha1 == u.sha1", + m_repo.table(m_repoId, "Unit"), + m_repo.table(m_repoId, "FileSha1")); + txn.prepare(*this, selectQuery); + } + RepoTxnQuery query(txn, *this); + query.bindInt64("@unitSn", unitSn); + query.step(); + if (!query.row()) { + return RepoStatus::error; + } + StringData* spath; query.getStaticString(0, spath); + path = String(spath); + txn.commit(); + return RepoStatus::success; + } catch (RepoExc& re) { + return RepoStatus::error; + } +} + +RepoStatus Repo::findPath(int64_t unitSn, const std::string& root, String& path) { + if (m_dbc == nullptr) { + return RepoStatus::error; + } + int repoId; + for (repoId = RepoIdCount - 1; repoId >= 0; --repoId) { + String relPath; + if (m_getUnitPath[repoId].get(unitSn, relPath) == RepoStatus::success) { + path = root + relPath; + TRACE(3, "Repo loaded file path for '%ld' from '%s'\n", + unitSn, repoName(repoId).c_str()); + return RepoStatus::success; + } + } + TRACE(3, "Repo file path: error loading '%ld'\n", unitSn); + return RepoStatus::error; +} + +RepoStatus Repo::GetUnitStmt::get(const char* path, int64_t& unitSn) { + try { + auto txn = RepoTxn{m_repo.begin()}; + if (!prepared()) { + auto selectQuery = folly::sformat( + "SELECT u.unitSn " + "FROM {} AS f, {} AS u " + "WHERE f.path == @path AND f.sha1 == u.sha1", + m_repo.table(m_repoId, "FileSha1"), + m_repo.table(m_repoId, "Unit")); + txn.prepare(*this, selectQuery); + } + RepoTxnQuery query(txn, *this); + query.bindText("@path", path, strlen(path)); + query.step(); + if (!query.row()) { + return RepoStatus::error; + } + int unitSn_; /**/ query.getInt(0, unitSn_); + unitSn = unitSn_; + txn.commit(); + return RepoStatus::success; + } catch (RepoExc& re) { + return RepoStatus::error; + } +} + +RepoStatus Repo::findUnit(const char* path, const std::string& root, + int64_t& unitSn) { + if (m_dbc == nullptr) { + return RepoStatus::error; + } + int repoId; + for (repoId = RepoIdCount - 1; repoId >= 0; --repoId) { + if (*path == '/' && !root.empty() && + !strncmp(root.c_str(), path, root.size()) && + (m_getUnit[repoId].get(path + root.size(), unitSn) == + RepoStatus::success)) { + TRACE(3, "Repo loaded unit for '%s' from '%s'\n", + path + root.size(), repoName(repoId).c_str()); + return RepoStatus::success; + } + if (m_getUnit[repoId].get(path, unitSn) == RepoStatus::success) { + TRACE(3, "Repo loaded unit for '%s' from '%s'\n", + path, repoName(repoId).c_str()); + return RepoStatus::success; + } + } + TRACE(3, "Repo unit: error loading '%s'\n", path); + return RepoStatus::error; +} + +RepoStatus Repo::findFile(const char *path, const std::string& root, SHA1& sha1) { tracing::Block _{ "repo-find-file", @@ -1151,6 +1249,13 @@ RepoStatus Repo::createSchema(int repoId, std::string& errorMsg) { "CREATE TABLE {} (path TEXT, sha1 BLOB, UNIQUE(path, sha1));", table(repoId, "FileSha1")); txn.exec(createQuery); + + auto indexQuery = folly::sformat( + "CREATE INDEX {}_sha1_index ON {}_{} (sha1);", + table(repoId, "FileSha1"), + "FileSha1", + repoSchemaId()); + txn.exec(indexQuery); } txn.exec(folly::sformat("CREATE TABLE {} (key TEXT, data BLOB);", table(repoId, "GlobalData"))); diff --git a/hphp/runtime/vm/repo.h b/hphp/runtime/vm/repo.h index 70bb48517e8..5b45a59db33 100644 --- a/hphp/runtime/vm/repo.h +++ b/hphp/runtime/vm/repo.h @@ -29,6 +29,7 @@ #include #include +#include "hphp/runtime/base/repo-autoload-map.h" #include "hphp/runtime/vm/class.h" #include "hphp/runtime/vm/func.h" #include "hphp/runtime/vm/litstr-repo-proxy.h" @@ -107,6 +108,8 @@ struct Repo : RepoProxy { const Native::FuncTable&); void forgetUnit(const std::string& path); RepoStatus findFile(const char* path, const std::string& root, SHA1& sha1); + RepoStatus findPath(int64_t unitSn, const std::string& root, String& path); + RepoStatus findUnit(const char* path, const std::string& root, int64_t& unitSn); RepoStatus insertSha1(UnitOrigin unitOrigin, UnitEmitter* ue, RepoTxn& txn); void commitSha1(UnitOrigin unitOrigin, UnitEmitter* ue); @@ -154,7 +157,7 @@ struct Repo : RepoProxy { * No other threads may be reading or writing the repo GlobalData * when this is called. */ - void saveGlobalData(GlobalData newData); + void saveGlobalData(GlobalData&& newData); private: /* @@ -176,9 +179,21 @@ struct Repo : RepoProxy { void remove(RepoTxn& txn, const std::string& path); }; + struct GetUnitPathStmt : public RepoProxy::Stmt { + GetUnitPathStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {} + RepoStatus get(int64_t unitSn, String& path); + }; + + struct GetUnitStmt : public RepoProxy::Stmt { + GetUnitStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {} + RepoStatus get(const char* path, int64_t& unitSn); + }; + InsertFileHashStmt m_insertFileHash[RepoIdCount]; GetFileHashStmt m_getFileHash[RepoIdCount]; RemoveFileHashStmt m_removeFileHash[RepoIdCount]; + GetUnitPathStmt m_getUnitPath[RepoIdCount]; + GetUnitStmt m_getUnit[RepoIdCount]; public: std::string table(int repoId, const char* tablePrefix); -- 2.11.4.GIT