~evarlast/ubuntu/utopic/mongodb/upstart-workaround-debian-bug-718702

« back to all changes in this revision

Viewing changes to src/mongo/s/balancer_policy.cpp

  • Committer: Package Import Robot
  • Author(s): James Page, James Page, Robie Basak
  • Date: 2013-05-29 17:44:42 UTC
  • mfrom: (44.1.7 sid)
  • Revision ID: package-import@ubuntu.com-20130529174442-z0a4qmoww4y0t458
Tags: 1:2.4.3-1ubuntu1
[ James Page ]
* Merge from Debian unstable, remaining changes:
  - Enable SSL support:
    + d/control: Add libssl-dev to BD's.
    + d/rules: Enabled --ssl option.
    + d/mongodb.conf: Add example SSL configuration options.
  - d/mongodb-server.mongodb.upstart: Add upstart configuration.
  - d/rules: Don't strip binaries during scons build for Ubuntu.
  - d/control: Add armhf to target archs.
  - d/p/SConscript.client.patch: fixup install of client libraries.
  - d/p/0010-install-libs-to-usr-lib-not-usr-lib64-Closes-588557.patch:
    Install libraries to lib not lib64.
* Dropped changes:
  - d/p/arm-support.patch: Included in Debian.
  - d/p/double-alignment.patch: Included in Debian.
  - d/rules,control: Debian also builds with avaliable system libraries
    now.
* Fix FTBFS due to gcc and boost upgrades in saucy:
  - d/p/0008-ignore-unused-local-typedefs.patch: Add -Wno-unused-typedefs
    to unbreak building with g++-4.8.
  - d/p/0009-boost-1.53.patch: Fixup signed/unsigned casting issue.

[ Robie Basak ]
* d/p/0011-Use-a-signed-char-to-store-BSONType-enumerations.patch: Fixup
  build failure on ARM due to missing signed'ness of char cast.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
