Skip to content

Commit c29fd6d

Browse files
authored
Merge pull request #3042 from tseaver/3011-spanner-heappush-timestamp-race
Ensure that 'Session' instances are orderable.
2 parents 3e0b105 + 93b681f commit c29fd6d

File tree

3 files changed

+44
-0
lines changed

3 files changed

+44
-0
lines changed

spanner/google/cloud/spanner/session.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
"""Wrapper for Cloud Spanner Session objects."""
1616

17+
from functools import total_ordering
1718
import time
1819

1920
from google.gax.errors import GaxError
@@ -34,6 +35,7 @@
3435
"""Default timeout used by :meth:`Session.run_in_transaction`."""
3536

3637

38+
@total_ordering
3739
class Session(object):
3840
"""Representation of a Cloud Spanner Session.
3941
@@ -53,6 +55,9 @@ class Session(object):
5355
def __init__(self, database):
5456
self._database = database
5557

58+
def __lt__(self, other):
59+
return self._session_id < other._session_id
60+
5661
@property
5762
def session_id(self):
5863
"""Read-only ID, set by the back-end during :meth:`create`."""

spanner/unit_tests/test_pool.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# limitations under the License.
1414

1515

16+
from functools import total_ordering
1617
import unittest
1718

1819

@@ -597,6 +598,32 @@ def test_bind(self):
597598

598599
self.assertTrue(pool._pending_sessions.empty())
599600

601+
def test_bind_w_timestamp_race(self):
602+
import datetime
603+
from google.cloud._testing import _Monkey
604+
from google.cloud.spanner import pool as MUT
605+
NOW = datetime.datetime.utcnow()
606+
pool = self._make_one()
607+
database = _Database('name')
608+
SESSIONS = [_Session(database) for _ in range(10)]
609+
database._sessions.extend(SESSIONS)
610+
611+
with _Monkey(MUT, _NOW=lambda: NOW):
612+
pool.bind(database)
613+
614+
self.assertIs(pool._database, database)
615+
self.assertEqual(pool.size, 10)
616+
self.assertEqual(pool.default_timeout, 10)
617+
self.assertEqual(pool._delta.seconds, 3000)
618+
self.assertTrue(pool._sessions.full())
619+
620+
for session in SESSIONS:
621+
self.assertTrue(session._created)
622+
txn = session._transaction
623+
self.assertTrue(txn._begun)
624+
625+
self.assertTrue(pool._pending_sessions.empty())
626+
600627
def test_put_full(self):
601628
from six.moves.queue import Full
602629

@@ -755,6 +782,7 @@ def committed(self):
755782
return self._committed
756783

757784

785+
@total_ordering
758786
class _Session(object):
759787

760788
_transaction = None
@@ -767,6 +795,9 @@ def __init__(self, database, exists=True, transaction=None):
767795
self._deleted = False
768796
self._transaction = transaction
769797

798+
def __lt__(self, other):
799+
return id(self) < id(other)
800+
770801
def create(self):
771802
self._created = True
772803

spanner/unit_tests/test_session.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ def test_constructor(self):
4242
self.assertTrue(session.session_id is None)
4343
self.assertTrue(session._database is database)
4444

45+
def test___lt___(self):
46+
database = _Database(self.DATABASE_NAME)
47+
lhs = self._make_one(database)
48+
lhs._session_id = b'123'
49+
rhs = self._make_one(database)
50+
rhs._session_id = b'234'
51+
self.assertTrue(lhs < rhs)
52+
4553
def test_name_property_wo_session_id(self):
4654
database = _Database(self.DATABASE_NAME)
4755
session = self._make_one(database)

0 commit comments

Comments
 (0)