1616#include " google/cloud/spanner/internal/connection_impl.h"
1717#include " google/cloud/spanner/internal/retry_loop.h"
1818#include " google/cloud/spanner/internal/session.h"
19+ #include " google/cloud/grpc_utils/completion_queue.h"
20+ #include " google/cloud/internal/background_threads_impl.h"
1921#include " google/cloud/internal/make_unique.h"
22+ #include " google/cloud/log.h"
2023#include " google/cloud/status.h"
2124#include < algorithm>
25+ #include < chrono>
2226#include < random>
27+ #include < thread>
2328
2429namespace google {
2530namespace cloud {
@@ -31,23 +36,28 @@ namespace spanner_proto = ::google::spanner::v1;
3136
3237std::shared_ptr<SessionPool> MakeSessionPool (
3338 Database db, std::vector<std::shared_ptr<SpannerStub>> stubs,
34- SessionPoolOptions options, std::unique_ptr<RetryPolicy> retry_policy,
39+ SessionPoolOptions options,
40+ std::unique_ptr<BackgroundThreads> background_threads,
41+ std::unique_ptr<RetryPolicy> retry_policy,
3542 std::unique_ptr<BackoffPolicy> backoff_policy) {
3643 auto pool = std::make_shared<SessionPool>(
3744 std::move (db), std::move (stubs), std::move (options),
38- std::move (retry_policy), std::move (backoff_policy));
45+ std::move (background_threads), std::move (retry_policy),
46+ std::move (backoff_policy));
3947 pool->Initialize ();
4048 return pool;
4149}
4250
4351SessionPool::SessionPool (Database db,
4452 std::vector<std::shared_ptr<SpannerStub>> stubs,
4553 SessionPoolOptions options,
54+ std::unique_ptr<BackgroundThreads> background_threads,
4655 std::unique_ptr<RetryPolicy> retry_policy,
4756 std::unique_ptr<BackoffPolicy> backoff_policy)
4857 : db_(std::move(db)),
4958 options_ (std::move(
5059 options.EnforceConstraints(static_cast <int >(stubs.size())))),
60+ background_threads_(std::move(background_threads)),
5161 retry_policy_prototype_(std::move(retry_policy)),
5262 backoff_policy_prototype_(std::move(backoff_policy)),
5363 max_pool_size_(options_.max_sessions_per_channel() *
@@ -89,6 +99,43 @@ void SessionPool::Initialize() {
8999 (void )CreateSessions (lk, channel, options_.labels (), num_sessions);
90100 }
91101 }
102+ ScheduleBackgroundWork (std::chrono::seconds (5 ));
103+ }
104+
105+ SessionPool::~SessionPool () {
106+ // All references to this object are via `shared_ptr`; since we're in the
107+ // destructor that implies there can be no concurrent accesses to any member
108+ // variables, including `current_timer_`.
109+ //
110+ // Note that it *is* possible the timer lambda in `ScheduleBackgroundWork`
111+ // is executing concurrently. However, since we are in the destructor we know
112+ // that the lambda must not have yet successfully finished a call to `lock()`
113+ // on the `weak_ptr` to `this` it holds. Any subsequent or in-progress calls
114+ // must return `nullptr`, and the lambda will not do any work nor reschedule
115+ // the timer.
116+ current_timer_.cancel ();
117+ }
118+
119+ void SessionPool::ScheduleBackgroundWork (std::chrono::seconds relative_time) {
120+ // See the comment in the destructor about the thread safety of this method.
121+ std::weak_ptr<SessionPool> pool = shared_from_this ();
122+ current_timer_ =
123+ background_threads_->cq ()
124+ .MakeRelativeTimer (relative_time)
125+ .then ([pool](future<StatusOr<std::chrono::system_clock::time_point>>
126+ result) {
127+ if (result.get ().ok ()) {
128+ if (auto shared_pool = pool.lock ()) {
129+ shared_pool->DoBackgroundWork ();
130+ }
131+ }
132+ });
133+ }
134+
135+ void SessionPool::DoBackgroundWork () {
136+ // TODO(#1171) Implement SessionPool session refresh
137+ // TODO(#1172) maintain desired SessionPool size
138+ ScheduleBackgroundWork (std::chrono::seconds (5 ));
92139}
93140
94141StatusOr<SessionHolder> SessionPool::Allocate (bool dissociate_from_pool) {
@@ -219,6 +266,7 @@ Status SessionPool::CreateSessions(
219266}
220267
221268void SessionPool::UpdateNextChannelForCreateSessions () {
269+ // `mu_` must be held by the caller.
222270 next_channel_for_create_sessions_ = channels_.begin ();
223271 for (auto it = channels_.begin (); it != channels_.end (); ++it) {
224272 if (it->session_count < next_channel_for_create_sessions_->session_count ) {
0 commit comments