mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-26 01:21:57 +00:00
Improvements to loading project.
- Don't reindex the file if the modification time has not changed. - Import file dependencies before importing other files, which might be a full-on index operation.
This commit is contained in:
parent
2780e18040
commit
9338bcfd0e
@ -867,6 +867,7 @@ void RegisterMessageTypes() {
|
|||||||
|
|
||||||
bool IndexMain_DoIndex(IndexerConfig* config,
|
bool IndexMain_DoIndex(IndexerConfig* config,
|
||||||
FileConsumer::SharedState* file_consumer_shared,
|
FileConsumer::SharedState* file_consumer_shared,
|
||||||
|
Project* project,
|
||||||
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();
|
||||||
@ -892,9 +893,11 @@ bool IndexMain_DoIndex(IndexerConfig* config,
|
|||||||
Index_DoIndex dep_index_request(Index_DoIndex::Type::ImportOnly);
|
Index_DoIndex dep_index_request(Index_DoIndex::Type::ImportOnly);
|
||||||
dep_index_request.path = dependency_path;
|
dep_index_request.path = dependency_path;
|
||||||
dep_index_request.args = index_request->args;
|
dep_index_request.args = index_request->args;
|
||||||
queue_do_index->Enqueue(std::move(dep_index_request));
|
queue_do_index->PriorityEnqueue(std::move(dep_index_request));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
project->UpdateModificationTime(index_request->path, old_index->last_modification_time);
|
||||||
|
|
||||||
Index_DoIdMap response(nullptr, std::move(old_index));
|
Index_DoIdMap response(nullptr, std::move(old_index));
|
||||||
queue_do_id_map->Enqueue(std::move(response));
|
queue_do_id_map->Enqueue(std::move(response));
|
||||||
|
|
||||||
@ -909,6 +912,17 @@ bool IndexMain_DoIndex(IndexerConfig* config,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse request and send a response.
|
// Parse request and send a response.
|
||||||
|
|
||||||
|
// Skip index if file modification time didn't change.
|
||||||
|
optional<Project::Entry> entry = project->FindCompilationEntryForFile(index_request->path);
|
||||||
|
if (entry && entry->last_modification_time) {
|
||||||
|
int64_t modification_time = GetLastModificationTime(index_request->path);
|
||||||
|
if (modification_time == *entry->last_modification_time) {
|
||||||
|
time.ResetAndPrint("Skipping index update on " + index_request->path + " since file modification time has not changed");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::unique_ptr<IndexedFile>> indexes = Parse(config, file_consumer_shared, index_request->path, index_request->args);
|
std::vector<std::unique_ptr<IndexedFile>> indexes = Parse(config, file_consumer_shared, index_request->path, index_request->args);
|
||||||
time.ResetAndPrint("Parsing/indexing " + index_request->path);
|
time.ResetAndPrint("Parsing/indexing " + index_request->path);
|
||||||
|
|
||||||
@ -973,6 +987,7 @@ void IndexJoinIndexUpdates(Index_OnIndexedQueue* queue_on_indexed) {
|
|||||||
void IndexMain(
|
void IndexMain(
|
||||||
IndexerConfig* config,
|
IndexerConfig* config,
|
||||||
FileConsumer::SharedState* file_consumer_shared,
|
FileConsumer::SharedState* file_consumer_shared,
|
||||||
|
Project* project,
|
||||||
Index_DoIndexQueue* queue_do_index,
|
Index_DoIndexQueue* queue_do_index,
|
||||||
Index_DoIdMapQueue* queue_do_id_map,
|
Index_DoIdMapQueue* queue_do_id_map,
|
||||||
Index_OnIdMappedQueue* queue_on_id_mapped,
|
Index_OnIdMappedQueue* queue_on_id_mapped,
|
||||||
@ -990,7 +1005,7 @@ void IndexMain(
|
|||||||
// IndexMain_DoCreateIndexUpdate so we don't starve querydb from doing any
|
// IndexMain_DoCreateIndexUpdate so we don't starve querydb from doing any
|
||||||
// work. Running both also lets the user query the partially constructed
|
// work. Running both also lets the user query the partially constructed
|
||||||
// index.
|
// index.
|
||||||
bool did_index = IndexMain_DoIndex(config, file_consumer_shared, queue_do_index, queue_do_id_map);
|
bool did_index = IndexMain_DoIndex(config, file_consumer_shared, project, queue_do_index, queue_do_id_map);
|
||||||
bool did_create_update = IndexMain_DoCreateIndexUpdate(queue_on_id_mapped, queue_on_indexed);
|
bool did_create_update = IndexMain_DoCreateIndexUpdate(queue_on_id_mapped, queue_on_indexed);
|
||||||
if (!did_index && !did_create_update) {
|
if (!did_index && !did_create_update) {
|
||||||
|
|
||||||
@ -1632,7 +1647,7 @@ void QueryDbMain(IndexerConfig* config) {
|
|||||||
std::cerr << "[querydb] Starting " << config->indexerCount << " indexers" << std::endl;
|
std::cerr << "[querydb] Starting " << config->indexerCount << " indexers" << std::endl;
|
||||||
for (int i = 0; i < config->indexerCount; ++i) {
|
for (int i = 0; i < config->indexerCount; ++i) {
|
||||||
new std::thread([&]() {
|
new std::thread([&]() {
|
||||||
IndexMain(config, &file_consumer_shared, &queue_do_index, &queue_do_id_map, &queue_on_id_mapped, &queue_on_indexed);
|
IndexMain(config, &file_consumer_shared, &project, &queue_do_index, &queue_do_id_map, &queue_on_id_mapped, &queue_on_indexed);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,13 +243,35 @@ std::vector<Project::Entry> LoadCompilationEntriesFromDirectory(const std::strin
|
|||||||
|
|
||||||
void Project::Load(const std::string& directory) {
|
void Project::Load(const std::string& directory) {
|
||||||
entries = LoadCompilationEntriesFromDirectory(directory);
|
entries = LoadCompilationEntriesFromDirectory(directory);
|
||||||
|
|
||||||
|
absolute_path_to_entry_index_.resize(entries.size());
|
||||||
|
for (int i = 0; i < entries.size(); ++i)
|
||||||
|
absolute_path_to_entry_index_[entries[i].filename] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<Project::Entry> Project::FindCompilationEntryForFile(const std::string& filename) {
|
optional<Project::Entry> Project::FindCompilationEntryForFile(const std::string& filename) {
|
||||||
for (auto& entry : entries) {
|
std::lock_guard<std::mutex> lock(entries_modification_mutex_);
|
||||||
if (filename == entry.filename)
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
auto it = absolute_path_to_entry_index_.find(filename);
|
||||||
|
if (it != absolute_path_to_entry_index_.end())
|
||||||
|
return entries[it->second];
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Project::UpdateModificationTime(const std::string& filename, uint64_t modification_time) {
|
||||||
|
// TODO: There might be a lot of thread contention here.
|
||||||
|
std::lock_guard<std::mutex> lock(entries_modification_mutex_);
|
||||||
|
|
||||||
|
auto it = absolute_path_to_entry_index_.find(filename);
|
||||||
|
if (it != absolute_path_to_entry_index_.end()) {
|
||||||
|
entries[it->second].last_modification_time = modification_time;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Project::Entry entry;
|
||||||
|
entry.filename = filename;
|
||||||
|
entry.last_modification_time = modification_time;
|
||||||
|
|
||||||
|
absolute_path_to_entry_index_[filename] = entries.size();
|
||||||
|
entries.push_back(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <optional.h>
|
#include <optional.h>
|
||||||
|
#include <sparsepp/spp.h>
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -11,10 +14,12 @@ struct Project {
|
|||||||
struct Entry {
|
struct Entry {
|
||||||
std::string filename;
|
std::string filename;
|
||||||
std::vector<std::string> args;
|
std::vector<std::string> args;
|
||||||
// optional<uint64_t> last_modification_time;
|
optional<uint64_t> last_modification_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Entry> entries;
|
std::vector<Entry> entries;
|
||||||
|
spp::sparse_hash_map<std::string, int> absolute_path_to_entry_index_;
|
||||||
|
std::mutex entries_modification_mutex_;
|
||||||
|
|
||||||
// Loads a project for the given |directory|.
|
// Loads a project for the given |directory|.
|
||||||
//
|
//
|
||||||
@ -26,5 +31,8 @@ struct Project {
|
|||||||
|
|
||||||
// Lookup the CompilationEntry for |filename|.
|
// Lookup the CompilationEntry for |filename|.
|
||||||
optional<Entry> FindCompilationEntryForFile(const std::string& filename);
|
optional<Entry> FindCompilationEntryForFile(const std::string& filename);
|
||||||
|
|
||||||
|
// Update the modification time for the given filename. This is thread-safe.
|
||||||
|
void UpdateModificationTime(const std::string& filename, uint64_t modification_time);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,6 +14,13 @@
|
|||||||
template <class T>
|
template <class T>
|
||||||
class ThreadedQueue {
|
class ThreadedQueue {
|
||||||
public:
|
public:
|
||||||
|
// Add an element to the front of the queue.
|
||||||
|
void PriorityEnqueue(T&& t) {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
priority_.push(std::move(t));
|
||||||
|
cv_.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
// 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_);
|
||||||
@ -26,7 +33,11 @@ public:
|
|||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
|
||||||
std::vector<T> result;
|
std::vector<T> result;
|
||||||
result.reserve(queue_.size());
|
result.reserve(priority_.size() + queue_.size());
|
||||||
|
while (!priority_.empty()) {
|
||||||
|
result.emplace_back(std::move(priority_.front()));
|
||||||
|
priority_.pop();
|
||||||
|
}
|
||||||
while (!queue_.empty()) {
|
while (!queue_.empty()) {
|
||||||
result.emplace_back(std::move(queue_.front()));
|
result.emplace_back(std::move(queue_.front()));
|
||||||
queue_.pop();
|
queue_.pop();
|
||||||
@ -38,11 +49,17 @@ public:
|
|||||||
// If the queue is empty, wait untill an element is avaiable.
|
// If the queue is empty, wait untill an element is avaiable.
|
||||||
T Dequeue() {
|
T Dequeue() {
|
||||||
std::unique_lock<std::mutex> lock(mutex_);
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
while (queue_.empty()) {
|
while (priority_.empty() && queue_.empty()) {
|
||||||
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!priority_.empty()) {
|
||||||
|
auto val = std::move(priority_.front());
|
||||||
|
priority_.pop();
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
auto val = std::move(queue_.front());
|
auto val = std::move(queue_.front());
|
||||||
queue_.pop();
|
queue_.pop();
|
||||||
return val;
|
return val;
|
||||||
@ -52,15 +69,22 @@ public:
|
|||||||
// value if the queue is empty.
|
// value if the queue is empty.
|
||||||
optional<T> TryDequeue() {
|
optional<T> TryDequeue() {
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
if (queue_.empty())
|
if (priority_.empty() && queue_.empty())
|
||||||
return nullopt;
|
return nullopt;
|
||||||
|
|
||||||
|
if (!priority_.empty()) {
|
||||||
|
auto val = std::move(priority_.front());
|
||||||
|
priority_.pop();
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
auto val = std::move(queue_.front());
|
auto val = std::move(queue_.front());
|
||||||
queue_.pop();
|
queue_.pop();
|
||||||
return std::move(val);
|
return std::move(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::queue<T> priority_;
|
||||||
std::queue<T> queue_;
|
std::queue<T> queue_;
|
||||||
mutable std::mutex mutex_;
|
mutable std::mutex mutex_;
|
||||||
std::condition_variable cv_;
|
std::condition_variable cv_;
|
||||||
|
Loading…
Reference in New Issue
Block a user