Skip to content

Commit f9d7cda

Browse files
author
Alberto Lerner
committed
ChunkMatcher now has per-chunk boundaries
1 parent 53f4dce commit f9d7cda

File tree

9 files changed

+123
-91
lines changed

9 files changed

+123
-91
lines changed

db/query.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ namespace mongo {
629629
_oldN(0),
630630
_nYields(),
631631
_nChunkSkips(),
632-
_chunkMatcher(shardingState.getChunkMatcher(pq.ns())),
632+
_chunkMatcher( shardingState.needChunkMatcher(pq.ns()) ? shardingState.getChunkMatcher(pq.ns()) : ChunkMatcherPtr() ),
633633
_inMemSort(false),
634634
_capped(false),
635635
_saveClientCursor(false),
@@ -749,7 +749,7 @@ namespace mongo {
749749
DiskLoc cl = _c->currLoc();
750750
if ( _chunkMatcher && ! _chunkMatcher->belongsToMe( cl.obj() ) ){
751751
_nChunkSkips++;
752-
// cout << "TEMP skipping un-owned chunk: " << _c->current() << endl;
752+
// log() << "TEMP skipping un-owned chunk: " << _c->current() << endl;
753753
}
754754
else if( _c->getsetdup(cl) ) {
755755
// dup

jstests/sharding/version1.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
s = new ShardingTest( "version1" , 1 , 2 )
44

5+
s.adminCommand( { enablesharding : "alleyinsider" } );
6+
s.adminCommand( { shardcollection : "alleyinsider.foo" , key : { num : 1 } } );
7+
58
a = s._connections[0].getDB( "admin" );
69

710
assert( a.runCommand( { "setShardVersion" : "alleyinsider.foo" , configdb : s._configDB } ).ok == 0 );

jstests/sharding/version2.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
s = new ShardingTest( "version2" , 1 , 2 )
44

5+
s.adminCommand( { enablesharding : "alleyinsider" } );
6+
s.adminCommand( { shardcollection : "alleyinsider.foo" , key : { num : 1 } } );
7+
s.adminCommand( { shardcollection : "alleyinsider.bar" , key : { num : 1 } } );
8+
59
a = s._connections[0].getDB( "admin" );
610

711
// setup from one client

s/chunk.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ namespace mongo {
103103

104104
q.sort( r.obj() );
105105
}
106-
106+
107107
// find the extreme key
108108
BSONObj end = conn->findOne( _manager->getns() , q );
109109
conn.done();

s/d_chunk_matcher.cpp

Lines changed: 79 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,34 +17,102 @@
1717
*/
1818

1919
#include "pch.h"
20+
21+
#include "../client/connpool.h"
22+
#include "../db/instance.h"
23+
2024
#include "d_chunk_matcher.h"
2125

2226
namespace mongo {
2327

24-
ChunkMatcher::ChunkMatcher( ShardChunkVersion version , const BSONObj& key ) : _version( version ) {
28+
ChunkMatcher::ChunkMatcher( const string& configServer , const string& ns , const string& shardName ) {
29+
30+
// have to get a connection to the config db
31+
// special case if i'm the configdb since i'm locked and if i connect to myself
32+
// its a deadlock
33+
auto_ptr<ScopedDbConnection> scoped;
34+
auto_ptr<DBDirectClient> direct;
35+
DBClientBase * conn;
36+
if ( configServer.empty() ){
37+
direct.reset( new DBDirectClient() );
38+
conn = direct.get();
39+
} else {
40+
scoped.reset( new ScopedDbConnection( configServer ) );
41+
conn = scoped->get();
42+
}
43+
44+
// get this collection's key
45+
BSONObj collection = conn->findOne( "config.collections", BSON( "_id" << ns ) );
46+
assert( ! collection["key"].eoo() && collection["key"].isABSONObj() );
47+
BSONObj key = collection["key"].Obj().getOwned();
2548
BSONObjBuilder b;
2649
BSONForEach( e , key ) {
2750
b.append( e.fieldName() , 1 );
2851
}
2952
_key = b.obj();
30-
}
3153

32-
void ChunkMatcher::addChunk( const BSONObj& min , const BSONObj& max ) {
33-
_chunksMap[min] == make_pair( min , max );
34-
}
54+
// actually query all the chunks for 'ns' that live in this shard, sorting so we can efficiently bucket them
55+
BSONObj q;
56+
{
57+
BSONObjBuilder b;
58+
b.append( "ns" , ns.c_str() );
59+
b.append( "shard" , shardName );
60+
q = b.obj();
61+
}
62+
auto_ptr<DBClientCursor> cursor = conn->query( "config.chunks" , Query(q).sort( "min" ) );
63+
64+
assert( cursor.get() );
65+
if ( ! cursor->more() ){
66+
log() << "No chunks for collection " << ns << " on shard " << shardName << endl;
67+
if ( scoped.get() )
68+
scoped->done();
69+
70+
return;
71+
}
3572

36-
void ChunkMatcher::addRange( const BSONObj& min , const BSONObj& max ){
37-
//TODO debug mode only?
38-
assert(min.nFields() == _key.nFields());
39-
assert(max.nFields() == _key.nFields());
73+
// load the tablet information, coallesceing the ranges
74+
// the version for this shard would be the highest version for any of the chunks
75+
ShardChunkVersion version;
76+
BSONObj min,max;
77+
while ( cursor->more() ){
78+
BSONObj d = cursor->next();
4079

41-
_rangesMap[min] = make_pair(min,max);
80+
_chunksMap[min] == make_pair( d["min"].Obj().getOwned() , d["max"].Obj().getOwned() );
81+
82+
ShardChunkVersion currVersion( d["lastmod"] );
83+
if ( currVersion > version ) {
84+
version = currVersion;
85+
}
86+
87+
// coallesce the chunk's bounds in ranges if they are adjacent chunks
88+
if ( min.isEmpty() ){
89+
min = d["min"].Obj().getOwned();
90+
max = d["max"].Obj().getOwned();
91+
continue;
92+
}
93+
if ( max == d["min"].Obj() ){
94+
max = d["max"].Obj().getOwned();
95+
continue;
96+
}
97+
98+
_rangesMap[min] = make_pair( min.getOwned() , max.getOwned() );
99+
100+
min = d["min"].Obj().getOwned();
101+
max = d["max"].Obj().getOwned();
102+
}
103+
assert( ! min.isEmpty() );
104+
105+
_rangesMap[min] = make_pair( min.getOwned() , max.getOwned() );
106+
_version = version;
107+
108+
if ( scoped.get() )
109+
scoped->done();
42110
}
43111

44112
bool ChunkMatcher::belongsToMe( const BSONObj& obj ) const {
45113
if ( _rangesMap.size() == 0 )
46114
return false;
47-
115+
48116
BSONObj x = obj.extractFields(_key);
49117

50118
RangeMap::const_iterator a = _rangesMap.upper_bound( x );

s/d_chunk_matcher.h

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,29 @@
2424

2525
namespace mongo {
2626

27+
/**
28+
* Controls the boundaries of all the chunks for a given collection that live in this shard.
29+
*/
2730
class ChunkMatcher {
2831
public:
29-
ChunkMatcher( ShardChunkVersion version , const BSONObj& key );
32+
33+
/**
34+
* Loads the ChunkMatcher with all boundaries for chunks of a given collection that live in an given
35+
* shard
36+
*
37+
* @param configServer name of the server where the configDB currently is. Can be empty to indicate
38+
* that the configDB is running locally
39+
* @param ns namespace for the collections whose chunks we're interested
40+
* @param shardName name of the shard that this chunk matcher should track
41+
*
42+
* This constructor throws on connectivity errors
43+
*/
44+
ChunkMatcher( const string& configServer , const string& ns , const string& shardName );
45+
3046
~ChunkMatcher() {}
3147

3248
bool belongsToMe( const BSONObj& obj ) const;
3349

34-
void addRange( const BSONObj& min , const BSONObj& max );
35-
void addChunk( const BSONObj& min , const BSONObj& max );
36-
3750
//void splitChunk( const BSONObj& min , const BSONObj& max , const BSONObj& middle );
3851
//void removeChunk( const BSONObj& min , const BSONObj& max );
3952

@@ -43,7 +56,7 @@ namespace mongo {
4356

4457
private:
4558
// highest ShardChunkVersion for which this ChunkMatcher's information is accurate
46-
const ShardChunkVersion _version;
59+
ShardChunkVersion _version;
4760

4861
// key pattern for chunks under this range
4962
BSONObj _key;

s/d_logic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ namespace mongo {
5252

5353
void appendInfo( BSONObjBuilder& b );
5454

55+
bool needChunkMatcher( const string& ns ) const;
5556
ChunkMatcherPtr getChunkMatcher( const string& ns );
5657

5758
bool inCriticalMigrateSection();

s/d_split.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ namespace mongo {
335335
// 4MB work of 'result' size. This should be okay for now.
336336

337337
result.append( "splitKeys" , splitKeys );
338+
338339
return true;
339340

340341
}

s/d_state.cpp

Lines changed: 14 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -167,13 +167,17 @@ namespace mongo {
167167

168168
}
169169

170-
ChunkMatcherPtr ShardingState::getChunkMatcher( const string& ns ){
170+
bool ShardingState::needChunkMatcher( const string& ns ) const {
171171
if ( ! _enabled )
172-
return ChunkMatcherPtr();
172+
return false;
173173

174174
if ( ! ShardedConnectionInfo::get( false ) )
175-
return ChunkMatcherPtr();
176-
175+
return false;
176+
177+
return true;
178+
}
179+
180+
ChunkMatcherPtr ShardingState::getChunkMatcher( const string& ns ){
177181
ConfigVersion version;
178182
{
179183
// check cache
@@ -193,75 +197,13 @@ namespace mongo {
193197
}
194198
}
195199

196-
// have to get a connection to the config db
197-
// special case if i'm the configdb since i'm locked and if i connect to myself
198-
// its a deadlock
199-
auto_ptr<ScopedDbConnection> scoped;
200-
auto_ptr<DBDirectClient> direct;
201-
202-
DBClientBase * conn;
203-
204-
if ( _configServer == _shardHost ){
205-
direct.reset( new DBDirectClient() );
206-
conn = direct.get();
207-
}
208-
else {
209-
scoped.reset( new ScopedDbConnection( _configServer ) );
210-
conn = scoped->get();
211-
}
212-
213-
// actually query all the chunks for 'ns' that live in this shard
214-
// sorting so we can efficiently bucket them
215-
BSONObj q;
216-
{
217-
BSONObjBuilder b;
218-
b.append( "ns" , ns.c_str() );
219-
b.append( "shard" , BSON( "$in" << BSON_ARRAY( _shardHost << _shardName ) ) );
220-
q = b.obj();
221-
}
222-
auto_ptr<DBClientCursor> cursor = conn->query( "config.chunks" , Query(q).sort( "min" ) );
223-
224-
assert( cursor.get() );
225-
if ( ! cursor->more() ){
226-
// TODO: should we update the local version or cache this result?
227-
if ( scoped.get() )
228-
scoped->done();
229-
return ChunkMatcherPtr();
230-
}
231-
232-
BSONObj collection = conn->findOne( "config.collections", BSON( "_id" << ns ) );
233-
assert( ! collection["key"].eoo() && collection["key"].isABSONObj() );
234-
ChunkMatcherPtr p( new ChunkMatcher( version , collection["key"].Obj().getOwned() ) );
235-
236-
BSONObj min,max;
237-
while ( cursor->more() ){
238-
BSONObj d = cursor->next();
239-
p->addChunk( d["min"].Obj().getOwned() , d["max"].Obj().getOwned() );
240-
241-
// coallesce the chunk's bounds in ranges if there are adjacent chunks
242-
if ( min.isEmpty() ){
243-
min = d["min"].Obj().getOwned();
244-
max = d["max"].Obj().getOwned();
245-
continue;
246-
}
247-
248-
// chunk is adjacent to last chunk
249-
if ( max == d["min"].Obj() ){
250-
max = d["max"].Obj().getOwned();
251-
continue;
252-
}
253-
254-
// discontinuity; register range and reset min/max
255-
p->addRange( min.getOwned() , max.getOwned() );
256-
min = d["min"].Obj().getOwned();
257-
max = d["max"].Obj().getOwned();
258-
}
259-
assert( ! min.isEmpty() );
260-
p->addRange( min.getOwned() , max.getOwned() );
261-
262-
if ( scoped.get() )
263-
scoped->done();
200+
// load the chunk information for this shard from the config database
201+
// a reminder: ChunkMatcher may throw on construction
202+
const string c = (_configServer == _shardHost) ? "" /* local */ : _configServer;
203+
ChunkMatcherPtr p( new ChunkMatcher( c , ns , _shardName ) );
264204

205+
// TODO 11-18-2010 verify that the version in _versions is compatible with _checks[ns]
206+
// Eventually, the version that will be authoritative is the ChunkMatcher's
265207
{
266208
scoped_lock lk( _mutex );
267209
_chunks[ns] = p;

0 commit comments

Comments
 (0)