Skip to content

Commit

Permalink
Delay requests if the document has not not indexed (MaskRay#176)
Browse files Browse the repository at this point in the history
This fixes a plethora of "not indexed" errors when the document has not been indexed.

* Message handler throws NotIndexed if not overdue
* The message is put into backlog and tagged with backlog_path
* path2backlog[path] tracks backlog associated with document `path`
* The backlog is cleared when the index is merged
* backlog[0] is forced to run if it becomes overdue
  • Loading branch information
MaskRay committed Nov 10, 2019
1 parent dd74d03 commit 8835a55
Show file tree
Hide file tree
Showing 22 changed files with 142 additions and 105 deletions.
10 changes: 9 additions & 1 deletion src/config.hh
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,12 @@ struct Config {
std::vector<std::string> whitelist;
} index;

struct Request {
// If the document of a request has not been indexed, wait up to this many
// milleseconds before reporting error.
int64_t timeout = 5000;
} request;

struct Session {
int maxNum = 10;
} session;
Expand Down Expand Up @@ -266,12 +272,14 @@ REFLECT_STRUCT(Config::Index, blacklist, comments, initialBlacklist,
initialWhitelist, multiVersion, multiVersionBlacklist,
multiVersionWhitelist, onChange, threads, trackDependency,
whitelist);
REFLECT_STRUCT(Config::Request, timeout);
REFLECT_STRUCT(Config::Session, maxNum);
REFLECT_STRUCT(Config::WorkspaceSymbol, caseSensitivity, maxNum, sort);
REFLECT_STRUCT(Config::Xref, maxNum);
REFLECT_STRUCT(Config, compilationDatabaseCommand, compilationDatabaseDirectory,
cacheDirectory, cacheFormat, clang, client, codeLens, completion,
diagnostics, highlight, index, session, workspaceSymbol, xref);
diagnostics, highlight, index, request, session, workspaceSymbol,
xref);

extern Config *g_config;

Expand Down
4 changes: 3 additions & 1 deletion src/lsp.hh
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

#include <rapidjson/fwd.h>

#include <chrono>
#include <iosfwd>
#include <unordered_map>

