File: //proc/self/root/usr/include/hphp/runtime/vm/repo.h
/*
+----------------------------------------------------------------------+
| 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. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_VM_REPO_H_
#define incl_HPHP_VM_REPO_H_
#include <vector>
#include <utility>
#include <string>
#include <memory>
#include <cstdlib>
#include <sqlite3.h>
// For getpwuid_r(3).
#include <sys/types.h>
#include <pwd.h>
#include "hphp/runtime/vm/class.h"
#include "hphp/runtime/vm/func.h"
#include "hphp/runtime/vm/litstr-repo-proxy.h"
#include "hphp/runtime/vm/preclass-emitter.h"
#include "hphp/runtime/vm/repo-status.h"
#include "hphp/runtime/vm/unit-emitter.h"
#include <folly/portability/Unistd.h>
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
struct Repo : RepoProxy {
struct GlobalData;
// Do not directly instantiate this class; a thread-local creates one per
// thread on demand when Repo::get() is called.
static Repo& get();
// Prefork is called before forking. It attempts to shut down other
// threads and returns true if forking should be prevented, false if
// it's ok to proceed.
static bool prefork();
static void postfork(pid_t pid);
/*
* In some command line programs that use the repo, it is necessary
* to shut it down at some point in the process. (See hhbbc.) This
* function accomplishes this.
*/
static void shutdown();
Repo();
~Repo();
const char* dbName(int repoId) const {
assert(repoId < RepoIdCount);
return kDbs[repoId];
}
sqlite3* dbc() const { return m_dbc; }
int repoIdForNewUnit(UnitOrigin unitOrigin) const {
switch (unitOrigin) {
case UnitOrigin::File:
return m_localWritable ? RepoIdLocal : RepoIdCentral;
case UnitOrigin::Eval:
return m_evalRepoId;
default:
assert(false);
return RepoIdInvalid;
}
}
std::string repoName(int repoId) const {
switch (repoId) {
case RepoIdLocal: return m_localRepo;
case RepoIdCentral: return m_centralRepo;
default: return "?";
}
}
UnitRepoProxy& urp() { return m_urp; }
PreClassRepoProxy& pcrp() { return m_pcrp; }
FuncRepoProxy& frp() { return m_frp; }
LitstrRepoProxy& lsrp() { return m_lsrp; }
static void setCliFile(const std::string& cliFile);
std::unique_ptr<Unit> loadUnit(const std::string& name, const MD5& md5);
RepoStatus findFile(const char* path, const std::string& root, MD5& md5);
RepoStatus insertMd5(UnitOrigin unitOrigin, UnitEmitter* ue, RepoTxn& txn);
void commitMd5(UnitOrigin unitOrigin, UnitEmitter* ue);
/*
* Return the largest size for a static string that can be inserted into the
* repo.
*/
size_t stringLengthLimit() const;
/*
* Return a vector of (filepath, MD5) for every unit in central
* repo.
*/
std::vector<std::pair<std::string,MD5>> enumerateUnits(
int repoId, bool preloadOnly, bool warn);
/*
* Load the repo-global metadata table, including the global litstr
* table. Normally called during process initialization.
*/
void loadGlobalData(bool allowFailure = false);
/*
* Access to global data.
*
* Pre: loadGlobalData() already called, and
* RuntimeOption::RepoAuthoritative.
*/
static const GlobalData& global() {
assert(RuntimeOption::RepoAuthoritative);
return s_globalData;
}
/*
* Used during repo creation to associate the supplied GlobalData
* with the repo that was being built. Also saves the global litstr
* table.
*
* No other threads may be reading or writing the repo GlobalData
* when this is called.
*/
void saveGlobalData(GlobalData newData);
private:
/*
* RepoStmts for setting/getting file hashes.
*/
struct InsertFileHashStmt : public RepoProxy::Stmt {
InsertFileHashStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
void insert(RepoTxn& txn, const StringData* path, const MD5& md5);
// throws(RepoExc)
};
struct GetFileHashStmt : public RepoProxy::Stmt {
GetFileHashStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
RepoStatus get(const char* path, MD5& md5);
};
InsertFileHashStmt m_insertFileHash[RepoIdCount];
GetFileHashStmt m_getFileHash[RepoIdCount];
public:
std::string table(int repoId, const char* tablePrefix);
void exec(const std::string& sQuery); // throws(RepoExc)
void begin(); // throws(RepoExc)
private:
void txPop(); // throws(RepoExc)
public:
void rollback(); // nothrow
void commit(); // throws(RepoExc)
RepoStatus insertUnit(UnitEmitter* ue, UnitOrigin unitOrigin,
RepoTxn& txn); // nothrow
void commitUnit(UnitEmitter* ue, UnitOrigin unitOrigin); // nothrow
// All database table names use the schema ID (md5 checksum based on the
// source code) as a suffix. For example, if the schema ID is
// "b02c58478ce89719782fea89f3009295", the file magic is stored in the
// magic_b02c58478ce89719782fea89f3009295 table:
//
// CREATE TABLE magic_b02c58478ce89719782fea89f3009295(product[TEXT]);
// INSERT INTO magic_b02c58478ce89719782fea89f3009295 VALUES(
// 'facebook.com HipHop Virtual Machine bytecode repository');
//
// This allows multiple schemas to coexist in the same database, which is
// especially important if multiple versions of hhvm are in use at the same
// time.
private:
// Magic product constant used to distinguish a .hhbc database.
static const char* kMagicProduct;
static const char* kSchemaPlaceholder;
static const char* kDbs[RepoIdCount];
void connect();
void disconnect();
void initCentral();
std::string insertSchema(const char* path);
RepoStatus openCentral(const char* repoPath, std::string& errorMsg);
void initLocal();
void attachLocal(const char* repoPath, bool isWritable);
void pragmas(int repoId); // throws(RepoExc)
void getIntPragma(int repoId, const char* name, int& val); // throws(RepoExc)
void setIntPragma(int repoId, const char* name, int val); // throws(RepoExc)
void getTextPragma(int repoId, const char* name, std::string& val);
// throws(RepoExc)
void setTextPragma(int repoId, const char* name, const char* val);
// throws(RepoExc)
RepoStatus initSchema(int repoId, bool& isWritable, std::string& errorMsg);
bool schemaExists(int repoId);
RepoStatus createSchema(int repoId, std::string& errorMsg);
bool writable(int repoId);
private:
static std::string s_cliFile;
static GlobalData s_globalData;
std::string m_localRepo;
std::string m_centralRepo;
sqlite3* m_dbc; // Database connection, shared by multiple attached databases.
bool m_localReadable;
bool m_localWritable;
int m_evalRepoId;
unsigned m_txDepth; // Transaction nesting depth.
bool m_rollback; // If true, rollback rather than commit.
RepoStmt m_beginStmt;
RepoStmt m_rollbackStmt;
RepoStmt m_commitStmt;
UnitRepoProxy m_urp;
PreClassRepoProxy m_pcrp;
FuncRepoProxy m_frp;
LitstrRepoProxy m_lsrp;
};
//////////////////////////////////////////////////////////////////////
/*
* Try to commit a vector of unit emitters to the current repo. Note that
* errors are ignored!
*/
void batchCommit(std::vector<std::unique_ptr<UnitEmitter>>);
//////////////////////////////////////////////////////////////////////
}
#endif