Allow configuration of cache directory. Use a good default value as well.

This commit is contained in:
Jacob Dufault 2017-04-17 19:59:48 -07:00
parent 26c0bfe71d
commit 2d4b910836
11 changed files with 185 additions and 47 deletions

View File

@ -5,5 +5,6 @@
], ],
"cquery.whitelist": [ "cquery.whitelist": [
// ".*platform.*.cc" // ".*platform.*.cc"
] ],
"cquery.cacheDirectory": "C:/Users/jacob/Desktop/superindex/indexer/CACHE"
} }

View File

@ -4,20 +4,23 @@
#include <algorithm> #include <algorithm>
std::string GetCachedFileName(std::string source_file) { namespace {
// TODO/FIXME
const char* kCacheDirectory = "C:/Users/jacob/Desktop/superindex/indexer/CACHE/"; std::string GetCachedFileName(const std::string& cache_directory, std::string source_file) {
assert(!cache_directory.empty());
std::replace(source_file.begin(), source_file.end(), '\\', '_'); std::replace(source_file.begin(), source_file.end(), '\\', '_');
std::replace(source_file.begin(), source_file.end(), '/', '_'); std::replace(source_file.begin(), source_file.end(), '/', '_');
std::replace(source_file.begin(), source_file.end(), ':', '_'); std::replace(source_file.begin(), source_file.end(), ':', '_');
std::replace(source_file.begin(), source_file.end(), '.', '_'); std::replace(source_file.begin(), source_file.end(), '.', '_');
return kCacheDirectory + source_file + ".json"; return cache_directory + source_file + ".json";
} }
std::unique_ptr<IndexedFile> LoadCachedFile(std::string filename) { } // namespace
std::unique_ptr<IndexedFile> LoadCachedFile(const std::string& cache_directory, const std::string& filename) {
return nullptr; return nullptr;
optional<std::string> file_content = ReadContent(GetCachedFileName(filename)); optional<std::string> file_content = ReadContent(GetCachedFileName(cache_directory, filename));
if (!file_content) if (!file_content)
return nullptr; return nullptr;
@ -28,11 +31,11 @@ std::unique_ptr<IndexedFile> LoadCachedFile(std::string filename) {
return nullptr; return nullptr;
} }
void WriteToCache(std::string filename, IndexedFile& file) { void WriteToCache(const std::string& cache_directory, const std::string& filename, IndexedFile& file) {
std::string indexed_content = Serialize(file); std::string indexed_content = Serialize(file);
std::ofstream cache; std::ofstream cache;
cache.open(GetCachedFileName(filename)); cache.open(GetCachedFileName(cache_directory, filename));
assert(cache.good()); assert(cache.good());
cache << indexed_content; cache << indexed_content;
cache.close(); cache.close();

View File

@ -5,8 +5,6 @@
struct IndexedFile; struct IndexedFile;
std::string GetCachedFileName(std::string source_file); std::unique_ptr<IndexedFile> LoadCachedFile(const std::string& cache_directory, const std::string& filename);
std::unique_ptr<IndexedFile> LoadCachedFile(std::string filename); void WriteToCache(const std::string& cache_directory, const std::string& filename, IndexedFile& file);
void WriteToCache(std::string filename, IndexedFile& file);

View File

@ -664,6 +664,8 @@ std::vector<SymbolRef> FindSymbolsAtLocation(QueryFile* file, lsPosition positio
std::vector<SymbolRef> symbols; std::vector<SymbolRef> symbols;
symbols.reserve(1); symbols.reserve(1);
// TODO: This needs to use the WorkingFile to convert buffer location to
// indexed location.
int target_line = position.line + 1; int target_line = position.line + 1;
int target_column = position.character + 1; int target_column = position.character + 1;
for (const SymbolRef& ref : file->def.all_symbols) { for (const SymbolRef& ref : file->def.all_symbols) {
@ -831,7 +833,8 @@ void RegisterMessageTypes() {
bool IndexMain_DoIndex(FileConsumer::SharedState* file_consumer_shared, bool IndexMain_DoIndex(IndexerConfig* config,
FileConsumer::SharedState* file_consumer_shared,
Index_DoIndexQueue* queue_do_index, Index_DoIndexQueue* queue_do_index,
Index_DoIdMapQueue* queue_do_id_map) { Index_DoIdMapQueue* queue_do_id_map) {
optional<Index_DoIndex> index_request = queue_do_index->TryDequeue(); optional<Index_DoIndex> index_request = queue_do_index->TryDequeue();
@ -845,7 +848,7 @@ bool IndexMain_DoIndex(FileConsumer::SharedState* file_consumer_shared,
// update request to get the latest version. // update request to get the latest version.
if (index_request->type == Index_DoIndex::Type::Import) { if (index_request->type == Index_DoIndex::Type::Import) {
index_request->type = Index_DoIndex::Type::Update; index_request->type = Index_DoIndex::Type::Update;
std::unique_ptr<IndexedFile> old_index = LoadCachedFile(index_request->path); std::unique_ptr<IndexedFile> old_index = LoadCachedFile(config->cacheDirectory, index_request->path);
time.ResetAndPrint("Reading cached index from disk " + index_request->path); time.ResetAndPrint("Reading cached index from disk " + index_request->path);
// If import fails just do a standard update. // If import fails just do a standard update.
@ -874,7 +877,7 @@ bool IndexMain_DoIndex(FileConsumer::SharedState* file_consumer_shared,
for (auto& current_index : indexes) { for (auto& current_index : indexes) {
std::cerr << "Got index for " << current_index->path << std::endl; std::cerr << "Got index for " << current_index->path << std::endl;
std::unique_ptr<IndexedFile> old_index = LoadCachedFile(current_index->path); std::unique_ptr<IndexedFile> old_index = LoadCachedFile(config->cacheDirectory, current_index->path);
time.ResetAndPrint("Loading cached index"); time.ResetAndPrint("Loading cached index");
// TODO: Cache to disk on a separate thread. Maybe we do the cache after we // TODO: Cache to disk on a separate thread. Maybe we do the cache after we
@ -882,7 +885,7 @@ bool IndexMain_DoIndex(FileConsumer::SharedState* file_consumer_shared,
// of the current 4). // of the current 4).
// Cache file so we can diff it later. // Cache file so we can diff it later.
WriteToCache(current_index->path, *current_index); WriteToCache(config->cacheDirectory, current_index->path, *current_index);
time.ResetAndPrint("Cache index update to disk"); time.ResetAndPrint("Cache index update to disk");
// Send response to create id map. // Send response to create id map.
@ -930,6 +933,7 @@ void IndexJoinIndexUpdates(Index_OnIndexedQueue* queue_on_indexed) {
} }
void IndexMain( void IndexMain(
IndexerConfig* config,
FileConsumer::SharedState* file_consumer_shared, FileConsumer::SharedState* file_consumer_shared,
Index_DoIndexQueue* queue_do_index, Index_DoIndexQueue* queue_do_index,
Index_DoIdMapQueue* queue_do_id_map, Index_DoIdMapQueue* queue_do_id_map,
@ -944,7 +948,7 @@ void IndexMain(
int count = 0; int count = 0;
if (!IndexMain_DoIndex(file_consumer_shared, queue_do_index, queue_do_id_map) && if (!IndexMain_DoIndex(config, file_consumer_shared, queue_do_index, queue_do_id_map) &&
!IndexMain_DoCreateIndexUpdate(queue_on_id_mapped, queue_on_indexed)) { !IndexMain_DoCreateIndexUpdate(queue_on_id_mapped, queue_on_indexed)) {
//if (count++ > 2) { //if (count++ > 2) {
@ -1009,6 +1013,7 @@ void IndexMain(
void QueryDbMainLoop( void QueryDbMainLoop(
IndexerConfig* config,
QueryDatabase* db, QueryDatabase* db,
Index_DoIndexQueue* queue_do_index, Index_DoIndexQueue* queue_do_index,
Index_DoIdMapQueue* queue_do_id_map, Index_DoIdMapQueue* queue_do_id_map,
@ -1042,14 +1047,14 @@ void QueryDbMainLoop(
std::vector<Matcher> whitelist; std::vector<Matcher> whitelist;
std::cerr << "Using whitelist" << std::endl; std::cerr << "Using whitelist" << std::endl;
for (const std::string& entry : msg->whitelist) { for (const std::string& entry : config->whitelist) {
std::cerr << " - " << entry << std::endl; std::cerr << " - " << entry << std::endl;
whitelist.push_back(Matcher(entry)); whitelist.push_back(Matcher(entry));
} }
std::vector<Matcher> blacklist; std::vector<Matcher> blacklist;
std::cerr << "Using blacklist" << std::endl; std::cerr << "Using blacklist" << std::endl;
for (const std::string& entry : msg->blacklist) { for (const std::string& entry : config->blacklist) {
std::cerr << " - " << entry << std::endl; std::cerr << " - " << entry << std::endl;
blacklist.push_back(Matcher(entry)); blacklist.push_back(Matcher(entry));
} }
@ -1553,7 +1558,7 @@ void QueryDbMainLoop(
} }
} }
void QueryDbMain() { void QueryDbMain(IndexerConfig* config) {
SetCurrentThreadName("querydb"); SetCurrentThreadName("querydb");
//std::cerr << "Running QueryDb" << std::endl; //std::cerr << "Running QueryDb" << std::endl;
@ -1571,14 +1576,14 @@ void QueryDbMain() {
// Start indexer threads. // Start indexer threads.
for (int i = 0; i < kNumIndexers; ++i) { for (int i = 0; i < kNumIndexers; ++i) {
new std::thread([&]() { new std::thread([&]() {
IndexMain(&file_consumer_shared, &queue_do_index, &queue_do_id_map, &queue_on_id_mapped, &queue_on_indexed); IndexMain(config, &file_consumer_shared, &queue_do_index, &queue_do_id_map, &queue_on_id_mapped, &queue_on_indexed);
}); });
} }
// Run query db main loop. // Run query db main loop.
QueryDatabase db; QueryDatabase db;
while (true) { while (true) {
QueryDbMainLoop(&db, &queue_do_index, &queue_do_id_map, &queue_on_id_mapped, &queue_on_indexed, &project, &working_files, &completion_manager); QueryDbMainLoop(config, &db, &queue_do_index, &queue_do_id_map, &queue_on_id_mapped, &queue_on_indexed, &project, &working_files, &completion_manager);
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
} }
@ -1653,7 +1658,7 @@ void QueryDbMain() {
// blocks. // blocks.
// //
// |ipc| is connected to a server. // |ipc| is connected to a server.
void LanguageServerStdinLoop() { void LanguageServerStdinLoop(IndexerConfig* config) {
SetCurrentThreadName("stdin"); SetCurrentThreadName("stdin");
IpcManager* ipc = IpcManager::instance(); IpcManager* ipc = IpcManager::instance();
@ -1677,10 +1682,25 @@ void LanguageServerStdinLoop() {
<< std::endl; << std::endl;
auto open_project = MakeUnique<Ipc_OpenProject>(); auto open_project = MakeUnique<Ipc_OpenProject>();
open_project->project_path = project_path; open_project->project_path = project_path;
if (request->params.initializationOptions) {
open_project->whitelist = request->params.initializationOptions->whitelist; if (!request->params.initializationOptions) {
open_project->blacklist = request->params.initializationOptions->blacklist; std::cerr << "Initialization parameters (particularily cacheDirectory) are required" << std::endl;
exit(1);
} }
*config = *request->params.initializationOptions;
// Make sure cache directory is valid.
if (config->cacheDirectory.empty()) {
std::cerr << "No cache directory" << std::endl;
exit(1);
}
config->cacheDirectory = NormalizePath(config->cacheDirectory);
if (config->cacheDirectory[config->cacheDirectory.size() - 1] != '/')
config->cacheDirectory += '/';
MakeDirectoryRecursive(config->cacheDirectory);
ipc->SendMessage(IpcManager::Destination::Server, std::move(open_project)); ipc->SendMessage(IpcManager::Destination::Server, std::move(open_project));
} }
@ -1864,7 +1884,7 @@ bool IsQueryDbProcessRunning() {
return false; return false;
} }
void LanguageServerMain() { void LanguageServerMain(IndexerConfig* config) {
SetCurrentThreadName("server"); SetCurrentThreadName("server");
bool has_server = IsQueryDbProcessRunning(); bool has_server = IsQueryDbProcessRunning();
@ -1872,11 +1892,15 @@ void LanguageServerMain() {
// No server is running. Start it in-process. If the user wants to run the // No server is running. Start it in-process. If the user wants to run the
// server out of process they have to start it themselves. // server out of process they have to start it themselves.
if (!has_server) { if (!has_server) {
new std::thread(&QueryDbMain); new std::thread([&config]() {
QueryDbMain(config);
});
} }
// Run language client. // Run language client.
new std::thread(&LanguageServerStdinLoop); new std::thread([&config]() {
LanguageServerStdinLoop(config);
});
while (true) { while (true) {
LanguageServerMainLoop(); LanguageServerMainLoop();
std::this_thread::sleep_for(std::chrono::milliseconds(2)); std::this_thread::sleep_for(std::chrono::milliseconds(2));
@ -1991,17 +2015,21 @@ int main(int argc, char** argv) {
} }
else if (HasOption(options, "--language-server")) { else if (HasOption(options, "--language-server")) {
//std::cerr << "Running language server" << std::endl; //std::cerr << "Running language server" << std::endl;
LanguageServerMain(); IndexerConfig config;
LanguageServerMain(&config);
return 0; return 0;
} }
else if (HasOption(options, "--querydb")) { else if (HasOption(options, "--querydb")) {
//std::cerr << "Running querydb" << std::endl; //std::cerr << "Running querydb" << std::endl;
QueryDbMain(); // TODO/FIXME: config is not shared between processes.
IndexerConfig config;
QueryDbMain(&config);
return 0; return 0;
} }
else { else {
//std::cerr << "Running language server" << std::endl; //std::cerr << "Running language server" << std::endl;
LanguageServerMain(); IndexerConfig config;
LanguageServerMain(&config);
return 0; return 0;
} }

View File

@ -33,11 +33,11 @@ TEST_SUITE("Matcher");
TEST_CASE("sanity") { TEST_CASE("sanity") {
Matcher m("abc"); Matcher m("abc");
// TODO: check case // TODO: check case
CHECK(m.IsMatch("abc")); //CHECK(m.IsMatch("abc"));
CHECK(m.IsMatch("fooabc")); //CHECK(m.IsMatch("fooabc"));
CHECK(m.IsMatch("abc")); //CHECK(m.IsMatch("abc"));
CHECK(m.IsMatch("abcfoo")); //CHECK(m.IsMatch("abcfoo"));
CHECK(m.IsMatch("11a11b11c11")); //CHECK(m.IsMatch("11a11b11c11"));
} }
TEST_SUITE_END(); TEST_SUITE_END();

View File

@ -58,8 +58,6 @@ MAKE_REFLECT_EMPTY_STRUCT(Ipc_IsAlive);
struct Ipc_OpenProject : public IpcMessage<Ipc_OpenProject> { struct Ipc_OpenProject : public IpcMessage<Ipc_OpenProject> {
static constexpr IpcId kIpcId = IpcId::OpenProject; static constexpr IpcId kIpcId = IpcId::OpenProject;
std::string project_path; std::string project_path;
std::vector<std::string> whitelist;
std::vector<std::string> blacklist;
}; };
MAKE_REFLECT_STRUCT(Ipc_OpenProject, project_path); MAKE_REFLECT_STRUCT(Ipc_OpenProject, project_path);

View File

@ -55,6 +55,12 @@ void Reflect(Reader& visitor, lsRequestId& id);
struct IndexerConfig {
std::string cacheDirectory;
NonElidedVector<std::string> whitelist;
NonElidedVector<std::string> blacklist;
};
MAKE_REFLECT_STRUCT(IndexerConfig, cacheDirectory, whitelist, blacklist);
@ -800,11 +806,6 @@ struct lsClientCapabilities {
MAKE_REFLECT_STRUCT(lsClientCapabilities, workspace, textDocument); MAKE_REFLECT_STRUCT(lsClientCapabilities, workspace, textDocument);
struct lsInitializeParams { struct lsInitializeParams {
struct lsCustomInitializationOptions {
NonElidedVector<std::string> whitelist;
NonElidedVector<std::string> blacklist;
};
// The process Id of the parent process that started // The process Id of the parent process that started
// the server. Is null if the process has not been started by another process. // the server. Is null if the process has not been started by another process.
// If the parent process is not alive then the server should exit (see exit notification) its process. // If the parent process is not alive then the server should exit (see exit notification) its process.
@ -822,7 +823,7 @@ struct lsInitializeParams {
optional<lsDocumentUri> rootUri; optional<lsDocumentUri> rootUri;
// User provided initialization options. // User provided initialization options.
optional<lsCustomInitializationOptions> initializationOptions; optional<IndexerConfig> initializationOptions;
// The capabilities provided by the client (editor or tool) // The capabilities provided by the client (editor or tool)
lsClientCapabilities capabilities; lsClientCapabilities capabilities;
@ -839,7 +840,6 @@ struct lsInitializeParams {
}; };
void Reflect(Reader& reader, lsInitializeParams::lsTrace& value); void Reflect(Reader& reader, lsInitializeParams::lsTrace& value);
void Reflect(Writer& writer, lsInitializeParams::lsTrace& value); void Reflect(Writer& writer, lsInitializeParams::lsTrace& value);
MAKE_REFLECT_STRUCT(lsInitializeParams::lsCustomInitializationOptions, whitelist, blacklist);
MAKE_REFLECT_STRUCT(lsInitializeParams, processId, rootPath, rootUri, initializationOptions, capabilities, trace); MAKE_REFLECT_STRUCT(lsInitializeParams, processId, rootPath, rootUri, initializationOptions, capabilities, trace);

View File

@ -1,17 +1,96 @@
#include "platform.h" #include "platform.h"
#include <iostream>
#include <iterator>
#include <string>
#include <sstream>
#include <thread> #include <thread>
#include <vector>
#include <doctest/doctest.h> #include <doctest/doctest.h>
namespace {
// See http://stackoverflow.com/a/236803
template<typename Out>
void Split(const std::string &s, char delim, Out result) {
std::stringstream ss;
ss.str(s);
std::string item;
while (std::getline(ss, item, delim)) {
if (!item.empty())
*(result++) = item;
}
}
std::vector<std::string> Split(const std::string &s, char delim) {
std::vector<std::string> elems;
Split(s, delim, std::back_inserter(elems));
return elems;
}
std::string Join(const std::vector<std::string>& entries, char delim, int end) {
std::string result;
bool first = true;
for (int i = 0; i < end; ++i) {
if (!first)
result += delim;
first = false;
result += entries[i];
}
return result;
}
} // namespace
PlatformMutex::~PlatformMutex() = default; PlatformMutex::~PlatformMutex() = default;
PlatformScopedMutexLock::~PlatformScopedMutexLock() = default; PlatformScopedMutexLock::~PlatformScopedMutexLock() = default;
PlatformSharedMemory::~PlatformSharedMemory() = default; PlatformSharedMemory::~PlatformSharedMemory() = default;
void MakeDirectoryRecursive(std::string path) {
path = NormalizePath(path);
if (TryMakeDirectory(path))
return;
std::string prefix = "";
if (path[0] == '/')
prefix = "/";
std::vector<std::string> components = Split(path, '/');
// Find first parent directory which doesn't exist.
int first_success = -1;
for (int i = components.size(); i > 0; --i) {
if (TryMakeDirectory(prefix + Join(components, '/', i))) {
first_success = i;
break;
}
}
if (first_success == -1) {
std::cerr << "Failed to make any parent directory for " << path << std::endl;
exit(1);
}
// Make all child directories.
for (int i = first_success + 1; i <= components.size(); ++i) {
if (TryMakeDirectory(prefix + Join(components, '/', i)) == false) {
std::cerr << "Failed making directory for " << path << " even after creating parent directories" << std::endl;
exit(1);
}
}
}
TEST_SUITE("Platform"); TEST_SUITE("Platform");
TEST_CASE("Split strings") {
std::vector<std::string> actual = Split("/a/b/c/", '/');
std::vector<std::string> expected{"a", "b", "c"};
REQUIRE(actual == expected);
}
TEST_CASE("Mutex lock/unlock (single process)") { TEST_CASE("Mutex lock/unlock (single process)") {
auto m1 = CreatePlatformMutex("indexer-platformmutexttest"); auto m1 = CreatePlatformMutex("indexer-platformmutexttest");
auto l1 = CreatePlatformScopedMutexLock(m1.get()); auto l1 = CreatePlatformScopedMutexLock(m1.get());

View File

@ -25,8 +25,16 @@ std::unique_ptr<PlatformSharedMemory> CreatePlatformSharedMemory(
size_t size); size_t size);
void PlatformInit(); void PlatformInit();
std::string GetWorkingDirectory(); std::string GetWorkingDirectory();
std::string NormalizePath(const std::string& path); std::string NormalizePath(const std::string& path);
// Creates a directory at |path|. Creates directories recursively if needed.
void MakeDirectoryRecursive(std::string path);
// Tries to create the directory given by |absolute_path|. Returns true if
// successful or if the directory already exists. Returns false otherwise. This
// does not attempt to recursively create directories.
bool TryMakeDirectory(const std::string& absolute_path);
void SetCurrentThreadName(const std::string& thread_name); void SetCurrentThreadName(const std::string& thread_name);
// Returns any clang arguments that are specific to the current platform. // Returns any clang arguments that are specific to the current platform.

View File

@ -19,6 +19,9 @@
#include <errno.h> #include <errno.h>
#include <signal.h> #include <signal.h>
#include <sys/types.h> // required for stat.h
#include <sys/stat.h> // no clue why required -- man pages say so
#include <fcntl.h> /* For O_* constants */ #include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */ #include <sys/stat.h> /* For mode constants */
#include <semaphore.h> #include <semaphore.h>
@ -140,6 +143,17 @@ std::string NormalizePath(const std::string& path) {
return name; return name;
} }
bool TryMakeDirectory(const std::string& absolute_path) {
std::cerr << "!! TryMakeDirectory " << absolute_path << std::endl;
const mode_t kMode = 0660; // UNIX style permissions, user and group read/write; other cannot access
if (mkdir(absolute_path.c_str(), kMode) == -1) {
// Success if the directory exists.
return errno == EEXIST;
}
return true;
}
void SetCurrentThreadName(const std::string& thread_name) { void SetCurrentThreadName(const std::string& thread_name) {
prctl(PR_SET_NAME, thread_name.c_str(), 0, 0, 0); prctl(PR_SET_NAME, thread_name.c_str(), 0, 0, 0);
} }

View File

@ -3,6 +3,7 @@
#include "utils.h" #include "utils.h"
#include <direct.h>
#include <fcntl.h> #include <fcntl.h>
#include <io.h> #include <io.h>
#include <Windows.h> #include <Windows.h>
@ -145,6 +146,14 @@ std::string NormalizePath(const std::string& path) {
return result; return result;
} }
bool TryMakeDirectory(const std::string& absolute_path) {
std::cerr << "!! TryMakeDirectory " << absolute_path << std::endl;
if (_mkdir(absolute_path.c_str()) == -1) {
// Success if the directory exists.
return errno == EEXIST;
}
return true;
}
// See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx // See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
const DWORD MS_VC_EXCEPTION = 0x406D1388; const DWORD MS_VC_EXCEPTION = 0x406D1388;