mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-03 22:04:24 +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));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										104
									
								
								src/query.cc
									
									
									
									
									
								
							
							
						
						
									
										104
									
								
								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)
 | 
					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());
 | 
				
			||||||
@ -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