Skip to content

Commit 0c9f23b

Browse files
committed
Merge pull request pandas-dev#26 from manahl/bugfix/delete-assertion-must-read-from-master
Delete assertion must read from master
2 parents dfbaa0f + e20cc85 commit 0c9f23b

File tree

2 files changed

+57
-15
lines changed

2 files changed

+57
-15
lines changed

arctic/store/version_store.py

+26-5
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ def __str__(self):
105105

106106
def __repr__(self):
107107
return str(self)
108+
109+
def _read_preference(self, allow_secondary):
110+
""" Return the mongo read preference given an 'allow_secondary' argument
111+
"""
112+
allow_secondary = self._allow_secondary if allow_secondary is None else allow_secondary
113+
return ReadPreference.NEAREST if allow_secondary else ReadPreference.PRIMARY
108114

109115
@mongo_retry
110116
def list_symbols(self, all_symbols=False, snapshot=None, regex=None, **kwargs):
@@ -177,9 +183,15 @@ def has_symbol(self, symbol, as_of=None):
177183
----------
178184
symbol : `str`
179185
symbol name for the item
186+
as_of : `str` or int or `datetime.datetime`
187+
Return the data as it was as_of the point in time.
188+
`int` : specific version number
189+
`str` : snapshot name which contains the version
190+
`datetime.datetime` : the version of the data that existed as_of the requested point in time
180191
"""
181192
try:
182-
self._read_metadata(symbol, as_of=as_of)
193+
# Always use the primary for has_symbol, it's safer
194+
self._read_metadata(symbol, as_of=as_of, read_preference=ReadPreference.PRIMARY)
183195
return True
184196
except NoDataFoundException:
185197
return False
@@ -287,14 +299,18 @@ def read(self, symbol, as_of=None, from_version=None, allow_secondary=None, **kw
287299
`int` : specific version number
288300
`str` : snapshot name which contains the version
289301
`datetime.datetime` : the version of the data that existed as_of the requested point in time
302+
allow_secondary : `bool` or `None`
303+
Override the default behavior for allowing reads from secondary members of a cluster:
304+
`None` : use the settings from the top-level `Arctic` object used to query this version store.
305+
`True` : allow reads from secondary members
306+
`False` : only allow reads from primary members
290307
291308
Returns
292309
-------
293310
VersionedItem namedtuple which contains a .data and .metadata element
294311
"""
295-
allow_secondary = self._allow_secondary if allow_secondary is None else allow_secondary
296312
try:
297-
read_preference = ReadPreference.NEAREST if allow_secondary else ReadPreference.PRIMARY
313+
read_preference = self._read_preference(allow_secondary)
298314
_version = self._read_metadata(symbol, as_of=as_of, read_preference=read_preference)
299315
return self._do_read(symbol, _version, from_version, read_preference=read_preference, **kwargs)
300316
except (OperationFailure, AutoReconnect) as e:
@@ -347,7 +363,7 @@ def _do_read(self, symbol, version, from_version=None, **kwargs):
347363
_do_read_retry = mongo_retry(_do_read)
348364

349365
@mongo_retry
350-
def read_metadata(self, symbol, as_of=None):
366+
def read_metadata(self, symbol, as_of=None, allow_secondary=None):
351367
"""
352368
Return the metadata saved for a symbol. This method is fast as it doesn't
353369
actually load the data.
@@ -361,8 +377,13 @@ def read_metadata(self, symbol, as_of=None):
361377
`int` : specific version number
362378
`str` : snapshot name which contains the version
363379
`datetime.datetime` : the version of the data that existed as_of the requested point in time
380+
allow_secondary : `bool` or `None`
381+
Override the default behavior for allowing reads from secondary members of a cluster:
382+
`None` : use the settings from the top-level `Arctic` object used to query this version store.
383+
`True` : allow reads from secondary members
384+
`False` : only allow reads from primary members
364385
"""
365-
_version = self._read_metadata(symbol, as_of=as_of)
386+
_version = self._read_metadata(symbol, as_of=as_of, read_preference=self._read_preference(allow_secondary))
366387
return VersionedItem(symbol=symbol, library=self._arctic_lib.get_name(), version=_version['version'],
367388
metadata=_version.pop('metadata', None), data=None)
368389

tests/unit/store/test_version_store.py

+31-10
Original file line numberDiff line numberDiff line change
@@ -44,31 +44,52 @@ def test_list_versions_localTime():
4444
'snapshots': 'snap'}
4545

4646

