Simplify completion session management code.

This commit is contained in:
Jacob Dufault 2017-10-23 00:28:21 -07:00
parent 3e9cffcc62
commit 76cc110cc2
2 changed files with 74 additions and 86 deletions

View File

@ -336,8 +336,9 @@ void CompletionParseMain(ClangCompleteManager* completion_manager) {
// If we don't get a session then that means we don't care about the file // If we don't get a session then that means we don't care about the file
// anymore - abandon the request. // anymore - abandon the request.
std::shared_ptr<CompletionSession> session = std::shared_ptr<CompletionSession> session =
completion_manager->TryGetEditSession(request.path, completion_manager->TryGetSession(request.path,
false /*create_if_needed*/); false /*mark_as_completion*/,
false /*create_if_needed*/);
if (!session) if (!session)
continue; continue;
@ -369,7 +370,8 @@ void CompletionQueryMain(ClangCompleteManager* completion_manager) {
std::string path = request->document.uri.GetPath(); std::string path = request->document.uri.GetPath();
std::shared_ptr<CompletionSession> session = std::shared_ptr<CompletionSession> session =
completion_manager->TryGetEditSession(path, true /*create_if_needed*/); completion_manager->TryGetSession(path, true /*mark_as_completion*/,
true /*create_if_needed*/);
std::lock_guard<std::mutex> lock(session->tu_lock); std::lock_guard<std::mutex> lock(session->tu_lock);
Timer timer; Timer timer;
@ -548,8 +550,8 @@ ClangCompleteManager::ClangCompleteManager(Config* config,
working_files_(working_files), working_files_(working_files),
on_diagnostic_(on_diagnostic), on_diagnostic_(on_diagnostic),
on_index_(on_index), on_index_(on_index),
view_sessions_(kMaxViewSessions), preloaded_sessions_(kMaxPreloadedSessions),
edit_sessions_(kMaxEditSessions) { completion_sessions_(kMaxCompletionSessions) {
new std::thread([&]() { new std::thread([&]() {
SetCurrentThreadName("completequery"); SetCurrentThreadName("completequery");
CompletionQueryMain(this); CompletionQueryMain(this);
@ -600,44 +602,19 @@ void ClangCompleteManager::NotifyView(const std::string& filename) {
// parsed soon. // parsed soon.
// //
std::lock_guard<std::mutex> lock(sessions_lock_); // Only reparse the file if we create a new CompletionSession.
if (EnsureCompletionOrCreatePreloadSession(filename))
// Already a view or edit session, do nothing. parse_requests_.PriorityEnqueue(ParseRequest(filename));
if (view_sessions_.TryGetEntry(filename) ||
edit_sessions_.TryGetEntry(filename)) {
return;
}
// Create new view session.
view_sessions_.InsertEntry(std::make_shared<CompletionSession>(
project_->FindCompilationEntryForFile(filename), working_files_));
parse_requests_.Enqueue(ParseRequest(filename));
} }
void ClangCompleteManager::NotifyEdit(const std::string& filename) { void ClangCompleteManager::NotifyEdit(const std::string& filename) {
// //
// On edit, we reparse only if the file has not been parsed. The existence of // We treat an edit like a view, because the completion logic will handle
// a CompletionSession instance implies the file is already parsed or will be // moving the CompletionSession instance from preloaded to completion
// parsed soon. // storage.
// //
std::lock_guard<std::mutex> lock(sessions_lock_); NotifyView(filename);
if (edit_sessions_.TryGetEntry(filename))
return;
// Move the session from view to edit.
std::shared_ptr<CompletionSession> view_session =
view_sessions_.TryTakeEntry(filename);
if (view_session) {
edit_sessions_.InsertEntry(view_session);
return;
}
// No view session, create a new session.
edit_sessions_.InsertEntry(std::make_shared<CompletionSession>(
project_->FindCompilationEntryForFile(filename), working_files_));
parse_requests_.PriorityEnqueue(ParseRequest(filename));
} }
void ClangCompleteManager::NotifySave(const std::string& filename) { void ClangCompleteManager::NotifySave(const std::string& filename) {
@ -645,22 +622,7 @@ void ClangCompleteManager::NotifySave(const std::string& filename) {
// On save, always reparse. // On save, always reparse.
// //
std::lock_guard<std::mutex> lock(sessions_lock_); EnsureCompletionOrCreatePreloadSession(filename);
// If for whatever reason we have a view session and not an edit session,
// move the session from view to edit.
std::shared_ptr<CompletionSession> view_session =
view_sessions_.TryTakeEntry(filename);
if (view_session) {
edit_sessions_.InsertEntry(view_session);
}
// If no edit session create one.
if (!edit_sessions_.TryGetEntry(filename)) {
edit_sessions_.InsertEntry(std::make_shared<CompletionSession>(
project_->FindCompilationEntryForFile(filename), working_files_));
}
parse_requests_.PriorityEnqueue(ParseRequest(filename)); parse_requests_.PriorityEnqueue(ParseRequest(filename));
} }
@ -673,39 +635,60 @@ void ClangCompleteManager::NotifyClose(const std::string& filename) {
// Take and drop. It's okay if we don't actually drop the file, it'll // Take and drop. It's okay if we don't actually drop the file, it'll
// eventually get pushed out of the caches as the user opens other files. // eventually get pushed out of the caches as the user opens other files.
auto view_ptr = view_sessions_.TryTakeEntry(filename); auto preloaded_ptr = preloaded_sessions_.TryTakeEntry(filename);
LOG_IF_S(INFO, !!view_ptr) LOG_IF_S(INFO, !!preloaded_ptr)
<< "Dropped view-based code completion session for " << filename; << "Dropped preloaded-based code completion session for " << filename;
auto edit_ptr = edit_sessions_.TryTakeEntry(filename); auto completion_ptr = completion_sessions_.TryTakeEntry(filename);
LOG_IF_S(INFO, !!edit_ptr) LOG_IF_S(INFO, !!completion_ptr)
<< "Dropped edit-based code completion session for " << filename; << "Dropped completion-based code completion session for " << filename;
// We should never have both a view and edit session. // We should never have both a preloaded and completion session.
assert((view_ptr && edit_ptr) == false); assert((preloaded_ptr && completion_ptr) == false);
} }
std::shared_ptr<CompletionSession> ClangCompleteManager::TryGetEditSession( bool ClangCompleteManager::EnsureCompletionOrCreatePreloadSession(
const std::string& filename) {
std::lock_guard<std::mutex> lock(sessions_lock_);
if (!preloaded_sessions_.TryGetEntry(filename) &&
!completion_sessions_.TryGetEntry(filename)) {
auto session = std::make_shared<CompletionSession>(
project_->FindCompilationEntryForFile(filename), working_files_);
preloaded_sessions_.InsertEntry(session);
return true;
}
return false;
}
std::shared_ptr<CompletionSession> ClangCompleteManager::TryGetSession(
const std::string& filename, const std::string& filename,
bool mark_as_completion,
bool create_if_needed) { bool create_if_needed) {
std::lock_guard<std::mutex> lock(sessions_lock_); std::lock_guard<std::mutex> lock(sessions_lock_);
// Try to find a view session. If found move it to |edit_sessions_|. // Try to find a preloaded session.
std::shared_ptr<CompletionSession> view_session = std::shared_ptr<CompletionSession> preloaded_session =
view_sessions_.TryTakeEntry(filename); preloaded_sessions_.TryGetEntry(filename);
if (view_session) {
assert(!edit_sessions_.TryGetEntry(filename)); if (preloaded_session) {
edit_sessions_.InsertEntry(view_session); // If this request is for a completion, we should move it to
return view_session; // |completion_sessions|.
if (mark_as_completion) {
assert(!completion_sessions_.TryGetEntry(filename));
preloaded_sessions_.TryTakeEntry(filename);
completion_sessions_.InsertEntry(preloaded_session);
}
return preloaded_session;
} }
// Try to find an edit session. If none create if requested. // Try to find a completion session. If none create one.
std::shared_ptr<CompletionSession> edit_session = std::shared_ptr<CompletionSession> completion_session =
edit_sessions_.TryTakeEntry(filename); completion_sessions_.TryTakeEntry(filename);
if (!edit_session && create_if_needed) { if (!completion_session && create_if_needed) {
edit_session = std::make_shared<CompletionSession>( completion_session = std::make_shared<CompletionSession>(
project_->FindCompilationEntryForFile(filename), working_files_); project_->FindCompilationEntryForFile(filename), working_files_);
edit_sessions_.InsertEntry(edit_session); completion_sessions_.InsertEntry(completion_session);
} }
return edit_session; return completion_session;
} }

View File

@ -99,15 +99,18 @@ struct ClangCompleteManager {
// completion session will be dropped. // completion session will be dropped.
void NotifyClose(const std::string& filename); void NotifyClose(const std::string& filename);
// Ensures there is a completion or preloaded session. Returns true if a new
// session was created.
bool EnsureCompletionOrCreatePreloadSession(const std::string& filename);
// Tries to find an edit session for |filename|. This will move the session // Tries to find an edit session for |filename|. This will move the session
// from view to edit. // from view to edit.
std::shared_ptr<CompletionSession> TryGetEditSession( std::shared_ptr<CompletionSession> TryGetSession(const std::string& filename,
const std::string& filename, bool mark_as_completion,
bool create_if_needed); bool create_if_needed);
// TODO: make these configurable. // TODO: make these configurable.
const int kMaxViewSessions = 10; const int kMaxPreloadedSessions = 10;
const int kMaxEditSessions = 5; const int kMaxCompletionSessions = 5;
// Global state. // Global state.
Config* config_; Config* config_;
@ -116,11 +119,13 @@ struct ClangCompleteManager {
OnDiagnostic on_diagnostic_; OnDiagnostic on_diagnostic_;
OnIndex on_index_; OnIndex on_index_;
// Sessions which have never had a real text-edit applied, but are preloaded // CompletionSession instances which are preloaded, ie, files which the user
// to give a fast initial experience. // has viewed but not requested code completion for.
LruSessionCache view_sessions_; LruSessionCache preloaded_sessions_;
// Completion sessions which have been edited. // CompletionSession instances which the user has actually performed
LruSessionCache edit_sessions_; // completion on. This is more rare so these instances tend to stay alive
// much longer than the ones in |preloaded_sessions_|.
LruSessionCache completion_sessions_;
// Mutex which protects |view_sessions_| and |edit_sessions_|. // Mutex which protects |view_sessions_| and |edit_sessions_|.
std::mutex sessions_lock_; std::mutex sessions_lock_;