mirror of
https://github.com/MaskRay/ccls.git
synced 2025-02-07 17:32:14 +00:00
Implement new threading model for computing index updates (prepare IdMap on querydb thread)
This commit is contained in:
parent
22cc140d80
commit
4249fc4a38
@ -30,7 +30,7 @@ const int kQueueSizeBytes = 1024 * 8;
|
|||||||
const int kMaxWorkspaceSearchResults = 1000;
|
const int kMaxWorkspaceSearchResults = 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct IndexTranslationUnitRequest {
|
struct Index_DoIndex {
|
||||||
enum class Type {
|
enum class Type {
|
||||||
Import,
|
Import,
|
||||||
Update
|
Update
|
||||||
@ -40,18 +40,37 @@ struct IndexTranslationUnitRequest {
|
|||||||
std::vector<std::string> args;
|
std::vector<std::string> args;
|
||||||
Type type;
|
Type type;
|
||||||
|
|
||||||
IndexTranslationUnitRequest(Type type) : type(type) {}
|
Index_DoIndex(Type type) : type(type) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IndexTranslationUnitResponse {
|
struct Index_DoIdMap {
|
||||||
|
std::unique_ptr<IndexedFile> previous;
|
||||||
|
std::unique_ptr<IndexedFile> current;
|
||||||
|
|
||||||
|
explicit Index_DoIdMap(std::unique_ptr<IndexedFile> previous,
|
||||||
|
std::unique_ptr<IndexedFile> current)
|
||||||
|
: previous(std::move(previous)),
|
||||||
|
current(std::move(current)) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Index_OnIdMapped {
|
||||||
|
std::unique_ptr<IndexedFile> previous_index;
|
||||||
|
std::unique_ptr<IndexedFile> current_index;
|
||||||
|
std::unique_ptr<IdMap> previous_id_map;
|
||||||
|
std::unique_ptr<IdMap> current_id_map;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Index_OnIndexed {
|
||||||
IndexUpdate update;
|
IndexUpdate update;
|
||||||
explicit IndexTranslationUnitResponse(IndexUpdate& update) : update(update) {}
|
explicit Index_OnIndexed(IndexUpdate& update) : update(update) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Rename TypedBidiMessageQueue to IpcTransport?
|
// TODO: Rename TypedBidiMessageQueue to IpcTransport?
|
||||||
using IpcMessageQueue = TypedBidiMessageQueue<IpcId, BaseIpcMessage>;
|
using IpcMessageQueue = TypedBidiMessageQueue<IpcId, BaseIpcMessage>;
|
||||||
using IndexRequestQueue = ThreadedQueue<IndexTranslationUnitRequest>;
|
using Index_DoIndexQueue = ThreadedQueue<std::unique_ptr<Index_DoIndex>>;
|
||||||
using IndexResponseQueue = ThreadedQueue<IndexTranslationUnitResponse>;
|
using Index_DoIdMapQueue = ThreadedQueue<std::unique_ptr<Index_DoIdMap>>;
|
||||||
|
using Index_OnIdMappedQueue = ThreadedQueue<std::unique_ptr<Index_OnIdMapped>>;
|
||||||
|
using Index_OnIndexedQueue = ThreadedQueue<std::unique_ptr<Index_OnIndexed>>;
|
||||||
|
|
||||||
template<typename TMessage>
|
template<typename TMessage>
|
||||||
void SendMessage(IpcMessageQueue& t, MessageQueue* destination, TMessage& message) {
|
void SendMessage(IpcMessageQueue& t, MessageQueue* destination, TMessage& message) {
|
||||||
@ -222,22 +241,26 @@ std::string GetCachedFileName(std::string source_file) {
|
|||||||
return kCacheDirectory + source_file + ".json";
|
return kCacheDirectory + source_file + ".json";
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<IndexedFile> LoadCachedFile(std::string filename) {
|
std::unique_ptr<IndexedFile> LoadCachedFile(std::string filename) {
|
||||||
// TODO FIXME FIXME FIXME
|
// TODO FIXME FIXME FIXME
|
||||||
return nullopt;
|
return nullptr;
|
||||||
|
|
||||||
std::string cache_file = GetCachedFileName(filename);
|
std::string cache_file = GetCachedFileName(filename);
|
||||||
|
|
||||||
std::ifstream cache;
|
std::ifstream cache;
|
||||||
cache.open(GetCachedFileName(filename));
|
cache.open(GetCachedFileName(filename));
|
||||||
if (!cache.good())
|
if (!cache.good())
|
||||||
return nullopt;
|
return nullptr;
|
||||||
|
|
||||||
std::string file_content = std::string(
|
std::string file_content = std::string(
|
||||||
std::istreambuf_iterator<char>(cache),
|
std::istreambuf_iterator<char>(cache),
|
||||||
std::istreambuf_iterator<char>());
|
std::istreambuf_iterator<char>());
|
||||||
|
|
||||||
return Deserialize(filename, file_content);
|
optional<IndexedFile> indexed = Deserialize(filename, file_content);
|
||||||
|
if (indexed)
|
||||||
|
return MakeUnique<IndexedFile>(indexed.value());
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteToCache(std::string filename, IndexedFile& file) {
|
void WriteToCache(std::string filename, IndexedFile& file) {
|
||||||
@ -250,111 +273,85 @@ void WriteToCache(std::string filename, IndexedFile& file) {
|
|||||||
cache.close();
|
cache.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IndexMain(IndexRequestQueue* requests, IndexResponseQueue* responses) {
|
|
||||||
while (true) {
|
bool IndexMain_DoIndex(Index_DoIndexQueue* queue_do_index,
|
||||||
// Try to get a request. If there isn't one, sleep for a little while.
|
Index_DoIdMapQueue* queue_do_id_map) {
|
||||||
optional<IndexTranslationUnitRequest> request = requests->TryDequeue();
|
optional<std::unique_ptr<Index_DoIndex>> opt_index_request = queue_do_index->TryDequeue();
|
||||||
if (!request) {
|
if (!opt_index_request)
|
||||||
// TODO: use CV to wakeup?
|
return false;
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
std::unique_ptr<Index_DoIndex> index_request = std::move(opt_index_request.value());
|
||||||
continue;
|
|
||||||
}
|
Timer time;
|
||||||
|
|
||||||
|
std::unique_ptr<IndexedFile> old_index = LoadCachedFile(index_request->path);
|
||||||
|
time.ResetAndPrint("Loading cached index");
|
||||||
|
|
||||||
|
|
||||||
Timer time;
|
// If the index update is an import, then we will load the previous index
|
||||||
|
// into memory if we have a previous index. After that, we dispatch an
|
||||||
// If the index update is an import, then we will load the previous index
|
// update request to get the latest version.
|
||||||
// into memory if we have a previous index. After that, we dispatch an
|
if (old_index && index_request->type == Index_DoIndex::Type::Import) {
|
||||||
// update request to get the latest version.
|
auto response = MakeUnique<Index_DoIdMap>(nullptr /*previous*/, std::move(old_index) /*current*/);
|
||||||
if (request->type == IndexTranslationUnitRequest::Type::Import) {
|
queue_do_id_map->Enqueue(std::move(response));
|
||||||
request->type = IndexTranslationUnitRequest::Type::Update;
|
|
||||||
|
|
||||||
// TODO: we're not serializing out the files cache. We only ever want to import references
|
|
||||||
// from the primary file though, so that should be ok. We need to cleanup indexer output.
|
|
||||||
optional<IndexedFile> old_index = LoadCachedFile(request->path);
|
|
||||||
if (old_index.has_value()) {
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO: We need to create IdMap on QueryDb thread.
|
|
||||||
IdMap old_id_map(nullptr, old_index->id_cache);
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
IndexUpdate update = IndexUpdate::CreateImport(old_id_map, old_index.value());
|
|
||||||
IndexTranslationUnitResponse response(update);
|
|
||||||
responses->Enqueue(response);
|
|
||||||
time.ResetAndPrint("Loading cached index");
|
|
||||||
requests->Enqueue(request.value());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(request->type == IndexTranslationUnitRequest::Type::Update);
|
|
||||||
|
|
||||||
|
index_request->type = Index_DoIndex::Type::Update;
|
||||||
|
queue_do_index->Enqueue(std::move(index_request));
|
||||||
|
}
|
||||||
|
else {
|
||||||
// Parse request and send a response.
|
// Parse request and send a response.
|
||||||
std::cerr << "Parsing file " << request->path << " with args "
|
std::cerr << "Parsing file " << index_request->path << " with args "
|
||||||
<< Join(request->args, ", ") << std::endl;
|
<< Join(index_request->args, ", ") << std::endl;
|
||||||
|
|
||||||
|
// TODO: parse should return unique_ptr. Then we can eliminate copy below. Make sure to not
|
||||||
|
// reuse moved pointer in WriteToCache if we do so.
|
||||||
|
IndexedFile current_index = Parse(index_request->path, index_request->args);
|
||||||
|
|
||||||
IndexedFile new_index = Parse(request->path, request->args);
|
|
||||||
time.ResetAndPrint("Parsing/indexing");
|
time.ResetAndPrint("Parsing/indexing");
|
||||||
|
|
||||||
// If we have a cached index, that means it is already imported, which
|
auto response = MakeUnique<Index_DoIdMap>(std::move(old_index) /*previous*/, MakeUnique<IndexedFile>(current_index) /*current*/);
|
||||||
// means we want to apply a delta update.
|
queue_do_id_map->Enqueue(std::move(response));
|
||||||
optional<IndexedFile> old_index = LoadCachedFile(request->path);
|
|
||||||
time.ResetAndPrint("Loading previous index");
|
|
||||||
if (old_index) {
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO: We need to create IdMap on QueryDb thread.
|
|
||||||
IdMap old_id_map(nullptr, old_index->id_cache);
|
|
||||||
IdMap new_id_map(nullptr, new_index.id_cache);
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
|
|
||||||
// Apply delta update.
|
|
||||||
IndexUpdate update = IndexUpdate::CreateDelta(old_id_map, new_id_map, old_index.value(), new_index);
|
|
||||||
IndexTranslationUnitResponse response(update);
|
|
||||||
time.ResetAndPrint("Creating delta index update/response");
|
|
||||||
responses->Enqueue(response);
|
|
||||||
time.ResetAndPrint("Sending update to server");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO: We need to create IdMap on QueryDb thread.
|
|
||||||
IdMap new_id_map(nullptr, new_index.id_cache);
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
// TODO/FIXME/TODO
|
|
||||||
|
|
||||||
// Apply full update.
|
|
||||||
IndexUpdate update = IndexUpdate::CreateImport(new_id_map, new_index);
|
|
||||||
IndexTranslationUnitResponse response(update);
|
|
||||||
time.ResetAndPrint("Creating index update/response");
|
|
||||||
responses->Enqueue(response);
|
|
||||||
time.ResetAndPrint("Sending update to server");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache file so we can diff it later.
|
// Cache file so we can diff it later.
|
||||||
WriteToCache(request->path, new_index);
|
WriteToCache(index_request->path, current_index);
|
||||||
time.ResetAndPrint("Cache index update to disk");
|
time.ResetAndPrint("Cache index update to disk");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IndexMain_DoCreateIndexUpdate(Index_OnIdMappedQueue* queue_on_id_mapped,
|
||||||
|
Index_OnIndexedQueue* queue_on_indexed) {
|
||||||
|
optional<std::unique_ptr<Index_OnIdMapped>> opt_response = queue_on_id_mapped->TryDequeue();
|
||||||
|
if (!opt_response)
|
||||||
|
return false;
|
||||||
|
std::unique_ptr<Index_OnIdMapped> response = std::move(opt_response.value());
|
||||||
|
|
||||||
|
Timer time;
|
||||||
|
IndexUpdate update = IndexUpdate::CreateDelta(response->previous_id_map.get(), response->current_id_map.get(),
|
||||||
|
response->previous_index.get(), response->current_index.get());
|
||||||
|
time.ResetAndPrint("Creating delta IndexUpdate");
|
||||||
|
auto reply = MakeUnique<Index_OnIndexed>(update);
|
||||||
|
queue_on_indexed->Enqueue(std::move(reply));
|
||||||
|
time.ResetAndPrint("Sending update to server");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IndexMain(Index_DoIndexQueue* queue_do_index,
|
||||||
|
Index_DoIdMapQueue* queue_do_id_map,
|
||||||
|
Index_OnIdMappedQueue* queue_on_id_mapped,
|
||||||
|
Index_OnIndexedQueue* queue_on_indexed) {
|
||||||
|
while (true) {
|
||||||
|
// TODO: process all off IndexMain_DoIndex before calling IndexMain_DoCreateIndexUpdate for
|
||||||
|
// better icache behavior. We need to have some threads spinning on both though
|
||||||
|
// otherwise memory usage will get bad.
|
||||||
|
|
||||||
|
if (!IndexMain_DoIndex(queue_do_index, queue_do_id_map) &&
|
||||||
|
!IndexMain_DoCreateIndexUpdate(queue_on_id_mapped, queue_on_indexed)) {
|
||||||
|
// TODO: use CV to wakeup?
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryableFile* FindFile(QueryableDatabase* db, const std::string& filename) {
|
QueryableFile* FindFile(QueryableDatabase* db, const std::string& filename) {
|
||||||
@ -457,8 +454,10 @@ void AddCodeLens(std::vector<TCodeLens>* result,
|
|||||||
void QueryDbMainLoop(
|
void QueryDbMainLoop(
|
||||||
QueryableDatabase* db,
|
QueryableDatabase* db,
|
||||||
IpcMessageQueue* language_client,
|
IpcMessageQueue* language_client,
|
||||||
IndexRequestQueue* index_requests,
|
Index_DoIndexQueue* queue_do_index,
|
||||||
IndexResponseQueue* index_responses,
|
Index_DoIdMapQueue* queue_do_id_map,
|
||||||
|
Index_OnIdMappedQueue* queue_on_id_mapped,
|
||||||
|
Index_OnIndexedQueue* queue_on_indexed,
|
||||||
Project* project,
|
Project* project,
|
||||||
WorkingFiles* working_files,
|
WorkingFiles* working_files,
|
||||||
CompletionManager* completion_manager) {
|
CompletionManager* completion_manager) {
|
||||||
@ -496,10 +495,10 @@ void QueryDbMainLoop(
|
|||||||
<< "] Dispatching index request for file " << filepath
|
<< "] Dispatching index request for file " << filepath
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
IndexTranslationUnitRequest request(IndexTranslationUnitRequest::Type::Import);
|
auto request = MakeUnique<Index_DoIndex>(Index_DoIndex::Type::Import);
|
||||||
request.path = filepath;
|
request->path = filepath;
|
||||||
request.args = entry.args;
|
request->args = entry.args;
|
||||||
index_requests->Enqueue(request);
|
queue_do_index->Enqueue(std::move(request));
|
||||||
}
|
}
|
||||||
std::cerr << "Done" << std::endl;
|
std::cerr << "Done" << std::endl;
|
||||||
break;
|
break;
|
||||||
@ -711,7 +710,7 @@ void QueryDbMainLoop(
|
|||||||
std::string query = msg->params.query;
|
std::string query = msg->params.query;
|
||||||
for (int i = 0; i < db->qualified_names.size(); ++i) {
|
for (int i = 0; i < db->qualified_names.size(); ++i) {
|
||||||
if (response.result.size() > kMaxWorkspaceSearchResults) {
|
if (response.result.size() > kMaxWorkspaceSearchResults) {
|
||||||
std::cerr << "Query exceeded maximum number of responses (" << kMaxWorkspaceSearchResults << "), output may not contain all results";
|
std::cerr << "Query exceeded maximum number of responses (" << kMaxWorkspaceSearchResults << "), output may not contain all results" << std::endl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -729,6 +728,8 @@ void QueryDbMainLoop(
|
|||||||
switch (symbol.kind) {
|
switch (symbol.kind) {
|
||||||
case SymbolKind::File: {
|
case SymbolKind::File: {
|
||||||
QueryableFile& def = db->files[symbol.idx];
|
QueryableFile& def = db->files[symbol.idx];
|
||||||
|
info.name = def.def.usr;
|
||||||
|
info.kind = lsSymbolKind::File;
|
||||||
info.location.uri.SetPath(def.def.usr);
|
info.location.uri.SetPath(def.def.usr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -795,10 +796,32 @@ void QueryDbMainLoop(
|
|||||||
|
|
||||||
// TODO: consider rate-limiting and checking for IPC messages so we don't block
|
// TODO: consider rate-limiting and checking for IPC messages so we don't block
|
||||||
// requests / we can serve partial requests.
|
// requests / we can serve partial requests.
|
||||||
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
optional<IndexTranslationUnitResponse> response = index_responses->TryDequeue();
|
optional<std::unique_ptr<Index_DoIdMap>> opt_request = queue_do_id_map->TryDequeue();
|
||||||
if (!response)
|
if (!opt_request)
|
||||||
break;
|
break;
|
||||||
|
std::unique_ptr<Index_DoIdMap> request = std::move(opt_request.value());
|
||||||
|
|
||||||
|
auto response = MakeUnique<Index_OnIdMapped>();
|
||||||
|
Timer time;
|
||||||
|
if (request->previous) {
|
||||||
|
response->previous_id_map = MakeUnique<IdMap>(db, request->previous->id_cache);
|
||||||
|
response->previous_index = std::move(request->previous);
|
||||||
|
}
|
||||||
|
response->current_id_map = MakeUnique<IdMap>(db, request->current->id_cache);
|
||||||
|
response->current_index = std::move(request->current);
|
||||||
|
time.ResetAndPrint("Create IdMap");
|
||||||
|
|
||||||
|
queue_on_id_mapped->Enqueue(std::move(response));
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
optional<std::unique_ptr<Index_OnIndexed>> opt_response = queue_on_indexed->TryDequeue();
|
||||||
|
if (!opt_response)
|
||||||
|
break;
|
||||||
|
std::unique_ptr<Index_OnIndexed> response = std::move(opt_response.value());
|
||||||
|
|
||||||
Timer time;
|
Timer time;
|
||||||
db->ApplyIndexUpdate(&response->update);
|
db->ApplyIndexUpdate(&response->update);
|
||||||
@ -811,8 +834,11 @@ void QueryDbMain() {
|
|||||||
|
|
||||||
// Create queues.
|
// Create queues.
|
||||||
std::unique_ptr<IpcMessageQueue> ipc = BuildIpcMessageQueue(kIpcLanguageClientName, kQueueSizeBytes);
|
std::unique_ptr<IpcMessageQueue> ipc = BuildIpcMessageQueue(kIpcLanguageClientName, kQueueSizeBytes);
|
||||||
IndexRequestQueue index_request_queue;
|
Index_DoIndexQueue queue_do_index;
|
||||||
IndexResponseQueue index_response_queue;
|
Index_DoIdMapQueue queue_do_id_map;
|
||||||
|
Index_OnIdMappedQueue queue_on_id_mapped;
|
||||||
|
Index_OnIndexedQueue queue_on_indexed;
|
||||||
|
|
||||||
Project project;
|
Project project;
|
||||||
WorkingFiles working_files;
|
WorkingFiles working_files;
|
||||||
CompletionManager completion_manager(&project, &working_files);
|
CompletionManager completion_manager(&project, &working_files);
|
||||||
@ -820,14 +846,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(&index_request_queue, &index_response_queue);
|
IndexMain(&queue_do_index, &queue_do_id_map, &queue_on_id_mapped, &queue_on_indexed);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run query db main loop.
|
// Run query db main loop.
|
||||||
QueryableDatabase db;
|
QueryableDatabase db;
|
||||||
while (true) {
|
while (true) {
|
||||||
QueryDbMainLoop(&db, ipc.get(), &index_request_queue, &index_response_queue, &project, &working_files, &completion_manager);
|
QueryDbMainLoop(&db, ipc.get(), &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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
106
src/query.cc
106
src/query.cc
@ -452,10 +452,8 @@ int GetOrAddSymbol(QueryableDatabase* query_db, SymbolKind kind, const Usr& usr)
|
|||||||
|
|
||||||
IdMap::IdMap(QueryableDatabase* query_db, const IdCache& local_ids)
|
IdMap::IdMap(QueryableDatabase* query_db, const IdCache& local_ids)
|
||||||
: local_ids(local_ids) {
|
: local_ids(local_ids) {
|
||||||
assert(query_db); // TODO: remove after testing.
|
|
||||||
|
|
||||||
index_file_id = GetQueryFileIdFromUsr(query_db, local_ids.primary_file);
|
index_file_id = GetQueryFileIdFromUsr(query_db, local_ids.primary_file);
|
||||||
|
|
||||||
cached_type_ids_.reserve(local_ids.type_id_to_usr.size());
|
cached_type_ids_.reserve(local_ids.type_id_to_usr.size());
|
||||||
for (const auto& entry : local_ids.type_id_to_usr)
|
for (const auto& entry : local_ids.type_id_to_usr)
|
||||||
cached_type_ids_[entry.first] = GetQueryTypeIdFromUsr(query_db, entry.second);
|
cached_type_ids_[entry.first] = GetQueryTypeIdFromUsr(query_db, entry.second);
|
||||||
@ -489,19 +487,16 @@ IdMap::IdMap(QueryableDatabase* query_db, const IdCache& local_ids)
|
|||||||
|
|
||||||
|
|
||||||
// static
|
// static
|
||||||
IndexUpdate IndexUpdate::CreateImport(const IdMap& id_map, IndexedFile& file) {
|
IndexUpdate IndexUpdate::CreateDelta(const IdMap* previous_id_map, const IdMap* current_id_map, IndexedFile* previous, IndexedFile* current) {
|
||||||
// Return standard diff constructor but with an empty file so everything is
|
if (!previous_id_map) {
|
||||||
// added.
|
assert(!previous);
|
||||||
IndexedFile previous(file.path);
|
IndexedFile previous(current->path);
|
||||||
return IndexUpdate(id_map, id_map, previous, file);
|
return IndexUpdate(*current_id_map, *current_id_map, previous, *current);
|
||||||
|
}
|
||||||
|
return IndexUpdate(*previous_id_map, *current_id_map, *previous, *current);
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
IndexUpdate::IndexUpdate(const IdMap& previous_id_map, const IdMap& current_id_map, IndexedFile& previous_file, IndexedFile& current_file) {
|
||||||
IndexUpdate IndexUpdate::CreateDelta(const IdMap& current_id_map, const IdMap& previous_id_map, IndexedFile& current, IndexedFile& updated) {
|
|
||||||
return IndexUpdate(current_id_map, previous_id_map, current, updated);
|
|
||||||
}
|
|
||||||
|
|
||||||
IndexUpdate::IndexUpdate(const IdMap& current_id_map, const IdMap& previous_id_map, IndexedFile& previous_file, IndexedFile& current_file) {
|
|
||||||
// |query_name| is the name of the variable on the query type.
|
// |query_name| is the name of the variable on the query type.
|
||||||
// |index_name| is the name of the variable on the index type.
|
// |index_name| is the name of the variable on the index type.
|
||||||
// |type| is the type of the variable.
|
// |type| is the type of the variable.
|
||||||
@ -638,7 +633,16 @@ void IndexUpdate::Merge(const IndexUpdate& update) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void UpdateQualifiedName(QueryableDatabase* db, int* qualified_name_index, SymbolKind kind, int symbol_index, const std::string& name) {
|
||||||
|
if (*qualified_name_index == -1) {
|
||||||
|
db->qualified_names.push_back(name);
|
||||||
|
db->symbols.push_back(SymbolIdx(kind, symbol_index));
|
||||||
|
*qualified_name_index = db->qualified_names.size() - 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
db->qualified_names[*qualified_name_index] = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -654,67 +658,53 @@ void QueryableDatabase::RemoveUsrs(const std::vector<Usr>& to_remove) {
|
|||||||
void QueryableDatabase::ImportOrUpdate(const std::vector<QueryableFile::DefUpdate>& updates) {
|
void QueryableDatabase::ImportOrUpdate(const std::vector<QueryableFile::DefUpdate>& updates) {
|
||||||
for (auto& def : updates) {
|
for (auto& def : updates) {
|
||||||
auto it = usr_to_symbol.find(def.usr);
|
auto it = usr_to_symbol.find(def.usr);
|
||||||
if (it == usr_to_symbol.end()) {
|
assert(it != usr_to_symbol.end());
|
||||||
qualified_names.push_back(def.usr);
|
|
||||||
symbols.push_back(SymbolIdx(SymbolKind::File, files.size()));
|
QueryableFile& existing = files[it->second.idx];
|
||||||
usr_to_symbol[def.usr] = SymbolIdx(SymbolKind::File, files.size());
|
existing.def = def;
|
||||||
files.push_back(QueryableFile(def));
|
UpdateQualifiedName(this, &existing.qualified_name_idx, SymbolKind::File, it->second.idx, def.usr);
|
||||||
}
|
|
||||||
else {
|
|
||||||
QueryableFile& existing = files[it->second.idx];
|
|
||||||
existing.def = def;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryableDatabase::ImportOrUpdate(const std::vector<QueryableTypeDef::DefUpdate>& updates) {
|
void QueryableDatabase::ImportOrUpdate(const std::vector<QueryableTypeDef::DefUpdate>& updates) {
|
||||||
for (auto& def : updates) {
|
for (auto& def : updates) {
|
||||||
|
if (!def.definition_extent)
|
||||||
|
continue;
|
||||||
|
|
||||||
auto it = usr_to_symbol.find(def.usr);
|
auto it = usr_to_symbol.find(def.usr);
|
||||||
if (it == usr_to_symbol.end()) {
|
assert(it != usr_to_symbol.end());
|
||||||
qualified_names.push_back(def.qualified_name);
|
|
||||||
symbols.push_back(SymbolIdx(SymbolKind::Type, types.size()));
|
QueryableTypeDef& existing = types[it->second.idx];
|
||||||
usr_to_symbol[def.usr] = SymbolIdx(SymbolKind::Type, types.size());
|
existing.def = def;
|
||||||
types.push_back(QueryableTypeDef(def));
|
UpdateQualifiedName(this, &existing.qualified_name_idx, SymbolKind::Type, it->second.idx, def.usr);
|
||||||
}
|
|
||||||
else {
|
|
||||||
QueryableTypeDef& existing = types[it->second.idx];
|
|
||||||
if (def.definition_extent)
|
|
||||||
existing.def = def;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryableDatabase::ImportOrUpdate(const std::vector<QueryableFuncDef::DefUpdate>& updates) {
|
void QueryableDatabase::ImportOrUpdate(const std::vector<QueryableFuncDef::DefUpdate>& updates) {
|
||||||
for (auto& def : updates) {
|
for (auto& def : updates) {
|
||||||
|
if (!def.definition_extent)
|
||||||
|
continue;
|
||||||
|
|
||||||
auto it = usr_to_symbol.find(def.usr);
|
auto it = usr_to_symbol.find(def.usr);
|
||||||
if (it == usr_to_symbol.end()) {
|
assert(it != usr_to_symbol.end());
|
||||||
qualified_names.push_back(def.qualified_name);
|
|
||||||
symbols.push_back(SymbolIdx(SymbolKind::Func, funcs.size()));
|
QueryableFuncDef& existing = funcs[it->second.idx];
|
||||||
usr_to_symbol[def.usr] = SymbolIdx(SymbolKind::Func, funcs.size());
|
existing.def = def;
|
||||||
funcs.push_back(QueryableFuncDef(def));
|
UpdateQualifiedName(this, &existing.qualified_name_idx, SymbolKind::Func, it->second.idx, def.usr);
|
||||||
}
|
|
||||||
else {
|
|
||||||
QueryableFuncDef& existing = funcs[it->second.idx];
|
|
||||||
if (def.definition_extent)
|
|
||||||
existing.def = def;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QueryableDatabase::ImportOrUpdate(const std::vector<QueryableVarDef::DefUpdate>& updates) {
|
void QueryableDatabase::ImportOrUpdate(const std::vector<QueryableVarDef::DefUpdate>& updates) {
|
||||||
for (auto& def : updates) {
|
for (auto& def : updates) {
|
||||||
|
if (!def.definition_extent)
|
||||||
|
continue;
|
||||||
|
|
||||||
auto it = usr_to_symbol.find(def.usr);
|
auto it = usr_to_symbol.find(def.usr);
|
||||||
if (it == usr_to_symbol.end()) {
|
assert(it != usr_to_symbol.end());
|
||||||
qualified_names.push_back(def.qualified_name);
|
|
||||||
symbols.push_back(SymbolIdx(SymbolKind::Var, vars.size()));
|
QueryableVarDef& existing = vars[it->second.idx];
|
||||||
usr_to_symbol[def.usr] = SymbolIdx(SymbolKind::Var, vars.size());
|
existing.def = def;
|
||||||
vars.push_back(QueryableVarDef(def));
|
UpdateQualifiedName(this, &existing.qualified_name_idx, SymbolKind::Var, it->second.idx, def.usr);
|
||||||
}
|
|
||||||
else {
|
|
||||||
QueryableVarDef& existing = vars[it->second.idx];
|
|
||||||
if (def.definition_extent)
|
|
||||||
existing.def = def;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
src/query.h
12
src/query.h
@ -118,6 +118,7 @@ struct QueryableFile {
|
|||||||
using DefUpdate = Def;
|
using DefUpdate = Def;
|
||||||
|
|
||||||
DefUpdate def;
|
DefUpdate def;
|
||||||
|
int qualified_name_idx = -1;
|
||||||
|
|
||||||
QueryableFile(const Usr& usr) { def.usr = usr; }
|
QueryableFile(const Usr& usr) { def.usr = usr; }
|
||||||
QueryableFile(const Def& def) : def(def) {}
|
QueryableFile(const Def& def) : def(def) {}
|
||||||
@ -134,6 +135,7 @@ struct QueryableTypeDef {
|
|||||||
std::vector<Usr> derived;
|
std::vector<Usr> derived;
|
||||||
std::vector<Usr> instantiations;
|
std::vector<Usr> instantiations;
|
||||||
std::vector<QueryableLocation> uses;
|
std::vector<QueryableLocation> uses;
|
||||||
|
int qualified_name_idx = -1;
|
||||||
|
|
||||||
QueryableTypeDef(const Usr& usr) : def(usr) {}
|
QueryableTypeDef(const Usr& usr) : def(usr) {}
|
||||||
QueryableTypeDef(const DefUpdate& def) : def(def) {}
|
QueryableTypeDef(const DefUpdate& def) : def(def) {}
|
||||||
@ -152,6 +154,7 @@ struct QueryableFuncDef {
|
|||||||
std::vector<Usr> derived;
|
std::vector<Usr> derived;
|
||||||
std::vector<UsrRef> callers;
|
std::vector<UsrRef> callers;
|
||||||
std::vector<QueryableLocation> uses;
|
std::vector<QueryableLocation> uses;
|
||||||
|
int qualified_name_idx = -1;
|
||||||
|
|
||||||
QueryableFuncDef(const Usr& usr) : def(usr) {}
|
QueryableFuncDef(const Usr& usr) : def(usr) {}
|
||||||
QueryableFuncDef(const DefUpdate& def) : def(def) {}
|
QueryableFuncDef(const DefUpdate& def) : def(def) {}
|
||||||
@ -164,6 +167,7 @@ struct QueryableVarDef {
|
|||||||
|
|
||||||
DefUpdate def;
|
DefUpdate def;
|
||||||
std::vector<QueryableLocation> uses;
|
std::vector<QueryableLocation> uses;
|
||||||
|
int qualified_name_idx = -1;
|
||||||
|
|
||||||
QueryableVarDef(const Usr& usr) : def(usr) {}
|
QueryableVarDef(const Usr& usr) : def(usr) {}
|
||||||
QueryableVarDef(const DefUpdate& def) : def(def) {}
|
QueryableVarDef(const DefUpdate& def) : def(def) {}
|
||||||
@ -181,9 +185,9 @@ struct SymbolIdx {
|
|||||||
|
|
||||||
|
|
||||||
struct IndexUpdate {
|
struct IndexUpdate {
|
||||||
// Creates a new IndexUpdate that will import |file|.
|
// Creates a new IndexUpdate based on the delta from previous to current. If
|
||||||
static IndexUpdate CreateImport(const IdMap& id_map, IndexedFile& file);
|
// no delta computation should be done just pass null for previous.
|
||||||
static IndexUpdate CreateDelta(const IdMap& current_id_map, const IdMap& previous_id_map, IndexedFile& current, IndexedFile& updated);
|
static IndexUpdate CreateDelta(const IdMap* previous_id_map, const IdMap* current_id_map, IndexedFile* previous, IndexedFile* current);
|
||||||
|
|
||||||
// Merge |update| into this update; this can reduce overhead / index update
|
// Merge |update| into this update; this can reduce overhead / index update
|
||||||
// work can be parallelized.
|
// work can be parallelized.
|
||||||
@ -217,7 +221,7 @@ struct IndexUpdate {
|
|||||||
// Creates an index update assuming that |previous| is already
|
// Creates an index update assuming that |previous| is already
|
||||||
// in the index, so only the delta between |previous| and |current|
|
// in the index, so only the delta between |previous| and |current|
|
||||||
// will be applied.
|
// will be applied.
|
||||||
IndexUpdate(const IdMap& current_id_map, const IdMap& previous_id_map, IndexedFile& previous, IndexedFile& current);
|
IndexUpdate(const IdMap& previous_id_map, const IdMap& current_id_map, IndexedFile& previous, IndexedFile& current);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,9 +15,9 @@ template <class T>
|
|||||||
class ThreadedQueue {
|
class ThreadedQueue {
|
||||||
public:
|
public:
|
||||||
// Add an element to the queue.
|
// Add an element to the queue.
|
||||||
void Enqueue(T t) {
|
void Enqueue(T&& t) {
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
queue_.push(t);
|
queue_.push(std::move(t));
|
||||||
cv_.notify_one();
|
cv_.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +29,8 @@ public:
|
|||||||
// release lock as long as the wait and reaquire it afterwards.
|
// release lock as long as the wait and reaquire it afterwards.
|
||||||
cv_.wait(lock);
|
cv_.wait(lock);
|
||||||
}
|
}
|
||||||
T val = queue_.front();
|
|
||||||
|
auto val = std::move(queue_.front());
|
||||||
queue_.pop();
|
queue_.pop();
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
@ -41,7 +42,7 @@ public:
|
|||||||
if (queue_.empty())
|
if (queue_.empty())
|
||||||
return nullopt;
|
return nullopt;
|
||||||
|
|
||||||
T val = queue_.front();
|
auto val = std::move(queue_.front());
|
||||||
queue_.pop();
|
queue_.pop();
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user