namespace ccls {
struct RequestId {
Expand All @@ -31,6 +31,8 @@ struct InMessage {
std::string method;
std::unique_ptr<char[]> message;
std::unique_ptr<rapidjson::Document> document;
std::chrono::steady_clock::time_point deadline;
std::string backlog_path;
};

enum class ErrorCode {
Expand Down
38 changes: 27 additions & 11 deletions src/message_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,8 @@ struct ScanLineEvent {
};
} // namespace

void ReplyOnce::NotReady(bool file) {
if (file)
Error(ErrorCode::InvalidRequest, "not opened");
else
Error(ErrorCode::InternalError, "not indexed");
void ReplyOnce::NotOpened(std::string_view path) {
Error(ErrorCode::InvalidRequest, std::string(path) + " is not opened");
}

void ReplyOnce::ReplyLocationLink(std::vector<LocationLink> &result) {
Expand Down Expand Up @@ -203,13 +200,11 @@ MessageHandler::MessageHandler() {

void MessageHandler::Run(InMessage &msg) {
rapidjson::Document &doc = *msg.document;
rapidjson::Value param;
rapidjson::Value null;
auto it = doc.FindMember("params");
if (it != doc.MemberEnd())
param = it->value;
JsonReader reader(&param);
JsonReader reader(it != doc.MemberEnd() ? &it->value : &null);
if (msg.id.Valid()) {
ReplyOnce reply{msg.id};
ReplyOnce reply{*this, msg.id};
auto it = method2request.find(msg.method);
if (it != method2request.end()) {
try {
Expand All @@ -218,6 +213,8 @@ void MessageHandler::Run(InMessage &msg) {
reply.Error(ErrorCode::InvalidParams,
"invalid params of " + msg.method + ": expected " +
ex.what() + " for " + reader.GetPath());
} catch (NotIndexed &) {
throw;
} catch (...) {
reply.Error(ErrorCode::InternalError, "failed to process " + msg.method);
}
Expand All @@ -237,7 +234,8 @@ void MessageHandler::Run(InMessage &msg) {
}
}

QueryFile *MessageHandler::FindFile(const std::string &path, int *out_file_id) {
QueryFile *MessageHandler::FindFile(const std::string &path,
int *out_file_id) {
QueryFile *ret = nullptr;
auto it = db->name2file_id.find(LowerPathIfInsensitive(path));
if (it != db->name2file_id.end()) {
Expand All @@ -254,6 +252,24 @@ QueryFile *MessageHandler::FindFile(const std::string &path, int *out_file_id) {
return ret;
}

std::pair<QueryFile *, WorkingFile *>
MessageHandler::FindOrFail(const std::string &path, ReplyOnce &reply,
int *out_file_id) {
WorkingFile *wf = wfiles->GetFile(path);
if (!wf) {
reply.NotOpened(path);
return {nullptr, nullptr};
}
QueryFile *file = FindFile(path, out_file_id);
if (!file) {
if (!overdue)
throw NotIndexed{path};
reply.Error(ErrorCode::InvalidRequest, "not indexed");
return {nullptr, nullptr};
}
return {file, wf};
}

void EmitSkippedRanges(WorkingFile *wfile, QueryFile &file) {
CclsSetSkippedRanges params;
params.uri = DocumentUri::FromPath(wfile->filename);
Expand Down
12 changes: 11 additions & 1 deletion src/message_handler.hh
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,13 @@ REFLECT_STRUCT(Diagnostic, range, severity, code, source, message);
REFLECT_STRUCT(ShowMessageParam, type, message);
REFLECT_UNDERLYING_B(LanguageId);

struct NotIndexed {
std::string path;
};
struct MessageHandler;

struct ReplyOnce {
MessageHandler &handler;
RequestId id;
template <typename Res> void operator()(Res &&result) const {
if (id.Valid())
Expand All @@ -198,7 +204,7 @@ struct ReplyOnce {
if (id.Valid())
pipeline::ReplyError(id, [&](JsonWriter &w) { Reflect(w, err); });
}
void NotReady(bool file);
void NotOpened(std::string_view path);
void ReplyLocationLink(std::vector<LocationLink> &result);
};

Expand All @@ -213,10 +219,14 @@ struct MessageHandler {
llvm::StringMap<std::function<void(JsonReader &)>> method2notification;
llvm::StringMap<std::function<void(JsonReader &, ReplyOnce &)>>
method2request;
bool overdue = false;

MessageHandler();
void Run(InMessage &msg);
QueryFile *FindFile(const std::string &path, int *out_file_id = nullptr);
std::pair<QueryFile *, WorkingFile *> FindOrFail(const std::string &path,
ReplyOnce &reply,
int *out_file_id = nullptr);

private:
void Bind(const char *method, void (MessageHandler::*handler)(JsonReader &));
Expand Down
3 changes: 1 addition & 2 deletions src/messages/ccls_call.cc
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,7 @@ void MessageHandler::ccls_call(JsonReader &reader, ReplyOnce &reply) {
Expand(this, &*result, param.callee, param.callType, param.qualified,
param.levels);
} else {
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
if (!wf)
return;
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position)) {
Expand Down
6 changes: 3 additions & 3 deletions src/messages/ccls_inheritance.cc
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,10 @@ void Inheritance(MessageHandler *m, Param &param, ReplyOnce &reply) {
Expand(m, &*result, param.derived, param.qualified, param.levels)))
result.reset();
} else {
QueryFile *file = m->FindFile(param.textDocument.uri.GetPath());
if (!file)
auto [file, wf] = m->FindOrFail(param.textDocument.uri.GetPath(), reply);
if (!wf) {
return;
WorkingFile *wf = m->wfiles->GetFile(file->def->path);
}
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position))
if (sym.kind == Kind::Func || sym.kind == Kind::Type) {
result = BuildInitial(m, sym, param.derived, param.qualified,
Expand Down
7 changes: 2 additions & 5 deletions src/messages/ccls_member.cc
Original file line number Diff line number Diff line change
Expand Up @@ -269,12 +269,9 @@ void MessageHandler::ccls_member(JsonReader &reader, ReplyOnce &reply) {
param.levels, param.kind)))
result.reset();
} else {
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
if (!wf) {
reply.NotReady(file);
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
if (!wf)
return;
}
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position)) {
switch (sym.kind) {
case Kind::Func:
Expand Down
4 changes: 1 addition & 3 deletions src/messages/ccls_navigate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,8 @@ Maybe<Range> FindParent(QueryFile *file, Pos pos) {
void MessageHandler::ccls_navigate(JsonReader &reader, ReplyOnce &reply) {
Param param;
Reflect(reader, param);
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
if (!wf) {
reply.NotReady(file);
return;
}
Position ls_pos = param.position;
Expand Down
4 changes: 1 addition & 3 deletions src/messages/ccls_vars.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,8 @@ REFLECT_STRUCT(Param, textDocument, position, kind);
void MessageHandler::ccls_vars(JsonReader &reader, ReplyOnce &reply) {
Param param;
Reflect(reader, param);
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
if (!wf) {
reply.NotReady(file);
return;
}

Expand Down
2 changes: 1 addition & 1 deletion src/messages/initialize.cc
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ void MessageHandler::initialize(JsonReader &reader, ReplyOnce &reply) {
void StandaloneInitialize(MessageHandler &handler, const std::string &root) {
InitializeParam param;
param.rootUri = DocumentUri::FromPath(root);
ReplyOnce reply;
ReplyOnce reply{handler};
Initialize(&handler, param, reply);
}

Expand Down
17 changes: 6 additions & 11 deletions src/messages/textDocument_code.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,9 @@ REFLECT_STRUCT(CodeAction, title, kind, edit);
}
void MessageHandler::textDocument_codeAction(CodeActionParam &param,
ReplyOnce &reply) {
WorkingFile *wf = wfiles->GetFile(param.textDocument.uri.GetPath());
if (!wf) {
reply.NotReady(true);
WorkingFile *wf = FindOrFail(param.textDocument.uri.GetPath(), reply).second;
if (!wf)
return;
}
std::vector<CodeAction> result;
std::vector<Diagnostic> diagnostics;
wfiles->WithLock([&]() { diagnostics = wf->diagnostics; });
Expand Down Expand Up @@ -84,16 +82,13 @@ struct CommonCodeLensParams {

void MessageHandler::textDocument_codeLens(TextDocumentParam &param,
ReplyOnce &reply) {
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
if (!wf) {
reply.NotReady(file);
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
if (!wf)
return;
}

std::vector<CodeLens> result;
auto Add = [&](const char *singular, Cmd_xref show, Range range, int num,
bool force_display = false) {
auto Add = [&, wf = wf](const char *singular, Cmd_xref show, Range range,
int num, bool force_display = false) {
if (!num && !force_display)
return;
std::optional<lsRange> ls_range = GetLsRange(wf, range);
Expand Down
2 changes: 1 addition & 1 deletion src/messages/textDocument_completion.cc
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ void MessageHandler::textDocument_completion(CompletionParam &param,
std::string path = param.textDocument.uri.GetPath();
WorkingFile *wf = wfiles->GetFile(path);
if (!wf) {
reply.NotReady(true);
reply.NotOpened(path);
return;
}

Expand Down
21 changes: 6 additions & 15 deletions src/messages/textDocument_definition.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,9 @@ std::vector<DeclRef> GetNonDefDeclarationTargets(DB *db, SymbolRef sym) {
void MessageHandler::textDocument_declaration(TextDocumentPositionParam &param,
ReplyOnce &reply) {
int file_id;
QueryFile *file = FindFile(param.textDocument.uri.GetPath(), &file_id);
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
if (!wf) {
reply.NotReady(file);
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply, &file_id);
if (!wf)
return;
}

std::vector<LocationLink> result;
Position &ls_pos = param.position;
Expand All @@ -57,12 +54,9 @@ void MessageHandler::textDocument_declaration(TextDocumentPositionParam &param,
void MessageHandler::textDocument_definition(TextDocumentPositionParam &param,
ReplyOnce &reply) {
int file_id;
QueryFile *file = FindFile(param.textDocument.uri.GetPath(), &file_id);
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
if (!wf) {
reply.NotReady(file);
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply, &file_id);
if (!wf)
return;
}

std::vector<LocationLink> result;
Maybe<DeclRef> on_def;
Expand Down Expand Up @@ -178,12 +172,9 @@ void MessageHandler::textDocument_definition(TextDocumentPositionParam &param,

void MessageHandler::textDocument_typeDefinition(
TextDocumentPositionParam &param, ReplyOnce &reply) {
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
if (!file) {
reply.NotReady(file);
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
if (!file)
return;
}

std::vector<LocationLink> result;
auto Add = [&](const QueryType &type) {
Expand Down
15 changes: 4 additions & 11 deletions src/messages/textDocument_document.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,9 @@ REFLECT_STRUCT(DocumentHighlight, range, kind, role);
void MessageHandler::textDocument_documentHighlight(
TextDocumentPositionParam &param, ReplyOnce &reply) {
int file_id;
QueryFile *file = FindFile(param.textDocument.uri.GetPath(), &file_id);
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
if (!wf) {
reply.NotReady(file);
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply, &file_id);
if (!wf)
return;
}

std::vector<DocumentHighlight> result;
std::vector<SymbolRef> syms =
Expand Down Expand Up @@ -78,10 +75,8 @@ REFLECT_STRUCT(DocumentLink, range, target);

void MessageHandler::textDocument_documentLink(TextDocumentParam &param,
ReplyOnce &reply) {
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
if (!wf) {
reply.NotReady(file);
return;
}

Expand Down Expand Up @@ -153,10 +148,8 @@ void MessageHandler::textDocument_documentSymbol(JsonReader &reader,
Reflect(reader, param);

int file_id;
QueryFile *file = FindFile(param.textDocument.uri.GetPath(), &file_id);
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply, &file_id);
if (!wf) {
reply.NotReady(file);
return;
}

Expand Down
7 changes: 2 additions & 5 deletions src/messages/textDocument_foldingRange.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,9 @@ REFLECT_STRUCT(FoldingRange, startLine, startCharacter, endLine, endCharacter,

void MessageHandler::textDocument_foldingRange(TextDocumentParam &param,
ReplyOnce &reply) {
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
if (!wf) {
reply.NotReady(file);
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
if (!wf)
return;
}
std::vector<FoldingRange> result;
std::optional<lsRange> ls_range;

Expand Down
Loading

0 comments on commit 8835a55

Please sign in to comment.