This is an automated email from the ASF dual-hosted git repository.

twice pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git


The following commit(s) were added to refs/heads/unstable by this push:
     new e86444d4 chore(search): improve code structure of IndexManager (#2650)
e86444d4 is described below

commit e86444d44119e7dd438085789a9b7ce554d40a53
Author: Twice <[email protected]>
AuthorDate: Fri Nov 8 10:08:36 2024 +0800

    chore(search): improve code structure of IndexManager (#2650)
---
 src/commands/cmd_search.cc  |   2 +-
 src/search/index_manager.cc | 328 ++++++++++++++++++++++++++++++++++++++++++++
 src/search/index_manager.h  | 298 +---------------------------------------
 3 files changed, 336 insertions(+), 292 deletions(-)

diff --git a/src/commands/cmd_search.cc b/src/commands/cmd_search.cc
index 8d3309ab..7a09885e 100644
--- a/src/commands/cmd_search.cc
+++ b/src/commands/cmd_search.cc
@@ -498,7 +498,7 @@ class CommandFTTagVals : public Commander {
   Status Execute(engine::Context &ctx, Server *srv, Connection *conn, 
std::string *output) override {
     const auto &index_name = args_[1];
     const auto &tag_field_name = args_[2];
-    auto field_values = GET_OR_RET(srv->index_mgr.FieldValues(ctx, index_name, 
tag_field_name, conn->GetNamespace()));
+    auto field_values = GET_OR_RET(srv->index_mgr.TagValues(ctx, index_name, 
tag_field_name, conn->GetNamespace()));
 
     std::vector<std::string> result_vec(field_values.begin(), 
field_values.end());
 
diff --git a/src/search/index_manager.cc b/src/search/index_manager.cc
new file mode 100644
index 00000000..7275a62d
--- /dev/null
+++ b/src/search/index_manager.cc
@@ -0,0 +1,328 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+#include "index_manager.h"
+
+#include "db_util.h"
+#include "encoding.h"
+#include "search/index_info.h"
+#include "search/indexer.h"
+#include "search/ir.h"
+#include "search/ir_sema_checker.h"
+#include "search/passes/manager.h"
+#include "search/plan_executor.h"
+#include "search/search_encoding.h"
+#include "search/value.h"
+#include "status.h"
+#include "storage/storage.h"
+#include "string_util.h"
+
+namespace redis {
+
+Status IndexManager::Load(engine::Context &ctx, const std::string &ns) {
+  // currently index cannot work in cluster mode
+  if (storage->GetConfig()->cluster_enabled) {
+    return Status::OK();
+  }
+  util::UniqueIterator iter(ctx, ctx.DefaultScanOptions(), 
ColumnFamilyID::Search);
+  auto begin = SearchKey{ns, ""}.ConstructIndexMeta();
+
+  for (iter->Seek(begin); iter->Valid(); iter->Next()) {
+    auto key = iter->key();
+
+    uint8_t ns_size = 0;
+    if (!GetFixed8(&key, &ns_size)) break;
+    if (ns_size != ns.size()) break;
+    if (!key.starts_with(ns)) break;
+    key.remove_prefix(ns_size);
+
+    uint8_t subkey_type = 0;
+    if (!GetFixed8(&key, &subkey_type)) break;
+    if (subkey_type != (uint8_t)SearchSubkeyType::INDEX_META) break;
+
+    Slice index_name;
+    if (!GetSizedString(&key, &index_name)) break;
+
+    IndexMetadata metadata;
+    auto index_meta_value = iter->value();
+    if (auto s = metadata.Decode(&index_meta_value); !s.ok()) {
+      return {Status::NotOK, fmt::format("fail to decode index metadata for 
index {}: {}", index_name, s.ToString())};
+    }
+
+    auto index_key = SearchKey(ns, index_name.ToStringView());
+    std::string prefix_value;
+    if (auto s = storage->Get(ctx, ctx.DefaultMultiGetOptions(), 
storage->GetCFHandle(ColumnFamilyID::Search),
+                              index_key.ConstructIndexPrefixes(), 
&prefix_value);
+        !s.ok()) {
+      return {Status::NotOK, fmt::format("fail to find index prefixes for 
index {}: {}", index_name, s.ToString())};
+    }
+
+    IndexPrefixes prefixes;
+    Slice prefix_slice = prefix_value;
+    if (auto s = prefixes.Decode(&prefix_slice); !s.ok()) {
+      return {Status::NotOK, fmt::format("fail to decode index prefixes for 
index {}: {}", index_name, s.ToString())};
+    }
+
+    auto info = std::make_unique<kqir::IndexInfo>(index_name.ToString(), 
metadata, ns);
+    info->prefixes = prefixes;
+
+    util::UniqueIterator field_iter(ctx, ctx.DefaultScanOptions(), 
ColumnFamilyID::Search);
+    auto field_begin = index_key.ConstructFieldMeta();
+
+    for (field_iter->Seek(field_begin); field_iter->Valid(); 
field_iter->Next()) {
+      auto key = field_iter->key();
+
+      uint8_t ns_size = 0;
+      if (!GetFixed8(&key, &ns_size)) break;
+      if (ns_size != ns.size()) break;
+      if (!key.starts_with(ns)) break;
+      key.remove_prefix(ns_size);
+
+      uint8_t subkey_type = 0;
+      if (!GetFixed8(&key, &subkey_type)) break;
+      if (subkey_type != (uint8_t)SearchSubkeyType::FIELD_META) break;
+
+      Slice value;
+      if (!GetSizedString(&key, &value)) break;
+      if (value != index_name) break;
+
+      if (!GetSizedString(&key, &value)) break;
+
+      auto field_name = value;
+      auto field_value = field_iter->value();
+
+      std::unique_ptr<IndexFieldMetadata> field_meta;
+      if (auto s = IndexFieldMetadata::Decode(&field_value, field_meta); 
!s.ok()) {
+        return {Status::NotOK, fmt::format("fail to decode index field 
metadata for index {}, field {}: {}", index_name,
+                                           field_name, s.ToString())};
+      }
+
+      info->Add(kqir::FieldInfo(field_name.ToString(), std::move(field_meta)));
+    }
+
+    auto updater = std::make_unique<IndexUpdater>(info.get());
+    indexer->Add(std::move(updater));
+    index_map.Insert(std::move(info));
+  }
+
+  if (auto s = iter->status(); !s.ok()) {
+    return {Status::NotOK, fmt::format("fail to load index metadata: {}", 
s.ToString())};
+  }
+
+  return Status::OK();
+}
+
+Status IndexManager::Create(engine::Context &ctx, 
std::unique_ptr<kqir::IndexInfo> info) {
+  if (storage->GetConfig()->cluster_enabled) {
+    return {Status::NotOK, "currently index cannot work in cluster mode"};
+  }
+
+  if (auto iter = index_map.Find(info->name, info->ns); iter != 
index_map.end()) {
+    return {Status::NotOK, "index already exists"};
+  }
+
+  SearchKey index_key(info->ns, info->name);
+  auto cf = storage->GetCFHandle(ColumnFamilyID::Search);
+
+  auto batch = storage->GetWriteBatchBase();
+
+  std::string meta_val;
+  info->metadata.Encode(&meta_val);
+  auto s = batch->Put(cf, index_key.ConstructIndexMeta(), meta_val);
+  if (!s.ok()) {
+    return {Status::NotOK, s.ToString()};
+  }
+
+  std::string prefix_val;
+  info->prefixes.Encode(&prefix_val);
+  s = batch->Put(cf, index_key.ConstructIndexPrefixes(), prefix_val);
+  if (!s.ok()) {
+    return {Status::NotOK, s.ToString()};
+  }
+
+  for (const auto &[_, field_info] : info->fields) {
+    SearchKey field_key(info->ns, info->name, field_info.name);
+
+    std::string field_val;
+    field_info.metadata->Encode(&field_val);
+
+    s = batch->Put(cf, field_key.ConstructFieldMeta(), field_val);
+    if (!s.ok()) {
+      return {Status::NotOK, s.ToString()};
+    }
+  }
+
+  if (auto s = storage->Write(ctx, storage->DefaultWriteOptions(), 
batch->GetWriteBatch()); !s.ok()) {
+    return {Status::NotOK, fmt::format("failed to write index metadata: {}", 
s.ToString())};
+  }
+
+  auto updater = std::make_unique<IndexUpdater>(info.get());
+  indexer->Add(std::move(updater));
+  index_map.Insert(std::move(info));
+
+  for (const auto &updater : indexer->updater_list) {
+    GET_OR_RET(updater->Build(ctx));
+  }
+
+  return Status::OK();
+}
+
+StatusOr<std::unique_ptr<kqir::PlanOperator>> 
IndexManager::GeneratePlan(std::unique_ptr<kqir::Node> ir,
+                                                                         const 
std::string &ns) const {
+  kqir::SemaChecker sema_checker(index_map);
+  sema_checker.ns = ns;
+
+  GET_OR_RET(sema_checker.Check(ir.get()));
+
+  auto plan_ir = kqir::PassManager::Execute(kqir::PassManager::Default(), 
std::move(ir));
+  std::unique_ptr<kqir::PlanOperator> plan_op;
+  if (plan_op = kqir::Node::As<kqir::PlanOperator>(std::move(plan_ir)); 
!plan_op) {
+    return {Status::NotOK, "failed to convert the query to plan operators"};
+  }
+
+  return plan_op;
+}
+
+StatusOr<std::vector<kqir::ExecutorContext::RowType>> 
IndexManager::Search(std::unique_ptr<kqir::Node> ir,
+                                                                           
const std::string &ns) const {
+  auto plan_op = GET_OR_RET(GeneratePlan(std::move(ir), ns));
+
+  kqir::ExecutorContext executor_ctx(plan_op.get(), storage);
+
+  std::vector<kqir::ExecutorContext::RowType> results;
+
+  auto iter_res = GET_OR_RET(executor_ctx.Next());
+  while (!std::holds_alternative<kqir::ExecutorNode::End>(iter_res)) {
+    results.push_back(std::get<kqir::ExecutorContext::RowType>(iter_res));
+
+    iter_res = GET_OR_RET(executor_ctx.Next());
+  }
+
+  return results;
+}
+
+Status IndexManager::Drop(engine::Context &ctx, std::string_view index_name, 
const std::string &ns) {
+  auto iter = index_map.Find(index_name, ns);
+  if (iter == index_map.end()) {
+    return {Status::NotOK, "index not found"};
+  }
+
+  auto info = iter->second.get();
+  indexer->Remove(info);
+
+  SearchKey index_key(info->ns, info->name);
+  auto cf = storage->GetCFHandle(ColumnFamilyID::Search);
+
+  auto batch = storage->GetWriteBatchBase();
+
+  auto s = batch->Delete(cf, index_key.ConstructIndexMeta());
+  if (!s.ok()) {
+    return {Status::NotOK, s.ToString()};
+  }
+  s = batch->Delete(cf, index_key.ConstructIndexPrefixes());
+  if (!s.ok()) {
+    return {Status::NotOK, s.ToString()};
+  }
+
+  auto begin = index_key.ConstructAllFieldMetaBegin();
+  auto end = index_key.ConstructAllFieldMetaEnd();
+  s = batch->DeleteRange(cf, begin, end);
+  if (!s.ok()) {
+    return {Status::NotOK, s.ToString()};
+  }
+
+  begin = index_key.ConstructAllFieldDataBegin();
+  end = index_key.ConstructAllFieldDataEnd();
+  s = batch->DeleteRange(cf, begin, end);
+  if (!s.ok()) {
+    return {Status::NotOK, s.ToString()};
+  }
+
+  if (auto s = storage->Write(ctx, storage->DefaultWriteOptions(), 
batch->GetWriteBatch()); !s.ok()) {
+    return {Status::NotOK, fmt::format("failed to delete index metadata and 
data: {}", s.ToString())};
+  }
+
+  index_map.erase(iter);
+
+  return Status::OK();
+}
+
+StatusOr<std::unordered_set<std::string>> 
IndexManager::TagValues(engine::Context &ctx, std::string_view index_name,
+                                                                  
std::string_view tag_field_name,
+                                                                  const 
std::string &ns) {
+  auto iter = index_map.Find(index_name, ns);
+  if (iter == index_map.end()) {
+    return {Status::NotOK, fmt::format("Index '{}' not found in namespace 
'{}'", index_name, ns)};
+  }
+  const auto &info = iter->second;
+
+  std::string tag_field_name_str(tag_field_name);
+  auto field_it = info->fields.find(tag_field_name_str);
+  if (field_it == info->fields.end()) {
+    return std::unordered_set<std::string>{};
+  }
+  const auto &[field_name, field_info] = *field_it;
+
+  if (!field_info.metadata || field_info.metadata->type != 
IndexFieldType::TAG) {
+    return std::unordered_set<std::string>{};
+  }
+
+  std::unordered_set<std::string> matching_values;
+  util::UniqueIterator index_iter(ctx, ctx.DefaultScanOptions(), 
ColumnFamilyID::Search);
+
+  auto index_key = SearchKey(ns, index_name, field_name);
+  std::string field_prefix;
+  index_key.PutNamespace(&field_prefix);
+  SearchKey::PutType(&field_prefix, SearchSubkeyType::FIELD);
+  index_key.PutIndex(&field_prefix);
+  PutSizedString(&field_prefix, field_name);
+
+  std::string last_tag;
+
+  for (index_iter->Seek(field_prefix); index_iter->Valid(); 
index_iter->Next()) {
+    auto key = index_iter->key();
+
+    if (!key.starts_with(field_prefix)) {
+      break;
+    }
+
+    Slice key_slice = key;
+    key_slice.remove_prefix(field_prefix.size());
+
+    Slice tag_slice;
+    if (!GetSizedString(&key_slice, &tag_slice)) continue;
+
+    std::string current_tag = tag_slice.ToString();
+
+    if (current_tag == last_tag) {
+      continue;
+    }
+
+    last_tag = current_tag;
+    matching_values.insert(std::move(current_tag));
+  }
+
+  if (auto s = index_iter->status(); !s.ok()) {
+    return {Status::NotOK, fmt::format("Failed to iterate over index data: 
{}", s.ToString())};
+  }
+
+  return matching_values;
+}
+}  // namespace redis
diff --git a/src/search/index_manager.h b/src/search/index_manager.h
index a89445ea..cfa7712a 100644
--- a/src/search/index_manager.h
+++ b/src/search/index_manager.h
@@ -20,19 +20,12 @@
 
 #pragma once
 
-#include "db_util.h"
-#include "encoding.h"
 #include "search/index_info.h"
 #include "search/indexer.h"
 #include "search/ir.h"
-#include "search/ir_sema_checker.h"
-#include "search/passes/manager.h"
 #include "search/plan_executor.h"
-#include "search/search_encoding.h"
-#include "search/value.h"
 #include "status.h"
 #include "storage/storage.h"
-#include "string_util.h"
 
 namespace redis {
 
@@ -43,293 +36,16 @@ struct IndexManager {
 
   IndexManager(GlobalIndexer *indexer, engine::Storage *storage) : 
indexer(indexer), storage(storage) {}
 
-  Status Load(engine::Context &ctx, const std::string &ns) {
-    // currently index cannot work in cluster mode
-    if (storage->GetConfig()->cluster_enabled) {
-      return Status::OK();
-    }
-    util::UniqueIterator iter(ctx, ctx.DefaultScanOptions(), 
ColumnFamilyID::Search);
-    auto begin = SearchKey{ns, ""}.ConstructIndexMeta();
-
-    for (iter->Seek(begin); iter->Valid(); iter->Next()) {
-      auto key = iter->key();
-
-      uint8_t ns_size = 0;
-      if (!GetFixed8(&key, &ns_size)) break;
-      if (ns_size != ns.size()) break;
-      if (!key.starts_with(ns)) break;
-      key.remove_prefix(ns_size);
-
-      uint8_t subkey_type = 0;
-      if (!GetFixed8(&key, &subkey_type)) break;
-      if (subkey_type != (uint8_t)SearchSubkeyType::INDEX_META) break;
-
-      Slice index_name;
-      if (!GetSizedString(&key, &index_name)) break;
-
-      IndexMetadata metadata;
-      auto index_meta_value = iter->value();
-      if (auto s = metadata.Decode(&index_meta_value); !s.ok()) {
-        return {Status::NotOK, fmt::format("fail to decode index metadata for 
index {}: {}", index_name, s.ToString())};
-      }
-
-      auto index_key = SearchKey(ns, index_name.ToStringView());
-      std::string prefix_value;
-      if (auto s = storage->Get(ctx, ctx.DefaultMultiGetOptions(), 
storage->GetCFHandle(ColumnFamilyID::Search),
-                                index_key.ConstructIndexPrefixes(), 
&prefix_value);
-          !s.ok()) {
-        return {Status::NotOK, fmt::format("fail to find index prefixes for 
index {}: {}", index_name, s.ToString())};
-      }
-
-      IndexPrefixes prefixes;
-      Slice prefix_slice = prefix_value;
-      if (auto s = prefixes.Decode(&prefix_slice); !s.ok()) {
-        return {Status::NotOK, fmt::format("fail to decode index prefixes for 
index {}: {}", index_name, s.ToString())};
-      }
-
-      auto info = std::make_unique<kqir::IndexInfo>(index_name.ToString(), 
metadata, ns);
-      info->prefixes = prefixes;
-
-      util::UniqueIterator field_iter(ctx, ctx.DefaultScanOptions(), 
ColumnFamilyID::Search);
-      auto field_begin = index_key.ConstructFieldMeta();
-
-      for (field_iter->Seek(field_begin); field_iter->Valid(); 
field_iter->Next()) {
-        auto key = field_iter->key();
-
-        uint8_t ns_size = 0;
-        if (!GetFixed8(&key, &ns_size)) break;
-        if (ns_size != ns.size()) break;
-        if (!key.starts_with(ns)) break;
-        key.remove_prefix(ns_size);
-
-        uint8_t subkey_type = 0;
-        if (!GetFixed8(&key, &subkey_type)) break;
-        if (subkey_type != (uint8_t)SearchSubkeyType::FIELD_META) break;
-
-        Slice value;
-        if (!GetSizedString(&key, &value)) break;
-        if (value != index_name) break;
-
-        if (!GetSizedString(&key, &value)) break;
-
-        auto field_name = value;
-        auto field_value = field_iter->value();
-
-        std::unique_ptr<IndexFieldMetadata> field_meta;
-        if (auto s = IndexFieldMetadata::Decode(&field_value, field_meta); 
!s.ok()) {
-          return {Status::NotOK, fmt::format("fail to decode index field 
metadata for index {}, field {}: {}",
-                                             index_name, field_name, 
s.ToString())};
-        }
-
-        info->Add(kqir::FieldInfo(field_name.ToString(), 
std::move(field_meta)));
-      }
-
-      auto updater = std::make_unique<IndexUpdater>(info.get());
-      indexer->Add(std::move(updater));
-      index_map.Insert(std::move(info));
-    }
-
-    if (auto s = iter->status(); !s.ok()) {
-      return {Status::NotOK, fmt::format("fail to load index metadata: {}", 
s.ToString())};
-    }
-
-    return Status::OK();
-  }
-
-  Status Create(engine::Context &ctx, std::unique_ptr<kqir::IndexInfo> info) {
-    if (storage->GetConfig()->cluster_enabled) {
-      return {Status::NotOK, "currently index cannot work in cluster mode"};
-    }
-
-    if (auto iter = index_map.Find(info->name, info->ns); iter != 
index_map.end()) {
-      return {Status::NotOK, "index already exists"};
-    }
-
-    SearchKey index_key(info->ns, info->name);
-    auto cf = storage->GetCFHandle(ColumnFamilyID::Search);
-
-    auto batch = storage->GetWriteBatchBase();
-
-    std::string meta_val;
-    info->metadata.Encode(&meta_val);
-    auto s = batch->Put(cf, index_key.ConstructIndexMeta(), meta_val);
-    if (!s.ok()) {
-      return {Status::NotOK, s.ToString()};
-    }
-
-    std::string prefix_val;
-    info->prefixes.Encode(&prefix_val);
-    s = batch->Put(cf, index_key.ConstructIndexPrefixes(), prefix_val);
-    if (!s.ok()) {
-      return {Status::NotOK, s.ToString()};
-    }
-
-    for (const auto &[_, field_info] : info->fields) {
-      SearchKey field_key(info->ns, info->name, field_info.name);
-
-      std::string field_val;
-      field_info.metadata->Encode(&field_val);
-
-      s = batch->Put(cf, field_key.ConstructFieldMeta(), field_val);
-      if (!s.ok()) {
-        return {Status::NotOK, s.ToString()};
-      }
-    }
-
-    if (auto s = storage->Write(ctx, storage->DefaultWriteOptions(), 
batch->GetWriteBatch()); !s.ok()) {
-      return {Status::NotOK, fmt::format("failed to write index metadata: {}", 
s.ToString())};
-    }
-
-    auto updater = std::make_unique<IndexUpdater>(info.get());
-    indexer->Add(std::move(updater));
-    index_map.Insert(std::move(info));
-
-    for (const auto &updater : indexer->updater_list) {
-      GET_OR_RET(updater->Build(ctx));
-    }
-
-    return Status::OK();
-  }
+  Status Load(engine::Context &ctx, const std::string &ns);
+  Status Create(engine::Context &ctx, std::unique_ptr<kqir::IndexInfo> info);
+  Status Drop(engine::Context &ctx, std::string_view index_name, const 
std::string &ns);
 
   StatusOr<std::unique_ptr<kqir::PlanOperator>> 
GeneratePlan(std::unique_ptr<kqir::Node> ir,
-                                                             const std::string 
&ns) const {
-    kqir::SemaChecker sema_checker(index_map);
-    sema_checker.ns = ns;
-
-    GET_OR_RET(sema_checker.Check(ir.get()));
-
-    auto plan_ir = kqir::PassManager::Execute(kqir::PassManager::Default(), 
std::move(ir));
-    std::unique_ptr<kqir::PlanOperator> plan_op;
-    if (plan_op = kqir::Node::As<kqir::PlanOperator>(std::move(plan_ir)); 
!plan_op) {
-      return {Status::NotOK, "failed to convert the query to plan operators"};
-    }
-
-    return plan_op;
-  }
-
+                                                             const std::string 
&ns) const;
   StatusOr<std::vector<kqir::ExecutorContext::RowType>> 
Search(std::unique_ptr<kqir::Node> ir,
-                                                               const 
std::string &ns) const {
-    auto plan_op = GET_OR_RET(GeneratePlan(std::move(ir), ns));
-
-    kqir::ExecutorContext executor_ctx(plan_op.get(), storage);
-
-    std::vector<kqir::ExecutorContext::RowType> results;
-
-    auto iter_res = GET_OR_RET(executor_ctx.Next());
-    while (!std::holds_alternative<kqir::ExecutorNode::End>(iter_res)) {
-      results.push_back(std::get<kqir::ExecutorContext::RowType>(iter_res));
-
-      iter_res = GET_OR_RET(executor_ctx.Next());
-    }
-
-    return results;
-  }
-
-  Status Drop(engine::Context &ctx, std::string_view index_name, const 
std::string &ns) {
-    auto iter = index_map.Find(index_name, ns);
-    if (iter == index_map.end()) {
-      return {Status::NotOK, "index not found"};
-    }
-
-    auto info = iter->second.get();
-    indexer->Remove(info);
-
-    SearchKey index_key(info->ns, info->name);
-    auto cf = storage->GetCFHandle(ColumnFamilyID::Search);
-
-    auto batch = storage->GetWriteBatchBase();
-
-    auto s = batch->Delete(cf, index_key.ConstructIndexMeta());
-    if (!s.ok()) {
-      return {Status::NotOK, s.ToString()};
-    }
-    s = batch->Delete(cf, index_key.ConstructIndexPrefixes());
-    if (!s.ok()) {
-      return {Status::NotOK, s.ToString()};
-    }
-
-    auto begin = index_key.ConstructAllFieldMetaBegin();
-    auto end = index_key.ConstructAllFieldMetaEnd();
-    s = batch->DeleteRange(cf, begin, end);
-    if (!s.ok()) {
-      return {Status::NotOK, s.ToString()};
-    }
-
-    begin = index_key.ConstructAllFieldDataBegin();
-    end = index_key.ConstructAllFieldDataEnd();
-    s = batch->DeleteRange(cf, begin, end);
-    if (!s.ok()) {
-      return {Status::NotOK, s.ToString()};
-    }
-
-    if (auto s = storage->Write(ctx, storage->DefaultWriteOptions(), 
batch->GetWriteBatch()); !s.ok()) {
-      return {Status::NotOK, fmt::format("failed to delete index metadata and 
data: {}", s.ToString())};
-    }
-
-    index_map.erase(iter);
-
-    return Status::OK();
-  }
-
-  StatusOr<std::unordered_set<std::string>> FieldValues(engine::Context &ctx, 
std::string_view index_name,
-                                                        std::string_view 
tag_field_name, const std::string &ns) {
-    auto iter = index_map.Find(index_name, ns);
-    if (iter == index_map.end()) {
-      return {Status::NotOK, fmt::format("Index '{}' not found in namespace 
'{}'", index_name, ns)};
-    }
-    const auto &info = iter->second;
-
-    std::string tag_field_name_str(tag_field_name);
-    auto field_it = info->fields.find(tag_field_name_str);
-    if (field_it == info->fields.end()) {
-      return std::unordered_set<std::string>{};
-    }
-    const auto &[field_name, field_info] = *field_it;
-
-    if (!field_info.metadata || field_info.metadata->type != 
IndexFieldType::TAG) {
-      return std::unordered_set<std::string>{};
-    }
-
-    std::unordered_set<std::string> matching_values;
-    util::UniqueIterator index_iter(ctx, ctx.DefaultScanOptions(), 
ColumnFamilyID::Search);
-
-    auto index_key = SearchKey(ns, index_name, field_name);
-    std::string field_prefix;
-    index_key.PutNamespace(&field_prefix);
-    SearchKey::PutType(&field_prefix, SearchSubkeyType::FIELD);
-    index_key.PutIndex(&field_prefix);
-    PutSizedString(&field_prefix, field_name);
-
-    std::string last_tag;
-
-    for (index_iter->Seek(field_prefix); index_iter->Valid(); 
index_iter->Next()) {
-      auto key = index_iter->key();
-
-      if (!key.starts_with(field_prefix)) {
-        break;
-      }
-
-      Slice key_slice = key;
-      key_slice.remove_prefix(field_prefix.size());
-
-      Slice tag_slice;
-      if (!GetSizedString(&key_slice, &tag_slice)) continue;
-
-      std::string current_tag = tag_slice.ToString();
-
-      if (current_tag == last_tag) {
-        continue;
-      }
-
-      last_tag = current_tag;
-      matching_values.insert(std::move(current_tag));
-    }
-
-    if (auto s = index_iter->status(); !s.ok()) {
-      return {Status::NotOK, fmt::format("Failed to iterate over index data: 
{}", s.ToString())};
-    }
+                                                               const 
std::string &ns) const;
 
-    return matching_values;
-  }
+  StatusOr<std::unordered_set<std::string>> TagValues(engine::Context &ctx, 
std::string_view index_name,
+                                                      std::string_view 
tag_field_name, const std::string &ns);
 };
 }  // namespace redis

Reply via email to