mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-04 06:15:20 +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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct IndexTranslationUnitRequest {
 | 
			
		||||
struct Index_DoIndex {
 | 
			
		||||
  enum class Type {
 | 
			
		||||
    Import,
 | 
			
		||||
    Update
 | 
			
		||||
@ -40,18 +40,37 @@ struct IndexTranslationUnitRequest {
 | 
			
		||||
  std::vector<std::string> args;
 | 
			
		||||
  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;
 | 
			
		||||
  explicit IndexTranslationUnitResponse(IndexUpdate& update) : update(update) {}
 | 
			
		||||
  explicit Index_OnIndexed(IndexUpdate& update) : update(update) {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// TODO: Rename TypedBidiMessageQueue to IpcTransport?
 | 
			
		||||
using IpcMessageQueue = TypedBidiMessageQueue<IpcId, BaseIpcMessage>;
 | 
			
		||||
using IndexRequestQueue = ThreadedQueue<IndexTranslationUnitRequest>;
 | 
			
		||||
using IndexResponseQueue = ThreadedQueue<IndexTranslationUnitResponse>;
 | 
			
		||||
using Index_DoIndexQueue = ThreadedQueue<std::unique_ptr<Index_DoIndex>>;
 | 
			
		||||
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>
 | 
			
		||||
void SendMessage(IpcMessageQueue& t, MessageQueue* destination, TMessage& message) {
 | 
			
		||||
@ -222,22 +241,26 @@ std::string GetCachedFileName(std::string source_file) {
 | 
			
		||||
  return kCacheDirectory + source_file + ".json";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
optional<IndexedFile> LoadCachedFile(std::string filename) {
 | 
			
		||||
std::unique_ptr<IndexedFile> LoadCachedFile(std::string filename) {
 | 
			
		||||
  // TODO FIXME FIXME FIXME
 | 
			
		||||
  return nullopt;
 | 
			
		||||
  return nullptr;
 | 
			
		||||
 | 
			
		||||
  std::string cache_file = GetCachedFileName(filename);
 | 
			
		||||
 | 
			
		||||
  std::ifstream cache;
 | 
			
		||||
  cache.open(GetCachedFileName(filename));
 | 
			
		||||
  if (!cache.good())
 | 
			
		||||
    return nullopt;
 | 
			
		||||
    return nullptr;
 | 
			
		||||
 | 
			
		||||
  std::string file_content = std::string(
 | 
			
		||||
    std::istreambuf_iterator<char>(cache),
 | 
			
		||||
    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) {
 | 
			
		||||
@ -250,111 +273,85 @@ void WriteToCache(std::string filename, IndexedFile& file) {
 | 
			
		||||
  cache.close();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void IndexMain(IndexRequestQueue* requests, IndexResponseQueue* responses) {
 | 
			
		||||
  while (true) {
 | 
			
		||||
    // Try to get a request. If there isn't one, sleep for a little while.
 | 
			
		||||
    optional<IndexTranslationUnitRequest> request = requests->TryDequeue();
 | 
			
		||||
    if (!request) {
 | 
			
		||||
      // TODO: use CV to wakeup?
 | 
			
		||||
      std::this_thread::sleep_for(std::chrono::milliseconds(500));
 | 
			
		||||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
bool IndexMain_DoIndex(Index_DoIndexQueue* queue_do_index,
 | 
			
		||||
                       Index_DoIdMapQueue* queue_do_id_map) {
 | 
			
		||||
  optional<std::unique_ptr<Index_DoIndex>> opt_index_request = queue_do_index->TryDequeue();
 | 
			
		||||
  if (!opt_index_request)
 | 
			
		||||
    return false;
 | 
			
		||||
  std::unique_ptr<Index_DoIndex> index_request = std::move(opt_index_request.value());
 | 
			
		||||
 | 
			
		||||
  Timer time;
 | 
			
		||||
 | 
			
		||||
  std::unique_ptr<IndexedFile> old_index = LoadCachedFile(index_request->path);
 | 
			
		||||
  time.ResetAndPrint("Loading cached index");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  // 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
 | 
			
		||||
  // update request to get the latest version.
 | 
			
		||||
    if (request->type == IndexTranslationUnitRequest::Type::Import) {
 | 
			
		||||
      request->type = IndexTranslationUnitRequest::Type::Update;
 | 
			
		||||
  if (old_index && index_request->type == Index_DoIndex::Type::Import) {
 | 
			
		||||
    auto response = MakeUnique<Index_DoIdMap>(nullptr /*previous*/, std::move(old_index) /*current*/);
 | 
			
		||||
    queue_do_id_map->Enqueue(std::move(response));
 | 
			
		||||
 | 
			
		||||
      // 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);
 | 
			
		||||
 | 
			
		||||
    // Parse request and send a response.
 | 
			
		||||
    std::cerr << "Parsing file " << request->path << " with args "
 | 
			
		||||
      << Join(request->args, ", ") << std::endl;
 | 
			
		||||
 | 
			
		||||
    IndexedFile new_index = Parse(request->path, request->args);
 | 
			
		||||
    time.ResetAndPrint("Parsing/indexing");
 | 
			
		||||
 | 
			
		||||
    // If we have a cached index, that means it is already imported, which
 | 
			
		||||
    // means we want to apply a delta update.
 | 
			
		||||
    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");
 | 
			
		||||
    index_request->type = Index_DoIndex::Type::Update;
 | 
			
		||||
    queue_do_index->Enqueue(std::move(index_request));
 | 
			
		||||
  }
 | 
			
		||||
  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
 | 
			
		||||
    // Parse request and send a response.
 | 
			
		||||
    std::cerr << "Parsing file " << index_request->path << " with args "
 | 
			
		||||
      << Join(index_request->args, ", ") << std::endl;
 | 
			
		||||
 | 
			
		||||
      // 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");
 | 
			
		||||
    }
 | 
			
		||||
    // 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);
 | 
			
		||||
 | 
			
		||||
    time.ResetAndPrint("Parsing/indexing");
 | 
			
		||||
 | 
			
		||||
    auto response = MakeUnique<Index_DoIdMap>(std::move(old_index) /*previous*/, MakeUnique<IndexedFile>(current_index) /*current*/);
 | 
			
		||||
    queue_do_id_map->Enqueue(std::move(response));
 | 
			
		||||
 | 
			
		||||
    // 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");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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) {
 | 
			
		||||
@ -457,8 +454,10 @@ void AddCodeLens(std::vector<TCodeLens>* result,
 | 
			
		||||
void QueryDbMainLoop(
 | 
			
		||||
  QueryableDatabase* db,
 | 
			
		||||
  IpcMessageQueue* language_client,
 | 
			
		||||
  IndexRequestQueue* index_requests,
 | 
			
		||||
  IndexResponseQueue* index_responses,
 | 
			
		||||
  Index_DoIndexQueue* queue_do_index,
 | 
			
		||||
  Index_DoIdMapQueue* queue_do_id_map,
 | 
			
		||||
  Index_OnIdMappedQueue* queue_on_id_mapped,
 | 
			
		||||
  Index_OnIndexedQueue* queue_on_indexed,
 | 
			
		||||
  Project* project,
 | 
			
		||||
  WorkingFiles* working_files,
 | 
			
		||||
  CompletionManager* completion_manager) {
 | 
			
		||||
@ -496,10 +495,10 @@ void QueryDbMainLoop(
 | 
			
		||||
          << "] Dispatching index request for file " << filepath
 | 
			
		||||
          << std::endl;
 | 
			
		||||
 | 
			
		||||
        IndexTranslationUnitRequest request(IndexTranslationUnitRequest::Type::Import);
 | 
			
		||||
        request.path = filepath;
 | 
			
		||||
        request.args = entry.args;
 | 
			
		||||
        index_requests->Enqueue(request);
 | 
			
		||||
        auto request = MakeUnique<Index_DoIndex>(Index_DoIndex::Type::Import);
 | 
			
		||||
        request->path = filepath;
 | 
			
		||||
        request->args = entry.args;
 | 
			
		||||
        queue_do_index->Enqueue(std::move(request));
 | 
			
		||||
      }
 | 
			
		||||
      std::cerr << "Done" << std::endl;
 | 
			
		||||
      break;
 | 
			
		||||
@ -711,7 +710,7 @@ void QueryDbMainLoop(
 | 
			
		||||
      std::string query = msg->params.query;
 | 
			
		||||
      for (int i = 0; i < db->qualified_names.size(); ++i) {
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -729,6 +728,8 @@ void QueryDbMainLoop(
 | 
			
		||||
          switch (symbol.kind) {
 | 
			
		||||
          case SymbolKind::File: {
 | 
			
		||||
            QueryableFile& def = db->files[symbol.idx];
 | 
			
		||||
            info.name = def.def.usr;
 | 
			
		||||
            info.kind = lsSymbolKind::File;
 | 
			
		||||
            info.location.uri.SetPath(def.def.usr);
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
@ -795,10 +796,32 @@ void QueryDbMainLoop(
 | 
			
		||||
 | 
			
		||||
  // TODO: consider rate-limiting and checking for IPC messages so we don't block
 | 
			
		||||
  // requests / we can serve partial requests.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  while (true) {
 | 
			
		||||
    optional<IndexTranslationUnitResponse> response = index_responses->TryDequeue();
 | 
			
		||||
    if (!response)
 | 
			
		||||
    optional<std::unique_ptr<Index_DoIdMap>> opt_request = queue_do_id_map->TryDequeue();
 | 
			
		||||
    if (!opt_request)
 | 
			
		||||
      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;
 | 
			
		||||
    db->ApplyIndexUpdate(&response->update);
 | 
			
		||||
@ -811,8 +834,11 @@ void QueryDbMain() {
 | 
			
		||||
 | 
			
		||||
  // Create queues.
 | 
			
		||||
  std::unique_ptr<IpcMessageQueue> ipc = BuildIpcMessageQueue(kIpcLanguageClientName, kQueueSizeBytes);
 | 
			
		||||
  IndexRequestQueue index_request_queue;
 | 
			
		||||
  IndexResponseQueue index_response_queue;
 | 
			
		||||
  Index_DoIndexQueue queue_do_index;
 | 
			
		||||
  Index_DoIdMapQueue queue_do_id_map;
 | 
			
		||||
  Index_OnIdMappedQueue queue_on_id_mapped;
 | 
			
		||||
  Index_OnIndexedQueue queue_on_indexed;
 | 
			
		||||
 | 
			
		||||
  Project project;
 | 
			
		||||
  WorkingFiles working_files;
 | 
			
		||||
  CompletionManager completion_manager(&project, &working_files);
 | 
			
		||||
@ -820,14 +846,14 @@ void QueryDbMain() {
 | 
			
		||||
  // Start indexer threads.
 | 
			
		||||
  for (int i = 0; i < kNumIndexers; ++i) {
 | 
			
		||||
    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.
 | 
			
		||||
  QueryableDatabase db;
 | 
			
		||||
  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));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										88
									
								
								src/query.cc
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								src/query.cc
									
									
									
									
									
								
							@ -452,8 +452,6 @@ int GetOrAddSymbol(QueryableDatabase* query_db, SymbolKind kind, const Usr& usr)
 | 
			
		||||
 | 
			
		||||
IdMap::IdMap(QueryableDatabase* query_db, const IdCache& local_ids)
 | 
			
		||||
  : local_ids(local_ids) {
 | 
			
		||||
  assert(query_db); // TODO: remove after testing.
 | 
			
		||||
 | 
			
		||||
  index_file_id = GetQueryFileIdFromUsr(query_db, local_ids.primary_file);
 | 
			
		||||
 | 
			
		||||
  cached_type_ids_.reserve(local_ids.type_id_to_usr.size());
 | 
			
		||||
@ -489,19 +487,16 @@ IdMap::IdMap(QueryableDatabase* query_db, const IdCache& local_ids)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// static
 | 
			
		||||
IndexUpdate IndexUpdate::CreateImport(const IdMap& id_map, IndexedFile& file) {
 | 
			
		||||
  // Return standard diff constructor but with an empty file so everything is
 | 
			
		||||
  // added.
 | 
			
		||||
  IndexedFile previous(file.path);
 | 
			
		||||
  return IndexUpdate(id_map, id_map, previous, file);
 | 
			
		||||
IndexUpdate IndexUpdate::CreateDelta(const IdMap* previous_id_map, const IdMap* current_id_map, IndexedFile* previous, IndexedFile* current) {
 | 
			
		||||
  if (!previous_id_map) {
 | 
			
		||||
    assert(!previous);
 | 
			
		||||
    IndexedFile previous(current->path);
 | 
			
		||||
    return IndexUpdate(*current_id_map, *current_id_map, previous, *current);
 | 
			
		||||
  }
 | 
			
		||||
  return IndexUpdate(*previous_id_map, *current_id_map, *previous, *current);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// static
 | 
			
		||||
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) {
 | 
			
		||||
IndexUpdate::IndexUpdate(const IdMap& previous_id_map, const IdMap& current_id_map, IndexedFile& previous_file, IndexedFile& current_file) {
 | 
			
		||||
  // |query_name| is the name of the variable on the query type.
 | 
			
		||||
  // |index_name| is the name of the variable on the index type.
 | 
			
		||||
  // |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) {
 | 
			
		||||
  for (auto& def : updates) {
 | 
			
		||||
    auto it = usr_to_symbol.find(def.usr);
 | 
			
		||||
    if (it == usr_to_symbol.end()) {
 | 
			
		||||
      qualified_names.push_back(def.usr);
 | 
			
		||||
      symbols.push_back(SymbolIdx(SymbolKind::File, files.size()));
 | 
			
		||||
      usr_to_symbol[def.usr] = SymbolIdx(SymbolKind::File, files.size());
 | 
			
		||||
      files.push_back(QueryableFile(def));
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
    assert(it != usr_to_symbol.end());
 | 
			
		||||
 | 
			
		||||
    QueryableFile& existing = files[it->second.idx];
 | 
			
		||||
    existing.def = def;
 | 
			
		||||
    }
 | 
			
		||||
    UpdateQualifiedName(this, &existing.qualified_name_idx, SymbolKind::File, it->second.idx, def.usr);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QueryableDatabase::ImportOrUpdate(const std::vector<QueryableTypeDef::DefUpdate>& updates) {
 | 
			
		||||
  for (auto& def : updates) {
 | 
			
		||||
    if (!def.definition_extent)
 | 
			
		||||
      continue;
 | 
			
		||||
 | 
			
		||||
    auto it = usr_to_symbol.find(def.usr);
 | 
			
		||||
    if (it == usr_to_symbol.end()) {
 | 
			
		||||
      qualified_names.push_back(def.qualified_name);
 | 
			
		||||
      symbols.push_back(SymbolIdx(SymbolKind::Type, types.size()));
 | 
			
		||||
      usr_to_symbol[def.usr] = SymbolIdx(SymbolKind::Type, types.size());
 | 
			
		||||
      types.push_back(QueryableTypeDef(def));
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
    assert(it != usr_to_symbol.end());
 | 
			
		||||
 | 
			
		||||
    QueryableTypeDef& existing = types[it->second.idx];
 | 
			
		||||
      if (def.definition_extent)
 | 
			
		||||
    existing.def = def;
 | 
			
		||||
    }
 | 
			
		||||
    UpdateQualifiedName(this, &existing.qualified_name_idx, SymbolKind::Type, it->second.idx, def.usr);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QueryableDatabase::ImportOrUpdate(const std::vector<QueryableFuncDef::DefUpdate>& updates) {
 | 
			
		||||
  for (auto& def : updates) {
 | 
			
		||||
    if (!def.definition_extent)
 | 
			
		||||
      continue;
 | 
			
		||||
 | 
			
		||||
    auto it = usr_to_symbol.find(def.usr);
 | 
			
		||||
    if (it == usr_to_symbol.end()) {
 | 
			
		||||
      qualified_names.push_back(def.qualified_name);
 | 
			
		||||
      symbols.push_back(SymbolIdx(SymbolKind::Func, funcs.size()));
 | 
			
		||||
      usr_to_symbol[def.usr] = SymbolIdx(SymbolKind::Func, funcs.size());
 | 
			
		||||
      funcs.push_back(QueryableFuncDef(def));
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
    assert(it != usr_to_symbol.end());
 | 
			
		||||
 | 
			
		||||
    QueryableFuncDef& existing = funcs[it->second.idx];
 | 
			
		||||
      if (def.definition_extent)
 | 
			
		||||
    existing.def = def;
 | 
			
		||||
    }
 | 
			
		||||
    UpdateQualifiedName(this, &existing.qualified_name_idx, SymbolKind::Func, it->second.idx, def.usr);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QueryableDatabase::ImportOrUpdate(const std::vector<QueryableVarDef::DefUpdate>& updates) {
 | 
			
		||||
  for (auto& def : updates) {
 | 
			
		||||
    if (!def.definition_extent)
 | 
			
		||||
      continue;
 | 
			
		||||
 | 
			
		||||
    auto it = usr_to_symbol.find(def.usr);
 | 
			
		||||
    if (it == usr_to_symbol.end()) {
 | 
			
		||||
      qualified_names.push_back(def.qualified_name);
 | 
			
		||||
      symbols.push_back(SymbolIdx(SymbolKind::Var, vars.size()));
 | 
			
		||||
      usr_to_symbol[def.usr] = SymbolIdx(SymbolKind::Var, vars.size());
 | 
			
		||||
      vars.push_back(QueryableVarDef(def));
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
    assert(it != usr_to_symbol.end());
 | 
			
		||||
 | 
			
		||||
    QueryableVarDef& existing = vars[it->second.idx];
 | 
			
		||||
      if (def.definition_extent)
 | 
			
		||||
    existing.def = def;
 | 
			
		||||
    }
 | 
			
		||||
    UpdateQualifiedName(this, &existing.qualified_name_idx, SymbolKind::Var, it->second.idx, def.usr);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								src/query.h
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								src/query.h
									
									
									
									
									
								
							@ -118,6 +118,7 @@ struct QueryableFile {
 | 
			
		||||
  using DefUpdate = Def;
 | 
			
		||||
 | 
			
		||||
  DefUpdate def;
 | 
			
		||||
  int qualified_name_idx = -1;
 | 
			
		||||
 | 
			
		||||
  QueryableFile(const Usr& usr) { def.usr = usr; }
 | 
			
		||||
  QueryableFile(const Def& def) : def(def) {}
 | 
			
		||||
@ -134,6 +135,7 @@ struct QueryableTypeDef {
 | 
			
		||||
  std::vector<Usr> derived;
 | 
			
		||||
  std::vector<Usr> instantiations;
 | 
			
		||||
  std::vector<QueryableLocation> uses;
 | 
			
		||||
  int qualified_name_idx = -1;
 | 
			
		||||
 | 
			
		||||
  QueryableTypeDef(const Usr& usr) : def(usr) {}
 | 
			
		||||
  QueryableTypeDef(const DefUpdate& def) : def(def) {}
 | 
			
		||||
@ -152,6 +154,7 @@ struct QueryableFuncDef {
 | 
			
		||||
  std::vector<Usr> derived;
 | 
			
		||||
  std::vector<UsrRef> callers;
 | 
			
		||||
  std::vector<QueryableLocation> uses;
 | 
			
		||||
  int qualified_name_idx = -1;
 | 
			
		||||
 | 
			
		||||
  QueryableFuncDef(const Usr& usr) : def(usr) {}
 | 
			
		||||
  QueryableFuncDef(const DefUpdate& def) : def(def) {}
 | 
			
		||||
@ -164,6 +167,7 @@ struct QueryableVarDef {
 | 
			
		||||
 | 
			
		||||
  DefUpdate def;
 | 
			
		||||
  std::vector<QueryableLocation> uses;
 | 
			
		||||
  int qualified_name_idx = -1;
 | 
			
		||||
 | 
			
		||||
  QueryableVarDef(const Usr& usr) : def(usr) {}
 | 
			
		||||
  QueryableVarDef(const DefUpdate& def) : def(def) {}
 | 
			
		||||
@ -181,9 +185,9 @@ struct SymbolIdx {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct IndexUpdate {
 | 
			
		||||
  // Creates a new IndexUpdate that will import |file|.
 | 
			
		||||
  static IndexUpdate CreateImport(const IdMap& id_map, IndexedFile& file);
 | 
			
		||||
  static IndexUpdate CreateDelta(const IdMap& current_id_map, const IdMap& previous_id_map, IndexedFile& current, IndexedFile& updated);
 | 
			
		||||
  // Creates a new IndexUpdate based on the delta from previous to current. If
 | 
			
		||||
  // no delta computation should be done just pass null for previous.
 | 
			
		||||
  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
 | 
			
		||||
  // work can be parallelized.
 | 
			
		||||
@ -217,7 +221,7 @@ struct IndexUpdate {
 | 
			
		||||
  // Creates an index update assuming that |previous| is already
 | 
			
		||||
  // in the index, so only the delta between |previous| and |current|
 | 
			
		||||
  // 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 {
 | 
			
		||||
public:
 | 
			
		||||
  // Add an element to the queue.
 | 
			
		||||
  void Enqueue(T t) {
 | 
			
		||||
  void Enqueue(T&& t) {
 | 
			
		||||
    std::lock_guard<std::mutex> lock(mutex_);
 | 
			
		||||
    queue_.push(t);
 | 
			
		||||
    queue_.push(std::move(t));
 | 
			
		||||
    cv_.notify_one();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -29,7 +29,8 @@ public:
 | 
			
		||||
      // release lock as long as the wait and reaquire it afterwards.
 | 
			
		||||
      cv_.wait(lock);
 | 
			
		||||
    }
 | 
			
		||||
    T val = queue_.front();
 | 
			
		||||
    
 | 
			
		||||
    auto val = std::move(queue_.front());
 | 
			
		||||
    queue_.pop();
 | 
			
		||||
    return val;
 | 
			
		||||
  }
 | 
			
		||||
@ -41,7 +42,7 @@ public:
 | 
			
		||||
    if (queue_.empty())
 | 
			
		||||
      return nullopt;
 | 
			
		||||
 | 
			
		||||
    T val = queue_.front();
 | 
			
		||||
    auto val = std::move(queue_.front());
 | 
			
		||||
    queue_.pop();
 | 
			
		||||
    return val;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user