assert_util.h   assert_util.h 
skipping to change at line 93 skipping to change at line 93
AssertionException() { code = 0; } AssertionException() { code = 0; }
virtual ~AssertionException() throw() { } virtual ~AssertionException() throw() { }
virtual bool severe() { virtual bool severe() {
return true; return true;
} }
virtual bool isUserAssertion() { virtual bool isUserAssertion() {
return false; return false;
} }
virtual int getCode(){ return code; } virtual int getCode(){ return code; }
virtual const char* what() const throw() { return msg.c_str(); } virtual const char* what() const throw() { return msg.c_str(); }
/* true if an interrupted exception - see KillCurrentOp */
bool interrupted() {
return code == 11600 || code == 11601;
}
}; };
/* UserExceptions are valid errors that a user can cause, like out of d isk space or duplicate key */ /* UserExceptions are valid errors that a user can cause, like out of d isk space or duplicate key */
class UserException : public AssertionException { class UserException : public AssertionException {
public: public:
UserException(int c , const string& m) { UserException(int c , const string& m) {
code = c; code = c;
msg = m; msg = m;
} }
virtual bool severe() { virtual bool severe() {
skipping to change at line 175 skipping to change at line 180
#define dassert(x) #define dassert(x)
#endif #endif
// some special ids that we want to duplicate // some special ids that we want to duplicate
// > 10000 asserts // > 10000 asserts
// < 10000 UserException // < 10000 UserException
#define ASSERT_ID_DUPKEY 11000 #define ASSERT_ID_DUPKEY 11000
void streamNotGood( int code , string msg , std::ios& myios );
#define ASSERT_STREAM_GOOD(msgid,msg,stream) (void)( (!!((stream).good()))
|| (mongo::streamNotGood(msgid, msg, stream), 0) )
} // namespace mongo } // namespace mongo
#define BOOST_CHECK_EXCEPTION( expression ) \ #define BOOST_CHECK_EXCEPTION( expression ) \
try { \ try { \
expression; \ expression; \
} catch ( const std::exception &e ) { \ } catch ( const std::exception &e ) { \
problem() << "caught boost exception: " << e.what() << endl; \ problem() << "caught boost exception: " << e.what() << endl; \
assert( false ); \ assert( false ); \
} catch ( ... ) { \ } catch ( ... ) { \
massert( 10437 , "unknown boost failed" , false ); \ massert( 10437 , "unknown boost failed" , false ); \
} }
#define DESTRUCTOR_GUARD( expression ) \
try { \
expression; \
} catch ( const std::exception &e ) { \
problem() << "caught exception (" << e.what() << ") in destructor (
" << __FUNCTION__ << ")" << endl; \
} catch ( ... ) { \
problem() << "caught unknown exception in destructor (" << __FUNCTI
ON__ << ")" << endl; \
}
 End of changes. 3 change blocks. 
0 lines changed or deleted 10 lines changed or added


 background.h   background.h 
// background.h /**
* Copyright (C) 2010 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 Licen
se
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Copyright 2009 10gen Inc. /* background.h
*
* Licensed under the Apache License, Version 2.0 (the "License"); Concurrency coordination for administrative operations.
* you may not use this file except in compliance with the License. */
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli
ed.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once #pragma once
namespace mongo { namespace mongo {
/* object-orienty background thread dispatching. /* these are administrative operations / jobs
for a namespace running in the background, and that only one
subclass and define run() at a time per namespace is permitted, and that if in progress,
you aren't allowed to do other NamespaceDetails major manipulations
(such as dropping ns or db) even in the foreground and must
instead uassert.
It is ok to call go() more than once -- if the previous invocation It's assumed this is not for super-high RPS things, so we don't do
has finished. Thus one pattern of use is to embed a backgroundjob anything special in the implementation here to be fast.
in your object and reuse it (or same thing with inheritance).
*/ */
class BackgroundOperation : public boost::noncopyable {
class BackgroundJob {
protected:
/* define this to do your work! */
virtual void run() = 0;
public: public:
enum State { static bool inProgForDb(const char *db);
NotStarted, static bool inProgForNs(const char *ns);
Running, static void assertNoBgOpInProgForDb(const char *db);
Done static void assertNoBgOpInProgForNs(const char *ns);
}; static void dump(stringstream&);
State getState() const {
return state;
}
bool running() const {
return state == Running;
}
bool deleteSelf; // delete self when Done?
BackgroundJob() {
deleteSelf = false;
state = NotStarted;
}
virtual ~BackgroundJob() { }
// start job. returns before it's finished. /* check for in progress before instantiating */
BackgroundJob& go(); BackgroundOperation(const char *ns);
// wait for completion. this spins with sleep() so not terribly ef virtual ~BackgroundOperation();
ficient.
// returns true if did not time out.
//
// note you can call wait() more than once if the first call times
out.
bool wait(int msMax = 0);
private: private:
static BackgroundJob *grab; NamespaceString _ns;
static boost::mutex &mutex; static map<string, unsigned> dbsInProg;
static void thr(); static set<string> nsInProg;
volatile State state;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 9 change blocks. 
60 lines changed or deleted 41 lines changed or added


 btree.h   btree.h 
skipping to change at line 23 skipping to change at line 23
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "../stdafx.h" #include "../stdafx.h"
#include "jsobj.h" #include "jsobj.h"
#include "storage.h" #include "diskloc.h"
#include "pdfile.h" #include "pdfile.h"
namespace mongo { namespace mongo {
#pragma pack(1) #pragma pack(1)
struct _KeyNode { struct _KeyNode {
DiskLoc prevChildBucket; DiskLoc prevChildBucket; // the lchild
DiskLoc recordLoc; DiskLoc recordLoc; // location of the record associated with the ke
y
short keyDataOfs() const { short keyDataOfs() const {
return (short) _kdo; return (short) _kdo;
} }
unsigned short _kdo; unsigned short _kdo;
void setKeyDataOfs(short s) { void setKeyDataOfs(short s) {
_kdo = s; _kdo = s;
assert(s>=0); assert(s>=0);
} }
void setKeyDataOfsSavingUse(short s) { void setKeyDataOfsSavingUse(short s) {
_kdo = s; _kdo = s;
skipping to change at line 91 skipping to change at line 91
friend class BtreeBuilder; friend class BtreeBuilder;
friend class KeyNode; friend class KeyNode;
public: public:
void dumpTree(DiskLoc thisLoc, const BSONObj &order); void dumpTree(DiskLoc thisLoc, const BSONObj &order);
bool isHead() { return parent.isNull(); } bool isHead() { return parent.isNull(); }
void assertValid(const BSONObj &order, bool force = false); void assertValid(const BSONObj &order, bool force = false);
int fullValidate(const DiskLoc& thisLoc, const BSONObj &order); /* traverses everything */ int fullValidate(const DiskLoc& thisLoc, const BSONObj &order); /* traverses everything */
protected: protected:
void modified(const DiskLoc& thisLoc); void modified(const DiskLoc& thisLoc);
KeyNode keyNode(int i) const { KeyNode keyNode(int i) const {
assert( i < n ); if ( i >= n ){
massert( 13000 , (string)"invalid keyNode: " + BSON( "i" <
< i << "n" << n ).jsonString() , i < n );
}
return KeyNode(*this, k(i)); return KeyNode(*this, k(i));
} }
char * dataAt(short ofs) { char * dataAt(short ofs) {
return data + ofs; return data + ofs;
} }
void init(); // initialize a new node void init(); // initialize a new node
/* returns false if node is full and must be split /* returns false if node is full and must be split
skipping to change at line 187 skipping to change at line 189
void dump(); void dump();
/* @return true if key exists in index /* @return true if key exists in index
order - indicates order of keys in the index. this is basically the index's key pattern, e.g.: order - indicates order of keys in the index. this is basically the index's key pattern, e.g.:
BSONObj order = ((IndexDetails&)idx).keyPattern(); BSONObj order = ((IndexDetails&)idx).keyPattern();
likewise below in bt_insert() etc. likewise below in bt_insert() etc.
*/ */
bool exists(const IndexDetails& idx, DiskLoc thisLoc, const BSONObj & key, BSONObj order); bool exists(const IndexDetails& idx, DiskLoc thisLoc, const BSONObj & key, BSONObj order);
bool wouldCreateDup(
const IndexDetails& idx, DiskLoc thisLoc,
const BSONObj& key, BSONObj order,
DiskLoc self);
static DiskLoc addBucket(IndexDetails&); /* start a new index off, empty */ static DiskLoc addBucket(IndexDetails&); /* start a new index off, empty */
void deallocBucket(const DiskLoc &thisLoc); // clear bucket memory, placeholder for deallocation
static void renameIndexNamespace(const char *oldNs, const char *new Ns); static void renameIndexNamespace(const char *oldNs, const char *new Ns);
int bt_insert(DiskLoc thisLoc, DiskLoc recordLoc, int bt_insert(DiskLoc thisLoc, DiskLoc recordLoc,
const BSONObj& key, const BSONObj &order, bool dupsAllow ed, const BSONObj& key, const BSONObj &order, bool dupsAllow ed,
IndexDetails& idx, bool toplevel = true); IndexDetails& idx, bool toplevel = true);
bool unindex(const DiskLoc& thisLoc, IndexDetails& id, BSONObj& key , const DiskLoc& recordLoc); bool unindex(const DiskLoc& thisLoc, IndexDetails& id, BSONObj& key , const DiskLoc& recordLoc);
/* locate may return an "unused" key that is just a marker. so be careful. /* locate may return an "unused" key that is just a marker. so be careful.
skipping to change at line 372 skipping to change at line 380
DiskLoc locAtKeyOfs; DiskLoc locAtKeyOfs;
BoundList bounds_; BoundList bounds_;
unsigned boundIndex_; unsigned boundIndex_;
}; };
#pragma pack() #pragma pack()
inline bool IndexDetails::hasKey(const BSONObj& key) { inline bool IndexDetails::hasKey(const BSONObj& key) {
return head.btree()->exists(*this, head, key, keyPattern()); return head.btree()->exists(*this, head, key, keyPattern());
} }
inline bool IndexDetails::wouldCreateDup(const BSONObj& key, DiskLoc se
lf) {
return head.btree()->wouldCreateDup(*this, head, key, keyPattern(),
self);
}
/* build btree from the bottom up */ /* build btree from the bottom up */
/* _ TODO dropDups */ /* _ TODO dropDups */
class BtreeBuilder { class BtreeBuilder {
bool dupsAllowed; bool dupsAllowed;
IndexDetails& idx; IndexDetails& idx;
unsigned long long n; unsigned long long n;
BSONObj keyLast; BSONObj keyLast;
BSONObj order; BSONObj order;
bool committed; bool committed;
 End of changes. 6 change blocks. 
4 lines changed or deleted 19 lines changed or added


 builder.h   builder.h 
skipping to change at line 93 skipping to change at line 93
void append(unsigned j) { void append(unsigned j) {
append<unsigned>(j); append<unsigned>(j);
} }
void append(bool j) { void append(bool j) {
append<bool>(j); append<bool>(j);
} }
void append(double j) { void append(double j) {
append<double>(j); append<double>(j);
} }
void append(const void *src, int len) { void append(const void *src, size_t len) {
memcpy(grow(len), src, len); memcpy(grow(len), src, len);
} }
void append(const char *str) { void append(const char *str) {
append((void*) str, strlen(str)+1); append((void*) str, strlen(str)+1);
} }
void append(const string &str) { void append(const string &str) {
append( (void *)str.c_str(), str.length() + 1 ); append( (void *)str.c_str(), str.length() + 1 );
} }
skipping to change at line 199 skipping to change at line 199
return *this; return *this;
} }
// access // access
void reset( int maxSize = 0 ){ void reset( int maxSize = 0 ){
_buf.reset( maxSize ); _buf.reset( maxSize );
} }
string str(){ string str(){
return string(_buf.data,0,_buf.l); return string(_buf.data, _buf.l);
} }
private: private:
BufBuilder _buf; BufBuilder _buf;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 chunk.h   chunk.h 
skipping to change at line 64 skipping to change at line 64
const BSONObj& getMin() const { return _min; } const BSONObj& getMin() const { return _min; }
const BSONObj& getMax() const { return _max; } const BSONObj& getMax() const { return _max; }
void setMin(const BSONObj& o){ void setMin(const BSONObj& o){
_min = o; _min = o;
} }
void setMax(const BSONObj& o){ void setMax(const BSONObj& o){
_max = o; _max = o;
} }
string getShard(){ string getShard() const{
return _shard; return _shard;
} }
void setShard( string shard ); void setShard( string shard );
bool contains( const BSONObj& obj ); bool contains( const BSONObj& obj ) const;
string toString() const; string toString() const;
operator string() const { return toString(); } operator string() const { return toString(); }
bool operator==(const Chunk& s); bool operator==(const Chunk& s) const;
bool operator!=(const Chunk& s){ bool operator!=(const Chunk& s) const{
return ! ( *this == s ); return ! ( *this == s );
} }
void getFilter( BSONObjBuilder& b ); void getFilter( BSONObjBuilder& b ) const;
BSONObj getFilter(){ BSONObjBuilder b; getFilter( b ); return b.obj BSONObj getFilter() const{ BSONObjBuilder b; getFilter( b ); return
(); } b.obj(); }
BSONObj pickSplitPoint(); BSONObj pickSplitPoint() const;
Chunk * split(); Chunk * split();
Chunk * split( const BSONObj& middle ); Chunk * split( const BSONObj& middle );
/** /**
* @return size of shard in bytes * @return size of shard in bytes
* talks to mongod to do this * talks to mongod to do this
*/ */
long getPhysicalSize(); long getPhysicalSize() const;
long countObjects( const BSONObj& filter = BSONObj() ); long countObjects( const BSONObj& filter = BSONObj() ) const;
/** /**
* if the amount of data written nears the max size of a shard * 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 * then we check the real size, and if its too big, we split
*/ */
bool splitIfShould( long dataWritten ); bool splitIfShould( long dataWritten );
/* /*
* moves either this shard or newShard if it makes sense too * moves either this shard or newShard if it makes sense too
* @return whether or not a shard was moved * @return whether or not a shard was moved
skipping to change at line 127 skipping to change at line 127
void _markModified(); void _markModified();
static long MaxChunkSize; static long MaxChunkSize;
private: private:
// main shard info // main shard info
ChunkManager * _manager; ChunkManager * _manager;
ShardKeyPattern skey(); ShardKeyPattern skey() const;
string _ns; string _ns;
BSONObj _min; BSONObj _min;
BSONObj _max; BSONObj _max;
string _shard; string _shard;
ShardChunkVersion _lastmod; ShardChunkVersion _lastmod;
bool _modified; bool _modified;
// transient stuff // transient stuff
skipping to change at line 219 skipping to change at line 219
vector<Chunk*> _chunks; vector<Chunk*> _chunks;
map<string,unsigned long long> _maxMarkers; map<string,unsigned long long> _maxMarkers;
unsigned long long _sequenceNumber; unsigned long long _sequenceNumber;
friend class Chunk; friend class Chunk;
static unsigned long long NextSequenceNumber; static unsigned long long NextSequenceNumber;
}; };
// like BSONObjCmp. for use as an STL comparison functor
// key-order in "order" argument must match key-order in shardkey
class ChunkCmp {
public:
ChunkCmp( const BSONObj &order = BSONObj() ) : _cmp( order ) {}
bool operator()( const Chunk &l, const Chunk &r ) const {
return _cmp(l.getMin(), r.getMin());
}
bool operator()( const Chunk *l, const Chunk *r ) const {
return operator()(*l, *r);
}
private:
BSONObjCmp _cmp;
};
} // namespace mongo } // namespace mongo
 End of changes. 10 change blocks. 
11 lines changed or deleted 27 lines changed or added


 client.h   client.h 
skipping to change at line 28 skipping to change at line 28
/* Client represents a connection to the database (the server-side) and cor responds /* Client represents a connection to the database (the server-side) and cor responds
to an open socket (or logical connection if pooling on sockets) from a c lient. to an open socket (or logical connection if pooling on sockets) from a c lient.
todo: switch to asio...this will fit nicely with that. todo: switch to asio...this will fit nicely with that.
*/ */
#pragma once #pragma once
#include "../stdafx.h" #include "../stdafx.h"
#include "security.h"
#include "namespace.h" #include "namespace.h"
#include "lasterror.h" #include "lasterror.h"
#include "../util/top.h" #include "stats/top.h"
namespace mongo { namespace mongo {
class AuthenticationInfo; class AuthenticationInfo;
class Database; class Database;
class CurOp; class CurOp;
class Command; class Command;
class Client; class Client;
extern boost::thread_specific_ptr<Client> currentClient; extern boost::thread_specific_ptr<Client> currentClient;
bool setClient(const char *ns, const string& path=dbpath, mongolock *lo
ck = 0);
class Client : boost::noncopyable { class Client : boost::noncopyable {
public: public:
static boost::mutex clientsMutex; static boost::mutex clientsMutex;
static set<Client*> clients; // always be in clientsMutex when mani pulating this static set<Client*> clients; // always be in clientsMutex when mani pulating this
class GodScope { class GodScope {
bool _prev; bool _prev;
public: public:
GodScope(); GodScope();
~GodScope(); ~GodScope();
}; };
/* Set database we want to use, then, restores when we finish (are out of scope) /* Set database we want to use, then, restores when we finish (are out of scope)
Note this is also helpful if an exception happens as the state i f fixed up. Note this is also helpful if an exception happens as the state i f fixed up.
*/ */
class Context { class Context : boost::noncopyable{
Client * _client; Client * _client;
Database * _olddb; Context * _oldContext;
string _oldns;
string _path;
mongolock * _lock;
bool _justCreated;
string _ns;
Database * _db;
/**
* at this point _client, _oldContext and _ns have to be set
* _db should not have been touched
* this will set _db and create if needed
* will also set _client->_context to this
*/
void _finishInit( bool doauth=true);
void _auth( int lockState = dbMutex.getState() );
public: public:
Context(const char *ns) Context(const string& ns, string path=dbpath, mongolock * lock
: _client( currentClient.get() ) { = 0 , bool doauth=true )
_olddb = _client->_database; : _client( currentClient.get() ) , _oldContext( _client->_c
_oldns = _client->_ns; ontext ) ,
setClient(ns); _path( path ) , _lock( lock ) ,
} _ns( ns ){
Context(string ns) _finishInit( doauth );
: _client( currentClient.get() ){
_olddb = _client->_database;
_oldns = _client->_ns;
setClient(ns.c_str());
} }
/* this version saves the context but doesn't yet set the new o ne: */ /* this version saves the context but doesn't yet set the new o ne: */
Context()
: _client( currentClient.get() ) {
_olddb = _client->database();
_oldns = _client->ns();
Context()
: _client( currentClient.get() ) , _oldContext( _client->_c
ontext ),
_path( dbpath ) , _lock(0) , _justCreated(false){
_client->_context = this;
clear();
} }
/** /**
* if you are doing this after allowing a write there could be a race condition * if you are doing this after allowing a write there could be a race condition
* if someone closes that db. this checks that the DB is still valid * if someone closes that db. this checks that the DB is still valid
*/ */
Context( string ns , Database * db ); Context( string ns , Database * db );
~Context() { ~Context();
DEV assert( _client == currentClient.get() );
_client->setns( _oldns.c_str(), _olddb ); Client* getClient() const { return _client; }
Database* db() const {
return _db;
}
const char * ns() const {
return _ns.c_str();
}
bool justCreated() const {
return _justCreated;
}
bool equals( const string& ns , const string& path=dbpath ) con
st {
return _ns == ns && _path == path;
} }
bool inDB( const string& db , const string& path=dbpath ) const
{
if ( _path != path )
return false;
if ( db == _ns )
return true;
string::size_type idx = _ns.find( db );
if ( idx != 0 )
return false;
return _ns[db.size()] == '.';
}
void clear(){
_ns = "";
_db = 0;
}
/**
* call before unlocking, so clear any non-thread safe state
*/
void unlocked(){
_db = 0;
}
/**
* call after going back into the lock, will re-establish non-t
hread safe stuff
*/
void relocked(){
_finishInit();
}
friend class CurOp;
}; };
private: private:
CurOp * const _curOp; CurOp * _curOp;
Database *_database; Context * _context;
Namespace _ns;
//NamespaceString _nsstr;
bool _shutdown; bool _shutdown;
list<string> _tempCollections; list<string> _tempCollections;
const char *_desc; const char *_desc;
bool _god; bool _god;
AuthenticationInfo _ai;
public: public:
AuthenticationInfo *ai;
Top top; AuthenticationInfo * getAuthenticationInfo(){ return &_ai; }
bool isAdmin() { return _ai.isAuthorized( "admin" ); }
CurOp* curop() { return _curOp; } CurOp* curop() { return _curOp; }
Database* database() {
return _database;
}
const char *ns() { return _ns.buf; }
void setns(const char *ns, Database *db) { Context* getContext(){ return _context; }
_database = db; Database* database() { return _context ? _context->db() : 0; }
_ns = ns; const char *ns() { return _context->ns(); }
//_nsstr = ns;
}
void clearns() { setns("", 0); }
Client(const char *desc); Client(const char *desc);
~Client(); ~Client();
const char *desc() const { return _desc; } const char *desc() const { return _desc; }
void addTempCollection( const string& ns ){ void addTempCollection( const string& ns ){
_tempCollections.push_back( ns ); _tempCollections.push_back( ns );
} }
skipping to change at line 145 skipping to change at line 198
*/ */
static void initThread(const char *desc); static void initThread(const char *desc);
/* /*
this has to be called as the client goes away, but before thread termination this has to be called as the client goes away, but before thread termination
@return true if anything was done @return true if anything was done
*/ */
bool shutdown(); bool shutdown();
bool isGod() const { return _god; } bool isGod() const { return _god; }
friend class CurOp;
string toString() const;
}; };
inline Client& cc() { inline Client& cc() {
return *currentClient.get(); return *currentClient.get();
} }
/* each thread which does db operations has a Client object in TLS. /* each thread which does db operations has a Client object in TLS.
call this when your thread starts. call this when your thread starts.
*/ */
inline void Client::initThread(const char *desc) { inline void Client::initThread(const char *desc) {
skipping to change at line 184 skipping to change at line 241
if( s != -1 ) { if( s != -1 ) {
log() << "error: releaseAndWriteLock() s == " << s << endl; log() << "error: releaseAndWriteLock() s == " << s << endl;
msgasserted( 12600, "releaseAndWriteLock: unlock_shared fai led, probably recursive" ); msgasserted( 12600, "releaseAndWriteLock: unlock_shared fai led, probably recursive" );
} }
#endif #endif
_writelock = true; _writelock = true;
dbMutex.unlock_shared(); dbMutex.unlock_shared();
dbMutex.lock(); dbMutex.lock();
/* this is defensive; as we were unlocked for a moment above, if ( cc().getContext() )
the Database object we reference could have been deleted: cc().getContext()->unlocked();
*/
cc().clearns();
} }
} }
string sayClientState();
}; };
 End of changes. 18 change blocks. 
45 lines changed or deleted 107 lines changed or added


