Skip to content

Commit 1cbaa96

Browse files
perf(spanner): Use arenas to speed up queries that fetch many rows (#15441)
1 parent 08da902 commit 1cbaa96

12 files changed

+436
-243
lines changed

google/cloud/spanner/internal/connection_impl.cc

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -137,15 +137,16 @@ class DefaultPartialResultSetReader : public PartialResultSetReader {
137137

138138
void TryCancel() override { context_->TryCancel(); }
139139

140-
absl::optional<PartialResultSet> Read(
141-
absl::optional<std::string> const&) override {
142-
google::spanner::v1::PartialResultSet result;
143-
auto status = reader_->Read(&result);
144-
if (status.has_value()) {
145-
final_status_ = *std::move(status);
146-
return absl::nullopt;
140+
bool Read(absl::optional<std::string> const&,
141+
UnownedPartialResultSet& response) override {
142+
auto opt_status = reader_->Read(&response.result);
143+
response.resumption = false;
144+
145+
if (opt_status.has_value()) {
146+
final_status_ = *std::move(opt_status);
147+
return false;
147148
}
148-
return PartialResultSet{std::move(result), false};
149+
return true;
149150
}
150151

151152
Status Finish() override { return final_status_; }

google/cloud/spanner/internal/logging_result_set_reader.cc

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,23 @@ using ::google::cloud::internal::DebugString;
2525

2626
void LoggingResultSetReader::TryCancel() { impl_->TryCancel(); }
2727

28-
absl::optional<PartialResultSet> LoggingResultSetReader::Read(
29-
absl::optional<std::string> const& resume_token) {
28+
bool LoggingResultSetReader::Read(
29+
absl::optional<std::string> const& resume_token,
30+
UnownedPartialResultSet& result) {
3031
if (resume_token) {
3132
GCP_LOG(DEBUG) << __func__ << "() << resume_token=\""
3233
<< DebugString(*resume_token, tracing_options_) << "\"";
3334
} else {
3435
GCP_LOG(DEBUG) << __func__ << "() << (unresumable)";
3536
}
36-
auto result = impl_->Read(resume_token);
37-
if (!result) {
38-
GCP_LOG(DEBUG) << __func__ << "() >> (optional-with-no-value)";
37+
bool success = impl_->Read(resume_token, result);
38+
if (!success) {
39+
GCP_LOG(DEBUG) << __func__ << "() >> (failed)";
3940
} else {
4041
GCP_LOG(DEBUG) << __func__ << "() >> resumption="
41-
<< (result->resumption ? "true" : "false");
42+
<< (result.resumption ? "true" : "false");
4243
}
43-
return result;
44+
return success;
4445
}
4546

4647
Status LoggingResultSetReader::Finish() { return impl_->Finish(); }

google/cloud/spanner/internal/logging_result_set_reader.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,8 @@ class LoggingResultSetReader : public PartialResultSetReader {
3939
~LoggingResultSetReader() override = default;
4040

4141
void TryCancel() override;
42-
absl::optional<PartialResultSet> Read(
43-
absl::optional<std::string> const& resume_token) override;
42+
bool Read(absl::optional<std::string> const& resume_token,
43+
UnownedPartialResultSet& result) override;
4444
Status Finish() override;
4545

4646
private:

google/cloud/spanner/internal/logging_result_set_reader_test.cc

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,30 +49,32 @@ TEST_F(LoggingResultSetReaderTest, TryCancel) {
4949

5050
TEST_F(LoggingResultSetReaderTest, Read) {
5151
auto mock = std::make_unique<spanner_testing::MockPartialResultSetReader>();
52-
EXPECT_CALL(*mock, Read(_))
53-
.WillOnce([] {
54-
google::spanner::v1::PartialResultSet result;
55-
result.set_resume_token("test-token");
56-
return PartialResultSet{std::move(result), false};
52+
EXPECT_CALL(*mock, Read(_, _))
53+
.WillOnce([](absl::optional<std::string> const&,
54+
UnownedPartialResultSet& result) {
55+
result.resumption = false;
56+
result.result.set_resume_token("test-token");
57+
return true;
5758
})
58-
.WillOnce([] { return absl::optional<PartialResultSet>{}; });
59+
.WillOnce([] { return false; });
5960
LoggingResultSetReader reader(std::move(mock), TracingOptions{});
60-
auto result = reader.Read("");
61-
ASSERT_TRUE(result.has_value());
62-
EXPECT_EQ("test-token", result->result.resume_token());
61+
google::spanner::v1::PartialResultSet partial_result_set;
62+
auto result =
63+
UnownedPartialResultSet::FromPartialResultSet(partial_result_set);
64+
ASSERT_TRUE(reader.Read("", result));
65+
EXPECT_EQ("test-token", result.result.resume_token());
6366

6467
auto log_lines = log_.ExtractLines();
6568
EXPECT_THAT(log_lines, AllOf(Contains(StartsWith("Read()"))));
6669
EXPECT_THAT(log_lines, Contains(HasSubstr("resume_token=\"\"")));
6770
EXPECT_THAT(log_lines, Contains(HasSubstr("resumption=false")));
6871

69-
result = reader.Read("test-token");
70-
ASSERT_FALSE(result.has_value());
72+
ASSERT_FALSE(reader.Read("test-token", result));
7173

7274
log_lines = log_.ExtractLines();
7375
EXPECT_THAT(log_lines, AllOf(Contains(StartsWith("Read()"))));
7476
EXPECT_THAT(log_lines, Contains(HasSubstr("resume_token=\"test-token\"")));
75-
EXPECT_THAT(log_lines, Contains(HasSubstr("(optional-with-no-value)")));
77+
EXPECT_THAT(log_lines, Contains(HasSubstr("(failed)")));
7678
}
7779

7880
TEST_F(LoggingResultSetReaderTest, Finish) {

google/cloud/spanner/internal/partial_result_set_reader.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,13 @@ GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
3636
* caller should discard any pending state not covered by the token, as that
3737
* data will be replayed.
3838
*/
39-
struct PartialResultSet {
40-
google::spanner::v1::PartialResultSet result;
39+
struct UnownedPartialResultSet {
40+
static UnownedPartialResultSet FromPartialResultSet(
41+
google::spanner::v1::PartialResultSet& result) {
42+
return UnownedPartialResultSet{result, false};
43+
}
44+
45+
google::spanner::v1::PartialResultSet& result;
4146
bool resumption;
4247
};
4348

@@ -54,8 +59,8 @@ class PartialResultSetReader {
5459
public:
5560
virtual ~PartialResultSetReader() = default;
5661
virtual void TryCancel() = 0;
57-
virtual absl::optional<PartialResultSet> Read(
58-
absl::optional<std::string> const& resume_token) = 0;
62+
virtual bool Read(absl::optional<std::string> const& resume_token,
63+
UnownedPartialResultSet& result) = 0;
5964
virtual Status Finish() = 0;
6065
};
6166

google/cloud/spanner/internal/partial_result_set_resume.cc

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,36 +22,36 @@ GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
2222

2323
void PartialResultSetResume::TryCancel() { child_->TryCancel(); }
2424

25-
absl::optional<PartialResultSet> PartialResultSetResume::Read(
26-
absl::optional<std::string> const& resume_token) {
25+
bool PartialResultSetResume::Read(
26+
absl::optional<std::string> const& resume_token,
27+
UnownedPartialResultSet& result) {
2728
bool resumption = false;
2829
do {
29-
absl::optional<PartialResultSet> result = child_->Read(resume_token);
30-
if (result) {
30+
if (child_->Read(resume_token, result)) {
3131
// Let the caller know if we recreated the PartialResultSetReader using
3232
// the resume_token so that they might discard any previous results that
3333
// will be contained in the new stream.
34-
if (resumption) result->resumption = true;
35-
return result;
34+
if (resumption) result.resumption = true;
35+
return true;
3636
}
3737
auto status = Finish();
38-
if (status.ok()) return {};
38+
if (status.ok()) return false;
3939
if (!resume_token) {
4040
// Our caller has requested that we not try to resume the stream,
4141
// probably because they have already delivered previous results that
4242
// would otherwise be replayed.
43-
return {};
43+
return false;
4444
}
4545
if (idempotency_ == google::cloud::Idempotency::kNonIdempotent ||
4646
!retry_policy_prototype_->OnFailure(status)) {
47-
return {};
47+
return false;
4848
}
4949
std::this_thread::sleep_for(backoff_policy_prototype_->OnCompletion());
5050
resumption = true;
5151
last_status_.reset();
5252
child_ = factory_(*resume_token);
5353
} while (!retry_policy_prototype_->IsExhausted());
54-
return {};
54+
return false;
5555
}
5656

5757
Status PartialResultSetResume::Finish() {

google/cloud/spanner/internal/partial_result_set_resume.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ class PartialResultSetResume : public PartialResultSetReader {
5252
~PartialResultSetResume() override = default;
5353

5454
void TryCancel() override;
55-
absl::optional<PartialResultSet> Read(
56-
absl::optional<std::string> const& resume_token) override;
55+
bool Read(absl::optional<std::string> const& resume_token,
56+
UnownedPartialResultSet& result) override;
5757
Status Finish() override;
5858

5959
private:

0 commit comments

Comments
 (0)