Skip to content

Commit 9395e4c

Browse files
authored
Merge pull request pandas-dev#509 from manahl/issue-508
Issue pandas-dev#508 - List symbols returning deleted symbols
2 parents 17bae97 + c710fc0 commit 9395e4c

File tree

4 files changed

+65
-5
lines changed

4 files changed

+65
-5
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
### 1.61
44
* Feature: #288 Mapping reads and writes over chunks in chunkstore
5+
* Bugfix: #508 VersionStore: list_symbols and read now always returns latest version
56

67
### 1.60 (2018-2-13)
78
* Bugfix: #503 ChunkStore: speedup check for -1 segments

arctic/store/version_store.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def list_symbols(self, all_symbols=False, snapshot=None, regex=None, **kwargs):
149149
pipeline.append({'$match': query})
150150
pipeline.extend([
151151
# Id is by insert time which matches version order
152-
{'$sort': {'_id':-1}},
152+
{'$sort': bson.SON([('symbol', pymongo.DESCENDING), ('version', pymongo.DESCENDING)])},
153153
# Group by 'symbol'
154154
{'$group': {'_id': '$symbol',
155155
'deleted': {'$first': '$metadata.deleted'},
@@ -422,7 +422,7 @@ def _read_metadata(self, symbol, as_of=None, read_preference=None):
422422
as_of = as_of.replace(tzinfo=mktz())
423423
_version = versions_coll.find_one({'symbol': symbol,
424424
'_id': {'$lt': bson.ObjectId.from_datetime(as_of + timedelta(seconds=1))}},
425-
sort=[('_id', pymongo.DESCENDING)])
425+
sort=[('symbol', pymongo.DESCENDING), ('version', pymongo.DESCENDING)])
426426
else:
427427
# Backward compatibility - as of is a version number
428428
_version = versions_coll.find_one({'symbol': symbol, 'version': as_of})

tests/integration/store/test_version_store.py

+44-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import bson
22
import six
3+
import struct
34
from bson.son import SON
45
from datetime import datetime as dt, timedelta as dtd
56
import pandas as pd
@@ -8,7 +9,7 @@
89
from pymongo.read_preferences import ReadPreference
910
from pymongo.server_type import SERVER_TYPE
1011
from datetime import datetime
11-
from mock import patch
12+
from mock import Mock, patch
1213
import time
1314
import pytest
1415
import numpy as np
@@ -151,6 +152,28 @@ def test_read_metadata(library):
151152
assert after.data is None
152153

153154

155+
def test_read_metadata_newer_version_with_lower_id(library):
156+
now_timestamp = int(time.time())
157+
now = struct.pack(">i", now_timestamp)
158+
old_id = bson.ObjectId(now + b"\x00\x00\x00\x00\x00\x00\x00\x00")
159+
new_id = bson.ObjectId(now + b"\x00\x00\x00\x00\x00\x00\x00\x01")
160+
object_id_class = Mock()
161+
object_id_class.from_datetime = bson.ObjectId.from_datetime
162+
163+
object_id_class.return_value = new_id
164+
with patch("bson.ObjectId", object_id_class):
165+
library.write(symbol, ts1)
166+
167+
library.snapshot('s1')
168+
169+
object_id_class.return_value = old_id
170+
with patch("bson.ObjectId", object_id_class):
171+
library.write(symbol, ts2)
172+
173+
now_dt = datetime.fromtimestamp(now_timestamp)
174+
assert library.read_metadata(symbol, as_of=now_dt).version == 2
175+
176+
154177
def test_read_metadata_throws_on_deleted_symbol(library):
155178
library.write(symbol, ts1, metadata={'key': 'value'})
156179
library.delete(symbol)
@@ -948,6 +971,26 @@ def test_list_symbols_regex(library):
948971
assert library.list_symbols(b={'$gt': 5}, regex='asd') == ['asdf']
949972

950973

974+
def test_list_symbols_newer_version_with_lower_id(library):
975+
now = struct.pack(">i", int(time.time()))
976+
old_id = bson.ObjectId(now + b"\x00\x00\x00\x00\x00\x00\x00\x00")
977+
new_id = bson.ObjectId(now + b"\x00\x00\x00\x00\x00\x00\x00\x01")
978+
object_id_class = Mock()
979+
object_id_class.from_datetime = bson.ObjectId.from_datetime
980+
981+
object_id_class.return_value = new_id
982+
with patch("bson.ObjectId", object_id_class):
983+
library.write(symbol, ts1)
984+
985+
library.snapshot('s1')
986+
987+
object_id_class.return_value = old_id
988+
with patch("bson.ObjectId", object_id_class):
989+
library.delete(symbol)
990+
991+
assert symbol not in library.list_symbols()
992+
993+
951994
def test_date_range_large(library):
952995
index = [dt(2017,1,1)]*20000 + [dt(2017,1,2)]*20000
953996
data = np.random.random((40000, 10))

tests/unit/store/test_version_store.py

+18-2
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def test_read_as_of_LondonTime():
105105
versions = vs._versions.with_options.return_value
106106
versions.find_one.assert_called_once_with({'symbol':'symbol', '_id':
107107
{'$lt': bson.ObjectId.from_datetime(dt(2013, 4, 1, 9, 0, tzinfo=mktz()) + dtd(seconds=1))}},
108-
sort=[('_id', pymongo.DESCENDING)])
108+
sort=[('symbol', pymongo.DESCENDING), ('version', pymongo.DESCENDING)])
109109

110110

111111
def test_read_as_of_NotNaive():
@@ -116,7 +116,7 @@ def test_read_as_of_NotNaive():
116116
versions = vs._versions.with_options.return_value
117117
versions.find_one.assert_called_once_with({'symbol':'symbol', '_id':
118118
{'$lt': bson.ObjectId.from_datetime(dt(2013, 4, 1, 9, 0, tzinfo=mktz('Europe/Paris')) + dtd(seconds=1))}},
119-
sort=[('_id', pymongo.DESCENDING)])
119+
sort=[('symbol', pymongo.DESCENDING), ('version', pymongo.DESCENDING)])
120120

121121

122122
def test_read_metadata_no_asof():
@@ -238,6 +238,22 @@ def test_snapshot():
238238
call('foo', as_of=None, read_preference=ReadPreference.PRIMARY)])
239239

240240

241+
def test_list_symbols_default_pipeline():
242+
versions = Mock()
243+
vs = create_autospec(VersionStore, _versions=versions)
244+
versions.aggregate.return_value = []
245+
246+
VersionStore.list_symbols(vs)
247+
248+
pipeline = [
249+
{'$sort': bson.SON([('symbol', pymongo.DESCENDING), ('version', pymongo.DESCENDING)])},
250+
{'$group': {'_id': '$symbol', 'deleted': {'$first': '$metadata.deleted'}}},
251+
{'$match': {'deleted': {'$ne': True}}},
252+
{'$project': {'_id': 0, 'symbol': '$_id'}}
253+
]
254+
versions.aggregate.assert_called_once_with(pipeline)
255+
256+
241257
def test_snapshot_duplicate_raises_exception():
242258
vs = create_autospec(VersionStore, _snapshots=Mock())
243259
with pytest.raises(DuplicateSnapshotException) as e:

0 commit comments

Comments
 (0)