 clientcursor.h   clientcursor.h 
skipping to change at line 31 skipping to change at line 31
ClientCursor is a wrapper that represents a cursorid from our database ClientCursor is a wrapper that represents a cursorid from our database
application's perspective. application's perspective.
*/ */
#pragma once #pragma once
#include "../stdafx.h" #include "../stdafx.h"
#include "cursor.h" #include "cursor.h"
#include "jsobj.h" #include "jsobj.h"
#include "../util/message.h" #include "../util/message.h"
#include "storage.h" #include "diskloc.h"
#include "dbhelpers.h" #include "dbhelpers.h"
#include "matcher.h" #include "matcher.h"
namespace mongo { namespace mongo {
typedef long long CursorId; /* passed to the client so it can send back on getMore */ typedef long long CursorId; /* passed to the client so it can send back on getMore */
class Cursor; /* internal server cursor base class */ class Cursor; /* internal server cursor base class */
class ClientCursor; class ClientCursor;
/* todo: make this map be per connection. this will prevent cursor hij acking security attacks perhaps. /* todo: make this map be per connection. this will prevent cursor hij acking security attacks perhaps.
skipping to change at line 108 skipping to change at line 108
} }
}; };
/*const*/ CursorId cursorid; /*const*/ CursorId cursorid;
string ns; string ns;
auto_ptr<CoveredIndexMatcher> matcher; auto_ptr<CoveredIndexMatcher> matcher;
auto_ptr<Cursor> c; auto_ptr<Cursor> c;
int pos; // # objects into the curs or so far int pos; // # objects into the curs or so far
BSONObj query; BSONObj query;
ClientCursor() : _idleAgeMillis(0), _pinValue(0), _doingDeletes(fal ClientCursor(auto_ptr<Cursor>& _c, const char *_ns, bool okToTimeou
se), pos(0) { t) :
_idleAgeMillis(0), _pinValue(0),
_doingDeletes(false),
ns(_ns), c(_c),
pos(0)
{
if( !okToTimeout )
noTimeout();
recursive_boostlock lock(ccmutex); recursive_boostlock lock(ccmutex);
cursorid = allocCursorId_inlock(); cursorid = allocCursorId_inlock();
clientCursorsById.insert( make_pair(cursorid, this) ); clientCursorsById.insert( make_pair(cursorid, this) );
} }
~ClientCursor(); ~ClientCursor();
DiskLoc lastLoc() const { DiskLoc lastLoc() const {
return _lastLoc; return _lastLoc;
} }
auto_ptr< FieldMatcher > filter; // which fields query wants return ed auto_ptr< FieldMatcher > filter; // which fields query wants return ed
Message originalMessage; // this is effectively an auto ptr for dat a the matcher points to Message originalMessage; // this is effectively an auto ptr for dat a the matcher points to
/* Get rid of cursors for namespaces that begin with nsprefix. /* Get rid of cursors for namespaces that begin with nsprefix.
Used by drop, deleteIndexes, dropDatabase. Used by drop, dropIndexes, dropDatabase.
*/ */
static void invalidate(const char *nsPrefix); static void invalidate(const char *nsPrefix);
/** /**
* do a dbtemprelease * do a dbtemprelease
* note: caller should check matcher.docMatcher().atomic() first an d not yield if atomic - * note: caller should check matcher.docMatcher().atomic() first an d not yield if atomic -
* we don't do herein as this->matcher (above) is only initia lized for true queries/getmore. * we don't do herein as this->matcher (above) is only initia lized for true queries/getmore.
* (ie not set for remote/update) * (ie not set for remote/update)
* @return if the cursor is still valid. * @return if the cursor is still valid.
* if false is returned, then this ClientCursor should be c * if false is returned, then this ClientCursor should be c
onsidered deleted onsidered deleted -
* in fact, the whole database could be gone.
*/ */
bool yield(); bool yield();
private: private:
void setLastLoc_inlock(DiskLoc); void setLastLoc_inlock(DiskLoc);
static ClientCursor* find_inlock(CursorId id, bool warn = true) { static ClientCursor* find_inlock(CursorId id, bool warn = true) {
CCById::iterator it = clientCursorsById.find(id); CCById::iterator it = clientCursorsById.find(id);
if ( it == clientCursorsById.end() ) { if ( it == clientCursorsById.end() ) {
if ( warn ) if ( warn )
OCCASIONALLY out() << "ClientCursor::find(): cursor not found in map " << id << " (ok after a drop)\n"; OCCASIONALLY out() << "ClientCursor::find(): cursor not found in map " << id << " (ok after a drop)\n";
return 0; return 0;
} }
return it->second; return it->second;
} }
public: public:
static ClientCursor* find(CursorId id, bool warn = true) { static ClientCursor* find(CursorId id, bool warn = true) {
recursive_boostlock lock(ccmutex); recursive_boostlock lock(ccmutex);
ClientCursor *c = find_inlock(id, warn); ClientCursor *c = find_inlock(id, warn);
// if this asserts, your code was not thread safe - you either need to set no timeout // if this asserts, your code was not thread safe - you either need to set no timeout
// for the cursor or keep a ClientCursor::Pointer in scope for it. // for the cursor or keep a ClientCursor::Pointer in scope for it.
massert( 12521, "internal error: use of an unlocked ClientCurso r", c->_pinValue ); massert( 12521, "internal error: use of an unlocked ClientCurso r", c == 0 || c->_pinValue );
return c; return c;
} }
static bool erase(CursorId id) { static bool erase(CursorId id) {
recursive_boostlock lock(ccmutex); recursive_boostlock lock(ccmutex);
ClientCursor *cc = find_inlock(id); ClientCursor *cc = find_inlock(id);
if ( cc ) { if ( cc ) {
assert( cc->_pinValue < 100 ); // you can't still have an a ctive ClientCursor::Pointer assert( cc->_pinValue < 100 ); // you can't still have an a ctive ClientCursor::Pointer
delete cc; delete cc;
return true; return true;
skipping to change at line 198 skipping to change at line 206
bool shouldTimeout( unsigned millis ){ bool shouldTimeout( unsigned millis ){
_idleAgeMillis += millis; _idleAgeMillis += millis;
return _idleAgeMillis > 600000 && _pinValue == 0; return _idleAgeMillis > 600000 && _pinValue == 0;
} }
unsigned idleTime(){ unsigned idleTime(){
return _idleAgeMillis; return _idleAgeMillis;
} }
static void idleTimeReport(unsigned millis); static void idleTimeReport(unsigned millis);
private:
// cursors normally timeout after an inactivy period to prevent exc ess memory use // cursors normally timeout after an inactivy period to prevent exc ess memory use
// setting this prevents timeout of the cursor in question. // setting this prevents timeout of the cursor in question.
void noTimeout() { void noTimeout() {
_pinValue++; _pinValue++;
} }
public:
void setDoingDeletes( bool doingDeletes ){ void setDoingDeletes( bool doingDeletes ){
_doingDeletes = doingDeletes; _doingDeletes = doingDeletes;
} }
static unsigned byLocSize(); // just for diagnostics static unsigned byLocSize(); // just for diagnostics
static void informAboutToDeleteBucket(const DiskLoc& b); static void informAboutToDeleteBucket(const DiskLoc& b);
static void aboutToDelete(const DiskLoc& dl); static void aboutToDelete(const DiskLoc& dl);
}; };
 End of changes. 7 change blocks. 
9 lines changed or deleted 17 lines changed or added


 concurrency.h   concurrency.h 
/*
* Copyright (C) 2010 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 Lice
nse
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* concurrency.h /* concurrency.h
mongod concurrency rules & notes will be placed here. mongod concurrency rules & notes will be placed here.
Mutex heirarchy (1 = "leaf") Mutex heirarchy (1 = "leaf")
name level name level
Logstream::mutex 1 Logstream::mutex 1
ClientCursor::ccmutex 2 ClientCursor::ccmutex 2
dblock 3 dblock 3
End func name with _inlock to indicate "caller must lock before callin g". End func name with _inlock to indicate "caller must lock before callin g".
*/ */
#pragma once #pragma once
#if BOOST_VERSION >= 103500 #if BOOST_VERSION >= 103500
#include <boost/thread/shared_mutex.hpp> #include <boost/thread/shared_mutex.hpp>
#undef assert #undef assert
#define assert xassert #define assert xassert
#define HAVE_READLOCK
#else #else
#warning built with boost version 1.34 or older limited concurrency #warning built with boost version 1.34 or older limited concurrency
#endif #endif
namespace mongo { namespace mongo {
inline bool readLockSupported(){
#ifdef HAVE_READLOCK
return true;
#else
return false;
#endif
}
string sayClientState();
void curopWaitingForLock( int type );
void curopGotLock();
/* mutex time stats */ /* mutex time stats */
class MutexInfo { class MutexInfo {
unsigned long long start, enter, timeLocked; // all in microseconds unsigned long long start, enter, timeLocked; // all in microseconds
int locked; int locked;
public: public:
MutexInfo() : locked(0) { MutexInfo() : timeLocked(0) , locked(0) {
start = curTimeMicros64(); start = curTimeMicros64();
} }
void entered() { void entered() {
if ( locked == 0 ) if ( locked == 0 )
enter = curTimeMicros64(); enter = curTimeMicros64();
locked++; locked++;
assert( locked >= 1 ); assert( locked >= 1 );
} }
void leaving() { void leaving() {
locked--; locked--;
skipping to change at line 54 skipping to change at line 84
if ( locked == 0 ) if ( locked == 0 )
timeLocked += curTimeMicros64() - enter; timeLocked += curTimeMicros64() - enter;
} }
int isLocked() const { int isLocked() const {
return locked; return locked;
} }
void getTimingInfo(unsigned long long &s, unsigned long long &tl) c onst { void getTimingInfo(unsigned long long &s, unsigned long long &tl) c onst {
s = start; s = start;
tl = timeLocked; tl = timeLocked;
} }
unsigned long long getTimeLocked() const {
return timeLocked;
}
}; };
#if BOOST_VERSION >= 103500 #ifdef HAVE_READLOCK
//#if 0 //#if 0
class MongoMutex { class MongoMutex {
MutexInfo _minfo; MutexInfo _minfo;
boost::shared_mutex _m; boost::shared_mutex _m;
ThreadLocalValue<int> _state; ThreadLocalValue<int> _state;
/* we use a separate TLS value for releasedEarly - that is ok as /* we use a separate TLS value for releasedEarly - that is ok as
our normal/common code path, we never even touch it. our normal/common code path, we never even touch it.
*/ */
ThreadLocalValue<bool> _releasedEarly; ThreadLocalValue<bool> _releasedEarly;
skipping to change at line 83 skipping to change at line 116
*/ */
int getState(){ return _state.get(); } int getState(){ return _state.get(); }
void assertWriteLocked() { void assertWriteLocked() {
assert( getState() > 0 ); assert( getState() > 0 );
DEV assert( !_releasedEarly.get() ); DEV assert( !_releasedEarly.get() );
} }
bool atLeastReadLocked() { return _state.get() != 0; } bool atLeastReadLocked() { return _state.get() != 0; }
void assertAtLeastReadLocked() { assert(atLeastReadLocked()); } void assertAtLeastReadLocked() { assert(atLeastReadLocked()); }
void lock() { void lock() {
DEV cout << "LOCK" << endl; //DEV cout << "LOCK" << endl;
int s = _state.get(); int s = _state.get();
if( s > 0 ) { if( s > 0 ) {
_state.set(s+1); _state.set(s+1);
return; return;
} }
massert( 10293 , "internal error: locks are not upgradeable", s == 0 ); massert( 10293 , (string)"internal error: locks are not upgrade able: " + sayClientState() , s == 0 );
_state.set(1); _state.set(1);
curopWaitingForLock( 1 );
_m.lock(); _m.lock();
curopGotLock();
_minfo.entered(); _minfo.entered();
} }
void unlock() { void unlock() {
DEV cout << "UNLOCK" << endl; //DEV cout << "UNLOCK" << endl;
int s = _state.get(); int s = _state.get();
if( s > 1 ) { if( s > 1 ) {
_state.set(s-1); _state.set(s-1);
return; return;
} }
if( s != 1 ) { if( s != 1 ) {
if( _releasedEarly.get() ) { if( _releasedEarly.get() ) {
_releasedEarly.set(false); _releasedEarly.set(false);
return; return;
} }
assert(false); // attempt to unlock when wasn't in a write lock massert( 12599, "internal error: attempt to unlock when was n't in a write lock", false);
} }
_state.set(0); _state.set(0);
_minfo.leaving(); _minfo.leaving();
_m.unlock(); _m.unlock();
} }
/* unlock (write lock), and when unlock() is called later, /* unlock (write lock), and when unlock() is called later,
be smart then and don't unlock it again. be smart then and don't unlock it again.
*/ */
void releaseEarly() { void releaseEarly() {
assert( getState() == 1 ); // must not be recursive assert( getState() == 1 ); // must not be recursive
assert( !_releasedEarly.get() ); assert( !_releasedEarly.get() );
_releasedEarly.set(true); _releasedEarly.set(true);
unlock(); unlock();
} }
void lock_shared() { void lock_shared() {
DEV cout << " LOCKSHARED" << endl; //DEV cout << " LOCKSHARED" << endl;
int s = _state.get(); int s = _state.get();
if( s ) { if( s ) {
if( s > 0 ) { if( s > 0 ) {
// already in write lock - just be recursive and stay w rite locked // already in write lock - just be recursive and stay w rite locked
_state.set(s+1); _state.set(s+1);
return; return;
} }
else { else {
// already in read lock - recurse // already in read lock - recurse
_state.set(s-1); _state.set(s-1);
return; return;
} }
} }
_state.set(-1); _state.set(-1);
curopWaitingForLock( -1 );
_m.lock_shared(); _m.lock_shared();
curopGotLock();
}
bool lock_shared_try( int millis ) {
int s = _state.get();
if ( s ){
// we already have a lock, so no need to try
lock_shared();
return true;
}
boost::system_time until = get_system_time();
until += boost::posix_time::milliseconds(2);
bool got = _m.timed_lock_shared( until );
if ( got )
_state.set(-1);
return got;
} }
void unlock_shared() { void unlock_shared() {
DEV cout << " UNLOCKSHARED" << endl; //DEV cout << " UNLOCKSHARED" << endl;
int s = _state.get(); int s = _state.get();
if( s > 0 ) { if( s > 0 ) {
assert( s > 1 ); /* we must have done a lock write first to have s > 1 */ assert( s > 1 ); /* we must have done a lock write first to have s > 1 */
_state.set(s-1); _state.set(s-1);
return; return;
} }
if( s < -1 ) { if( s < -1 ) {
_state.set(s+1); _state.set(s+1);
return; return;
} }
skipping to change at line 168 skipping to change at line 225
}; };
#else #else
/* this will be for old versions of boost */ /* this will be for old versions of boost */
class MongoMutex { class MongoMutex {
MutexInfo _minfo; MutexInfo _minfo;
boost::recursive_mutex m; boost::recursive_mutex m;
ThreadLocalValue<bool> _releasedEarly; ThreadLocalValue<bool> _releasedEarly;
public: public:
MongoMutex() { } MongoMutex() { }
void lock() { void lock() {
#if BOOST_VERSION >= 103500 #ifdef HAVE_READLOCK
m.lock(); m.lock();
#else #else
boost::detail::thread::lock_ops<boost::recursive_mutex>::lock(m ); boost::detail::thread::lock_ops<boost::recursive_mutex>::lock(m );
#endif #endif
_minfo.entered(); _minfo.entered();
} }
void releaseEarly() { void releaseEarly() {
assertWriteLocked(); // aso must not be recursive, although we don't verify that in the old boost version assertWriteLocked(); // aso must not be recursive, although we don't verify that in the old boost version
assert( !_releasedEarly.get() ); assert( !_releasedEarly.get() );
_releasedEarly.set(true); _releasedEarly.set(true);
_unlock(); _unlock();
} }
void _unlock() { void _unlock() {
_minfo.leaving(); _minfo.leaving();
#if BOOST_VERSION >= 103500 #ifdef HAVE_READLOCK
m.unlock(); m.unlock();
#else #else
boost::detail::thread::lock_ops<boost::recursive_mutex>::unlock (m); boost::detail::thread::lock_ops<boost::recursive_mutex>::unlock (m);
#endif #endif
} }
void unlock() { void unlock() {
if( _releasedEarly.get() ) { if( _releasedEarly.get() ) {
_releasedEarly.set(false); _releasedEarly.set(false);
return; return;
} }
_unlock(); _unlock();
} }
void lock_shared() { lock(); } void lock_shared() { lock(); }
bool lock_shared_try( int millis ) {
while ( millis-- ){
if ( getState() ){
sleepmillis(1);
continue;
}
lock_shared();
return true;
}
return false;
}
void unlock_shared() { unlock(); } void unlock_shared() { unlock(); }
MutexInfo& info() { return _minfo; } MutexInfo& info() { return _minfo; }
void assertWriteLocked() { void assertWriteLocked() {
assert( info().isLocked() ); assert( info().isLocked() );
} }
void assertAtLeastReadLocked() { void assertAtLeastReadLocked() {
assert( info().isLocked() ); assert( info().isLocked() );
} }
bool atLeastReadLocked() { return info().isLocked(); } bool atLeastReadLocked() { return info().isLocked(); }
int getState(){ return info().isLocked() ? 1 : 0; } int getState(){ return info().isLocked() ? 1 : 0; }
skipping to change at line 223 skipping to change at line 292
extern MongoMutex &dbMutex; extern MongoMutex &dbMutex;
void dbunlocking_write(); void dbunlocking_write();
void dbunlocking_read(); void dbunlocking_read();
struct writelock { struct writelock {
writelock(const string& ns) { writelock(const string& ns) {
dbMutex.lock(); dbMutex.lock();
} }
~writelock() { ~writelock() {
dbunlocking_write(); DESTRUCTOR_GUARD(
dbMutex.unlock(); dbunlocking_write();
dbMutex.unlock();
);
} }
}; };
struct readlock { struct readlock {
readlock(const string& ns) { readlock(const string& ns) {
dbMutex.lock_shared(); dbMutex.lock_shared();
} }
~readlock() { ~readlock() {
dbunlocking_read(); DESTRUCTOR_GUARD(
dbMutex.unlock_shared(); dbunlocking_read();
dbMutex.unlock_shared();
);
} }
}; };
struct readlocktry {
readlocktry( const string&ns , int tryms ){
_got = dbMutex.lock_shared_try( tryms );
}
~readlocktry() {
if ( _got ){
dbunlocking_read();
dbMutex.unlock_shared();
}
}
bool got(){
return _got;
}
bool _got;
};
class mongolock { class mongolock {
bool _writelock; bool _writelock;
public: public:
mongolock(bool write) : _writelock(write) { mongolock(bool write) : _writelock(write) {
if( _writelock ) { if( _writelock ) {
dbMutex.lock(); dbMutex.lock();
} }
else else
dbMutex.lock_shared(); dbMutex.lock_shared();
} }
~mongolock() { ~mongolock() {
if( _writelock ) { DESTRUCTOR_GUARD(
dbunlocking_write(); if( _writelock ) {
dbMutex.unlock(); dbunlocking_write();
} dbMutex.unlock();
else { } else {
dbunlocking_read(); dbunlocking_read();
dbMutex.unlock_shared(); dbMutex.unlock_shared();
} }
);
} }
/* this unlocks, does NOT upgrade. that works for our current usage */ /* this unlocks, does NOT upgrade. that works for our current usage */
void releaseAndWriteLock(); void releaseAndWriteLock();
}; };
/* use writelock and readlock instead */ /* use writelock and readlock instead */
struct dblock : public writelock { struct dblock : public writelock {
dblock() : writelock("") { } dblock() : writelock("") { }
~dblock() { ~dblock() {
} }
 End of changes. 24 change blocks. 
22 lines changed or deleted 113 lines changed or added


 curop.h   curop.h 
// curop.h // curop.h
/*
* Copyright (C) 2010 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 Lice
nse
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once #pragma once
#include "namespace.h" #include "namespace.h"
#include "security.h"
#include "client.h" #include "client.h"
#include "../util/atomic_int.h"
#include "db.h"
namespace mongo { namespace mongo {
class OpDebug { class OpDebug {
public: public:
StringBuilder str; StringBuilder str;
void reset(){ void reset(){
str.reset(); str.reset();
} }
}; };
/* Current operation (for the current Client). /* Current operation (for the current Client).
an embedded member of Client class, and typically used from within t he mutex there. */ an embedded member of Client class, and typically used from within t he mutex there. */
class CurOp : boost::noncopyable { class CurOp : boost::noncopyable {
static WrappingInt _nextOpNum; static AtomicUInt _nextOpNum;
static BSONObj _tooBig; // { $msg : "query not recording (too large )" } static BSONObj _tooBig; // { $msg : "query not recording (too large )" }
Client * _client;
CurOp * _wrapped;
unsigned long long _start;
unsigned long long _checkpoint;
unsigned long long _end;
bool _active; bool _active;
Timer _timer;
int _op; int _op;
WrappingInt _opNum; bool _command;
int _lockType; // see concurrency.h for values
bool _waitingForLock;
int _dbprofile; // 0=off, 1=slow, 2=all
AtomicUInt _opNum;
char _ns[Namespace::MaxNsLen+2]; char _ns[Namespace::MaxNsLen+2];
struct sockaddr_in client; struct sockaddr_in _remote;
char _queryBuf[256]; char _queryBuf[256];
bool haveQuery() const { return *((int *) _queryBuf) != 0; }
void resetQuery(int x=0) { *((int *)_queryBuf) = x; } void resetQuery(int x=0) { *((int *)_queryBuf) = x; }
OpDebug _debug;
void _reset(){
_command = false;
_lockType = 0;
_dbprofile = 0;
_end = 0;
_waitingForLock = false;
}
void setNS(const char *ns) {
strncpy(_ns, ns, Namespace::MaxNsLen);
}
public:
bool haveQuery() const { return *((int *) _queryBuf) != 0; }
BSONObj query() { BSONObj query() {
if( *((int *) _queryBuf) == 1 ) { if( *((int *) _queryBuf) == 1 ) {
return _tooBig; return _tooBig;
} }
BSONObj o(_queryBuf); BSONObj o(_queryBuf);
return o; return o;
} }
OpDebug _debug; void ensureStarted(){
public: if ( _start == 0 )
void reset( const sockaddr_in &_client) { _start = _checkpoint = curTimeMicros64();
}
void enter( Client::Context * context ){
ensureStarted();
setNS( context->ns() );
if ( context->_db && context->_db->profile > _dbprofile )
_dbprofile = context->_db->profile;
}
void leave( Client::Context * context ){
unsigned long long now = curTimeMicros64();
Top::global.record( _ns , _op , _lockType , now - _checkpoint ,
_command );
_checkpoint = now;
}
void reset( const sockaddr_in & remote, int op ) {
_reset();
_start = _checkpoint = 0;
_active = true; _active = true;
_opNum = _nextOpNum.atomicIncrement(); _opNum = _nextOpNum++;
_timer.reset();
_ns[0] = '?'; // just in case not set later _ns[0] = '?'; // just in case not set later
_debug.reset(); _debug.reset();
resetQuery(); resetQuery();
client = _client; _remote = remote;
_op = op;
}
void markCommand(){
_command = true;
}
void waitingForLock( int type ){
_waitingForLock = true;
if ( type > 0 )
_lockType = 1;
else
_lockType = -1;
}
void gotLock(){
_waitingForLock = false;
} }
OpDebug& debug(){ OpDebug& debug(){
return _debug; return _debug;
} }
WrappingInt opNum() const { return _opNum; } int profileLevel() const {
return _dbprofile;
}
const char * getNS() const {
return _ns;
}
bool shouldDBProfile( int ms ) const {
if ( _dbprofile <= 0 )
return false;
return _dbprofile >= 2 || ms >= cmdLine.slowMS;
}
AtomicUInt opNum() const { return _opNum; }
/** if this op is running */
bool active() const { return _active; } bool active() const { return _active; }
int elapsedMillis(){ return _timer.millis(); } int getLockType() const { return _lockType; }
bool isWaitingForLock() const { return _waitingForLock; }
int getOp() const { return _op; }
/** micros */ /** micros */
unsigned long long startTime(){ unsigned long long startTime() {
return _timer.startTime(); ensureStarted();
return _start;
} }
void setActive(bool active) { _active = active; } void done() {
void setNS(const char *ns) { _active = false;
strncpy(_ns, ns, Namespace::MaxNsLen); _end = curTimeMicros64();
} }
void setOp(int op) { _op = op; }
unsigned long long totalTimeMicros() {
massert( 12601 , "CurOp not marked done yet" , ! _active );
return _end - startTime();
}
int totalTimeMillis() {
return (int) (totalTimeMicros() / 1000);
}
int elapsedMillis() {
unsigned long long total = curTimeMicros64() - startTime();
return (int) (total / 1000);
}
int elapsedSeconds() {
return elapsedMillis() / 1000;
}
void setQuery(const BSONObj& query) { void setQuery(const BSONObj& query) {
if( query.objsize() > (int) sizeof(_queryBuf) ) { if( query.objsize() > (int) sizeof(_queryBuf) ) {
resetQuery(1); // flag as too big and return resetQuery(1); // flag as too big and return
return; return;
} }
memcpy(_queryBuf, query.objdata(), query.objsize()); memcpy(_queryBuf, query.objdata(), query.objsize());
} }
CurOp() { CurOp( Client * client , CurOp * wrapped = 0 ) {
_client = client;
_wrapped = wrapped;
if ( _wrapped ){
_client->_curOp = this;
}
_start = _checkpoint = 0;
_active = false; _active = false;
// opNum = 0; _reset();
_op = 0; _op = 0;
// These addresses should never be written to again. The zeroe s are // These addresses should never be written to again. The zeroe s are
// placed here as a precaution because currentOp may be accesse d // placed here as a precaution because currentOp may be accesse d
// without the db mutex. // without the db mutex.
memset(_ns, 0, sizeof(_ns)); memset(_ns, 0, sizeof(_ns));
memset(_queryBuf, 0, sizeof(_queryBuf)); memset(_queryBuf, 0, sizeof(_queryBuf));
} }
~CurOp(){
if ( _wrapped )
_client->_curOp = _wrapped;
}
BSONObj info() { BSONObj info() {
AuthenticationInfo *ai = currentClient.get()->ai; if( ! cc().getAuthenticationInfo()->isAuthorized("admin") ) {
if( !ai->isAuthorized("admin") ) {
BSONObjBuilder b; BSONObjBuilder b;
b.append("err", "unauthorized"); b.append("err", "unauthorized");
return b.obj(); return b.obj();
} }
return infoNoauth(); return infoNoauth();
} }
BSONObj infoNoauth() { BSONObj infoNoauth();
BSONObjBuilder b;
b.append("opid", _opNum);
b.append("active", _active);
if( _active )
b.append("secs_running", _timer.seconds() );
if( _op == 2004 )
b.append("op", "query");
else if( _op == 2005 )
b.append("op", "getMore");
else if( _op == 2001 )
b.append("op", "update");
else if( _op == 2002 )
b.append("op", "insert");
else if( _op == 2006 )
b.append("op", "delete");
else
b.append("op", _op);
b.append("ns", _ns);
if( haveQuery() ) { string getRemoteString(){
b.append("query", query()); stringstream ss;
} ss << inet_ntoa( _remote.sin_addr ) << ":" << ntohs( _remote.si
// b.append("inLock", ?? n_port );
stringstream clientStr; return ss.str();
clientStr << inet_ntoa( client.sin_addr ) << ":" << ntohs( clie
nt.sin_port );
b.append("client", clientStr.str());
return b.obj();
} }
friend class Client;
}; };
/* 0 = ok /* 0 = ok
1 = kill current operation and reset this to 0 1 = kill current operation and reset this to 0
future: maybe use this as a "going away" thing on process terminatio n with a higher flag value future: maybe use this as a "going away" thing on process terminatio n with a higher flag value
*/ */
extern class KillCurrentOp { extern class KillCurrentOp {
enum { Off, On, All } state; enum { Off, On, All } state;
WrappingInt toKill; AtomicUInt toKill;
public: public:
void killAll() { state = All; } void killAll() { state = All; }
void kill(WrappingInt i) { toKill = i; state = On; } void kill(AtomicUInt i) { toKill = i; state = On; }
void checkForInterrupt() { void checkForInterrupt() {
if( state != Off ) { if( state != Off ) {
if( state == All ) if( state == All )
uasserted(11600,"interrupted at shutdown"); uasserted(11600,"interrupted at shutdown");
if( cc().curop()->opNum() == toKill ) { if( cc().curop()->opNum() == toKill ) {
state = Off; state = Off;
uasserted(11601,"interrupted"); uasserted(11601,"interrupted");
} }
} }
 End of changes. 27 change blocks. 
54 lines changed or deleted 162 lines changed or added


 cursor.h   cursor.h 
skipping to change at line 22 skipping to change at line 22
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "../stdafx.h" #include "../stdafx.h"
#include "jsobj.h" #include "jsobj.h"
#include "storage.h" #include "diskloc.h"
namespace mongo { namespace mongo {
class Record; class Record;
/* Query cursors, base class. This is for our internal cursors. "Clie ntCursor" is a separate /* Query cursors, base class. This is for our internal cursors. "Clie ntCursor" is a separate
concept and is for the user's cursor. concept and is for the user's cursor.
WARNING concurrency: the vfunctions below are called back from withi n a WARNING concurrency: the vfunctions below are called back from withi n a
ClientCursor::ccmutex. Don't cause a deadlock, you've been warned. ClientCursor::ccmutex. Don't cause a deadlock, you've been warned.
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 cursors.h   cursors.h 
// cursors.h // cursors.h
/*
* Copyright (C) 2010 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 Lice
nse
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once #pragma once
#include "../stdafx.h" #include "../stdafx.h"
#include "../db/jsobj.h" #include "../db/jsobj.h"
#include "../db/dbmessage.h" #include "../db/dbmessage.h"
#include "../client/dbclient.h" #include "../client/dbclient.h"
#include "../client/parallel.h" #include "../client/parallel.h"
 End of changes. 1 change blocks. 
0 lines changed or deleted 17 lines changed or added


 d_logic.h   d_logic.h 
// d_logic.h // d_logic.h
/*
* Copyright (C) 2010 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 Lice
nse
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once #pragma once
#include "../stdafx.h" #include "../stdafx.h"
namespace mongo { namespace mongo {
/** /**
* @return true if we have any shard info for the ns * @return true if we have any shard info for the ns
*/ */
 End of changes. 1 change blocks. 
0 lines changed or deleted 17 lines changed or added


 database.h   database.h 
skipping to change at line 38 skipping to change at line 38
* NOT memory mapped * NOT memory mapped
*/ */
class Database { class Database {
public: public:
static bool _openAllFiles; static bool _openAllFiles;
Database(const char *nm, bool& newDb, const string& _path = dbpath) Database(const char *nm, bool& newDb, const string& _path = dbpath)
: name(nm), path(_path), namespaceIndex( path, name ) { : name(nm), path(_path), namespaceIndex( path, name ) {
{ // check db name is valid { // check db name is valid
int L = strlen(nm); size_t L = strlen(nm);
uassert( 10028 , "db name is empty", L > 0 ); uassert( 10028 , "db name is empty", L > 0 );
uassert( 10029 , "bad db name [1]", *nm != '.' ); uassert( 10029 , "bad db name [1]", *nm != '.' );
uassert( 10030 , "bad db name [2]", nm[L-1] != '.' ); uassert( 10030 , "bad db name [2]", nm[L-1] != '.' );
uassert( 10031 , "bad char(s) in db name", strchr(nm, ' ') == 0 ); uassert( 10031 , "bad char(s) in db name", strchr(nm, ' ') == 0 );
uassert( 10032 , "db name too long", L < 64 ); uassert( 10032 , "db name too long", L < 64 );
} }
newDb = namespaceIndex.exists(); newDb = namespaceIndex.exists();
profile = 0; profile = 0;
profileName = name + ".system.profile"; profileName = name + ".system.profile";
skipping to change at line 65 skipping to change at line 65
openAllFiles(); openAllFiles();
} }
magic = 781231; magic = 781231;
} }
~Database() { ~Database() {
magic = 0; magic = 0;
btreeStore->closeFiles(name, path); btreeStore->closeFiles(name, path);
int n = files.size(); size_t n = files.size();
for ( int i = 0; i < n; i++ ) for ( size_t i = 0; i < n; i++ )
delete files[i]; delete files[i];
} }
/** /**
* tries to make sure that this hasn't been deleted * tries to make sure that this hasn't been deleted
*/ */
bool isOk(){ bool isOk(){
return magic == 781231; return magic == 781231;
} }
bool isEmpty(){ bool isEmpty(){
return ! namespaceIndex.allocated(); return ! namespaceIndex.allocated();
} }
bool exists(int n) { boost::filesystem::path fileName( int n ) {
stringstream ss; stringstream ss;
ss << name << '.' << n; ss << name << '.' << n;
boost::filesystem::path fullName; boost::filesystem::path fullName;
fullName = boost::filesystem::path(path) / ss.str(); fullName = boost::filesystem::path(path);
return boost::filesystem::exists(fullName); if ( directoryperdb )
fullName /= name;
fullName /= ss.str();
return fullName;
}
bool exists(int n) {
return boost::filesystem::exists( fileName( n ) );
} }
void openAllFiles() { void openAllFiles() {
int n = 0; int n = 0;
while( exists(n) ) { while( exists(n) ) {
getFile(n); getFile(n);
n++; n++;
} }
// If last file is empty, consider it preallocated and make sur e it's not mapped // If last file is empty, consider it preallocated and make sur e it's not mapped
// until a write is requested // until a write is requested
skipping to change at line 126 skipping to change at line 133
if ( n > 100 ) if ( n > 100 )
out() << "getFile(): n=" << n << "?" << endl; out() << "getFile(): n=" << n << "?" << endl;
} }
MongoDataFile* p = 0; MongoDataFile* p = 0;
if ( !preallocateOnly ) { if ( !preallocateOnly ) {
while ( n >= (int) files.size() ) while ( n >= (int) files.size() )
files.push_back(0); files.push_back(0);
p = files[n]; p = files[n];
} }
if ( p == 0 ) { if ( p == 0 ) {
stringstream ss; boost::filesystem::path fullName = fileName( n );
ss << name << '.' << n;
boost::filesystem::path fullName;
fullName = boost::filesystem::path(path) / ss.str();
string fullNameString = fullName.string(); string fullNameString = fullName.string();
p = new MongoDataFile(n); p = new MongoDataFile(n);
int minSize = 0; int minSize = 0;
if ( n != 0 && files[ n - 1 ] ) if ( n != 0 && files[ n - 1 ] )
minSize = files[ n - 1 ]->getHeader()->fileLength; minSize = files[ n - 1 ]->getHeader()->fileLength;
if ( sizeNeeded + MDFHeader::headerSize() > minSize ) if ( sizeNeeded + MDFHeader::headerSize() > minSize )
minSize = sizeNeeded + MDFHeader::headerSize(); minSize = sizeNeeded + MDFHeader::headerSize();
try { try {
p->open( fullNameString.c_str(), minSize, preallocateOn ly ); p->open( fullNameString.c_str(), minSize, preallocateOn ly );
} }
 End of changes. 5 change blocks. 
10 lines changed or deleted 14 lines changed or added


 db.h   db.h 
skipping to change at line 21 skipping to change at line 21
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "../stdafx.h" #include "../stdafx.h"
#include "../util/message.h" #include "../util/message.h"
#include "../util/top.h"
#include "boost/version.hpp" #include "boost/version.hpp"
#include "concurrency.h" #include "concurrency.h"
#include "pdfile.h" #include "pdfile.h"
#include "client.h" #include "client.h"
namespace mongo { namespace mongo {
// void jniCallback(Message& m, Message& out); // void jniCallback(Message& m, Message& out);
/* Note the limit here is rather arbitrary and is simply a standard. ge nerally the code works /* Note the limit here is rather arbitrary and is simply a standard. ge nerally the code works
skipping to change at line 53 skipping to change at line 52
/** /**
* class to hold path + dbname -> Database * class to hold path + dbname -> Database
* might be able to optimizer further * might be able to optimizer further
*/ */
class DatabaseHolder { class DatabaseHolder {
public: public:
DatabaseHolder() : _size(0){ DatabaseHolder() : _size(0){
} }
bool isLoaded( const string& ns , const string& path ){
dbMutex.assertAtLeastReadLocked();
map<string,Database*>& m = _paths[path];
string db = _todb( ns );
map<string,Database*>::iterator it = m.find(db);
return it != m.end();
}
Database * get( const string& ns , const string& path ){ Database * get( const string& ns , const string& path ){
dbMutex.assertAtLeastReadLocked(); dbMutex.assertAtLeastReadLocked();
map<string,Database*>& m = _paths[path]; map<string,Database*>& m = _paths[path];
string db = _todb( ns ); string db = _todb( ns );
map<string,Database*>::iterator it = m.find(db); map<string,Database*>::iterator it = m.find(db);
if ( it != m.end() ) if ( it != m.end() )
return it->second; return it->second;
return 0; return 0;
skipping to change at line 74 skipping to change at line 83
void put( const string& ns , const string& path , Database * db ){ void put( const string& ns , const string& path , Database * db ){
dbMutex.assertWriteLocked(); dbMutex.assertWriteLocked();
map<string,Database*>& m = _paths[path]; map<string,Database*>& m = _paths[path];
Database*& d = m[_todb(ns)]; Database*& d = m[_todb(ns)];
if ( ! d ) if ( ! d )
_size++; _size++;
d = db; d = db;
} }
Database* getOrCreate( const string& ns , const string& path , bool
& justCreated ){
dbMutex.assertWriteLocked();
map<string,Database*>& m = _paths[path];
string dbname = _todb( ns );
Database* & db = m[dbname];
if ( db ){
justCreated = false;
return db;
}
log(1) << "Accessing: " << dbname << " for the first time" << e
ndl;
db = new Database( dbname.c_str() , justCreated , path );
_size++;
return db;
}
void erase( const string& ns , const string& path ){ void erase( const string& ns , const string& path ){
dbMutex.assertWriteLocked(); dbMutex.assertWriteLocked();
map<string,Database*>& m = _paths[path]; map<string,Database*>& m = _paths[path];
_size -= m.erase( _todb( ns ) ); _size -= (int)m.erase( _todb( ns ) );
} }
bool closeAll( const string& path , BSONObjBuilder& result ); /* force - force close even if something underway - use at shutdown
*/
bool closeAll( const string& path , BSONObjBuilder& result, bool fo
rce );
int size(){ int size(){
return _size; return _size;
} }
/** /**
* gets all unique db names, ignoring paths * gets all unique db names, ignoring paths
*/ */
void getAllShortNames( set<string>& all ) const{ void getAllShortNames( set<string>& all ) const{
dbMutex.assertAtLeastReadLocked(); dbMutex.assertAtLeastReadLocked();
skipping to change at line 115 skipping to change at line 143
return ns.substr( 0 , i ); return ns.substr( 0 , i );
} }
map<string, map<string,Database*> > _paths; map<string, map<string,Database*> > _paths;
int _size; int _size;
}; };
extern DatabaseHolder dbHolder; extern DatabaseHolder dbHolder;
/* returns true if the database ("database") did not exist, and it was
created on this call
path - datafiles directory, if not the default, so we can differenti
ate between db's of the same
name in different places (for example temp ones on repair).
*/
inline bool setClient(const char *ns, const string& path , mongolock *l
ock ) {
if( logLevel > 5 )
log() << "setClient: " << ns << endl;
dbMutex.assertAtLeastReadLocked();
Client& c = cc();
c.top.clientStart( ns );
Database * db = dbHolder.get( ns , path );
if ( db ){
c.setns(ns, db );
return false;
}
if( lock )
lock->releaseAndWriteLock();
assertInWriteLock();
char cl[256];
nsToDatabase(ns, cl);
bool justCreated;
Database *newdb = new Database(cl, justCreated, path);
dbHolder.put(ns,path,newdb);
c.setns(ns, newdb);
newdb->finishInit();
return justCreated;
}
// shared functionality for removing references to a database from this program instance // shared functionality for removing references to a database from this program instance
// does not delete the files on disk // does not delete the files on disk
void closeDatabase( const char *cl, const string& path = dbpath ); void closeDatabase( const char *cl, const string& path = dbpath );
struct dbtemprelease { struct dbtemprelease {
string clientname; Client::Context * _context;
string clientpath; int _locktype;
int locktype;
dbtemprelease() { dbtemprelease() {
Client& client = cc(); _context = cc().getContext();
Database *database = client.database(); _locktype = dbMutex.getState();
if ( database ) { assert( _locktype );
clientname = database->name;
clientpath = database->path; if ( _locktype > 0 ) {
} massert( 10298 , "can't temprelease nested w
client.top.clientStop(); rite lock", _locktype == 1);
locktype = dbMutex.getState(); if ( _context ) _context->unlocked();
assert( locktype );
if ( locktype > 0 ) {
massert( 10298 , "can't temprelease nested w
rite lock", locktype == 1);
dbMutex.unlock(); dbMutex.unlock();
} }
else { else {
massert( 10299 , "can't temprelease nested r massert( 10299 , "can't temprelease nested r
ead lock", locktype == -1); ead lock", _locktype == -1);
if ( _context ) _context->unlocked();
dbMutex.unlock_shared(); dbMutex.unlock_shared();
} }
} }
~dbtemprelease() { ~dbtemprelease() {
if ( locktype > 0 ) if ( _locktype > 0 )
dbMutex.lock(); dbMutex.lock();
else else
dbMutex.lock_shared(); dbMutex.lock_shared();
if ( clientname.empty() )
cc().setns("", 0); if ( _context ) _context->relocked();
else
setClient(clientname.c_str(), clientpath.c_str());
} }
}; };
/** /**
only does a temp release if we're not nested and have a lock only does a temp release if we're not nested and have a lock
*/ */
struct dbtempreleasecond { struct dbtempreleasecond {
dbtemprelease * real; dbtemprelease * real;
int locktype; int locktype;
 End of changes. 12 change blocks. 
64 lines changed or deleted 53 lines changed or added


 dbclient.h   dbclient.h 
skipping to change at line 208 skipping to change at line 208
}; };
/** Queries return a cursor object */ /** Queries return a cursor object */
class DBClientCursor : boost::noncopyable { class DBClientCursor : boost::noncopyable {
friend class DBClientBase; friend class DBClientBase;
bool init(); bool init();
public: public:
/** If true, safe to call next(). Requests more from server if necessary. */ /** If true, safe to call next(). Requests more from server if necessary. */
bool more(); bool more();
/** If true, there is more in our local buffers to be fetched via n
ext(). Returns
false when a getMore request back to server would be required.
You can use this
if you want to exhaust whatever data has been fetched to the cl
ient already but
then perhaps stop.
*/
bool moreInCurrentBatch() { return pos < nReturned; }
/** next /** next
@return next object in the result cursor. @return next object in the result cursor.
on an error at the remote server, you will get back: on an error at the remote server, you will get back:
{ $err: <string> } { $err: <string> }
if you do not want to handle that yourself, call nextSafe(). if you do not want to handle that yourself, call nextSafe().
*/ */
BSONObj next(); BSONObj next();
/** throws AssertionException if get back { $err : ... } */ /** throws AssertionException if get back { $err : ... } */
BSONObj nextSafe() { BSONObj nextSafe() {
 End of changes. 1 change blocks. 
0 lines changed or deleted 10 lines changed or added


 dbmessage.h   dbmessage.h 
skipping to change at line 19 skipping to change at line 19
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "storage.h" #include "diskloc.h"
#include "jsobj.h" #include "jsobj.h"
#include "namespace.h" #include "namespace.h"
#include "../util/message.h" #include "../util/message.h"
namespace mongo { namespace mongo {
/* db response format /* db response format
Query or GetMore: // see struct QueryResult Query or GetMore: // see struct QueryResult
int resultFlags; int resultFlags;
skipping to change at line 223 skipping to change at line 223
b.skip(sizeof(QueryResult)); b.skip(sizeof(QueryResult));
b.append(data, size); b.append(data, size);
QueryResult *qr = (QueryResult *) b.buf(); QueryResult *qr = (QueryResult *) b.buf();
qr->_resultFlags() = queryResultFlags; qr->_resultFlags() = queryResultFlags;
qr->len = b.len(); qr->len = b.len();
qr->setOperation(opReply); qr->setOperation(opReply);
qr->cursorId = cursorId; qr->cursorId = cursorId;
qr->startingFrom = startingFrom; qr->startingFrom = startingFrom;
qr->nReturned = nReturned; qr->nReturned = nReturned;
b.decouple(); b.decouple();
Message *resp = new Message(); Message resp(qr, true);
resp->setData(qr, true); // transport will free p->reply(requestMsg, resp, requestMsg.data->id);
p->reply(requestMsg, *resp, requestMsg.data->id);
} }
} // namespace mongo } // namespace mongo
//#include "bsonobj.h" //#include "bsonobj.h"
#include "instance.h" #include "instance.h"
namespace mongo { namespace mongo {
/* object reply helper. */ /* object reply helper. */
 End of changes. 2 change blocks. 
4 lines changed or deleted 3 lines changed or added


 engine.h   engine.h 
skipping to change at line 114 skipping to change at line 114
} }
static void validateObjectIdString( const string &str ); static void validateObjectIdString( const string &str );
protected: protected:
virtual ScriptingFunction _createFunction( const char * code ) = 0; virtual ScriptingFunction _createFunction( const char * code ) = 0;
string _localDBName; string _localDBName;
long long _loadedVersion; long long _loadedVersion;
set<string> _storedNames;
static long long _lastVersion; static long long _lastVersion;
map<string,ScriptingFunction> _cachedFunctions; map<string,ScriptingFunction> _cachedFunctions;
static int _numScopes; static int _numScopes;
}; };
void installGlobalUtils( Scope& scope );
class ScriptEngine : boost::noncopyable { class ScriptEngine : boost::noncopyable {
public: public:
ScriptEngine(); ScriptEngine();
virtual ~ScriptEngine(); virtual ~ScriptEngine();
virtual Scope * newScope() { virtual Scope * newScope() {
Scope *s = createScope(); Scope *s = createScope();
if ( s && _scopeInitCallback ) if ( s && _scopeInitCallback )
_scopeInitCallback( *s ); _scopeInitCallback( *s );
installGlobalUtils( *s );
return s; return s;
} }
virtual void runTest() = 0; virtual void runTest() = 0;
virtual bool utf8Ok() const = 0; virtual bool utf8Ok() const = 0;
static void setup(); static void setup();
auto_ptr<Scope> getPooledScope( const string& pool ); auto_ptr<Scope> getPooledScope( const string& pool );
 End of changes. 3 change blocks. 
0 lines changed or deleted 4 lines changed or added


 engine_spidermonkey.h   engine_spidermonkey.h 
skipping to change at line 96 skipping to change at line 96
class Convertor; class Convertor;
extern JSClass bson_class; extern JSClass bson_class;
extern JSClass bson_ro_class; extern JSClass bson_ro_class;
extern JSClass object_id_class; extern JSClass object_id_class;
extern JSClass dbpointer_class; extern JSClass dbpointer_class;
extern JSClass dbref_class; extern JSClass dbref_class;
extern JSClass bindata_class; extern JSClass bindata_class;
extern JSClass timestamp_class; extern JSClass timestamp_class;
extern JSClass numberlong_class;
extern JSClass minkey_class; extern JSClass minkey_class;
extern JSClass maxkey_class; extern JSClass maxkey_class;
// internal things // internal things
void dontDeleteScope( SMScope * s ){} void dontDeleteScope( SMScope * s ){}
void errorReporter( JSContext *cx, const char *message, JSErrorReport * report ); void errorReporter( JSContext *cx, const char *message, JSErrorReport * report );
extern boost::thread_specific_ptr<SMScope> currentScope; extern boost::thread_specific_ptr<SMScope> currentScope;
// bson // bson
JSBool resolveBSONField( JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp ); JSBool resolveBSONField( JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp );
// mongo // mongo
void initMongoJS( SMScope * scope , JSContext * cx , JSObject * global , bool local ); void initMongoJS( SMScope * scope , JSContext * cx , JSObject * global , bool local );
bool appendSpecialDBObject( Convertor * c , BSONObjBuilder& b , const s tring& name , jsval val , JSObject * o ); bool appendSpecialDBObject( Convertor * c , BSONObjBuilder& b , const s tring& name , jsval val , JSObject * o );
#define JSVAL_IS_OID(v) ( JSVAL_IS_OBJECT( v ) && JS_InstanceOf( cx , JSVAL _TO_OBJECT( v ) , &object_id_class , 0 ) ) #define JSVAL_IS_OID(v) ( JSVAL_IS_OBJECT( v ) && JS_InstanceOf( cx , JSVAL _TO_OBJECT( v ) , &object_id_class , 0 ) )
bool isDate( JSContext * cx , JSObject * o ); bool isDate( JSContext * cx , JSObject * o );
// JS private data must be 2byte aligned, so we use a holder to refer t
o an unaligned pointer.
struct BinDataHolder {
BinDataHolder( const char *c, int copyLen = -1 ) :
c_( const_cast< char * >( c ) ),
iFree_( copyLen != -1 ) {
if ( copyLen != -1 ) {
c_ = (char*)malloc( copyLen );
memcpy( c_, c, copyLen );
}
}
~BinDataHolder() {
if ( iFree_ )
free( c_ );
}
char *c_;
bool iFree_;
};
} }
 End of changes. 2 change blocks. 
0 lines changed or deleted 19 lines changed or added


 file_allocator.h   file_allocator.h 
skipping to change at line 160 skipping to change at line 160
string name; string name;
long size; long size;
{ {
boostlock lk( a_.pendingMutex_ ); boostlock lk( a_.pendingMutex_ );
if ( a_.pending_.size() == 0 ) if ( a_.pending_.size() == 0 )
break; break;
name = a_.pending_.front(); name = a_.pending_.front();
size = a_.pendingSize_[ name ]; size = a_.pendingSize_[ name ];
} }
try { try {
log() << "allocating new datafile " << name << ", filling with zeroes..." << endl;
long fd = open(name.c_str(), O_CREAT | O_RDWR | O_NOATIME, S_IRUSR | S_IWUSR); long fd = open(name.c_str(), O_CREAT | O_RDWR | O_NOATIME, S_IRUSR | S_IWUSR);
if ( fd <= 0 ) { if ( fd <= 0 ) {
stringstream ss; stringstream ss;
ss << "couldn't open " << name << ' ' << OU TPUT_ERRNO; ss << "couldn't open " << name << ' ' << OU TPUT_ERRNO;
massert( 10439 , ss.str(), fd <= 0 ); massert( 10439 , ss.str(), fd <= 0 );
} }
#if defined(POSIX_FADV_DONTNEED) #if defined(POSIX_FADV_DONTNEED)
if( posix_fadvise(fd, 0, size, POSIX_FADV_DONTN EED) ) { if( posix_fadvise(fd, 0, size, POSIX_FADV_DONTN EED) ) {
log() << "warning: posix_fadvise fails " << name << ' ' << OUTPUT_ERRNO << endl; log() << "warning: posix_fadvise fails " << name << ' ' << OUTPUT_ERRNO << endl;
skipping to change at line 183 skipping to change at line 184
/* make sure the file is the full desired lengt h */ /* make sure the file is the full desired lengt h */
off_t filelen = lseek(fd, 0, SEEK_END); off_t filelen = lseek(fd, 0, SEEK_END);
if ( filelen < size ) { if ( filelen < size ) {
massert( 10440 , "failure creating new dat afile", filelen == 0 ); massert( 10440 , "failure creating new dat afile", filelen == 0 );
// Check for end of disk. // Check for end of disk.
massert( 10441 , "Unable to allocate file of desired size", massert( 10441 , "Unable to allocate file of desired size",
size - 1 == lseek(fd, size - 1, SEE K_SET) ); size - 1 == lseek(fd, size - 1, SEE K_SET) );
massert( 10442 , "Unable to allocate file of desired size", massert( 10442 , "Unable to allocate file of desired size",
1 == write(fd, "", 1) ); 1 == write(fd, "", 1) );
lseek(fd, 0, SEEK_SET); lseek(fd, 0, SEEK_SET);
log() << "allocating new datafile " << name << ", filling with zeroes..." << endl;
Timer t; Timer t;
long z = 256 * 1024; long z = 256 * 1024;
char buf[z]; char buf[z];
memset(buf, 0, z); memset(buf, 0, z);
long left = size; long left = size;
while ( 1 ) { while ( left > 0 ) {
if ( left <= z ) { long towrite = left;
massert( 10443 , "write failed", l if ( towrite > z )
eft == write(fd, buf, left) ); towrite = z;
break;
} int written = write( fd , buf , towrite
massert( 10444 , "write failed", z == );
write(fd, buf, z) ); massert( 10443 , errnostring("write fai
left -= z; led" ), written > 0 );
left -= written;
} }
log() << "done allocating datafile " << nam e << ", size: " << size/1024/1024 << "MB, took " << ((double)t.millis())/10 00.0 << " secs" << endl; log() << "done allocating datafile " << nam e << ", size: " << size/1024/1024 << "MB, took " << ((double)t.millis())/10 00.0 << " secs" << endl;
} }
close( fd ); close( fd );
} catch ( ... ) { } catch ( ... ) {
problem() << "Failed to allocate new file: " << name problem() << "Failed to allocate new file: " << name
<< ", size: " << size << ", aborting. " << endl; << ", size: " << size << ", aborting. " << endl;
try { try {
BOOST_CHECK_EXCEPTION( boost::filesystem::r emove( name ) ); BOOST_CHECK_EXCEPTION( boost::filesystem::r emove( name ) );
 End of changes. 3 change blocks. 
10 lines changed or deleted 11 lines changed or added


 goodies.h   goodies.h 
skipping to change at line 27 skipping to change at line 27
*/ */
#pragma once #pragma once
#if defined(_WIN32) #if defined(_WIN32)
# include <windows.h> # include <windows.h>
#endif #endif
namespace mongo { namespace mongo {
#if !defined(_WIN32) && !defined(NOEXECINFO) #if !defined(_WIN32) && !defined(NOEXECINFO) && !defined(__freebsd__)
} // namespace mongo } // namespace mongo
#include <pthread.h> #include <pthread.h>
#include <execinfo.h> #include <execinfo.h>
namespace mongo { namespace mongo {
inline pthread_t GetCurrentThreadId() { inline pthread_t GetCurrentThreadId() {
return pthread_self(); return pthread_self();
skipping to change at line 123 skipping to change at line 123
#undef assert #undef assert
#define assert xassert #define assert xassert
#define yassert 1 #define yassert 1
struct WrappingInt { struct WrappingInt {
WrappingInt() { WrappingInt() {
x = 0; x = 0;
} }
WrappingInt(unsigned z) : x(z) { } WrappingInt(unsigned z) : x(z) { }
volatile unsigned x; unsigned x;
operator unsigned() const { operator unsigned() const {
return x; return x;
} }
// returns original value (like x++)
WrappingInt atomicIncrement(){
#if defined(_WIN32)
// InterlockedIncrement returns the new value
return InterlockedIncrement((volatile long*)&x)-1; //long is 32
bits in Win64
#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
// this is in GCC >= 4.1
return __sync_fetch_and_add(&x, 1);
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
// from boost 1.39 interprocess/detail/atomic.hpp
int r;
int val = 1;
asm volatile
(
"lock\n\t"
"xadd %1, %0":
"+m"( x ), "=r"( r ): // outputs (%0, %1)
"1"( val ): // inputs (%2 == %1)
"memory", "cc" // clobbers
);
return r;
#else
# error "unsupported compiler or platform"
#endif
}
static int diff(unsigned a, unsigned b) { static int diff(unsigned a, unsigned b) {
return a-b; return a-b;
} }
bool operator<=(WrappingInt r) { bool operator<=(WrappingInt r) {
// platform dependent // platform dependent
int df = (r.x - x); int df = (r.x - x);
return df >= 0; return df >= 0;
} }
bool operator>(WrappingInt r) { bool operator>(WrappingInt r) {
return !(r<=*this); return !(r<=*this);
skipping to change at line 333 skipping to change at line 307
public: public:
DebugMutex() : locked(0); { } DebugMutex() : locked(0); { }
bool isLocked() { return locked; } bool isLocked() { return locked; }
}; };
*/ */
//typedef boostlock lock; //typedef boostlock lock;
inline bool startsWith(const char *str, const char *prefix) { inline bool startsWith(const char *str, const char *prefix) {
unsigned l = strlen(prefix); size_t l = strlen(prefix);
if ( strlen(str) < l ) return false; if ( strlen(str) < l ) return false;
return strncmp(str, prefix, l) == 0; return strncmp(str, prefix, l) == 0;
} }
inline bool endsWith(const char *p, const char *suffix) { inline bool endsWith(const char *p, const char *suffix) {
int a = strlen(p); size_t a = strlen(p);
int b = strlen(suffix); size_t b = strlen(suffix);
if ( b > a ) return false; if ( b > a ) return false;
return strcmp(p + a - b, suffix) == 0; return strcmp(p + a - b, suffix) == 0;
} }
} // namespace mongo } // namespace mongo
#include "boost/detail/endian.hpp" #include "boost/detail/endian.hpp"
namespace mongo { namespace mongo {
 End of changes. 5 change blocks. 
32 lines changed or deleted 5 lines changed or added


 hashtab.h   hashtab.h 
skipping to change at line 152 skipping to change at line 152
} }
else { else {
assert( nodes[i].hash == k.hash() ); assert( nodes[i].hash == k.hash() );
} }
nodes[i].value = value; nodes[i].value = value;
return true; return true;
} }
typedef void (*IteratorCallback)( const Key& k , Type& v ); typedef void (*IteratorCallback)( const Key& k , Type& v );
void iterall( IteratorCallback callback ){ void iterAll( IteratorCallback callback ){
for ( int i=0; i<n; i++ ){ for ( int i=0; i<n; i++ ){
if ( ! nodes[i].inUse() ) if ( ! nodes[i].inUse() )
continue; continue;
callback( nodes[i].k , nodes[i].value ); callback( nodes[i].k , nodes[i].value );
} }
} }
}; };
#pragma pack() #pragma pack()
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 index.h   index.h 
skipping to change at line 25 skipping to change at line 25
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "../stdafx.h" #include "../stdafx.h"
namespace mongo { namespace mongo {
/* precomputed details about an index, used for inserting keys on updat
es
stored/cached in NamespaceDetailsTransient, or can be used standalon
e
*/
class IndexSpec { class IndexSpec {
public: public:
BSONObj keys; BSONObj keyPattern; // e.g., { name : 1 }
BSONObj meta; BSONObj info; // this is the same as IndexDetails::info.obj()
IndexSpec(){ IndexSpec(){
} }
IndexSpec( const BSONObj& k , const BSONObj& m = BSONObj() ) IndexSpec( const BSONObj& k , const BSONObj& m = BSONObj() )
: keys(k) , meta(m){ : keyPattern(k) , info(m){
_init(); _init();
} }
/** /**
this is a DickLock of an IndexDetails info this is a DiscLoc of an IndexDetails info
should have a key field should have a key field
*/ */
IndexSpec( const DiskLoc& loc ){ IndexSpec( const DiskLoc& loc ){
reset( loc ); reset( loc );
} }
void reset( const DiskLoc& loc ){ void reset( const DiskLoc& loc ){
meta = loc.obj(); info = loc.obj();
keys = meta["key"].embeddedObjectUserCheck(); keyPattern = info["key"].embeddedObjectUserCheck();
if ( keys.objsize() == 0 ) { if ( keyPattern.objsize() == 0 ) {
out() << meta.toString() << endl; out() << info.toString() << endl;
assert(false); assert(false);
} }
_init(); _init();
} }
void getKeys( const BSONObj &obj, BSONObjSetDefaultOrder &keys ) co nst; void getKeys( const BSONObj &obj, BSONObjSetDefaultOrder &keys ) co nst;
private: private:
void _getKeys( vector<const char*> fieldNames , vector<BSONElement> fixed , const BSONObj &obj, BSONObjSetDefaultOrder &keys ) const; void _getKeys( vector<const char*> fieldNames , vector<BSONElement> fixed , const BSONObj &obj, BSONObjSetDefaultOrder &keys ) const;
vector<const char*> _fieldNames; vector<const char*> _fieldNames;
vector<BSONElement> _fixed; vector<BSONElement> _fixed;
BSONObj _nullKey; BSONObj _nullKey;
BSONObj _nullObj; BSONObj _nullObj;
BSONElement _nullElt; BSONElement _nullElt;
void _init(); void _init();
skipping to change at line 77 skipping to change at line 78
BSONObj _nullObj; BSONObj _nullObj;
BSONElement _nullElt; BSONElement _nullElt;
void _init(); void _init();
}; };
/* Details about a particular index. There is one of these effective ly for each object in /* Details about a particular index. There is one of these effective ly for each object in
system.namespaces (although this also includes the head pointer, which is not in that system.namespaces (although this also includes the head pointer, which is not in that
collection). collection).
** MemoryMapped Record ** ** MemoryMapped Record ** (i.e., this is on disk data)
*/ */
class IndexDetails { class IndexDetails {
public: public:
DiskLoc head; /* btree head disk location */ DiskLoc head; /* btree head disk location */
/* Location of index info object. Format: /* Location of index info object. Format:
{ name:"nameofindex", ns:"parentnsname", key: {keypattobject} { name:"nameofindex", ns:"parentnsname", key: {keypattobject}
[, unique: <bool>, background: <bool>] [, unique: <bool>, background: <bool>]
} }
skipping to change at line 120 skipping to change at line 121
/* get the key pattern for this object. /* get the key pattern for this object.
e.g., { lastname:1, firstname:1 } e.g., { lastname:1, firstname:1 }
*/ */
BSONObj keyPattern() const { BSONObj keyPattern() const {
return info.obj().getObjectField("key"); return info.obj().getObjectField("key");
} }
/* true if the specified key is in the index */ /* true if the specified key is in the index */
bool hasKey(const BSONObj& key); bool hasKey(const BSONObj& key);
bool wouldCreateDup(const BSONObj& key, DiskLoc self);
// returns name of this index's storage area // returns name of this index's storage area
// database.table.$index // database.table.$index
string indexNamespace() const { string indexNamespace() const {
BSONObj io = info.obj(); BSONObj io = info.obj();
string s; string s;
s.reserve(Namespace::MaxNsLen); s.reserve(Namespace::MaxNsLen);
s = io.getStringField("ns"); s = io.getStringField("ns");
assert( !s.empty() ); assert( !s.empty() );
s += ".$"; s += ".$";
skipping to change at line 187 skipping to change at line 189
return info.obj().toString(); return info.obj().toString();
} }
}; };
struct IndexChanges/*on an update*/ { struct IndexChanges/*on an update*/ {
BSONObjSetDefaultOrder oldkeys; BSONObjSetDefaultOrder oldkeys;
BSONObjSetDefaultOrder newkeys; BSONObjSetDefaultOrder newkeys;
vector<BSONObj*> removed; // these keys were removed as part of the change vector<BSONObj*> removed; // these keys were removed as part of the change
vector<BSONObj*> added; // these keys were added as part of the c hange vector<BSONObj*> added; // these keys were added as part of the c hange
void dupCheck(IndexDetails& idx) { /** @curObjLoc - the object we want to add's location. if it is al
ready in the
index, that is allowed here (for bg indexing case)
.
*/
void dupCheck(IndexDetails& idx, DiskLoc curObjLoc) {
if( added.empty() || !idx.unique() ) if( added.empty() || !idx.unique() )
return; return;
for( vector<BSONObj*>::iterator i = added.begin(); i != added.e for( vector<BSONObj*>::iterator i = added.begin(); i != added.e
nd(); i++ ) nd(); i++ ) {
uassert( 11001 , "E11001 duplicate key on update", !idx.has bool dup = idx.wouldCreateDup(**i, curObjLoc);
Key(**i)); uassert( 11001 , "E11001 duplicate key on update", !dup);
}
} }
}; };
class NamespaceDetails; class NamespaceDetails;
void getIndexChanges(vector<IndexChanges>& v, NamespaceDetails& d, BSON Obj newObj, BSONObj oldObj); void getIndexChanges(vector<IndexChanges>& v, NamespaceDetails& d, BSON Obj newObj, BSONObj oldObj);
void dupCheck(vector<IndexChanges>& v, NamespaceDetails& d); void dupCheck(vector<IndexChanges>& v, NamespaceDetails& d, DiskLoc cur ObjLoc);
} // namespace mongo } // namespace mongo
 End of changes. 12 change blocks. 
17 lines changed or deleted 27 lines changed or added


 instance.h   instance.h 
skipping to change at line 41 skipping to change at line 41
#define OPWRITE if( _diaglog.level & 1 ) _diaglog.write((char *) m.data, m. data->len); #define OPWRITE if( _diaglog.level & 1 ) _diaglog.write((char *) m.data, m. data->len);
#define OPREAD if( _diaglog.level & 2 ) _diaglog.readop((char *) m.data, m. data->len); #define OPREAD if( _diaglog.level & 2 ) _diaglog.readop((char *) m.data, m. data->len);
struct DiagLog { struct DiagLog {
ofstream *f; ofstream *f;
/* 0 = off; 1 = writes, 2 = reads, 3 = both /* 0 = off; 1 = writes, 2 = reads, 3 = both
7 = log a few reads, and all writes. 7 = log a few reads, and all writes.
*/ */
int level; int level;
boost::mutex mutex;
DiagLog() : f(0) , level(0) { } DiagLog() : f(0) , level(0) { }
void init() { void init() {
if ( ! f && level ){ if ( ! f && level ){
log() << "diagLogging = " << level << endl; log() << "diagLogging = " << level << endl;
stringstream ss; stringstream ss;
ss << "diaglog." << hex << time(0); ss << dbpath << "/diaglog." << hex << time(0);
string name = ss.str(); string name = ss.str();
f = new ofstream(name.c_str(), ios::out | ios::binary); f = new ofstream(name.c_str(), ios::out | ios::binary);
if ( ! f->good() ) { if ( ! f->good() ) {
problem() << "couldn't open log stream" << endl; problem() << "couldn't open log stream" << endl;
throw 1717; throw 1717;
} }
} }
} }
/** /**
* @return old * @return old
*/ */
int setLevel( int newLevel ){ int setLevel( int newLevel ){
int old = level; int old = level;
level = newLevel; level = newLevel;
init(); init();
return old; return old;
} }
void flush() { void flush() {
if ( level ) f->flush(); if ( level ){
boostlock lk(mutex);
f->flush();
}
} }
void write(char *data,int len) { void write(char *data,int len) {
if ( level & 1 ) f->write(data,len); if ( level & 1 ){
boostlock lk(mutex);
f->write(data,len);
}
} }
void readop(char *data, int len) { void readop(char *data, int len) {
if ( level & 2 ) { if ( level & 2 ) {
bool log = (level & 4) == 0; bool log = (level & 4) == 0;
OCCASIONALLY log = true; OCCASIONALLY log = true;
if ( log ) if ( log ){
boostlock lk(mutex);
f->write(data,len); f->write(data,len);
}
} }
} }
}; };
extern DiagLog _diaglog; extern DiagLog _diaglog;
/* we defer response until we unlock. don't want a blocked socket to /* we defer response until we unlock. don't want a blocked socket to
keep things locked. keep things locked.
*/ */
struct DbResponse { struct DbResponse {
skipping to change at line 127 skipping to change at line 137
} }
virtual string getServerAddress() const{ virtual string getServerAddress() const{
return "localhost"; // TODO: should this have the port? return "localhost"; // TODO: should this have the port?
} }
virtual bool call( Message &toSend, Message &response, bool assertO k=true ); virtual bool call( Message &toSend, Message &response, bool assertO k=true );
virtual void say( Message &toSend ); virtual void say( Message &toSend );
virtual void sayPiggyBack( Message &toSend ) { virtual void sayPiggyBack( Message &toSend ) {
// don't need to piggy back when connected locally // don't need to piggy back when connected locally
return say( toSend ); return say( toSend );
} }
class AlwaysAuthorized : public AuthenticationInfo {
virtual bool isAuthorized( const char *dbname ) {
return true;
}
};
/* TODO: this looks bad that auth is set to always. is that really
always safe? */
class SavedContext {
public:
SavedContext() {
_save = dbMutex.atLeastReadLocked();
Client *c = currentClient.get();
oldAuth = c->ai;
// careful, don't want to free this:
c->ai = &always;
/* it only makes sense to manipulate a pointer - c->databas
e() - if locked.
thus the _saved flag.
*/
if( _save ) {
if ( c->database() ) {
dbMutex.assertAtLeastReadLocked();
_oldName = c->database()->name;
}
}
}
~SavedContext() {
Client *c = currentClient.get();
c->ai = oldAuth;
if( _save ) {
if ( !_oldName.empty() ) {
dbMutex.assertAtLeastReadLocked();
setClient( _oldName.c_str() );
}
}
else {
// defensive
cc().clearns();
}
}
private:
bool _save;
static AlwaysAuthorized always;
AuthenticationInfo *oldAuth;
string _oldName;
};
}; };
extern int lockFile; extern int lockFile;
void acquirePathLock(); void acquirePathLock();
} // namespace mongo } // namespace mongo
 End of changes. 7 change blocks. 
53 lines changed or deleted 14 lines changed or added


 jsobj.h   jsobj.h 
skipping to change at line 512 skipping to change at line 512
const char *binData(int& len) const { const char *binData(int& len) const {
// BinData: <int len> <byte subtype> <byte[len] data> // BinData: <int len> <byte subtype> <byte[len] data>
assert( type() == BinData ); assert( type() == BinData );
len = valuestrsize(); len = valuestrsize();
return value() + 5; return value() + 5;
} }
BinDataType binDataType() const { BinDataType binDataType() const {
// BinData: <int len> <byte subtype> <byte[len] data> // BinData: <int len> <byte subtype> <byte[len] data>
assert( type() == BinData ); assert( type() == BinData );
char c = (value() + 4)[0]; unsigned char c = (value() + 4)[0];
return (BinDataType)c; return (BinDataType)c;
} }
/** Retrieve the regex string for a Regex element */ /** Retrieve the regex string for a Regex element */
const char *regex() const { const char *regex() const {
assert(type() == RegEx); assert(type() == RegEx);
return value(); return value();
} }
/** Retrieve the regex flags (options) for a Regex element */ /** Retrieve the regex flags (options) for a Regex element */
skipping to change at line 576 skipping to change at line 576
int getGtLtOp( int def = 0 ) const; int getGtLtOp( int def = 0 ) const;
/** Constructs an empty element */ /** Constructs an empty element */
BSONElement(); BSONElement();
/** Check that data is internally consistent. */ /** Check that data is internally consistent. */
void validate() const; void validate() const;
/** True if this element may contain subobjects. */ /** True if this element may contain subobjects. */
bool mayEncapsulate() const { bool mayEncapsulate() const {
return type() == Object || switch ( type() ){
type() == Array || case Object:
type() == CodeWScope; case Array:
case CodeWScope:
return true;
default:
return false;
}
}
/** True if this element can be a BSONObj */
bool isABSONObj() const {
switch( type() ){
case Object:
case Array:
return true;
default:
return false;
}
} }
Date_t timestampTime() const{ Date_t timestampTime() const{
unsigned long long t = ((unsigned int*)(value() + 4 ))[0]; unsigned long long t = ((unsigned int*)(value() + 4 ))[0];
return t * 1000; return t * 1000;
} }
unsigned int timestampInc() const{ unsigned int timestampInc() const{
return ((unsigned int*)(value() ))[0]; return ((unsigned int*)(value() ))[0];
} }
skipping to change at line 627 skipping to change at line 643
fieldNameSize_ = size + 1; fieldNameSize_ = size + 1;
} }
} }
totalSize = -1; totalSize = -1;
} }
private: private:
const char *data; const char *data;
mutable int fieldNameSize_; // cached value mutable int fieldNameSize_; // cached value
int fieldNameSize() const { int fieldNameSize() const {
if ( fieldNameSize_ == -1 ) if ( fieldNameSize_ == -1 )
fieldNameSize_ = strlen( fieldName() ) + 1; fieldNameSize_ = (int)strlen( fieldName() ) + 1;
return fieldNameSize_; return fieldNameSize_;
} }
mutable int totalSize; /* caches the computed size */ mutable int totalSize; /* caches the computed size */
}; };
int getGtLtOp(const BSONElement& e); int getGtLtOp(const BSONElement& e);
struct BSONElementCmpWithoutField { struct BSONElementCmpWithoutField {
bool operator()( const BSONElement &l, const BSONElement &r ) const { bool operator()( const BSONElement &l, const BSONElement &r ) const {
return l.woCompare( r, false ); return l.woCompare( r, false );
skipping to change at line 702 skipping to change at line 718
}; };
const char *_objdata; const char *_objdata;
boost::shared_ptr< Holder > _holder; boost::shared_ptr< Holder > _holder;
void init(const char *data, bool ifree) { void init(const char *data, bool ifree) {
if ( ifree ) if ( ifree )
_holder.reset( new Holder( data ) ); _holder.reset( new Holder( data ) );
_objdata = data; _objdata = data;
if ( ! isValid() ){ if ( ! isValid() ){
stringstream ss; stringstream ss;
ss << "Invalid BSONObj spec size: " << objsize(); ss << "Invalid BSONObj spec size: " << objsize();
try {
BSONElement e = firstElement();
ss << " first element:" << e.toString() << " ";
}
catch ( ... ){}
string s = ss.str(); string s = ss.str();
massert( 10334 , s , 0 ); massert( 10334 , s , 0 );
} }
} }
#pragma pack(1) #pragma pack(1)
static struct EmptyObject { static struct EmptyObject {
EmptyObject() { EmptyObject() {
len = 5; len = 5;
jstype = EOO; jstype = EOO;
} }
skipping to change at line 770 skipping to change at line 791
*/ */
void getFieldsDotted(const char *name, BSONElementSet &ret, bool *d eep = 0) const; void getFieldsDotted(const char *name, BSONElementSet &ret, bool *d eep = 0) const;
/** Like getFieldDotted(), but returns first array encountered whil e traversing the /** Like getFieldDotted(), but returns first array encountered whil e traversing the
dotted fields of name. The name variable is updated to represe nt field dotted fields of name. The name variable is updated to represe nt field
names with respect to the returned element. */ names with respect to the returned element. */
BSONElement getFieldDottedOrArray(const char *&name) const; BSONElement getFieldDottedOrArray(const char *&name) const;
/** Get the field of the specified name. eoo() is true on the retur ned /** Get the field of the specified name. eoo() is true on the retur ned
element if not found. element if not found.
*/ */
BSONElement getField(const string name) const { BSONElement getField(const char *name) const;
return getField( name.c_str() );
};
/** Get the field of the specified name. eoo() is true on the retur ned /** Get the field of the specified name. eoo() is true on the retur ned
element if not found. element if not found.
*/ */
BSONElement getField(const char *name) const; /* return has eoo() t BSONElement getField(const string name) const {
rue if no match */ return getField( name.c_str() );
};
/** Get the field of the specified name. eoo() is true on the retur ned /** Get the field of the specified name. eoo() is true on the retur ned
element if not found. element if not found.
*/ */
BSONElement operator[] (const char *field) const { BSONElement operator[] (const char *field) const {
return getField(field); return getField(field);
} }
BSONElement operator[] (const string& field) const { BSONElement operator[] (const string& field) const {
return getField(field); return getField(field);
skipping to change at line 904 skipping to change at line 925
return (os == 0 || memcmp(objdata(),r.objdata(),os)==0); return (os == 0 || memcmp(objdata(),r.objdata(),os)==0);
} }
return false; return false;
} }
/** @return first field of the object */ /** @return first field of the object */
BSONElement firstElement() const { BSONElement firstElement() const {
return BSONElement(objdata() + 4); return BSONElement(objdata() + 4);
} }
/** @return element with fieldname "name". returnvalue.eoo( /** use getField() instead. */
) is true if not found */ //BSONElement getField(const char *name) const;
BSONElement findElement(const char *name) const; //BSONElement getField(string name) const {
/** @return element with fieldname "name". returnvalue.eoo(
) is true if not found */
BSONElement findElement(string name) const {
return findElement(name.c_str());
}
/** @return true if field exists in the object */ /** @return true if field exists in the object */
bool hasElement(const char *name) const; bool hasElement(const char *name) const;
/** Get the _id field from the object. For good performance drivers should /** Get the _id field from the object. For good performance drivers should
assure that _id is the first element of the object; however, co rrect operation assure that _id is the first element of the object; however, co rrect operation
is assured regardless. is assured regardless.
@return true if found @return true if found
*/ */
bool getObjectID(BSONElement& e) const; bool getObjectID(BSONElement& e) const;
skipping to change at line 1188 skipping to change at line 1205
return b; return b;
} }
/** Append a boolean element */ /** Append a boolean element */
void appendBool(const char *fieldName, int val) { void appendBool(const char *fieldName, int val) {
b.append((char) Bool); b.append((char) Bool);
b.append(fieldName); b.append(fieldName);
b.append((char) (val?1:0)); b.append((char) (val?1:0));
} }
/** Append a boolean element */
void append(const char *fieldName, bool val) {
b.append((char) Bool);
b.append(fieldName);
b.append((char) (val?1:0));
}
/** Append a 32 bit integer element */ /** Append a 32 bit integer element */
void append(const char *fieldName, int n) { void append(const char *fieldName, int n) {
b.append((char) NumberInt); b.append((char) NumberInt);
b.append(fieldName); b.append(fieldName);
b.append(n); b.append(n);
} }
/** Append a 32 bit integer element */ /** Append a 32 bit integer element */
void append(const string &fieldName, int n) { void append(const string &fieldName, int n) {
append( fieldName.c_str(), n ); append( fieldName.c_str(), n );
} }
skipping to change at line 1214 skipping to change at line 1238
b.append((char) NumberLong); b.append((char) NumberLong);
b.append(fieldName); b.append(fieldName);
b.append(n); b.append(n);
} }
/** Append a NumberLong */ /** Append a NumberLong */
void append(const string& fieldName, long long n) { void append(const string& fieldName, long long n) {
append( fieldName.c_str() , n ); append( fieldName.c_str() , n );
} }
/** appends a number. if n < max(int)/2 then uses int, otherwise l
ong long */
void appendIntOrLL( const string& fieldName , long long n ){
long long x = n;
if ( x < 0 )
x = x * -1;
if ( x < ( numeric_limits<int>::max() / 2 ) )
append( fieldName.c_str() , (int)n );
else
append( fieldName.c_str() , n );
}
/** Append a double element */ /** Append a double element */
BSONObjBuilder& append(const char *fieldName, double n) { BSONObjBuilder& append(const char *fieldName, double n) {
b.append((char) NumberDouble); b.append((char) NumberDouble);
b.append(fieldName); b.append(fieldName);
b.append(n); b.append(n);
return *this; return *this;
} }
/** tries to append the data as a number /** tries to append the data as a number
* @return true if the data was able to be converted to a number * @return true if the data was able to be converted to a number
skipping to change at line 1450 skipping to change at line 1485
/** Fetch the object we have built. /** Fetch the object we have built.
BSONObjBuilder still frees the object when the build er goes out of BSONObjBuilder still frees the object when the build er goes out of
scope -- very important to keep in mind. Use obj() if you scope -- very important to keep in mind. Use obj() if you
would like the BSONObj to last longer than the build er. would like the BSONObj to last longer than the build er.
*/ */
BSONObj done() { BSONObj done() {
return BSONObj(_done()); return BSONObj(_done());
} }
/** Peek at what is in the builder, but leave the builder ready for
more appends.
The returned object is only valid until the next modification o
r destruction of the builder.
Intended use case: append a field if not already there.
*/
BSONObj asTempObj() {
BSONObj temp(_done());
b.setlen(b.len()-1); //next append should overwrite the EOO
return temp;
}
/* assume ownership of the buffer - you must then free it (with fre e()) */ /* assume ownership of the buffer - you must then free it (with fre e()) */
char* decouple(int& l) { char* decouple(int& l) {
char *x = _done(); char *x = _done();
assert( x ); assert( x );
l = b.len(); l = b.len();
b.decouple(); b.decouple();
return x; return x;
} }
void decouple() { void decouple() {
b.decouple(); // post done() call version. be sure jsobj fr ees... b.decouple(); // post done() call version. be sure jsobj fr ees...
skipping to change at line 1581 skipping to change at line 1626
/** @return true if more elements exist to be enumerated. */ /** @return true if more elements exist to be enumerated. */
bool moreWithEOO() { bool moreWithEOO() {
return pos < theend; return pos < theend;
} }
bool more(){ bool more(){
return pos < theend && pos[0]; return pos < theend && pos[0];
} }
/** @return the next element in the object. For the final element, element.eoo() will be true. */ /** @return the next element in the object. For the final element, element.eoo() will be true. */
BSONElement next( bool checkEnd = false ) { BSONElement next( bool checkEnd = false ) {
assert( pos < theend ); assert( pos < theend );
BSONElement e( pos, checkEnd ? theend - pos : -1 ); BSONElement e( pos, checkEnd ? (int)(theend - pos) : -1 );
pos += e.size( checkEnd ? theend - pos : -1 ); pos += e.size( checkEnd ? (int)(theend - pos) : -1 );
return e; return e;
} }
private: private:
const char *pos; const char *pos;
const char *theend; const char *theend;
}; };
/* iterator a BSONObj which is an array, in array order. /* iterator a BSONObj which is an array, in array order.
class JSArrayIter { class JSArrayIter {
public: public:
skipping to change at line 1651 skipping to change at line 1696
#pragma pack() #pragma pack()
extern JSObj1 js1; extern JSObj1 js1;
#ifdef _DEBUG #ifdef _DEBUG
#define CHECK_OBJECT( o , msg ) massert( 10337 , (string)"object not valid " + (msg) , (o).isValid() ) #define CHECK_OBJECT( o , msg ) massert( 10337 , (string)"object not valid " + (msg) , (o).isValid() )
#else #else
#define CHECK_OBJECT( o , msg ) #define CHECK_OBJECT( o , msg )
#endif #endif
inline BSONObj BSONElement::embeddedObjectUserCheck() { inline BSONObj BSONElement::embeddedObjectUserCheck() {
uassert( 10065 , "invalid parameter: expected an object", type()== Object || type()==Array ); uassert( 10065 , "invalid parameter: expected an object", isABSONO bj() );
return BSONObj(value()); return BSONObj(value());
} }
inline BSONObj BSONElement::embeddedObject() const { inline BSONObj BSONElement::embeddedObject() const {
assert( type()==Object || type()==Array ); assert( isABSONObj() );
return BSONObj(value()); return BSONObj(value());
} }
inline BSONObj BSONElement::codeWScopeObject() const { inline BSONObj BSONElement::codeWScopeObject() const {
assert( type() == CodeWScope ); assert( type() == CodeWScope );
int strSizeWNull = *(int *)( value() + 4 ); int strSizeWNull = *(int *)( value() + 4 );
return BSONObj( value() + 4 + 4 + strSizeWNull ); return BSONObj( value() + 4 + 4 + strSizeWNull );
} }
inline BSONObj BSONObj::copy() const { inline BSONObj BSONObj::copy() const {
skipping to change at line 1697 skipping to change at line 1742
BSONObjIterator it(*this); BSONObjIterator it(*this);
while ( it.moreWithEOO() ) { while ( it.moreWithEOO() ) {
BSONElement e = it.next(); BSONElement e = it.next();
if ( strcmp(name, e.fieldName()) == 0 ) if ( strcmp(name, e.fieldName()) == 0 )
return true; return true;
} }
} }
return false; return false;
} }
inline BSONElement BSONObj::findElement(const char *name) const { inline BSONElement BSONObj::getField(const char *name) const {
if ( !isEmpty() ) { BSONObjIterator i(*this);
BSONObjIterator it(*this); while ( i.more() ) {
while ( it.moreWithEOO() ) { BSONElement e = i.next();
BSONElement e = it.next(); if ( strcmp(e.fieldName(), name) == 0 )
if ( strcmp(name, e.fieldName()) == 0 ) return e;
return e;
}
} }
return BSONElement(); return BSONElement();
} }
/* add all the fields from the object specified to this object */ /* add all the fields from the object specified to this object */
inline BSONObjBuilder& BSONObjBuilder::appendElements(BSONObj x) { inline BSONObjBuilder& BSONObjBuilder::appendElements(BSONObj x) {
BSONObjIterator it(x); BSONObjIterator it(x);
while ( it.moreWithEOO() ) { while ( it.moreWithEOO() ) {
BSONElement e = it.next(); BSONElement e = it.next();
if ( e.eoo() ) break; if ( e.eoo() ) break;
append(e); append(e);
} }
return *this; return *this;
} }
inline bool BSONObj::isValid(){ inline bool BSONObj::isValid(){
return objsize() > 0 && objsize() <= 1024 * 1024 * 8; return objsize() > 0 && objsize() <= 1024 * 1024 * 8;
} }
inline bool BSONObj::getObjectID(BSONElement& e) const { inline bool BSONObj::getObjectID(BSONElement& e) const {
BSONElement f = findElement("_id"); BSONElement f = getField("_id");
if( !f.eoo() ) { if( !f.eoo() ) {
e = f; e = f;
return true; return true;
} }
return false; return false;
} }
inline BSONObjBuilderValueStream::BSONObjBuilderValueStream( BSONObjBui lder * builder ) { inline BSONObjBuilderValueStream::BSONObjBuilderValueStream( BSONObjBui lder * builder ) {
_fieldName = 0; _fieldName = 0;
_builder = builder; _builder = builder;
 End of changes. 15 change blocks. 
32 lines changed or deleted 75 lines changed or added


 jsobjmanipulator.h   jsobjmanipulator.h 
skipping to change at line 25 skipping to change at line 25
* You should have received a copy of the GNU Affero General Public Lice nse * You should have received a copy of the GNU Affero General Public Lice nse
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "jsobj.h" #include "jsobj.h"
namespace mongo { namespace mongo {
/** Manipulate the binary representation of a BSONElement in-place. /** Manipulate the binary representation of a BSONElement in-place.
Careful, this casts away const. Careful, this casts away const.
*/ */
class BSONElementManipulator { class BSONElementManipulator {
public: public:
BSONElementManipulator( const BSONElement &element ) : BSONElementManipulator( const BSONElement &element ) :
element_( element ) { _element( element ) {
assert( !element_.eoo() ); assert( !_element.eoo() );
} }
/** Replace a Timestamp type with a Date type initialized to /** Replace a Timestamp type with a Date type initialized to
OpTime::now().asDate() OpTime::now().asDate()
*/ */
void initTimestamp(); void initTimestamp();
/** Change the value, in place, of the number. */ /** Change the value, in place, of the number. */
void setNumber(double d) { void setNumber(double d) {
if ( element_.type() == NumberDouble ) *reinterpret_cast< double * if ( _element.type() == NumberDouble ) *reinterpret_cast< doubl
>( value() ) = d; e * >( value() ) = d;
else if ( element_.type() == NumberInt ) *reinterpret_cast< int * > else if ( _element.type() == NumberInt ) *reinterpret_cast< int
( value() ) = (int) d; * >( value() ) = (int) d;
} }
void setLong(long long n) { void setLong(long long n) {
if( element_.type() == NumberLong ) *reinterpret_cast< long long * if( _element.type() == NumberLong ) *reinterpret_cast< long lon
>( value() ) = n; g * >( value() ) = n;
} }
void setInt(int n) {
assert( _element.type() == NumberInt );
*reinterpret_cast< int * >( value() ) = n;
}
/** Replace the type and value of the element with the type and value o /** Replace the type and value of the element with the type and val
f e, ue of e,
preserving the original fieldName */ preserving the original fieldName */
void replaceTypeAndValue( const BSONElement &e ) { void replaceTypeAndValue( const BSONElement &e ) {
*data() = e.type(); *data() = e.type();
memcpy( value(), e.value(), e.valuesize() ); memcpy( value(), e.value(), e.valuesize() );
} }
static void lookForTimestamps( const BSONObj& obj ){ static void lookForTimestamps( const BSONObj& obj ){
// If have a Timestamp field as the first or second element, // If have a Timestamp field as the first or second element,
// update it to a Date field set to OpTime::now().asDate(). The // update it to a Date field set to OpTime::now().asDate(). Th
// replacement policy is a work in progress. e
// replacement policy is a work in progress.
BSONObjIterator i( obj ); BSONObjIterator i( obj );
for( int j = 0; i.moreWithEOO() && j < 2; ++j ) { for( int j = 0; i.moreWithEOO() && j < 2; ++j ) {
BSONElement e = i.next(); BSONElement e = i.next();
if ( e.eoo() ) if ( e.eoo() )
break; break;
if ( e.type() == Timestamp ){ if ( e.type() == Timestamp ){
BSONElementManipulator( e ).initTimestamp(); BSONElementManipulator( e ).initTimestamp();
break; break;
}
} }
} }
} private:
private: char *data() { return nonConst( _element.rawdata() ); }
char *data() { return nonConst( element_.rawdata() ); } char *value() { return nonConst( _element.value() ); }
char *value() { return nonConst( element_.value() ); } static char *nonConst( const char *s ) { return const_cast< char *
static char *nonConst( const char *s ) { return const_cast< char * >( s >( s ); }
); }
const BSONElement element_; const BSONElement _element;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 6 change blocks. 
51 lines changed or deleted 57 lines changed or added


 lasterror.h   lasterror.h 
skipping to change at line 33 skipping to change at line 33
namespace mongo { namespace mongo {
class BSONObjBuilder; class BSONObjBuilder;
class Message; class Message;
struct LastError { struct LastError {
int code; int code;
string msg; string msg;
enum UpdatedExistingType { NotUpdate, True, False } updatedExisting ; enum UpdatedExistingType { NotUpdate, True, False } updatedExisting ;
/* todo: nObjects should be 64 bit */ /* todo: nObjects should be 64 bit */
int nObjects; long long nObjects;
int nPrev; int nPrev;
bool valid; bool valid;
bool overridenById; bool overridenById;
bool disabled; bool disabled;
void raiseError(int _code , const char *_msg) { void raiseError(int _code , const char *_msg) {
reset( true ); reset( true );
code = _code; code = _code;
msg = _msg; msg = _msg;
} }
void recordUpdate( bool _updatedExisting, int nChanged ) { void recordUpdate( bool _updatedExisting, long long nChanged ) {
reset( true ); reset( true );
nObjects = nChanged; nObjects = nChanged;
updatedExisting = _updatedExisting ? True : False; updatedExisting = _updatedExisting ? True : False;
} }
void recordDelete( int nDeleted ) { void recordDelete( long long nDeleted ) {
reset( true ); reset( true );
nObjects = nDeleted; nObjects = nDeleted;
} }
LastError() { LastError() {
overridenById = false; overridenById = false;
reset(); reset();
} }
void reset( bool _valid = false ) { void reset( bool _valid = false ) {
code = 0; code = 0;
msg.clear(); msg.clear();
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 log.h   log.h 
skipping to change at line 21 skipping to change at line 21
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include <string.h> #include <string.h>
#include <errno.h>
namespace mongo { namespace mongo {
using boost::shared_ptr; using boost::shared_ptr;
// Utility interface for stringifying object only when val() called. // Utility interface for stringifying object only when val() called.
class LazyString { class LazyString {
public: public:
virtual ~LazyString() {} virtual ~LazyString() {}
virtual string val() const = 0; virtual string val() const = 0;
skipping to change at line 247 skipping to change at line 248
/** /**
log to a file rather than stdout log to a file rather than stdout
defined in assert_util.cpp defined in assert_util.cpp
*/ */
void initLogging( const string& logpath , bool append ); void initLogging( const string& logpath , bool append );
void rotateLogs( int signal = 0 ); void rotateLogs( int signal = 0 );
#define OUTPUT_ERRNOX(x) "errno:" << x << " " << strerror(x) #define OUTPUT_ERRNOX(x) "errno:" << x << " " << strerror(x)
#define OUTPUT_ERRNO OUTPUT_ERRNOX(errno) #define OUTPUT_ERRNO OUTPUT_ERRNOX(errno)
string errnostring( const char * prefix = 0 );
} // namespace mongo } // namespace mongo
 End of changes. 2 change blocks. 
0 lines changed or deleted 3 lines changed or added


 matcher.h   matcher.h 
skipping to change at line 73 skipping to change at line 73
myset.reset( new set<BSONElement,element_lt>() ); myset.reset( new set<BSONElement,element_lt>() );
BSONObjIterator i( array ); BSONObjIterator i( array );
while ( i.more() ) { while ( i.more() ) {
BSONElement ie = i.next(); BSONElement ie = i.next();
myset->insert(ie); myset->insert(ie);
} }
} }
~ElementMatcher(); ~ElementMatcher() { }
BSONElement toMatch; BSONElement toMatch;
int compareOp; int compareOp;
shared_ptr< set<BSONElement,element_lt> > myset; shared_ptr< set<BSONElement,element_lt> > myset;
// these are for specific operators // these are for specific operators
int mod; int mod;
int modm; int modm;
BSONType type; BSONType type;
shared_ptr<Matcher> subMatcher; shared_ptr<Matcher> subMatcher;
}; };
// SQL where clause equivalent class Where; // used for $where javascript eval
class Where;
class DiskLoc; class DiskLoc;
/* Match BSON objects against a query pattern. /* Match BSON objects against a query pattern.
e.g. e.g.
db.foo.find( { a : 3 } ); db.foo.find( { a : 3 } );
{ a : 3 } is the pattern object. See wiki documentation for full in fo. { a : 3 } is the pattern object. See wiki documentation for full in fo.
GT/LT: GT/LT:
skipping to change at line 147 skipping to change at line 146
return; return;
basics.push_back( ElementMatcher( e , c ) ); basics.push_back( ElementMatcher( e , c ) );
} }
int valuesMatch(const BSONElement& l, const BSONElement& r, int op, const ElementMatcher& bm); int valuesMatch(const BSONElement& l, const BSONElement& r, int op, const ElementMatcher& bm);
Where *where; // set if query uses $where Where *where; // set if query uses $where
BSONObj jsobj; // the query pattern. e.g., { name : "joe" } BSONObj jsobj; // the query pattern. e.g., { name : "joe" }
BSONObj constrainIndexKey_; BSONObj constrainIndexKey_;
vector<ElementMatcher> basics; vector<ElementMatcher> basics;
// int n; // # of basicmatcher items
bool haveSize; bool haveSize;
bool all; bool all;
bool hasArray; bool hasArray;
/* $atomic - if true, a multi document operation (some removes, upd ates) /* $atomic - if true, a multi document operation (some removes, upd ates)
should be done atomically. in that case, we do not yi eld - should be done atomically. in that case, we do not yi eld -
i.e. we stay locked the whole time. i.e. we stay locked the whole time.
http://www.mongodb.org/display/DOCS/Removing[ http://www.mongodb.org/display/DOCS/Removing[
*/ */
bool _atomic; bool _atomic;
 End of changes. 3 change blocks. 
4 lines changed or deleted 2 lines changed or added


 message.h   message.h 
skipping to change at line 21 skipping to change at line 21
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include "../util/sock.h" #include "../util/sock.h"
#include "../util/atomic_int.h"
namespace mongo { namespace mongo {
class Message; class Message;
class MessagingPort; class MessagingPort;
class PiggyBackData; class PiggyBackData;
typedef WrappingInt MSGID; typedef AtomicUInt MSGID;
class Listener { class Listener {
public: public:
Listener(const string &_ip, int p) : ip(_ip), port(p) { } Listener(const string &_ip, int p) : ip(_ip), port(p) { }
virtual ~Listener() {} virtual ~Listener() {}
bool init(); // set up socket bool init(); // set up socket
int socket() const { return sock; } int socket() const { return sock; }
void listen(); // never returns (start a thread) void listen(); // never returns (start a thread)
/* spawn a thread, etc., then return */ /* spawn a thread, etc., then return */
skipping to change at line 102 skipping to change at line 103
dbInsert = 2002, dbInsert = 2002,
//dbGetByOID = 2003, //dbGetByOID = 2003,
dbQuery = 2004, dbQuery = 2004,
dbGetMore = 2005, dbGetMore = 2005,
dbDelete = 2006, dbDelete = 2006,
dbKillCursors = 2007 dbKillCursors = 2007
}; };
bool doesOpGetAResponse( int op ); bool doesOpGetAResponse( int op );
inline const char * opToString( int op ){
switch ( op ){
case 0: return "none";
case opReply: return "reply";
case dbMsg: return "msg";
case dbUpdate: return "update";
case dbInsert: return "insert";
case dbQuery: return "query";
case dbGetMore: return "getmore";
case dbDelete: return "remove";
case dbKillCursors: return "killcursors";
default:
PRINT(op);
assert(0);
return "";
}
}
struct MsgData { struct MsgData {
int len; /* len of the msg, including this field */ int len; /* len of the msg, including this field */
MSGID id; /* request/reply id's match... */ MSGID id; /* request/reply id's match... */
MSGID responseTo; /* id of the message we are responding to */ MSGID responseTo; /* id of the message we are responding to */
int _operation; int _operation;
int operation() const { int operation() const {
return _operation; return _operation;
} }
void setOperation(int o) { void setOperation(int o) {
_operation = o; _operation = o;
skipping to change at line 178 skipping to change at line 197
} }
void setData(MsgData *d, bool _freeIt) { void setData(MsgData *d, bool _freeIt) {
assert( data == 0 ); assert( data == 0 );
freeIt = _freeIt; freeIt = _freeIt;
data = d; data = d;
} }
void setData(int operation, const char *msgtxt) { void setData(int operation, const char *msgtxt) {
setData(operation, msgtxt, strlen(msgtxt)+1); setData(operation, msgtxt, strlen(msgtxt)+1);
} }
void setData(int operation, const char *msgdata, int len) { void setData(int operation, const char *msgdata, size_t len) {
assert(data == 0); assert(data == 0);
int dataLen = len + sizeof(MsgData) - 4; size_t dataLen = len + sizeof(MsgData) - 4;
MsgData *d = (MsgData *) malloc(dataLen); MsgData *d = (MsgData *) malloc(dataLen);
memcpy(d->_data, msgdata, len); memcpy(d->_data, msgdata, len);
d->len = fixEndian(dataLen); d->len = fixEndian(dataLen);
d->setOperation(operation); d->setOperation(operation);
freeIt= true; freeIt= true;
data = d; data = d;
} }
bool doIFreeIt() { bool doIFreeIt() {
return freeIt; return freeIt;
 End of changes. 5 change blocks. 
3 lines changed or deleted 22 lines changed or added


 mmap.h   mmap.h 
skipping to change at line 25 skipping to change at line 25
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
namespace mongo { namespace mongo {
class MemoryMappedFile { class MemoryMappedFile {
public: public:
enum Options {
SEQUENTIAL = 1
};
MemoryMappedFile(); MemoryMappedFile();
~MemoryMappedFile(); /* closes the file if open */ ~MemoryMappedFile(); /* closes the file if open */
void close(); void close();
// Throws exception if file doesn't exist. // Throws exception if file doesn't exist.
void* map( const char *filename ); void* map( const char *filename );
/* Creates with length if DNE, otherwise uses existing file length, /* Creates with length if DNE, otherwise uses existing file length,
passed length. passed length.
*/ */
void* map(const char *filename, long &length); void* map(const char *filename, long &length, int options = 0 );
void flush(bool sync); void flush(bool sync);
void* viewOfs() { void* viewOfs() {
return view; return view;
} }
long length() { long length() {
return len; return len;
} }
 End of changes. 2 change blocks. 
1 lines changed or deleted 5 lines changed or added


 namespace.h   namespace.h 
skipping to change at line 24 skipping to change at line 24
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "../stdafx.h" #include "../stdafx.h"
#include "jsobj.h" #include "jsobj.h"
#include "queryutil.h" #include "queryutil.h"
#include "storage.h" #include "diskloc.h"
#include "../util/hashtab.h" #include "../util/hashtab.h"
#include "../util/mmap.h" #include "../util/mmap.h"
namespace mongo { namespace mongo {
class Cursor; class Cursor;
#pragma pack(1) #pragma pack(1)
/* in the mongo source code, "client" means "database". */ /* in the mongo source code, "client" means "database". */
skipping to change at line 78 skipping to change at line 78
void init(const char *ns) { void init(const char *ns) {
const char *p = strchr(ns, '.'); const char *p = strchr(ns, '.');
if( p == 0 ) return; if( p == 0 ) return;
db = string(ns, p - ns); db = string(ns, p - ns);
coll = p + 1; coll = p + 1;
} }
public: public:
NamespaceString( const char * ns ) { init(ns); } NamespaceString( const char * ns ) { init(ns); }
NamespaceString( const string& ns ) { init(ns.c_str()); } NamespaceString( const string& ns ) { init(ns.c_str()); }
string ns() const {
return db + '.' + coll;
}
bool isSystem() { bool isSystem() {
return strncmp(coll.c_str(), "system.", 7) == 0; return strncmp(coll.c_str(), "system.", 7) == 0;
} }
}; };
/* This helper class is used to make the HashMap below in NamespaceD etails */ /* This helper class is used to make the HashMap below in NamespaceD etails */
class Namespace { class Namespace {
public: public:
enum MaxNsLenValue { MaxNsLen = 128 }; enum MaxNsLenValue { MaxNsLen = 128 };
Namespace(const char *ns) { Namespace(const char *ns) {
skipping to change at line 103 skipping to change at line 107
strcpy_s(buf, MaxNsLen, ns); strcpy_s(buf, MaxNsLen, ns);
return *this; return *this;
} }
/* for more than 10 indexes -- see NamespaceDetails::Extra */ /* for more than 10 indexes -- see NamespaceDetails::Extra */
string extraName() { string extraName() {
string s = string(buf) + "$extra"; string s = string(buf) + "$extra";
massert( 10348 , "ns name too long", s.size() < MaxNsLen); massert( 10348 , "ns name too long", s.size() < MaxNsLen);
return s; return s;
} }
bool isExtra() const {
const char *p = strstr(buf, "$extra");
return p && p[6] == 0; //==0 important in case an index uses na
me "$extra_1" for example
}
void kill() { void kill() {
buf[0] = 0x7f; buf[0] = 0x7f;
} }
bool operator==(const char *r) { bool operator==(const char *r) {
return strcmp(buf, r) == 0; return strcmp(buf, r) == 0;
} }
bool operator==(const Namespace& r) { bool operator==(const Namespace& r) {
return strcmp(buf, r.buf) == 0; return strcmp(buf, r.buf) == 0;
skipping to change at line 188 skipping to change at line 196
assert( extraOffset ); assert( extraOffset );
return (Extra *) (((char *) this) + extraOffset); return (Extra *) (((char *) this) + extraOffset);
} }
public: public:
void copyingFrom(const char *thisns, NamespaceDetails *src); // mus t be called when renaming a NS to fix up extra void copyingFrom(const char *thisns, NamespaceDetails *src); // mus t be called when renaming a NS to fix up extra
enum { NIndexesMax = 40 }; enum { NIndexesMax = 40 };
BOOST_STATIC_ASSERT( NIndexesMax == NIndexesBase + NIndexesExtra ); BOOST_STATIC_ASSERT( NIndexesMax == NIndexesBase + NIndexesExtra );
/* called when loaded from disk */
void onLoad(const Namespace& k);
NamespaceDetails( const DiskLoc &loc, bool _capped ) { NamespaceDetails( const DiskLoc &loc, bool _capped ) {
/* be sure to initialize new fields here -- doesn't default to zeroes the way we use it */ /* be sure to initialize new fields here -- doesn't default to zeroes the way we use it */
firstExtent = lastExtent = capExtent = loc; firstExtent = lastExtent = capExtent = loc;
datasize = nrecords = 0; datasize = nrecords = 0;
lastExtentSize = 0; lastExtentSize = 0;
nIndexes = 0; nIndexes = 0;
capped = _capped; capped = _capped;
max = 0x7fffffff; max = 0x7fffffff;
paddingFactor = 1.0; paddingFactor = 1.0;
flags = 0; flags = 0;
skipping to change at line 253 skipping to change at line 264
unsigned short indexFileVersion; unsigned short indexFileVersion;
unsigned long long multiKeyIndexBits; unsigned long long multiKeyIndexBits;
private: private:
unsigned long long reservedA; unsigned long long reservedA;
long long extraOffset; // where the $extra info is located (bytes r elative to this) long long extraOffset; // where the $extra info is located (bytes r elative to this)
public: public:
int backgroundIndexBuildInProgress; // 1 if in prog int backgroundIndexBuildInProgress; // 1 if in prog
char reserved[76]; char reserved[76];
/* when a background index build is in progress, we don't count the
index in nIndexes until
complete, yet need to still use it in _indexRecord() - thus we u
se this function for that.
*/
int nIndexesBeingBuilt() const {
return nIndexes + backgroundIndexBuildInProgress;
}
/* NOTE: be careful with flags. are we manipulating them in read l ocks? if so, /* NOTE: be careful with flags. are we manipulating them in read l ocks? if so,
this isn't thread safe. TODO this isn't thread safe. TODO
*/ */
enum NamespaceFlags { enum NamespaceFlags {
Flag_HaveIdIndex = 1 << 0, // set when we have _id index (ONLY if ensureIdIndex was called -- 0 if that has never been called) Flag_HaveIdIndex = 1 << 0, // set when we have _id index (ONLY if ensureIdIndex was called -- 0 if that has never been called)
Flag_CappedDisallowDelete = 1 << 1 // set when deletes not allo wed during capped table allocation. Flag_CappedDisallowDelete = 1 << 1 // set when deletes not allo wed during capped table allocation.
}; };
IndexDetails& idx(int idxNo) { IndexDetails& idx(int idxNo) {
if( idxNo < NIndexesBase ) if( idxNo < NIndexesBase )
return _indexes[idxNo]; return _indexes[idxNo];
return extra()->details[idxNo-NIndexesBase]; return extra()->details[idxNo-NIndexesBase];
} }
IndexDetails& backgroundIdx() {
DEV assert(backgroundIndexBuildInProgress);
return idx(nIndexes);
}
class IndexIterator { class IndexIterator {
friend class NamespaceDetails; friend class NamespaceDetails;
int i; int i;
int n; int n;
NamespaceDetails *d; NamespaceDetails *d;
Extra *e; Extra *e;
IndexIterator(NamespaceDetails *_d) { IndexIterator(NamespaceDetails *_d) {
d = _d; d = _d;
i = 0; i = 0;
skipping to change at line 412 skipping to change at line 434
// Start from firstExtent by default. // Start from firstExtent by default.
DiskLoc firstRecord( const DiskLoc &startExtent = DiskLoc() ) const ; DiskLoc firstRecord( const DiskLoc &startExtent = DiskLoc() ) const ;
// Start from lastExtent by default. // Start from lastExtent by default.
DiskLoc lastRecord( const DiskLoc &startExtent = DiskLoc() ) const; DiskLoc lastRecord( const DiskLoc &startExtent = DiskLoc() ) const;
bool inCapExtent( const DiskLoc &dl ) const; bool inCapExtent( const DiskLoc &dl ) const;
void checkMigrate(); void checkMigrate();
long long storageSize(); long long storageSize( int * numExtents = 0 );
private: private:
bool cappedMayDelete() const { bool cappedMayDelete() const {
return !( flags & Flag_CappedDisallowDelete ); return !( flags & Flag_CappedDisallowDelete );
} }
Extent *theCapExtent() const { Extent *theCapExtent() const {
return capExtent.ext(); return capExtent.ext();
} }
void advanceCapExtent( const char *ns ); void advanceCapExtent( const char *ns );
void maybeComplain( const char *ns, int len ) const; void maybeComplain( const char *ns, int len ) const;
skipping to change at line 490 skipping to change at line 512
return _indexKeys; return _indexKeys;
} }
/* IndexSpec caching */ /* IndexSpec caching */
private: private:
map<const IndexDetails*,IndexSpec> _indexSpecs; map<const IndexDetails*,IndexSpec> _indexSpecs;
public: public:
const IndexSpec& getIndexSpec( const IndexDetails * details ){ const IndexSpec& getIndexSpec( const IndexDetails * details ){
DEV assertInWriteLock(); DEV assertInWriteLock();
IndexSpec& spec = _indexSpecs[details]; IndexSpec& spec = _indexSpecs[details];
if ( spec.meta.isEmpty() ){ if ( spec.info.isEmpty() ){
spec.reset( details->info ); spec.reset( details->info );
} }
return spec; return spec;
} }
/* query cache (for query optimizer) ------------------------------ ------- */ /* query cache (for query optimizer) ------------------------------ ------- */
private: private:
int _qcWriteCount; int _qcWriteCount;
map< QueryPattern, pair< BSONObj, long long > > _qcCache; map< QueryPattern, pair< BSONObj, long long > > _qcCache;
public: public:
skipping to change at line 557 skipping to change at line 579
} }
/* NamespaceIndex is the ".ns" file you see in the data directory. It is the "system catalog" /* NamespaceIndex is the ".ns" file you see in the data directory. It is the "system catalog"
if you will: at least the core parts. (Additional info in system.* collections.) if you will: at least the core parts. (Additional info in system.* collections.)
*/ */
class NamespaceIndex { class NamespaceIndex {
friend class NamespaceCursor; friend class NamespaceCursor;
BOOST_STATIC_ASSERT( sizeof(NamespaceDetails::Extra) <= sizeof(Name spaceDetails) ); BOOST_STATIC_ASSERT( sizeof(NamespaceDetails::Extra) <= sizeof(Name spaceDetails) );
public: public:
NamespaceIndex(const string &dir, const string &database) : NamespaceIndex(const string &dir, const string &database) :
ht( 0 ), ht( 0 ),
dir_( dir ), dir_( dir ),
database_( database ) {} database_( database ) {}
/* returns true if new db will be created if we init lazily */ /* returns true if new db will be created if we init lazily */
bool exists() const; bool exists() const;
void init(); void init();
void add_ns(const char *ns, DiskLoc& loc, bool capped) { void add_ns(const char *ns, DiskLoc& loc, bool capped) {
NamespaceDetails details( loc, capped ); NamespaceDetails details( loc, capped );
add_ns( ns, details ); add_ns( ns, details );
} }
skipping to change at line 639 skipping to change at line 661
} }
return false; return false;
} }
bool allocated() const { bool allocated() const {
return ht != 0; return ht != 0;
} }
private: private:
boost::filesystem::path path() const; boost::filesystem::path path() const;
void maybeMkdir() const;
MemoryMappedFile f; MemoryMappedFile f;
HashTable<Namespace,NamespaceDetails> *ht; HashTable<Namespace,NamespaceDetails> *ht;
string dir_; string dir_;
string database_; string database_;
}; };
extern string dbpath; // --dbpath parm extern string dbpath; // --dbpath parm
extern bool directoryperdb;
// Rename a namespace within current 'client' db. // Rename a namespace within current 'client' db.
// (Arguments should include db name) // (Arguments should include db name)
void renameNamespace( const char *from, const char *to ); void renameNamespace( const char *from, const char *to );
} // namespace mongo } // namespace mongo
 End of changes. 11 change blocks. 
6 lines changed or deleted 33 lines changed or added


 parallel.h   parallel.h 
skipping to change at line 99 skipping to change at line 99
BSONObj _extra; BSONObj _extra;
BSONObj _orderObject; BSONObj _orderObject;
}; };
/** /**
* runs a query in serial across any number of servers * runs a query in serial across any number of servers
* returns all results from 1 server, then the next, etc... * returns all results from 1 server, then the next, etc...
*/ */
class SerialServerClusteredCursor : public ClusteredCursor { class SerialServerClusteredCursor : public ClusteredCursor {
public: public:
SerialServerClusteredCursor( set<ServerAndQuery> servers , QueryMes sage& q , int sortOrder=0); SerialServerClusteredCursor( const set<ServerAndQuery>& servers , Q ueryMessage& q , int sortOrder=0);
virtual bool more(); virtual bool more();
virtual BSONObj next(); virtual BSONObj next();
virtual string type() const { return "SerialServer"; } virtual string type() const { return "SerialServer"; }
private: private:
vector<ServerAndQuery> _servers; vector<ServerAndQuery> _servers;
unsigned _serverIndex; unsigned _serverIndex;
auto_ptr<DBClientCursor> _current; auto_ptr<DBClientCursor> _current;
}; };
/** /**
* runs a query in parellel across N servers * runs a query in parellel across N servers
* sots * sots
*/ */
class ParallelSortClusteredCursor : public ClusteredCursor { class ParallelSortClusteredCursor : public ClusteredCursor {
public: public:
ParallelSortClusteredCursor( set<ServerAndQuery> servers , QueryMes ParallelSortClusteredCursor( const set<ServerAndQuery>& servers , Q
sage& q , const BSONObj& sortKey ); ueryMessage& q , const BSONObj& sortKey );
ParallelSortClusteredCursor( set<ServerAndQuery> servers , const st ParallelSortClusteredCursor( const set<ServerAndQuery>& servers , c
ring& ns , onst string& ns ,
const Query& q , int options=0, const BSONObj& fields=BSONObj() ); const Query& q , int options=0, const BSONObj& fields=BSONObj() );
virtual ~ParallelSortClusteredCursor(); virtual ~ParallelSortClusteredCursor();
virtual bool more(); virtual bool more();
virtual BSONObj next(); virtual BSONObj next();
virtual string type() const { return "ParallelSort"; } virtual string type() const { return "ParallelSort"; }
private: private:
void _init(); void _init();
void advance(); void advance();
 End of changes. 2 change blocks. 
5 lines changed or deleted 5 lines changed or added


 pdfile.h   pdfile.h 
skipping to change at line 30 skipping to change at line 30
database.ns - namespace index database.ns - namespace index
database.1 - data files database.1 - data files
database.2 database.2
... ...
*/ */
#pragma once #pragma once
#include "../stdafx.h" #include "../stdafx.h"
#include "../util/mmap.h" #include "../util/mmap.h"
#include "storage.h" #include "diskloc.h"
#include "jsobjmanipulator.h" #include "jsobjmanipulator.h"
#include "namespace.h" #include "namespace.h"
#include "client.h" #include "client.h"
namespace mongo { namespace mongo {
class MDFHeader; class MDFHeader;
class Extent; class Extent;
class Record; class Record;
class Cursor; class Cursor;
skipping to change at line 101 skipping to change at line 101
class DataFileMgr { class DataFileMgr {
friend class BasicCursor; friend class BasicCursor;
public: public:
void init(const string& path ); void init(const string& path );
/* see if we can find an extent of the right size in the freelist. */ /* see if we can find an extent of the right size in the freelist. */
static Extent* allocFromFreeList(const char *ns, int approxSize, bo ol capped = false); static Extent* allocFromFreeList(const char *ns, int approxSize, bo ol capped = false);
/** @return DiskLoc where item ends up */ /** @return DiskLoc where item ends up */
const DiskLoc update( const DiskLoc updateRecord(
const char *ns, const char *ns,
NamespaceDetails *d,
NamespaceDetailsTransient *nsdt,
Record *toupdate, const DiskLoc& dl, Record *toupdate, const DiskLoc& dl,
const char *buf, int len, OpDebug& debug); const char *buf, int len, OpDebug& debug);
// The object o may be updated if modified on insert. // The object o may be updated if modified on insert.
void insertAndLog( const char *ns, const BSONObj &o, bool god = fal se ); void insertAndLog( const char *ns, const BSONObj &o, bool god = fal se );
DiskLoc insert(const char *ns, BSONObj &o, bool god = false); DiskLoc insert(const char *ns, BSONObj &o, bool god = false);
DiskLoc insert(const char *ns, const void *buf, int len, bool god = false, const BSONElement &writeId = BSONElement(), bool mayAddIndex = true ); DiskLoc insert(const char *ns, const void *buf, int len, bool god = false, const BSONElement &writeId = BSONElement(), bool mayAddIndex = true );
void deleteRecord(const char *ns, Record *todelete, const DiskLoc& dl, bool cappedOK = false, bool noWarn = false); void deleteRecord(const char *ns, Record *todelete, const DiskLoc& dl, bool cappedOK = false, bool noWarn = false);
static auto_ptr<Cursor> findAll(const char *ns, const DiskLoc &star tLoc = DiskLoc()); static auto_ptr<Cursor> findAll(const char *ns, const DiskLoc &star tLoc = DiskLoc());
/* special version of insert for transaction logging -- streamlined a bit. /* special version of insert for transaction logging -- streamlined a bit.
skipping to change at line 395 skipping to change at line 397
public: public:
virtual ~FileOp() {} virtual ~FileOp() {}
// Return true if file exists and operation successful // Return true if file exists and operation successful
virtual bool apply( const boost::filesystem::path &p ) = 0; virtual bool apply( const boost::filesystem::path &p ) = 0;
virtual const char * op() const = 0; virtual const char * op() const = 0;
}; };
void _applyOpToDataFiles( const char *database, FileOp &fo, bool afterA llocator = false, const string& path = dbpath ); void _applyOpToDataFiles( const char *database, FileOp &fo, bool afterA llocator = false, const string& path = dbpath );
inline void _deleteDataFiles(const char *database) { inline void _deleteDataFiles(const char *database) {
if ( directoryperdb ) {
BOOST_CHECK_EXCEPTION( boost::filesystem::remove_all( boost::fi
lesystem::path( dbpath ) / database ) );
return;
}
class : public FileOp { class : public FileOp {
virtual bool apply( const boost::filesystem::path &p ) { virtual bool apply( const boost::filesystem::path &p ) {
return boost::filesystem::remove( p ); return boost::filesystem::remove( p );
} }
virtual const char * op() const { virtual const char * op() const {
return "remove"; return "remove";
} }
} deleter; } deleter;
_applyOpToDataFiles( database, deleter, true ); _applyOpToDataFiles( database, deleter, true );
} }
skipping to change at line 446 skipping to change at line 452
return cc().database()->getFile(dl.a())->getExtent(dl); return cc().database()->getFile(dl.a())->getExtent(dl);
} }
inline Record* DataFileMgr::getRecord(const DiskLoc& dl) { inline Record* DataFileMgr::getRecord(const DiskLoc& dl) {
assert( dl.a() != -1 ); assert( dl.a() != -1 );
return cc().database()->getFile(dl.a())->recordAt(dl); return cc().database()->getFile(dl.a())->recordAt(dl);
} }
void ensureHaveIdIndex(const char *ns); void ensureHaveIdIndex(const char *ns);
bool deleteIndexes( NamespaceDetails *d, const char *ns, const char *na me, string &errmsg, BSONObjBuilder &anObjBuilder, bool maydeleteIdIndex ); bool dropIndexes( NamespaceDetails *d, const char *ns, const char *name , string &errmsg, BSONObjBuilder &anObjBuilder, bool maydeleteIdIndex );
} // namespace mongo } // namespace mongo
 End of changes. 5 change blocks. 
3 lines changed or deleted 10 lines changed or added


 processinfo.h   processinfo.h 
skipping to change at line 55 skipping to change at line 55
*/ */
int getResidentSize(); int getResidentSize();
/** /**
* Append platform-specific data to obj * Append platform-specific data to obj
*/ */
void getExtraInfo(BSONObjBuilder& info); void getExtraInfo(BSONObjBuilder& info);
bool supported(); bool supported();
bool blockCheckSupported();
bool blockInMemory( char * start );
private: private:
pid_t _pid; pid_t _pid;
}; };
} }
 End of changes. 1 change blocks. 
0 lines changed or deleted 3 lines changed or added


 query.h   query.h 
skipping to change at line 25 skipping to change at line 25
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "../stdafx.h" #include "../stdafx.h"
#include "../util/message.h" #include "../util/message.h"
#include "dbmessage.h" #include "dbmessage.h"
#include "jsobj.h" #include "jsobj.h"
#include "storage.h" #include "diskloc.h"
/* db request message format /* db request message format
unsigned opid; // arbitary; will be echoed back unsigned opid; // arbitary; will be echoed back
byte operation; byte operation;
int options; int options;
then for: then for:
dbInsert: dbInsert:
skipping to change at line 80 skipping to change at line 80
#include "../client/dbclient.h" #include "../client/dbclient.h"
namespace mongo { namespace mongo {
// for an existing query (ie a ClientCursor), send back additional info rmation. // for an existing query (ie a ClientCursor), send back additional info rmation.
QueryResult* getMore(const char *ns, int ntoreturn, long long cursorid , CurOp& op); QueryResult* getMore(const char *ns, int ntoreturn, long long cursorid , CurOp& op);
struct UpdateResult { struct UpdateResult {
bool existing; bool existing;
bool mod; bool mod;
unsigned long long num; long long num;
UpdateResult( bool e, bool m, unsigned long long n ) UpdateResult( bool e, bool m, unsigned long long n )
: existing(e) , mod(m), num(n ){} : existing(e) , mod(m), num(n ){}
int oldCode(){ int oldCode(){
if ( ! num ) if ( ! num )
return 0; return 0;
if ( existing ){ if ( existing ){
if ( mod ) if ( mod )
skipping to change at line 104 skipping to change at line 104
if ( mod ) if ( mod )
return 3; return 3;
return 4; return 4;
} }
}; };
/* returns true if an existing object was updated, false if no existing object was found. /* returns true if an existing object was updated, false if no existing object was found.
multi - update multiple objects - mostly useful with things like $se t multi - update multiple objects - mostly useful with things like $se t
*/ */
UpdateResult updateObjects(const char *ns, BSONObj updateobj, BSONObj p attern, bool upsert, bool multi , bool logop , OpDebug& debug ); UpdateResult updateObjects(const char *ns, const BSONObj& updateobj, BS ONObj pattern, bool upsert, bool multi , bool logop , OpDebug& debug );
// If justOne is true, deletedId is set to the id of the deleted object . // If justOne is true, deletedId is set to the id of the deleted object .
int deleteObjects(const char *ns, BSONObj pattern, bool justOne, bool l ogop = false, bool god=false); long long deleteObjects(const char *ns, BSONObj pattern, bool justOne, bool logop = false, bool god=false);
long long runCount(const char *ns, const BSONObj& cmd, string& err); long long runCount(const char *ns, const BSONObj& cmd, string& err);
auto_ptr< QueryResult > runQuery(Message& m, QueryMessage& q, CurOp& cu rop ); auto_ptr< QueryResult > runQuery(Message& m, QueryMessage& q, CurOp& cu rop );
} // namespace mongo } // namespace mongo
#include "clientcursor.h" #include "clientcursor.h"
 End of changes. 4 change blocks. 
4 lines changed or deleted 4 lines changed or added


 queryoptimizer.h   queryoptimizer.h 
skipping to change at line 53 skipping to change at line 53
*/ */
bool exactKeyMatch() const { return exactKeyMatch_; } bool exactKeyMatch() const { return exactKeyMatch_; }
/* If true, the startKey and endKey are unhelpful and the index ord er doesn't match the /* If true, the startKey and endKey are unhelpful and the index ord er doesn't match the
requested sort order */ requested sort order */
bool unhelpful() const { return unhelpful_; } bool unhelpful() const { return unhelpful_; }
int direction() const { return direction_; } int direction() const { return direction_; }
auto_ptr< Cursor > newCursor( const DiskLoc &startLoc = DiskLoc() ) const; auto_ptr< Cursor > newCursor( const DiskLoc &startLoc = DiskLoc() ) const;
auto_ptr< Cursor > newReverseCursor() const; auto_ptr< Cursor > newReverseCursor() const;
BSONObj indexKey() const; BSONObj indexKey() const;
const char *ns() const { return fbs_.ns(); } const char *ns() const { return fbs_.ns(); }
NamespaceDetails *nsd() const { return d; }
BSONObj query() const { return fbs_.query(); } BSONObj query() const { return fbs_.query(); }
BSONObj simplifiedQuery( const BSONObj& fields = BSONObj() ) const { return fbs_.simplifiedQuery( fields ); } BSONObj simplifiedQuery( const BSONObj& fields = BSONObj() ) const { return fbs_.simplifiedQuery( fields ); }
const FieldRange &range( const char *fieldName ) const { return fbs _.range( fieldName ); } const FieldRange &range( const char *fieldName ) const { return fbs _.range( fieldName ); }
void registerSelf( long long nScanned ) const; void registerSelf( long long nScanned ) const;
// just for testing // just for testing
BoundList indexBounds() const { return indexBounds_; } BoundList indexBounds() const { return indexBounds_; }
private: private:
NamespaceDetails *d; NamespaceDetails *d;
int idxNo; int idxNo;
const FieldRangeSet &fbs_; const FieldRangeSet &fbs_;
skipping to change at line 146 skipping to change at line 147
void addHint( IndexDetails &id ); void addHint( IndexDetails &id );
struct Runner { struct Runner {
Runner( QueryPlanSet &plans, QueryOp &op ); Runner( QueryPlanSet &plans, QueryOp &op );
shared_ptr< QueryOp > run(); shared_ptr< QueryOp > run();
QueryOp &op_; QueryOp &op_;
QueryPlanSet &plans_; QueryPlanSet &plans_;
static void initOp( QueryOp &op ); static void initOp( QueryOp &op );
static void nextOp( QueryOp &op ); static void nextOp( QueryOp &op );
}; };
const char *ns; const char *ns;
BSONObj query_;
FieldRangeSet fbs_; FieldRangeSet fbs_;
PlanSet plans_; PlanSet plans_;
bool mayRecordPlan_; bool mayRecordPlan_;
bool usingPrerecordedPlan_; bool usingPrerecordedPlan_;
BSONObj hint_; BSONObj hint_;
BSONObj order_; BSONObj order_;
long long oldNScanned_; long long oldNScanned_;
bool honorRecordedPlan_; bool honorRecordedPlan_;
BSONObj min_; BSONObj min_;
BSONObj max_; BSONObj max_;
}; };
// NOTE min, max, and keyPattern will be updated to be consistent with the selected index. // NOTE min, max, and keyPattern will be updated to be consistent with the selected index.
IndexDetails *indexDetailsForRange( const char *ns, string &errmsg, BSO NObj &min, BSONObj &max, BSONObj &keyPattern ); IndexDetails *indexDetailsForRange( const char *ns, string &errmsg, BSO NObj &min, BSONObj &max, BSONObj &keyPattern );
inline bool isSimpleIdQuery( const BSONObj& query ){
return
strcmp( query.firstElement().fieldName() , "_id" ) == 0 &&
query.nFields() == 1 &&
query.firstElement().isSimpleType();
}
} // namespace mongo } // namespace mongo
 End of changes. 3 change blocks. 
0 lines changed or deleted 9 lines changed or added


 rec.h   rec.h 
// rec.h // rec.h
/*
* Copyright (C) 2010 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 Lice
nse
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* TODO for _RECSTORE /* TODO for _RECSTORE
_ support > 2GB data per file _ support > 2GB data per file
_ multiple files, not just indexes.dat _ multiple files, not just indexes.dat
_ lazier writes? (may be done?) _ lazier writes? (may be done?)
_ configurable cache size _ configurable cache size
_ fix on abnormal terminations to be able to restart some _ fix on abnormal terminations to be able to restart some
*/ */
 End of changes. 1 change blocks. 
0 lines changed or deleted 17 lines changed or added


 reccache.h   reccache.h 
// reccache.h // reccache.h
/*
* Copyright (C) 2010 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 Lice
nse
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* CachedBasicRecStore /* CachedBasicRecStore
This is our store which implements a traditional page-cache type of stor age This is our store which implements a traditional page-cache type of stor age
(not memory mapped files). (not memory mapped files).
*/ */
/* LOCK HIERARCHY /* LOCK HIERARCHY
dblock dblock
RecCache::rcmutex RecCache::rcmutex
skipping to change at line 232 skipping to change at line 247
theRecCache.closeFiles(dbname, dbpath); theRecCache.closeFiles(dbname, dbpath);
} }
}; };
/* see concurrency.h - note on a lock reset from read->write we don't /* see concurrency.h - note on a lock reset from read->write we don't
call dbunlocking_read, we just wait for the final dbunlocking_write call dbunlocking_read, we just wait for the final dbunlocking_write
call call
*/ */
inline void dbunlocking_read() { inline void dbunlocking_read() {
/*
Client *c = currentClient.get(); Client *c = currentClient.get();
if ( c ) if ( c )
c->top.clientStop(); c->top.clientStop();
*/
} }
inline void dbunlocking_write() { inline void dbunlocking_write() {
theRecCache.ejectOld(); theRecCache.ejectOld();
dbunlocking_read(); dbunlocking_read();
} }
} /*namespace*/ } /*namespace*/
 End of changes. 3 change blocks. 
0 lines changed or deleted 19 lines changed or added


 reci.h   reci.h 
// reci.h // reci.h
/*
* Copyright (C) 2010 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 Lice
nse
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once #pragma once
#include "storage.h" #include "diskloc.h"
namespace mongo { namespace mongo {
/* Subclass this and implement your real storage interface. /* Subclass this and implement your real storage interface.
*/ */
class RecStoreInterface { class RecStoreInterface {
public: public:
virtual ~RecStoreInterface() {} virtual ~RecStoreInterface() {}
/* Get a pointer to the data at diskloc d. Pointer guaranteed to stay in /* Get a pointer to the data at diskloc d. Pointer guaranteed to stay in
 End of changes. 2 change blocks. 
1 lines changed or deleted 18 lines changed or added


 recstore.h   recstore.h 
// recstore.h // recstore.h
/*
* Copyright (C) 2010 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 Lice
nse
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once #pragma once
#include "../util/file.h" #include "../util/file.h"
namespace mongo { namespace mongo {
using boost::uint32_t; using boost::uint32_t;
using boost::uint64_t; using boost::uint64_t;
 End of changes. 1 change blocks. 
0 lines changed or deleted 17 lines changed or added


 repl.h   repl.h 
skipping to change at line 49 skipping to change at line 49
namespace mongo { namespace mongo {
class DBClientConnection; class DBClientConnection;
class DBClientCursor; class DBClientCursor;
/* replication slave? (possibly with slave or repl pair nonmaster) /* replication slave? (possibly with slave or repl pair nonmaster)
--slave cmd line setting -> SimpleSlave --slave cmd line setting -> SimpleSlave
*/ */
typedef enum { NotSlave=0, SimpleSlave, ReplPairSlave } SlaveTypes; typedef enum { NotSlave=0, SimpleSlave, ReplPairSlave } SlaveTypes;
extern SlaveTypes slave;
/* true means we are master and doing replication. if we are not wr class ReplSettings {
iting to oplog (no --master or repl pairing), public:
this won't be true. SlaveTypes slave;
*/
extern bool master;
extern int opIdMem; /* true means we are master and doing replication. if we are not w
riting to oplog (no --master or repl pairing),
this won't be true.
*/
bool master;
int opIdMem;
bool autoresync;
ReplSettings()
: slave(NotSlave) , master(false) , opIdMem(100000000) , autore
sync(false) {
}
};
extern ReplSettings replSettings;
bool cloneFrom(const char *masterHost, string& errmsg, const string& fr omdb, bool logForReplication, bool cloneFrom(const char *masterHost, string& errmsg, const string& fr omdb, bool logForReplication,
bool slaveOk, bool useReplAuth, bool snap shot); bool slaveOk, bool useReplAuth, bool snap shot);
/* A replication exception */ /* A replication exception */
class SyncException : public DBException { class SyncException : public DBException {
public: public:
virtual const char* what() const throw() { return "sync exception"; } virtual const char* what() const throw() { return "sync exception"; }
virtual int getCode(){ return 10001; } virtual int getCode(){ return 10001; }
}; };
skipping to change at line 242 skipping to change at line 255
// All functions must be called with db mutex held // All functions must be called with db mutex held
// Kind of sloppy class structure, for now just want to keep the in mem // Kind of sloppy class structure, for now just want to keep the in mem
// version speedy. // version speedy.
// see http://www.mongodb.org/display/DOCS/Pairing+Internals // see http://www.mongodb.org/display/DOCS/Pairing+Internals
class IdTracker { class IdTracker {
public: public:
IdTracker() : IdTracker() :
dbIds_( "local.temp.replIds" ), dbIds_( "local.temp.replIds" ),
dbModIds_( "local.temp.replModIds" ), dbModIds_( "local.temp.replModIds" ),
inMem_( true ), inMem_( true ),
maxMem_( opIdMem ) { maxMem_( replSettings.opIdMem ) {
} }
void reset( int maxMem = opIdMem ) { void reset( int maxMem = replSettings.opIdMem ) {
memIds_.reset(); memIds_.reset();
memModIds_.reset(); memModIds_.reset();
dbIds_.reset(); dbIds_.reset();
dbModIds_.reset(); dbModIds_.reset();
maxMem_ = maxMem; maxMem_ = maxMem;
inMem_ = true; inMem_ = true;
} }
bool haveId( const char *ns, const BSONObj &id ) { bool haveId( const char *ns, const BSONObj &id ) {
if ( inMem_ ) if ( inMem_ )
return get( memIds_, ns, id ); return get( memIds_, ns, id );
skipping to change at line 315 skipping to change at line 328
} }
} }
MemIds memIds_; MemIds memIds_;
MemIds memModIds_; MemIds memModIds_;
DbIds dbIds_; DbIds dbIds_;
DbIds dbModIds_; DbIds dbModIds_;
bool inMem_; bool inMem_;
int maxMem_; int maxMem_;
}; };
bool anyReplEnabled();
void appendReplicationInfo( BSONObjBuilder& result , bool authed , int
level = 0 );
} // namespace mongo } // namespace mongo
 End of changes. 6 change blocks. 
9 lines changed or deleted 27 lines changed or added


 replset.h   replset.h 
skipping to change at line 114 skipping to change at line 114
/* note we always return true for the "local" namespace. /* note we always return true for the "local" namespace.
we should not allow most operations when not the master we should not allow most operations when not the master
also we report not master if we are "dead". also we report not master if we are "dead".
See also CmdIsMaster. See also CmdIsMaster.
If 'client' is not specified, the current client is used. If 'client' is not specified, the current client is used.
*/ */
inline bool isMaster( const char *client = 0 ) { inline bool isMaster( const char *client = 0 ) {
if( !slave ) if( ! replSettings.slave )
return true; return true;
if ( !client ) { if ( !client ) {
Database *database = cc().database(); Database *database = cc().database();
assert( database ); assert( database );
client = database->name.c_str(); client = database->name.c_str();
} }
if ( replAllDead ) if ( replAllDead )
return strcmp( client, "local" ) == 0; return strcmp( client, "local" ) == 0;
if ( replPair ) { if ( replPair ) {
if( replPair->state == ReplPair::State_Master ) if( replPair->state == ReplPair::State_Master )
return true; return true;
} }
else { else {
if( master ) { if( replSettings.master ) {
// if running with --master --slave, allow. note that mast er is also true // if running with --master --slave, allow. note that mast er is also true
// for repl pairs so the check for replPair above is import ant. // for repl pairs so the check for replPair above is import ant.
return true; return true;
} }
} }
if ( cc().isGod() ) if ( cc().isGod() )
return true; return true;
return strcmp( client, "local" ) == 0; return strcmp( client, "local" ) == 0;
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 request.h   request.h 
// request.h // request.h
/*
* Copyright (C) 2010 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 Lice
nse
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once #pragma once
#include "../stdafx.h" #include "../stdafx.h"
#include "../util/message.h" #include "../util/message.h"
#include "../db/dbmessage.h" #include "../db/dbmessage.h"
#include "config.h" #include "config.h"
#include "util.h" #include "util.h"
namespace mongo { namespace mongo {
 End of changes. 1 change blocks. 
0 lines changed or deleted 17 lines changed or added


 security.h   security.h 
skipping to change at line 25 skipping to change at line 25
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <boost/thread/tss.hpp> #include <boost/thread/tss.hpp>
#undef assert #undef assert
#define assert xassert #define assert xassert
#include "db.h"
#include "dbhelpers.h"
#include "nonce.h" #include "nonce.h"
#include "concurrency.h"
namespace mongo { namespace mongo {
// --noauth cmd line option // --noauth cmd line option
extern bool noauth; extern bool noauth;
/* for a particular db */ /* for a particular db */
struct Auth { struct Auth {
Auth() { level = 0; } Auth() { level = 0; }
int level; int level;
}; };
class AuthenticationInfo : boost::noncopyable { class AuthenticationInfo : boost::noncopyable {
map<string, Auth> m; // dbname -> auth map<string, Auth> m; // dbname -> auth
static int warned; static int warned;
public: public:
bool isLocalHost; bool isLocalHost;
AuthenticationInfo() { isLocalHost = false; } AuthenticationInfo() { isLocalHost = false; }
virtual ~AuthenticationInfo() { ~AuthenticationInfo() {
} }
void logout(const char *dbname) { void logout(const string& dbname ) {
assertInWriteLock(); assertInWriteLock(); // TODO: can we get rid of this
? only 1 thread should be looking at an AuthenticationInfo
m.erase(dbname); m.erase(dbname);
} }
void authorize(const char *dbname) { void authorize(const string& dbname ) {
assertInWriteLock(); assertInWriteLock();
m[dbname].level = 2; m[dbname].level = 2;
} }
virtual bool isAuthorized(const char *dbname) { void authorizeReadOnly(const string& dbname) {
if( m[dbname].level == 2 ) return true; assertInWriteLock();
m[dbname].level = 1;
}
bool isAuthorized(const string& dbname) { return _isAuthorized( dbn
ame, 2 ); }
bool isAuthorizedReads(const string& dbname) { return _isAuthorized
( dbname, 1 ); }
bool isAuthorizedForLock(const string& dbname, int lockType ) { ret
urn _isAuthorized( dbname , lockType > 0 ? 2 : 1 ); }
void print();
protected:
bool _isAuthorized(const string& dbname, int level) {
if( m[dbname].level >= level ) return true;
if( noauth ) return true; if( noauth ) return true;
if( m["admin"].level == 2 ) return true; if( m["admin"].level >= level ) return true;
if( m["local"].level == 2 ) return true; if( m["local"].level >= level ) return true;
if( isLocalHost ) { return _isAuthorizedSpecialChecks( dbname );
readlock l("");
Client::Context c("admin.system.users");
BSONObj result;
if( Helpers::getSingleton("admin.system.user
s", result) )
return false;
if( warned == 0 ) {
warned++;
log() << "warning: no users configur
ed in admin.system.users, allowing localhost access" << endl;
}
return true;
}
return false;
} }
bool _isAuthorizedSpecialChecks( const string& dbname );
}; };
} // namespace mongo } // namespace mongo
 End of changes. 8 change blocks. 
25 lines changed or deleted 27 lines changed or added


 strategy.h   strategy.h 
// strategy.h // strategy.h
/*
* Copyright (C) 2010 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 Lice
nse
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once #pragma once
#include "../stdafx.h" #include "../stdafx.h"
#include "chunk.h" #include "chunk.h"
#include "request.h" #include "request.h"
namespace mongo { namespace mongo {
class Strategy { class Strategy {
 End of changes. 1 change blocks. 
0 lines changed or deleted 17 lines changed or added


 syncclusterconnection.h   syncclusterconnection.h 
// syncclusterconnection.h // syncclusterconnection.h
/*
* Copyright 2010 10gen Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli
ed.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "../stdafx.h" #include "../stdafx.h"
#include "dbclient.h" #include "dbclient.h"
namespace mongo { namespace mongo {
/** /**
* this is a connection to a cluster of servers that operate as one * this is a connection to a cluster of servers that operate as one
* for super high durability * for super high durability
*/ */
class SyncCluterConnection : public DBClientWithCommands { class SyncClusterConnection : public DBClientWithCommands {
public: public:
/** /**
* @param commaSeperated should be 3 hosts comma seperated * @param commaSeperated should be 3 hosts comma seperated
*/ */
SyncCluterConnection( string commaSeperated ); SyncClusterConnection( string commaSeperated );
SyncCluterConnection( string a , string b , string c ); SyncClusterConnection( string a , string b , string c );
~SyncCluterConnection(); ~SyncClusterConnection();
/** /**
* @return true if all servers are up and ready for writes * @return true if all servers are up and ready for writes
*/ */
bool prepare( string& errmsg ); bool prepare( string& errmsg );
/** /**
* runs fsync on all servers * runs fsync on all servers
*/ */
bool fsync( string& errmsg ); bool fsync( string& errmsg );
 End of changes. 3 change blocks. 
4 lines changed or deleted 20 lines changed or added


 tool.h   tool.h 
/*
* Copyright (C) 2010 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 Lice
nse
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Tool.h // Tool.h
#pragma once #pragma once
#include <string> #include <string>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#if defined(_WIN32) #if defined(_WIN32)
#include <io.h> #include <io.h>
 End of changes. 1 change blocks. 
0 lines changed or deleted 18 lines changed or added


 top.h   top.h 
skipping to change at line 26 skipping to change at line 26
*/ */
#pragma once #pragma once
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#undef assert #undef assert
#define assert xassert #define assert xassert
namespace mongo { namespace mongo {
/**
* tracks usage by collection
*/
class Top {
public:
class UsageData {
public:
UsageData() : time(0) , count(0){}
UsageData( UsageData& older , UsageData& newer );
long long time;
long long count;
void inc( long long micros ){
count++;
time += micros;
}
};
class CollectionData {
public:
/**
* constructs a diff
*/
CollectionData(){}
CollectionData( CollectionData& older , CollectionData& newer )
;
UsageData total;
UsageData readLock;
UsageData writeLock;
UsageData queries;
UsageData getmore;
UsageData insert;
UsageData update;
UsageData remove;
UsageData commands;
};
typedef map<string,CollectionData> UsageMap;
public:
void record( const string& ns , int op , int lockType , long long m
icros , bool command );
void append( BSONObjBuilder& b );
UsageMap cloneMap();
CollectionData getGlobalData(){ return _global; }
public: // static stuff
static Top global;
void append( BSONObjBuilder& b , const char * name , const UsageDat
a& map );
void append( BSONObjBuilder& b , const UsageMap& map );
private:
void _record( CollectionData& c , int op , int lockType , long long
micros , bool command );
boost::mutex _lock;
CollectionData _global;
UsageMap _usage;
};
/* Records per namespace utilization of the mongod process. /* Records per namespace utilization of the mongod process.
No two functions of this class may be called concurrently. No two functions of this class may be called concurrently.
*/ */
class Top { class TopOld {
typedef boost::posix_time::ptime T; typedef boost::posix_time::ptime T;
typedef boost::posix_time::time_duration D; typedef boost::posix_time::time_duration D;
typedef boost::tuple< D, int, int, int > UsageData; typedef boost::tuple< D, int, int, int > UsageData;
public: public:
Top() : _read(false), _write(false) { } TopOld() : _read(false), _write(false) { }
/* these are used to record activity: */ /* these are used to record activity: */
void clientStart( const char *client ) { void clientStart( const char *client ) {
clientStop(); clientStop();
_currentStart = currentTime(); _currentStart = currentTime();
_current = client; _current = client;
} }
/* indicate current request is a read operation. */ /* indicate current request is a read operation. */
 End of changes. 3 change blocks. 
2 lines changed or deleted 69 lines changed or added


 update.h   update.h 
skipping to change at line 26 skipping to change at line 26
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "../stdafx.h" #include "../stdafx.h"
#include "jsobj.h" #include "jsobj.h"
#include "../util/embedded_builder.h" #include "../util/embedded_builder.h"
#include "matcher.h" #include "matcher.h"
namespace mongo { namespace mongo {
/* Used for modifiers such as $inc, $set, $push, ... */ class ModState;
class ModSetState;
/* Used for modifiers such as $inc, $set, $push, ...
* stores the info about a single operation
* once created should never be modified
*/
struct Mod { struct Mod {
// See opFromStr below // See opFromStr below
// 0 1 2 3 4 5 6 7 8 // 0 1 2 3 4 5 6 7 8
9 10 9 10 11
enum Op { INC, SET, PUSH, PUSH_ALL, PULL, PULL_ALL , POP, UNSET, BI enum Op { INC, SET, PUSH, PUSH_ALL, PULL, PULL_ALL , POP, UNSET, BI
TAND, BITOR , BIT } op; TAND, BITOR , BIT , ADDTOSET } op;
static const char* modNames[]; static const char* modNames[];
static unsigned modNamesNum; static unsigned modNamesNum;
const char *fieldName; const char *fieldName;
const char *shortFieldName; const char *shortFieldName;
// kind of lame; fix one day?
double *ndouble;
int *nint;
long long *nlong;
BSONElement elt; // x:5 note: this is the actual element from the u pdateobj BSONElement elt; // x:5 note: this is the actual element from the u pdateobj
int pushStartSize;
boost::shared_ptr<Matcher> matcher; boost::shared_ptr<Matcher> matcher;
void init( Op o , BSONElement& e ){ void init( Op o , BSONElement& e ){
op = o; op = o;
elt = e; elt = e;
if ( op == PULL && e.type() == Object ) if ( op == PULL && e.type() == Object )
matcher.reset( new Matcher( e.embeddedObject() ) ); matcher.reset( new Matcher( e.embeddedObject() ) );
} }
void setFieldName( const char * s ){ void setFieldName( const char * s ){
fieldName = s; fieldName = s;
shortFieldName = strrchr( fieldName , '.' ); shortFieldName = strrchr( fieldName , '.' );
if ( shortFieldName ) if ( shortFieldName )
shortFieldName++; shortFieldName++;
else else
shortFieldName = fieldName; shortFieldName = fieldName;
} }
/* [dm] why is this const? (or rather, why was setn const?) i see /**
why but think maybe clearer if were not. */ * @param in incrememnts the actual value inside in
void inc(BSONElement& n) const { */
uassert( 10160 , "$inc value is not a number", n.isNumber() ); void incrementMe( BSONElement& in ) const {
if( ndouble ) BSONElementManipulator manip( in );
*ndouble += n.numberDouble();
else if( nint )
*nint += n.numberInt();
else
*nlong += n.numberLong();
}
void setElementToOurNumericValue(BSONElement& e) const { switch ( in.type() ){
BSONElementManipulator manip(e); case NumberDouble:
if( e.type() == NumberLong ) manip.setNumber( elt.numberDouble() + in.numberDouble() );
manip.setLong(_getlong()); break;
else case NumberLong:
manip.setNumber(_getn()); manip.setLong( elt.numberLong() + in.numberLong() );
} break;
case NumberInt:
manip.setInt( elt.numberInt() + in.numberInt() );
break;
default:
assert(0);
}
double _getn() const {
if( ndouble ) return *ndouble;
if( nint ) return *nint;
return (double) *nlong;
}
long long _getlong() const {
if( nlong ) return *nlong;
if( ndouble ) return (long long) *ndouble;
return *nint;
} }
void appendIncremented( BSONObjBuilder& bb , const BSONElement& in,
ModState& ms ) const;
bool operator<( const Mod &other ) const { bool operator<( const Mod &other ) const {
return strcmp( fieldName, other.fieldName ) < 0; return strcmp( fieldName, other.fieldName ) < 0;
} }
bool arrayDep() const { bool arrayDep() const {
switch (op){ switch (op){
case PUSH: case PUSH:
case PUSH_ALL: case PUSH_ALL:
case POP: case POP:
return true; return true;
skipping to change at line 123 skipping to change at line 118
// check if there is an index key equal to mod // check if there is an index key equal to mod
if ( idxKeys.count(fullName) ) if ( idxKeys.count(fullName) )
return true; return true;
// check if there is an index key that is a child of mod // check if there is an index key that is a child of mod
set< string >::const_iterator j = idxKeys.upper_bound( fullName ); set< string >::const_iterator j = idxKeys.upper_bound( fullName );
if ( j != idxKeys.end() && j->find( fullName ) == 0 && (*j)[ful lName.size()] == '.' ) if ( j != idxKeys.end() && j->find( fullName ) == 0 && (*j)[ful lName.size()] == '.' )
return true; return true;
return false; return false;
} }
void apply( BSONObjBuilder& b , BSONElement in ); void apply( BSONObjBuilder& b , BSONElement in , ModState& ms ) con st;
/** /**
* @return true iff toMatch should be removed from the array * @return true iff toMatch should be removed from the array
*/ */
bool _pullElementMatch( BSONElement& toMatch ) const; bool _pullElementMatch( BSONElement& toMatch ) const;
bool needOpLogRewrite() const { void _checkForAppending( const BSONElement& e ) const {
switch( op ){
case BIT:
case BITAND:
case BITOR:
// TODO: should we convert this to $set?
return false;
default:
return false;
}
}
void appendForOpLog( BSONObjBuilder& b ) const {
const char * name = modNames[op];
BSONObjBuilder bb( b.subobjStart( name ) );
bb.append( elt );
bb.done();
}
void _checkForAppending( BSONElement& e ){
if ( e.type() == Object ){ if ( e.type() == Object ){
// this is a tiny bit slow, but rare and important // this is a tiny bit slow, but rare and important
// only when setting something TO an object, not setting so mething in an object // only when setting something TO an object, not setting so mething in an object
// and it checks for { $set : { x : { 'a.b' : 1 } } } // and it checks for { $set : { x : { 'a.b' : 1 } } }
// which is feel has been common // which is feel has been common
uassert( 12527 , "not okForStorage" , e.embeddedObject().ok ForStorage() ); uassert( 12527 , "not okForStorage" , e.embeddedObject().ok ForStorage() );
} }
} }
}; };
class ModSet { /**
* stores a set of Mods
* once created, should never be changed
*/
class ModSet : boost::noncopyable {
typedef map<string,Mod> ModHolder; typedef map<string,Mod> ModHolder;
ModHolder _mods; ModHolder _mods;
int _isIndexed;
static void extractFields( map< string, BSONElement > &fields, cons t BSONElement &top, const string &base ); static void extractFields( map< string, BSONElement > &fields, cons t BSONElement &top, const string &base );
FieldCompareResult compare( const ModHolder::iterator &m, map< stri ng, BSONElement >::iterator &p, const map< string, BSONElement >::iterator &pEnd ) const { FieldCompareResult compare( const ModHolder::iterator &m, map< stri ng, BSONElement >::iterator &p, const map< string, BSONElement >::iterator &pEnd ) const {
bool mDone = ( m == _mods.end() ); bool mDone = ( m == _mods.end() );
bool pDone = ( p == pEnd ); bool pDone = ( p == pEnd );
assert( ! mDone ); assert( ! mDone );
assert( ! pDone ); assert( ! pDone );
if ( mDone && pDone ) if ( mDone && pDone )
return SAME; return SAME;
// If one iterator is done we want to read from the other one, so say the other one is lower. // If one iterator is done we want to read from the other one, so say the other one is lower.
if ( mDone ) if ( mDone )
return RIGHT_BEFORE; return RIGHT_BEFORE;
if ( pDone ) if ( pDone )
return LEFT_BEFORE; return LEFT_BEFORE;
return compareDottedFieldNames( m->first, p->first.c_str() ); return compareDottedFieldNames( m->first, p->first.c_str() );
} }
void _appendNewFromMods( const string& root , Mod& m , BSONObjBuild
er& b , set<string>& onedownseen );
void appendNewFromMod( Mod& m , BSONObjBuilder& b ){
switch ( m.op ){
case Mod::PUSH: {
BSONObjBuilder arr( b.subarrayStart( m.shortFieldName ) );
arr.appendAs( m.elt, "0" );
arr.done();
m.pushStartSize = -1;
break;
}
case Mod::PUSH_ALL: {
b.appendAs( m.elt, m.shortFieldName );
m.pushStartSize = -1;
break;
}
case Mod::UNSET:
case Mod::PULL:
case Mod::PULL_ALL:
// no-op b/c unset/pull of nothing does nothing
break;
case Mod::INC:
case Mod::SET: {
m._checkForAppending( m.elt );
b.appendAs( m.elt, m.shortFieldName );
break;
}
default:
stringstream ss;
ss << "unknown mod in appendNewFromMod: " << m.op;
throw UserException( 9015, ss.str() );
}
}
bool mayAddEmbedded( map< string, BSONElement > &existing, string r ight ) { bool mayAddEmbedded( map< string, BSONElement > &existing, string r ight ) {
for( string left = EmbeddedBuilder::splitDot( right ); for( string left = EmbeddedBuilder::splitDot( right );
left.length() > 0 && left[ left.length() - 1 ] != '.'; left.length() > 0 && left[ left.length() - 1 ] != '.';
left += "." + EmbeddedBuilder::splitDot( right ) ) { left += "." + EmbeddedBuilder::splitDot( right ) ) {
if ( existing.count( left ) > 0 && existing[ left ].type() != Object ) if ( existing.count( left ) > 0 && existing[ left ].type() != Object )
return false; return false;
if ( haveModForField( left.c_str() ) ) if ( haveModForField( left.c_str() ) )
return false; return false;
} }
return true; return true;
skipping to change at line 282 skipping to change at line 223
if ( fn[2] == 'i' && fn[3] == 't' ){ if ( fn[2] == 'i' && fn[3] == 't' ){
if ( fn[4] == 0 ) if ( fn[4] == 0 )
return Mod::BIT; return Mod::BIT;
if ( fn[4] == 'a' && fn[5] == 'n' && fn[6] == 'd' && fn [7] == 0 ) if ( fn[4] == 'a' && fn[5] == 'n' && fn[6] == 'd' && fn [7] == 0 )
return Mod::BITAND; return Mod::BITAND;
if ( fn[4] == 'o' && fn[5] == 'r' && fn[6] == 0 ) if ( fn[4] == 'o' && fn[5] == 'r' && fn[6] == 0 )
return Mod::BITOR; return Mod::BITOR;
} }
break; break;
} }
case 'a': {
if ( fn[2] == 'd' && fn[3] == 'd' ){
// add
if ( fn[4] == 'T' && fn[5] == 'o' && fn[6] == 'S' && fn
[7] == 'e' && fn[8] == 't' && fn[9] == 0 )
return Mod::ADDTOSET;
}
}
default: break; default: break;
} }
uassert( 10161 , "Invalid modifier specified " + string( fn ), false ); uassert( 10161 , "Invalid modifier specified " + string( fn ), false );
return Mod::INC; return Mod::INC;
} }
public: public:
void getMods( const BSONObj &from ); ModSet( const BSONObj &from ,
const set<string>& idxKeys = set<string>(),
const set<string>* backgroundKeys = 0
);
/** /**
will return if can be done in place, or uassert if there is an e * creates a ModSetState suitable for operation on obj
rror * doesn't change or modify this ModSet or any underying Mod
@return whether or not the mods can be done in place
*/ */
bool canApplyInPlaceAndVerify( const BSONObj &obj ) const; auto_ptr<ModSetState> prepare( const BSONObj& obj ) const;
void applyModsInPlace( const BSONObj &obj ) const;
// new recursive version, will replace at some point
void createNewFromMods( const string& root , BSONObjBuilder& b , co
nst BSONObj &obj );
BSONObj createNewFromMods( const BSONObj &obj );
/**
* given a query pattern, builds an object suitable for an upsert
* will take the query spec and combine all $ operators
*/
BSONObj createNewFromQuery( const BSONObj& query ); BSONObj createNewFromQuery( const BSONObj& query );
/** /**
* *
*/ */
int isIndexed( const set<string>& idxKeys ) const { int isIndexed() const {
int numIndexes = 0; return _isIndexed;
for ( ModHolder::const_iterator i = _mods.begin(); i != _mods.e
nd(); i++ ){
if ( i->second.isIndexed( idxKeys ) )
numIndexes++;
}
return numIndexes;
} }
unsigned size() const { return _mods.size(); } unsigned size() const { return _mods.size(); }
bool haveModForField( const char *fieldName ) const { bool haveModForField( const char *fieldName ) const {
return _mods.find( fieldName ) != _mods.end(); return _mods.find( fieldName ) != _mods.end();
} }
bool haveConflictingMod( const string& fieldName ){ bool haveConflictingMod( const string& fieldName ){
size_t idx = fieldName.find( '.' ); size_t idx = fieldName.find( '.' );
skipping to change at line 343 skipping to change at line 289
case LEFT_BEFORE: return false; case LEFT_BEFORE: return false;
case SAME: return true; case SAME: return true;
case RIGHT_BEFORE: return false; case RIGHT_BEFORE: return false;
case RIGHT_SUBFIELD: return true; case RIGHT_SUBFIELD: return true;
} }
} }
return false; return false;
} }
};
/**
* stores any information about a single Mod operating on a single Obje
ct
*/
class ModState {
public:
const Mod * m;
BSONElement old;
const char * fixedName;
BSONElement * fixed;
int pushStartSize;
BSONType incType;
int incint;
double incdouble;
long long inclong;
ModState(){
fixedName = 0;
fixed = 0;
pushStartSize = -1;
incType = EOO;
}
Mod::Op op() const {
return m->op;
}
const char * fieldName() const {
return m->fieldName;
}
bool needOpLogRewrite() const {
if ( fixed || incType )
return true;
switch( op() ){
case Mod::BIT:
case Mod::BITAND:
case Mod::BITOR:
// TODO: should we convert this to $set?
return false;
default:
return false;
}
}
void appendForOpLog( BSONObjBuilder& b ) const {
if ( incType ){
BSONObjBuilder bb( b.subobjStart( "$set" ) );
appendIncValue( bb );
bb.done();
return;
}
const char * name = fixedName ? fixedName : Mod::modNames[op()]
;
BSONObjBuilder bb( b.subobjStart( name ) );
if ( fixed )
bb.append( *fixed );
else
bb.append( m->elt );
bb.done();
}
void apply( BSONObjBuilder& b , BSONElement in ){
m->apply( b , in , *this );
}
void appendIncValue( BSONObjBuilder& b ) const {
switch ( incType ){
case NumberDouble:
b.append( m->shortFieldName , incdouble ); break;
case NumberLong:
b.append( m->shortFieldName , inclong ); break;
case NumberInt:
b.append( m->shortFieldName , incint ); break;
default:
assert(0);
}
}
};
/**
* this is used to hold state, meta data while applying a ModSet to a B
SONObj
* the goal is to make ModSet const so its re-usable
*/
class ModSetState : boost::noncopyable {
typedef map<string,ModState> ModStateHolder;
const BSONObj& _obj;
ModStateHolder _mods;
bool _inPlacePossible;
ModSetState( const BSONObj& obj )
: _obj( obj ) , _inPlacePossible(true){
}
/**
* @return if in place is still possible
*/
bool amIInPlacePossible( bool inPlacePossible ){
if ( ! inPlacePossible )
_inPlacePossible = false;
return _inPlacePossible;
}
void createNewFromMods( const string& root , BSONObjBuilder& b , co
nst BSONObj &obj );
void _appendNewFromMods( const string& root , ModState& m , BSONObj
Builder& b , set<string>& onedownseen );
void appendNewFromMod( ModState& ms , BSONObjBuilder& b ){
//const Mod& m = *(ms.m); // HACK
Mod& m = *((Mod*)(ms.m)); // HACK
switch ( m.op ){
case Mod::PUSH: {
BSONObjBuilder arr( b.subarrayStart( m.shortFieldName ) );
arr.appendAs( m.elt, "0" );
arr.done();
break;
}
case Mod::PUSH_ALL: {
b.appendAs( m.elt, m.shortFieldName );
break;
}
case Mod::UNSET:
case Mod::PULL:
case Mod::PULL_ALL:
// no-op b/c unset/pull of nothing does nothing
break;
case Mod::INC:
case Mod::SET: {
m._checkForAppending( m.elt );
b.appendAs( m.elt, m.shortFieldName );
break;
}
default:
stringstream ss;
ss << "unknown mod in appendNewFromMod: " << m.op;
throw UserException( 9015, ss.str() );
}
}
public:
bool canApplyInPlace() const {
return _inPlacePossible;
}
/**
* modified underlying _obj
*/
void applyModsInPlace();
BSONObj createNewFromMods();
// re-writing for oplog // re-writing for oplog
bool needOpLogRewrite() const { bool needOpLogRewrite() const {
for ( ModHolder::const_iterator i = _mods.begin(); i != _mods.e nd(); i++ ) for ( ModStateHolder::const_iterator i = _mods.begin(); i != _m ods.end(); i++ )
if ( i->second.needOpLogRewrite() ) if ( i->second.needOpLogRewrite() )
return true; return true;
return false; return false;
} }
BSONObj getOpLogRewrite() const { BSONObj getOpLogRewrite() const {
BSONObjBuilder b; BSONObjBuilder b;
for ( ModHolder::const_iterator i = _mods.begin(); i != _mods.e nd(); i++ ) for ( ModStateHolder::const_iterator i = _mods.begin(); i != _m ods.end(); i++ )
i->second.appendForOpLog( b ); i->second.appendForOpLog( b );
return b.obj(); return b.obj();
} }
bool haveArrayDepMod() const { bool haveArrayDepMod() const {
for ( ModHolder::const_iterator i = _mods.begin(); i != _mods.e for ( ModStateHolder::const_iterator i = _mods.begin(); i != _m
nd(); i++ ) ods.end(); i++ )
if ( i->second.arrayDep() ) if ( i->second.m->arrayDep() )
return true; return true;
return false; return false;
} }
void appendSizeSpecForArrayDepMods( BSONObjBuilder &b ) const { void appendSizeSpecForArrayDepMods( BSONObjBuilder &b ) const {
for ( ModHolder::const_iterator i = _mods.begin(); i != _mods.e for ( ModStateHolder::const_iterator i = _mods.begin(); i != _m
nd(); i++ ) { ods.end(); i++ ) {
const Mod& m = i->second; const ModState& m = i->second;
if ( m.arrayDep() ){ if ( m.m->arrayDep() ){
if ( m.pushStartSize == -1 ) if ( m.pushStartSize == -1 )
b.appendNull( m.fieldName ); b.appendNull( m.fieldName() );
else else
b << m.fieldName << BSON( "$size" << m.pushStartSiz e ); b << m.fieldName() << BSON( "$size" << m.pushStartS ize );
} }
} }
} }
friend class ModSet;
}; };
} }
 End of changes. 27 change blocks. 
132 lines changed or deleted 245 lines changed or added


 utils.h   utils.h 
// utils.h // utils.h
/*
* Copyright 2010 10gen Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli
ed.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once #pragma once
#include "../scripting/engine.h" #include "../scripting/engine.h"
namespace mongo { namespace mongo {
namespace shellUtils { namespace shellUtils {
extern std::string _dbConnect; extern std::string _dbConnect;
 End of changes. 1 change blocks. 
0 lines changed or deleted 16 lines changed or added


 v8_db.h   v8_db.h 
skipping to change at line 62 skipping to change at line 62
// DB members // DB members
v8::Handle<v8::Value> dbInit(const v8::Arguments& args); v8::Handle<v8::Value> dbInit(const v8::Arguments& args);
v8::Handle<v8::Value> collectionInit( const v8::Arguments& args ); v8::Handle<v8::Value> collectionInit( const v8::Arguments& args );
v8::Handle<v8::Value> objectIdInit( const v8::Arguments& args ); v8::Handle<v8::Value> objectIdInit( const v8::Arguments& args );
v8::Handle<v8::Value> dbRefInit( const v8::Arguments& args ); v8::Handle<v8::Value> dbRefInit( const v8::Arguments& args );
v8::Handle<v8::Value> dbPointerInit( const v8::Arguments& args ); v8::Handle<v8::Value> dbPointerInit( const v8::Arguments& args );
v8::Handle<v8::Value> binDataInit( const v8::Arguments& args ); v8::Handle<v8::Value> binDataInit( const v8::Arguments& args );
v8::Handle<v8::Value> binDataToString( const v8::Arguments& args );
v8::Handle<v8::Value> numberLongInit( const v8::Arguments& args );
v8::Handle<v8::Value> numberLongToNumber(const v8::Arguments& args);
v8::Handle<v8::Value> numberLongValueOf(const v8::Arguments& args);
v8::Handle<v8::Value> numberLongToString(const v8::Arguments& args);
v8::Handle<v8::Value> dbQueryInit( const v8::Arguments& args ); v8::Handle<v8::Value> dbQueryInit( const v8::Arguments& args );
v8::Handle<v8::Value> dbQueryIndexAccess( uint32_t index , const v8::Ac cessorInfo& info ); v8::Handle<v8::Value> dbQueryIndexAccess( uint32_t index , const v8::Ac cessorInfo& info );
v8::Handle<v8::Value> collectionFallback( v8::Local<v8::String> name, c onst v8::AccessorInfo &info); v8::Handle<v8::Value> collectionFallback( v8::Local<v8::String> name, c onst v8::AccessorInfo &info);
v8::Handle<v8::Value> bsonsize( const v8::Arguments& args ); v8::Handle<v8::Value> bsonsize( const v8::Arguments& args );
} }
 End of changes. 1 change blocks. 
0 lines changed or deleted 6 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/