Skip to content

Commit 3f2addb

Browse files
fix(coordinator): return error when INFIELDS exceeds max instead of silently dropping
When InfieldsFromGRPC received more than kMaxTextFieldsCount fields, it logged a warning and returned std::nullopt. This caused the filter parser to interpret the result as "search all text fields", silently broadening the search scope instead of restricting it as the caller requested. In a version-skewed cluster where a newer coordinator encodes more than 64 fields, each shard would run an unrestricted full-text scan and return incorrect results with no error surfaced to the client. Change InfieldsFromGRPC to return absl::StatusOr and propagate an InvalidArgumentError when the limit is exceeded, consistent with the local FT.SEARCH parser path (ft_search_parser.cc). Signed-off-by: Riley Des <riley.desserre@improving.com>
1 parent 6ee4e5a commit 3f2addb

3 files changed

Lines changed: 30 additions & 15 deletions

File tree

src/coordinator/search_converter.cc

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#include "src/query/predicate.h"
2626
#include "src/query/search.h"
2727
#include "src/schema_manager.h"
28-
#include "vmsdk/src/log.h"
2928
#include "vmsdk/src/managed_pointers.h"
3029
#include "vmsdk/src/status/status_macros.h"
3130
#include "vmsdk/src/type_conversions.h"
@@ -44,17 +43,15 @@ void SortByToGRPC(const std::optional<query::SortByParameter>& sortby,
4443
: coordinator::SORT_ORDER_DESCENDING);
4544
}
4645

47-
std::optional<absl::flat_hash_set<std::string>> InfieldsFromGRPC(
48-
const SearchIndexPartitionRequest& request) {
46+
absl::StatusOr<std::optional<absl::flat_hash_set<std::string>>>
47+
InfieldsFromGRPC(const SearchIndexPartitionRequest& request) {
4948
if (request.infields().empty()) {
5049
return std::nullopt;
5150
}
5251
if (static_cast<size_t>(request.infields().size()) > kMaxTextFieldsCount) {
53-
VMSDK_LOG(WARNING, nullptr)
54-
<< "INFIELDS count (" << request.infields().size()
55-
<< ") exceeds maximum supported (" << kMaxTextFieldsCount
56-
<< "), ignoring INFIELDS";
57-
return std::nullopt;
52+
return absl::InvalidArgumentError(absl::StrCat(
53+
"INFIELDS count (", request.infields().size(),
54+
") exceeds maximum supported (", kMaxTextFieldsCount, ")"));
5855
}
5956
absl::flat_hash_set<std::string> infields;
6057
infields.reserve(request.infields().size());
@@ -274,7 +271,7 @@ absl::Status GRPCSearchRequestToParameters(
274271
parameters->filter_parse_results.query_operations =
275272
static_cast<QueryOperations>(request.query_operations());
276273
parameters->sortby_parameter = SortByFromGRPC(request);
277-
parameters->infields = InfieldsFromGRPC(request);
274+
VMSDK_ASSIGN_OR_RETURN(parameters->infields, InfieldsFromGRPC(request));
278275
return absl::OkStatus();
279276
}
280277

src/coordinator/search_converter.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,10 @@ void SortByToGRPC(const std::optional<query::SortByParameter>& sortby,
3434

3535
// Decodes the infields repeated field from a proto request into an optional
3636
// set. Returns nullopt when no infields are present on the wire (same semantics
37-
// as an unset optional in SearchParameters).
38-
std::optional<absl::flat_hash_set<std::string>> InfieldsFromGRPC(
39-
const SearchIndexPartitionRequest& request);
37+
// as an unset optional in SearchParameters). Returns an error if the infields
38+
// count exceeds kMaxTextFieldsCount.
39+
absl::StatusOr<std::optional<absl::flat_hash_set<std::string>>>
40+
InfieldsFromGRPC(const SearchIndexPartitionRequest& request);
4041

4142
} // namespace valkey_search::coordinator
4243

testing/search_converter_test.cc

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
#include <string>
1313

1414
#include "absl/container/flat_hash_set.h"
15+
#include "absl/status/status.h"
1516
#include "gmock/gmock.h"
1617
#include "gtest/gtest.h"
1718
#include "src/coordinator/coordinator.pb.h"
19+
#include "src/index_schema.h"
1820
#include "src/query/search.h"
1921
#include "testing/common.h"
2022
#include "vmsdk/src/testing_infra/utils.h"
@@ -35,7 +37,8 @@ absl::flat_hash_set<std::string> SerializeAndReadBackInfields(
3537

3638
auto request = ParametersToGRPCSearchRequest(params);
3739
auto decoded = InfieldsFromGRPC(*request);
38-
return decoded.value_or(absl::flat_hash_set<std::string>{});
40+
EXPECT_TRUE(decoded.ok());
41+
return decoded->value_or(absl::flat_hash_set<std::string>{});
3942
}
4043

4144
TEST_F(SearchConverterInfieldsTest, SerializeSingleField) {
@@ -50,7 +53,9 @@ TEST_F(SearchConverterInfieldsTest, UnsetIsNotSerialized) {
5053

5154
auto request = ParametersToGRPCSearchRequest(params);
5255
EXPECT_EQ(request->infields_size(), 0);
53-
EXPECT_FALSE(InfieldsFromGRPC(*request).has_value());
56+
auto result = InfieldsFromGRPC(*request);
57+
ASSERT_TRUE(result.ok());
58+
EXPECT_FALSE(result->has_value());
5459
}
5560

5661
// An engaged-but-empty set collapses to the same wire bytes as unset. This is
@@ -62,7 +67,9 @@ TEST_F(SearchConverterInfieldsTest, EngagedEmptyCollapsesToUnset) {
6267

6368
auto request = ParametersToGRPCSearchRequest(params);
6469
EXPECT_EQ(request->infields_size(), 0);
65-
EXPECT_FALSE(InfieldsFromGRPC(*request).has_value());
70+
auto result = InfieldsFromGRPC(*request);
71+
ASSERT_TRUE(result.ok());
72+
EXPECT_FALSE(result->has_value());
6673
}
6774

6875
TEST_F(SearchConverterInfieldsTest, WireRoundTrip) {
@@ -81,5 +88,15 @@ TEST_F(SearchConverterInfieldsTest, WireRoundTrip) {
8188
EXPECT_EQ(deserialized, *params.infields);
8289
}
8390

91+
TEST_F(SearchConverterInfieldsTest, ExceedsMaxFieldsReturnsError) {
92+
coordinator::SearchIndexPartitionRequest request;
93+
for (size_t i = 0; i <= kMaxTextFieldsCount; ++i) {
94+
request.add_infields("field_" + std::to_string(i));
95+
}
96+
auto result = InfieldsFromGRPC(request);
97+
EXPECT_FALSE(result.ok());
98+
EXPECT_EQ(result.status().code(), absl::StatusCode::kInvalidArgument);
99+
}
100+
84101
} // namespace
85102
} // namespace valkey_search

0 commit comments

Comments
 (0)