47+
def test__read_preference__allow_secondary_true():
48+
self = create_autospec(VersionStore)
49+
assert VersionStore._read_preference(self, True) == ReadPreference.NEAREST
50+
51+
52+
def test__read_preference__allow_secondary_false():
53+
self = create_autospec(VersionStore)
54+
assert VersionStore._read_preference(self, False) == ReadPreference.PRIMARY
55+
56+
57+
def test__read_preference__default_true():
58+
self = create_autospec(VersionStore, _allow_secondary=True)
59+
assert VersionStore._read_preference(self, None) == ReadPreference.NEAREST
60+
61+
62+
def test__read_preference__default_false():
63+
self = create_autospec(VersionStore, _allow_secondary=False)
64+
assert VersionStore._read_preference(self, None) == ReadPreference.PRIMARY
65+
66+
4767
def test_get_version_allow_secondary_True():
4868
vs = create_autospec(VersionStore, instance=True,
4969
_versions=Mock())
50-
vs._allow_secondary = True
70+
vs._read_preference.return_value = sentinel.read_preference
5171
vs._find_snapshots.return_value = 'snap'
5272
vs._versions.find.return_value = [{'_id': bson.ObjectId.from_datetime(dt(2013, 4, 1, 9, 0)),
5373
'symbol': 's', 'version': 10}]
5474

5575
VersionStore.read(vs, "symbol")
56-
assert vs._read_metadata.call_args_list == [call('symbol', as_of=None, read_preference=ReadPreference.NEAREST)]
57-
assert vs._do_read.call_args_list == [call('symbol', vs._read_metadata.return_value, None, read_preference=ReadPreference.NEAREST)]
76+
assert vs._read_metadata.call_args_list == [call('symbol', as_of=None, read_preference=sentinel.read_preference)]
77+
assert vs._do_read.call_args_list == [call('symbol', vs._read_metadata.return_value, None, read_preference=sentinel.read_preference)]
5878

5979

6080
def test_get_version_allow_secondary_user_override_False():
6181
"""Ensure user can override read preference when calling read"""
6282
vs = create_autospec(VersionStore, instance=True,
6383
_versions=Mock())
64-
vs._allow_secondary = True
84+
vs._read_preference.return_value = sentinel.read_preference
6585
vs._find_snapshots.return_value = 'snap'
6686
vs._versions.find.return_value = [{'_id': bson.ObjectId.from_datetime(dt(2013, 4, 1, 9, 0)),
6787
'symbol': 's', 'version': 10}]
6888

6989
VersionStore.read(vs, "symbol", allow_secondary=False)
70-
assert vs._read_metadata.call_args_list == [call('symbol', as_of=None, read_preference=ReadPreference.PRIMARY)]
71-
assert vs._do_read.call_args_list == [call('symbol', vs._read_metadata.return_value, None, read_preference=ReadPreference.PRIMARY)]
90+
assert vs._read_metadata.call_args_list == [call('symbol', as_of=None, read_preference=sentinel.read_preference)]
91+
assert vs._do_read.call_args_list == [call('symbol', vs._read_metadata.return_value, None, read_preference=sentinel.read_preference)]
92+
vs._read_preference.assert_called_once_with(False)
7293

7394

7495
def test_read_as_of_LondonTime():
@@ -176,17 +197,17 @@ def test_prune_previous_versions_0_timeout():
176197

177198

178199
def test_read_handles_operation_failure():
179-
self = create_autospec(VersionStore, _versions=Mock(), _arctic_lib=Mock(),
180-
_allow_secondary=True)
200+
self = create_autospec(VersionStore, _versions=Mock(), _arctic_lib=Mock())
201+
self._read_preference.return_value = sentinel.read_preference
181202
self._collection = create_autospec(Collection)
182203
self._read_metadata.side_effect = [sentinel.meta1, sentinel.meta2]
183204
self._read_metadata.__name__ = 'name'
184205
self._do_read.__name__ = 'name' # feh: mongo_retry decorator cares about this
185206
self._do_read.side_effect = [OperationFailure('error'), sentinel.read]
186207
VersionStore.read(self, sentinel.symbol, sentinel.as_of, sentinel.from_version)
187-
# Assert that, for the two read calls, the second uses the new metadata
208+
# Assert that, for the two read calls, the second uses the new metadata and forces a read from primary
188209
assert self._do_read.call_args_list == [call(sentinel.symbol, sentinel.meta1, sentinel.from_version,
189-
read_preference=ReadPreference.NEAREST)]
210+
read_preference=sentinel.read_preference)]
190211
assert self._do_read_retry.call_args_list == [call(sentinel.symbol, sentinel.meta2, sentinel.from_version,
191212
read_preference=ReadPreference.PRIMARY)]
192213

0 commit comments

Comments
 (0)