// @file chunk.h
/**
* Copyright (C) 2008 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects
* for all of the code used other than as permitted herein. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you do not
* wish to do so, delete this exception statement from your version. If you
* delete this exception statement from all source files in the program,
* then also delete it in the license file.
*/
#pragma once
#include
#include "mongo/db/keypattern.h"
#include "mongo/platform/atomic_word.h"
#include "mongo/s/chunk_version.h"
#include "mongo/s/client/shard.h"
#include "mongo/s/shard_key_pattern.h"
#include "mongo/util/concurrency/ticketholder.h"
#include "mongo/util/debug_util.h"
#include "mongo/util/ptr.h"
namespace mongo {
class ChunkManager;
struct WriteConcernOptions;
/**
config.chunks
{ ns : "alleyinsider.fs.chunks" , min : {} , max : {} , server : "localhost:30001" }
x is in a shard iff
min <= x < max
*/
class Chunk {
MONGO_DISALLOW_COPYING(Chunk);
public:
enum SplitPointMode {
// Determines the split points that will make the current chunk smaller than
// the current chunk size setting. Gives empty result if chunk is not big enough.
normal,
// Will get a split which approximately splits the chunk into 2 halves,
// regardless of the size of the chunk.
atMedian,
// Behaves like normal, with additional special heuristics for "top chunks"
// (the 1 or 2 chunks in the extreme ends of the chunk key space).
autoSplitInternal
};
Chunk( const ChunkManager * info , BSONObj from);
Chunk( const ChunkManager * info ,
const BSONObj& min,
const BSONObj& max,
const Shard& shard,
ChunkVersion lastmod = ChunkVersion() );
//
// serialization support
//
void serialize(BSONObjBuilder& to, ChunkVersion myLastMod = ChunkVersion(0, 0, OID()));
//
// chunk boundary support
//
const BSONObj& getMin() const { return _min; }
const BSONObj& getMax() const { return _max; }
// Returns true if this chunk contains the given shard key, and false otherwise
//
// Note: this function takes an extracted *key*, not an original document
// (the point may be computed by, say, hashing a given field or projecting
// to a subset of fields).
bool containsKey( const BSONObj& shardKey ) const;
std::string genID() const;
static std::string genID( const std::string& ns , const BSONObj& min );
//
// chunk version support
//
void appendShortVersion( const char * name , BSONObjBuilder& b ) const;
ChunkVersion getLastmod() const { return _lastmod; }
void setLastmod( ChunkVersion v ) { _lastmod = v; }
//
// split support
//
long long getBytesWritten() const { return _dataWritten; }
// Const since _dataWritten is mutable and a heuristic
// TODO: Split data tracking and chunk information
void setBytesWritten(long long bytesWritten) const { _dataWritten = bytesWritten; }
/**
* if the amount of data written nears the max size of a shard
* then we check the real size, and if its too big, we split
* @return if something was split
*/
bool splitIfShould( long dataWritten ) const;
/**
* Splits this chunk at a non-specificed split key to be chosen by the mongod holding this chunk.
*
* @param mode
* @param res the object containing details about the split execution
* @param resultingSplits the number of resulting split points. Set to NULL to ignore.
*
* @throws UserException
*/
Status split(SplitPointMode mode,
size_t* resultingSplits,
BSONObj* res) const;
/**
* Splits this chunk at the given key (or keys)
*
* @param splitPoints the vector of keys that should be used to divide this chunk
* @param res the object containing details about the split execution
*
* @throws UserException
*/
Status multiSplit(const std::vector& splitPoints, BSONObj* res) const;
/**
* Asks the mongod holding this chunk to find a key that approximately divides this chunk in two
*
* @param medianKey the key that divides this chunk, if there is one, or empty
*/
void pickMedianKey( BSONObj& medianKey ) const;
/**
* @param splitPoints vector to be filled in
* @param chunkSize chunk size to target in bytes
* @param maxPoints limits the number of split points that are needed, zero is max (optional)
* @param maxObjs limits the number of objects in each chunk, zero is as max (optional)
*/
void pickSplitVector(std::vector& splitPoints,
long long chunkSize,
int maxPoints = 0,
int maxObjs = 0) const;
//
// migration support
//
/**
* Issues a migrate request for this chunk
*
* @param to shard to move this chunk to
* @param chunSize maximum number of bytes beyond which the migrate should no go trhough
* @param writeConcern detailed write concern. NULL means the default write concern.
* @param waitForDelete whether chunk move should wait for cleanup or return immediately
* @param maxTimeMS max time for the migrate request
* @param res the object containing details about the migrate execution
* @return true if move was successful
*/
bool moveAndCommit(const Shard& to,
long long chunkSize,
const WriteConcernOptions* writeConcern,
bool waitForDelete,
int maxTimeMS,
BSONObj& res) const;
/**
* @return size of shard in bytes
* talks to mongod to do this
*/
long getPhysicalSize() const;
/**
* marks this chunk as a jumbo chunk
* that means the chunk will be inelligble for migrates
*/
void markAsJumbo() const;
bool isJumbo() const { return _jumbo; }
/**
* Attempt to refresh maximum chunk size from config.
*/
static void refreshChunkSize();
/**
* sets MaxChunkSize
* 1 <= newMaxChunkSize <= 1024
* @return true if newMaxChunkSize is valid and was set
*/
static bool setMaxChunkSizeSizeMB( int newMaxChunkSize );
//
// public constants
//
static long long MaxChunkSize;
static int MaxObjectPerChunk;
static bool ShouldAutoSplit;
//
// accessors and helpers
//
std::string toString() const;
friend std::ostream& operator << (std::ostream& out, const Chunk& c) { return (out << c.toString()); }
// chunk equality is determined by comparing the min and max bounds of the chunk
bool operator==(const Chunk& s) const;
bool operator!=(const Chunk& s) const { return ! ( *this == s ); }
std::string getns() const;
Shard getShard() const { return _shard; }
const ChunkManager* getManager() const { return _manager; }
private:
// if min/max key is pos/neg infinity
bool _minIsInf() const;
bool _maxIsInf() const;
// The chunk manager, which owns this chunk. Not owned by the chunk.
const ChunkManager* _manager;
BSONObj _min;
BSONObj _max;
Shard _shard;
ChunkVersion _lastmod;
mutable bool _jumbo;
// transient stuff
mutable long long _dataWritten;
// methods, etc..
/**
* Returns the split point that will result in one of the chunk having exactly one
* document. Also returns an empty document if the split point cannot be determined.
*
* @param doSplitAtLower determines which side of the split will have exactly one document.
* True means that the split point chosen will be closer to the lower bound.
*
* Warning: this assumes that the shard key is not "special"- that is, the shardKeyPattern
* is simply an ordered list of ascending/descending field names. Examples:
* {a : 1, b : -1} is not special. {a : "hashed"} is.
*/
BSONObj _getExtremeKey(bool doSplitAtLower) const;
/**
* Determines the appropriate split points for this chunk.
*
* @param atMedian perform a single split at the middle of this chunk.
* @param splitPoints out parameter containing the chosen split points. Can be empty.
*/
void determineSplitPoints(bool atMedian, std::vector* splitPoints) const;
/** initializes _dataWritten with a random value so that a mongos restart wouldn't cause delay in splitting */
static int mkDataWritten();
};
typedef boost::shared_ptr ChunkPtr;
} // namespace mongo