// balancer_policy.cpp
2
 
 
3
2
/**
4
3
*    Copyright (C) 2010 10gen Inc.
5
4
*
31
30
        return str::stream() << min << " -->> " << max << "  on  " << tag;
32
31
    }
33
32
 
34
 
 
35
33
    DistributionStatus::DistributionStatus( const ShardInfoMap& shardInfo,
36
34
                                            const ShardToChunksMap& shardToChunksMap )
37
35
        : _shardInfo( shardInfo ), _shardChunks( shardToChunksMap ) {
38
 
        
 
36
 
39
37
        for ( ShardInfoMap::const_iterator i = _shardInfo.begin(); i != _shardInfo.end(); ++i ) {
40
38
            _shards.insert( i->first );
41
39
        }
 
40
    }
42
41
 
43
 
    }
44
 
        
45
42
    const ShardInfo& DistributionStatus::shardInfo( const string& shard ) const {
46
43
        ShardInfoMap::const_iterator i = _shardInfo.find( shard );
47
44
        verify( i != _shardInfo.end() );
50
47
 
51
48
    unsigned DistributionStatus::totalChunks() const {
52
49
        unsigned total = 0;
53
 
        for ( ShardToChunksMap::const_iterator i = _shardChunks.begin(); i != _shardChunks.end(); ++i ) 
 
50
        for ( ShardToChunksMap::const_iterator i = _shardChunks.begin(); i != _shardChunks.end(); ++i )
54
51
            total += i->second.size();
55
52
        return total;
56
53
    }
66
63
        ShardToChunksMap::const_iterator i = _shardChunks.find( shard );
67
64
        if ( i == _shardChunks.end() )
68
65
            return 0;
69
 
        
 
66
 
70
67
        unsigned total = 0;
71
 
        for ( unsigned j=0; j<i->second.size(); j++ ) 
 
68
        for ( unsigned j=0; j<i->second.size(); j++ )
72
69
            if ( tag == getTagForChunk( i->second[j] ) )
73
70
                total++;
74
71
 
78
75
    string DistributionStatus::getBestReceieverShard( const string& tag ) const {
79
76
        string best;
80
77
        unsigned minChunks = numeric_limits<unsigned>::max();
81
 
        
 
78
 
82
79
        for ( ShardInfoMap::const_iterator i = _shardInfo.begin(); i != _shardInfo.end(); ++i ) {
83
 
            
84
80
            if ( i->second.isSizeMaxed() || i->second.isDraining() || i->second.hasOpsQueued() ) {
85
81
                LOG(1) << i->first << " is unavailable" << endl;
86
82
                continue;
87
83
            }
88
 
            
 
84
 
89
85
            if ( ! i->second.hasTag( tag ) ) {
90
86
                LOG(1) << i->first << " doesn't have right tag" << endl;
91
87
                continue;
96
92
                LOG(1) << i->first << " has more chunks me:" << myChunks << " best: " << best << ":" << minChunks << endl;
97
93
                continue;
98
94
            }
99
 
            
 
95
 
100
96
            best = i->first;
101
97
            minChunks = myChunks;
102
98
        }
109
105
        unsigned maxChunks = 0;
110
106
 
111
107
        for ( ShardInfoMap::const_iterator i = _shardInfo.begin(); i != _shardInfo.end(); ++i ) {
112
 
            
 
108
 
113
109
            if ( i->second.hasOpsQueued() ) {
114
110
                // we can't move stuff off anyway
115
111
                continue;
116
112
            }
117
 
            
 
113
 
118
114
            unsigned myChunks = numberOfChunksInShardWithTag( i->first, tag );
119
115
            if ( myChunks <= maxChunks )
120
116
                continue;
121
 
            
 
117
 
122
118
            worst = i->first;
123
119
            maxChunks = myChunks;
124
120
        }
125
 
        
 
121
 
126
122
        return worst;
127
123
    }
128
 
    
129
124
 
130
 
    const vector<BSONObj>& DistributionStatus::getChunks( const string& shard ) const { 
 
125
    const vector<BSONObj>& DistributionStatus::getChunks( const string& shard ) const {
131
126
        ShardToChunksMap::const_iterator i = _shardChunks.find(shard);
132
127
        verify( i != _shardChunks.end() );
133
128
        return i->second;
135
130
 
136
131
    bool DistributionStatus::addTagRange( const TagRange& range ) {
137
132
        // first check for overlaps
138
 
        
139
133
        for ( map<BSONObj,TagRange>::const_iterator i = _tagRanges.begin();
140
 
              i != _tagRanges.end(); 
 
134
              i != _tagRanges.end();
141
135
              ++i ) {
142
136
            const TagRange& tocheck = i->second;
143
137
 
145
139
                LOG(1) << "have 2 ranges with the same min " << range << " " << tocheck << endl;
146
140
                return false;
147
141
            }
148
 
            
 
142
 
149
143
            if ( range.min < tocheck.min ) {
150
144
                if ( range.max > tocheck.min ) {
151
145
                    LOG(1) << "have overlapping ranges " << range << " " << tocheck << endl;
159
153
                    return false;
160
154
                }
161
155
            }
162
 
            
 
156
 
163
157
        }
164
158
 
165
159
        _tagRanges[range.max.getOwned()] = range;
172
166
        if ( _tagRanges.size() == 0 )
173
167
            return "";
174
168
 
175
 
        BSONObj min = chunk["min"].Obj();
 
169
        BSONObj min = chunk[ChunkType::min()].Obj();
176
170
 
177
171
        map<BSONObj,TagRange>::const_iterator i = _tagRanges.upper_bound( min );
178
172
        if ( i == _tagRanges.end() )
179
173
            return "";
180
 
        
 
174
 
181
175
        const TagRange& range = i->second;
182
176
        if ( min < range.min )
183
177
            return "";
184
 
        
 
178
 
185
179
        return range.tag;
186
180
    }
187
181
 
196
190
            for ( unsigned x = 0; x < v.size(); x++ )
197
191
                log() << "          " << v[x] << endl;
198
192
        }
199
 
        
 
193
 
200
194
        if ( _tagRanges.size() > 0 ) {
201
195
            log() << " tag ranges" << endl;
202
 
            
203
 
            for ( map<BSONObj,TagRange>::const_iterator i = _tagRanges.begin(); 
204
 
                  i != _tagRanges.end(); 
 
196
 
 
197
            for ( map<BSONObj,TagRange>::const_iterator i = _tagRanges.begin();
 
198
                  i != _tagRanges.end();
205
199
                  ++i )
206
200
                log() << i->second.toString() << endl;
207
201
        }
208
202
    }
209
203
 
 
204
    bool BalancerPolicy::_isJumbo( const BSONObj& chunk ) {
 
205
        if ( chunk[ChunkType::jumbo()].trueValue() ) {
 
206
            LOG(1) << "chunk: " << chunk << "is marked as jumbo" << endl;
 
207
            return true;
 
208
        }
 
209
        return false;
 
210
    }
210
211
    MigrateInfo* BalancerPolicy::balance( const string& ns,
211
 
                                          const DistributionStatus& distribution, 
 
212
                                          const DistributionStatus& distribution,
212
213
                                          int balancedLastTime ) {
213
214
 
214
215
 
216
217
        //    draining only
217
218
        // 2) check tag policy violations
218
219
        // 3) then we make sure chunks are balanced for each tag
219
 
        
 
220
 
220
221
        // ----
221
222
 
222
223
        // 1) check things we have to move
225
226
            for ( set<string>::const_iterator z = shards.begin(); z != shards.end(); ++z ) {
226
227
                string shard = *z;
227
228
                const ShardInfo& info = distribution.shardInfo( shard );
228
 
                
 
229
 
229
230
                if ( ! info.isDraining() )
230
231
                    continue;
231
 
                
 
232
 
232
233
                if ( distribution.numberOfChunksInShard( shard ) == 0 )
233
234
                    continue;
234
 
                
 
235
 
235
236
                // now we know we need to move to chunks off this shard
236
237
                // we will if we are allowed
237
 
                
 
238
 
238
239
                if ( info.hasOpsQueued() ) {
239
240
                    warning() << "want to shed load from " << shard << " but can't because it has ops queued" << endl;
240
241
                    continue;
241
242
                }
242
 
                
 
243
 
243
244
                const vector<BSONObj>& chunks = distribution.getChunks( shard );
244
 
            
 
245
                unsigned numJumboChunks = 0;
 
246
 
245
247
                // since we have to move all chunks, lets just do in order
246
248
                for ( unsigned i=0; i<chunks.size(); i++ ) {
247
249
                    BSONObj chunkToMove = chunks[i];
 
250
                    if ( _isJumbo( chunkToMove ) ) {
 
251
                        numJumboChunks++;
 
252
                        continue;
 
253
                    }
 
254
 
248
255
                    string tag = distribution.getTagForChunk( chunkToMove );
249
256
                    string to = distribution.getBestReceieverShard( tag );
250
 
                    
 
257
 
251
258
                    if ( to.size() == 0 ) {
252
259
                        warning() << "want to move chunk: " << chunkToMove << "(" << tag << ") "
253
260
                                  << "from " << shard << " but can't find anywhere to put it" << endl;
254
261
                        continue;
255
262
                    }
256
 
                
 
263
 
257
264
                    log() << "going to move " << chunkToMove << " from " << shard << "(" << tag << ")" << " to " << to << endl;
258
 
                
 
265
 
259
266
                    return new MigrateInfo( ns, to, shard, chunkToMove.getOwned() );
260
267
                }
261
 
                
262
 
                warning() << "can't find any chunk to move from: " << shard << " but we want to" << endl;
 
268
 
 
269
                warning() << "can't find any chunk to move from: " << shard
 
270
                          << " but we want to. "
 
271
                          << " numJumboChunks: " << numJumboChunks
 
272
                          << endl;
263
273
            }
264
274
        }
265
 
        
266
275
 
267
276
        // 2) tag violations
268
277
        if ( distribution.tags().size() > 0 ) {
269
278
            const set<string>& shards = distribution.shards();
270
 
            
 
279
 
271
280
            for ( set<string>::const_iterator i = shards.begin(); i != shards.end(); ++i ) {
272
281
                string shard = *i;
273
282
                const ShardInfo& info = distribution.shardInfo( shard );
274
 
                
 
283
 
275
284
                const vector<BSONObj>& chunks = distribution.getChunks( shard );
276
285
                for ( unsigned j = 0; j < chunks.size(); j++ ) {
277
286
                    string tag = distribution.getTagForChunk( chunks[j] );
278
 
                    
 
287
 
279
288
                    if ( info.hasTag( tag ) )
280
289
                        continue;
281
 
                    
 
290
 
282
291
                    // uh oh, this chunk is in the wrong place
283
 
                    log() << "chunk " << chunks[j] << " is not on a shard with the right tag: " << tag << endl;
284
 
                    
 
292
                    log() << "chunk " << chunks[j]
 
293
                          << " is not on a shard with the right tag: "
 
294
                          << tag << endl;
 
295
 
 
296
                    if ( _isJumbo( chunks[j] ) ) {
 
297
                        warning() << "chunk " << chunks[j] << " is jumbo, so cannot be moved" << endl;
 
298
                        continue;
 
299
                    }
 
300
 
285
301
                    string to = distribution.getBestReceieverShard( tag );
286
302
                    if ( to.size() == 0 ) {
287
303
                        log() << "no where to put it :(" << endl;
295
311
        }
296
312
 
297
313
        // 3) for each tag balance
298
 
        
 
314
 
299
315
        int threshold = 8;
300
 
        if ( balancedLastTime || distribution.totalChunks() < 20 ) 
 
316
        if ( balancedLastTime || distribution.totalChunks() < 20 )
301
317
            threshold = 2;
302
318
        else if ( distribution.totalChunks() < 80 )
303
319
            threshold = 4;
310
326
            for ( set<string>::const_iterator i = t.begin(); i != t.end(); ++i )
311
327
                tags.push_back( *i );
312
328
            tags.push_back( "" );
313
 
            
 
329
 
314
330
            std::random_shuffle( tags.begin(), tags.end() );
315
331
        }
316
332
 
330
346
                log() << "no available shards to take chunks for tag [" << tag << "]" << endl;
331
347
                return NULL;
332
348
            }
333
 
            
334
349
 
335
350
            unsigned min = distribution.numberOfChunksInShardWithTag( to, tag );
336
 
            
 
351
 
337
352
            const int imbalance = max - min;
338
 
            
 
353
 
339
354
            LOG(1) << "collection : " << ns << endl;
340
355
            LOG(1) << "donor      : " << from << " chunks on " << max << endl;
341
356
            LOG(1) << "receiver   : " << to << " chunks on " << min << endl;
345
360
                continue;
346
361
 
347
362
            const vector<BSONObj>& chunks = distribution.getChunks( from );
 
363
            unsigned numJumboChunks = 0;
348
364
            for ( unsigned j = 0; j < chunks.size(); j++ ) {
349
365
                if ( distribution.getTagForChunk( chunks[j] ) != tag )
350
366
                    continue;
351
 
                log() << " ns: " << ns << " going to move " << chunks[j] 
 
367
 
 
368
                if ( _isJumbo( chunks[j] ) ) {
 
369
                    numJumboChunks++;
 
370
                    continue;
 
371
                }
 
372
 
 
373
                log() << " ns: " << ns << " going to move " << chunks[j]
352
374
                      << " from: " << from << " to: " << to << " tag [" << tag << "]"
353
375
                      << endl;
354
376
                return new MigrateInfo( ns, to, from, chunks[j] );
355
377
            }
 
378
 
 
379
            if ( numJumboChunks ) {
 
380
                error() << "shard: " << from << "ns: " << ns
 
381
                        << "has too many chunks, but they are all jumbo "
 
382
                        << " numJumboChunks: " << numJumboChunks
 
383
                        << endl;
 
384
                continue;
 
385
            }
 
386
 
356
387
            verify( false ); // should be impossible
357
388
        }
358
389
 
359
 
        // Everything is balanced here!        
 
390
        // Everything is balanced here!
360
391
        return NULL;
361
392
    }
362
393
 
363
394
 
364
 
    ShardInfo::ShardInfo( long long maxSize, long long currSize, 
365
 
                          bool draining, bool opsQueued, 
366
 
                          const set<string>& tags )
367
 
        : _maxSize( maxSize ), 
 
395
    ShardInfo::ShardInfo( long long maxSize, long long currSize,
 
396
                          bool draining, bool opsQueued,
 
397
                          const set<string>& tags, 
 
398
                          const string& mongoVersion )
 
399
        : _maxSize( maxSize ),
368
400
          _currSize( currSize ),
369
401
          _draining( draining ),
370
402
          _hasOpsQueued( opsQueued ),
371
 
          _tags( tags ) {
 
403
          _tags( tags ),
 
404
          _mongoVersion( mongoVersion ) {
372
405
    }
373
406
 
374
407
    ShardInfo::ShardInfo()
375
 
        : _maxSize( 0 ), 
 
408
        : _maxSize( 0 ),
376
409
          _currSize( 0 ),
377
410
          _draining( false ),
378
411
          _hasOpsQueued( false ) {
386
419
    bool ShardInfo::isSizeMaxed() const {
387
420
        if ( _maxSize == 0 || _currSize == 0 )
388
421
            return false;
389
 
        
 
422
 
390
423
        return _currSize >= _maxSize;
391
424
    }
392
425
 
393
 
    bool ShardInfo::hasTag( const string& tag ) const { 
 
426
    bool ShardInfo::hasTag( const string& tag ) const {
394
427
        if ( tag.size() == 0 )
395
428
            return true;
396
 
        return _tags.count( tag ) > 0; 
 
429
        return _tags.count( tag ) > 0;
397
430
    }
398
431
 
399
432
    string ShardInfo::toString() const {
404
437
        ss << " hasOpsQueued: " << _hasOpsQueued;
405
438
        if ( _tags.size() > 0 ) {
406
439
            ss << "tags : ";
407
 
            for ( set<string>::const_iterator i = _tags.begin(); i != _tags.end(); ++i ) 
 
440
            for ( set<string>::const_iterator i = _tags.begin(); i != _tags.end(); ++i )
408
441
                ss << *i << ",";
409
442
        }
 
443
        ss << " version: " << _mongoVersion;
410
444
        return ss.str();
411
445
    }
412
446