| action_type.h | | action_type.h | |
| // AUTO-GENERATED FILE DO NOT EDIT | | // AUTO-GENERATED FILE DO NOT EDIT | |
| // See src/mongo/db/auth/generate_action_types.py | | // See src/mongo/db/auth/generate_action_types.py | |
|
| /* | | /* Copyright 2012 10gen Inc. | |
| * Copyright (C) 2012 10gen Inc. | | * | |
| * | | * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * This program is free software: you can redistribute it and/or modify | | * you may not use this file except in compliance with the License. | |
| * it under the terms of the GNU Affero General Public License, version 3 | | * You may obtain a copy of the License at | |
| , | | * | |
| * as published by the Free Software Foundation. | | * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | | * | |
| * This program is distributed in the hope that it will be useful, | | * Unless required by applicable law or agreed to in writing, software | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | | * distributed under the License is distributed on an "AS IS" BASIS, | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli | |
| * GNU Affero General Public License for more details. | | ed. | |
| * | | * See the License for the specific language governing permissions and | |
| * You should have received a copy of the GNU Affero General Public Licen | | * limitations under the License. | |
| se | | */ | |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. | | | |
| */ | | | |
| | | | |
| #pragma once | | #pragma once | |
| | | | |
| #include <iosfwd> | | #include <iosfwd> | |
| #include <map> | | #include <map> | |
| #include <string> | | #include <string> | |
| | | | |
| #include "mongo/base/status.h" | | #include "mongo/base/status.h" | |
| #include "mongo/platform/cstdint.h" | | #include "mongo/platform/cstdint.h" | |
| | | | |
| | | | |
| skipping to change at line 55 | | skipping to change at line 54 | |
| // ActionType enum. | | // ActionType enum. | |
| static Status parseActionFromString(const std::string& actionString
, ActionType* result); | | static Status parseActionFromString(const std::string& actionString
, ActionType* result); | |
| | | | |
| // Takes an ActionType and returns the string representation | | // Takes an ActionType and returns the string representation | |
| static std::string actionToString(const ActionType& action); | | static std::string actionToString(const ActionType& action); | |
| | | | |
| static const ActionType addShard; | | static const ActionType addShard; | |
| static const ActionType applyOps; | | static const ActionType applyOps; | |
| static const ActionType captrunc; | | static const ActionType captrunc; | |
| static const ActionType clean; | | static const ActionType clean; | |
|
| | | static const ActionType clone; | |
| | | static const ActionType cloneCollectionLocalSource; | |
| | | static const ActionType cloneCollectionTarget; | |
| static const ActionType closeAllDatabases; | | static const ActionType closeAllDatabases; | |
| static const ActionType collMod; | | static const ActionType collMod; | |
| static const ActionType collStats; | | static const ActionType collStats; | |
| static const ActionType compact; | | static const ActionType compact; | |
| static const ActionType connPoolStats; | | static const ActionType connPoolStats; | |
| static const ActionType connPoolSync; | | static const ActionType connPoolSync; | |
| static const ActionType convertToCapped; | | static const ActionType convertToCapped; | |
| static const ActionType cpuProfiler; | | static const ActionType cpuProfiler; | |
| static const ActionType createCollection; | | static const ActionType createCollection; | |
| static const ActionType cursorInfo; | | static const ActionType cursorInfo; | |
| | | | |
| skipping to change at line 84 | | skipping to change at line 86 | |
| static const ActionType find; | | static const ActionType find; | |
| static const ActionType flushRouterConfig; | | static const ActionType flushRouterConfig; | |
| static const ActionType fsync; | | static const ActionType fsync; | |
| static const ActionType getCmdLineOpts; | | static const ActionType getCmdLineOpts; | |
| static const ActionType getLog; | | static const ActionType getLog; | |
| static const ActionType getParameter; | | static const ActionType getParameter; | |
| static const ActionType getShardMap; | | static const ActionType getShardMap; | |
| static const ActionType getShardVersion; | | static const ActionType getShardVersion; | |
| static const ActionType handshake; | | static const ActionType handshake; | |
| static const ActionType hostInfo; | | static const ActionType hostInfo; | |
|
| | | static const ActionType indexStats; | |
| | | static const ActionType inprog; | |
| static const ActionType insert; | | static const ActionType insert; | |
|
| | | static const ActionType killop; | |
| static const ActionType listDatabases; | | static const ActionType listDatabases; | |
| static const ActionType listShards; | | static const ActionType listShards; | |
| static const ActionType logRotate; | | static const ActionType logRotate; | |
|
| | | static const ActionType mapReduceShardedFinish; | |
| static const ActionType moveChunk; | | static const ActionType moveChunk; | |
| static const ActionType movePrimary; | | static const ActionType movePrimary; | |
| static const ActionType netstat; | | static const ActionType netstat; | |
|
| static const ActionType profile; | | static const ActionType profileEnable; | |
| | | static const ActionType profileRead; | |
| static const ActionType reIndex; | | static const ActionType reIndex; | |
| static const ActionType remove; | | static const ActionType remove; | |
| static const ActionType removeShard; | | static const ActionType removeShard; | |
|
| static const ActionType renameCollection; | | static const ActionType renameCollectionSameDB; | |
| static const ActionType repairDatabase; | | static const ActionType repairDatabase; | |
| static const ActionType replSetElect; | | static const ActionType replSetElect; | |
| static const ActionType replSetFreeze; | | static const ActionType replSetFreeze; | |
| static const ActionType replSetFresh; | | static const ActionType replSetFresh; | |
| static const ActionType replSetGetRBID; | | static const ActionType replSetGetRBID; | |
| static const ActionType replSetGetStatus; | | static const ActionType replSetGetStatus; | |
| static const ActionType replSetHeartbeat; | | static const ActionType replSetHeartbeat; | |
| static const ActionType replSetInitiate; | | static const ActionType replSetInitiate; | |
| static const ActionType replSetMaintenance; | | static const ActionType replSetMaintenance; | |
| static const ActionType replSetReconfig; | | static const ActionType replSetReconfig; | |
| static const ActionType replSetStepDown; | | static const ActionType replSetStepDown; | |
| static const ActionType replSetSyncFrom; | | static const ActionType replSetSyncFrom; | |
| static const ActionType resync; | | static const ActionType resync; | |
|
| | | static const ActionType serverStatus; | |
| static const ActionType setParameter; | | static const ActionType setParameter; | |
| static const ActionType setShardVersion; | | static const ActionType setShardVersion; | |
| static const ActionType shardCollection; | | static const ActionType shardCollection; | |
| static const ActionType shardingState; | | static const ActionType shardingState; | |
| static const ActionType shutdown; | | static const ActionType shutdown; | |
| static const ActionType split; | | static const ActionType split; | |
| static const ActionType splitChunk; | | static const ActionType splitChunk; | |
| static const ActionType splitVector; | | static const ActionType splitVector; | |
|
| | | static const ActionType storageDetails; | |
| static const ActionType top; | | static const ActionType top; | |
| static const ActionType touch; | | static const ActionType touch; | |
|
| | | static const ActionType unlock; | |
| static const ActionType unsetSharding; | | static const ActionType unsetSharding; | |
| static const ActionType update; | | static const ActionType update; | |
| static const ActionType userAdmin; | | static const ActionType userAdmin; | |
| static const ActionType validate; | | static const ActionType validate; | |
| static const ActionType writebacklisten; | | static const ActionType writebacklisten; | |
| static const ActionType writeBacksQueued; | | static const ActionType writeBacksQueued; | |
| static const ActionType _migrateClone; | | static const ActionType _migrateClone; | |
| static const ActionType _recvChunkAbort; | | static const ActionType _recvChunkAbort; | |
| static const ActionType _recvChunkCommit; | | static const ActionType _recvChunkCommit; | |
| static const ActionType _recvChunkStart; | | static const ActionType _recvChunkStart; | |
| static const ActionType _recvChunkStatus; | | static const ActionType _recvChunkStatus; | |
| static const ActionType _transferMods; | | static const ActionType _transferMods; | |
|
| static const ActionType oldRead; | | | |
| static const ActionType oldWrite; | | | |
| | | | |
| enum ActionTypeIdentifier { | | enum ActionTypeIdentifier { | |
| addShardValue, | | addShardValue, | |
| applyOpsValue, | | applyOpsValue, | |
| captruncValue, | | captruncValue, | |
| cleanValue, | | cleanValue, | |
|
| | | cloneValue, | |
| | | cloneCollectionLocalSourceValue, | |
| | | cloneCollectionTargetValue, | |
| closeAllDatabasesValue, | | closeAllDatabasesValue, | |
| collModValue, | | collModValue, | |
| collStatsValue, | | collStatsValue, | |
| compactValue, | | compactValue, | |
| connPoolStatsValue, | | connPoolStatsValue, | |
| connPoolSyncValue, | | connPoolSyncValue, | |
| convertToCappedValue, | | convertToCappedValue, | |
| cpuProfilerValue, | | cpuProfilerValue, | |
| createCollectionValue, | | createCollectionValue, | |
| cursorInfoValue, | | cursorInfoValue, | |
| | | | |
| skipping to change at line 168 | | skipping to change at line 179 | |
| findValue, | | findValue, | |
| flushRouterConfigValue, | | flushRouterConfigValue, | |
| fsyncValue, | | fsyncValue, | |
| getCmdLineOptsValue, | | getCmdLineOptsValue, | |
| getLogValue, | | getLogValue, | |
| getParameterValue, | | getParameterValue, | |
| getShardMapValue, | | getShardMapValue, | |
| getShardVersionValue, | | getShardVersionValue, | |
| handshakeValue, | | handshakeValue, | |
| hostInfoValue, | | hostInfoValue, | |
|
| | | indexStatsValue, | |
| | | inprogValue, | |
| insertValue, | | insertValue, | |
|
| | | killopValue, | |
| listDatabasesValue, | | listDatabasesValue, | |
| listShardsValue, | | listShardsValue, | |
| logRotateValue, | | logRotateValue, | |
|
| | | mapReduceShardedFinishValue, | |
| moveChunkValue, | | moveChunkValue, | |
| movePrimaryValue, | | movePrimaryValue, | |
| netstatValue, | | netstatValue, | |
|
| profileValue, | | profileEnableValue, | |
| | | profileReadValue, | |
| reIndexValue, | | reIndexValue, | |
| removeValue, | | removeValue, | |
| removeShardValue, | | removeShardValue, | |
|
| renameCollectionValue, | | renameCollectionSameDBValue, | |
| repairDatabaseValue, | | repairDatabaseValue, | |
| replSetElectValue, | | replSetElectValue, | |
| replSetFreezeValue, | | replSetFreezeValue, | |
| replSetFreshValue, | | replSetFreshValue, | |
| replSetGetRBIDValue, | | replSetGetRBIDValue, | |
| replSetGetStatusValue, | | replSetGetStatusValue, | |
| replSetHeartbeatValue, | | replSetHeartbeatValue, | |
| replSetInitiateValue, | | replSetInitiateValue, | |
| replSetMaintenanceValue, | | replSetMaintenanceValue, | |
| replSetReconfigValue, | | replSetReconfigValue, | |
| replSetStepDownValue, | | replSetStepDownValue, | |
| replSetSyncFromValue, | | replSetSyncFromValue, | |
| resyncValue, | | resyncValue, | |
|
| | | serverStatusValue, | |
| setParameterValue, | | setParameterValue, | |
| setShardVersionValue, | | setShardVersionValue, | |
| shardCollectionValue, | | shardCollectionValue, | |
| shardingStateValue, | | shardingStateValue, | |
| shutdownValue, | | shutdownValue, | |
| splitValue, | | splitValue, | |
| splitChunkValue, | | splitChunkValue, | |
| splitVectorValue, | | splitVectorValue, | |
|
| | | storageDetailsValue, | |
| topValue, | | topValue, | |
| touchValue, | | touchValue, | |
|
| | | unlockValue, | |
| unsetShardingValue, | | unsetShardingValue, | |
| updateValue, | | updateValue, | |
| userAdminValue, | | userAdminValue, | |
| validateValue, | | validateValue, | |
| writebacklistenValue, | | writebacklistenValue, | |
| writeBacksQueuedValue, | | writeBacksQueuedValue, | |
| _migrateCloneValue, | | _migrateCloneValue, | |
| _recvChunkAbortValue, | | _recvChunkAbortValue, | |
| _recvChunkCommitValue, | | _recvChunkCommitValue, | |
| _recvChunkStartValue, | | _recvChunkStartValue, | |
| _recvChunkStatusValue, | | _recvChunkStatusValue, | |
| _transferModsValue, | | _transferModsValue, | |
|
| oldReadValue, | | | |
| oldWriteValue, | | | |
| | | | |
| actionTypeEndValue, // Should always be last in this enum | | actionTypeEndValue, // Should always be last in this enum | |
| }; | | }; | |
| | | | |
| static const int NUM_ACTION_TYPES = actionTypeEndValue; | | static const int NUM_ACTION_TYPES = actionTypeEndValue; | |
| | | | |
| private: | | private: | |
| | | | |
| uint32_t _identifier; // unique identifier for this action. | | uint32_t _identifier; // unique identifier for this action. | |
| }; | | }; | |
| | | | |
End of changes. 21 change blocks. |
| 25 lines changed or deleted | | 41 lines changed or added | |
|
| assert_util.h | | assert_util.h | |
| | | | |
| skipping to change at line 24 | | skipping to change at line 24 | |
| * 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 <iostream> | | #include <iostream> | |
| #include <typeinfo> | | #include <typeinfo> | |
| #include <string> | | #include <string> | |
| | | | |
|
| | | #include "mongo/base/status.h" // NOTE: This is safe as utils depend on bas
e | |
| #include "mongo/bson/inline_decls.h" | | #include "mongo/bson/inline_decls.h" | |
| #include "mongo/platform/compiler.h" | | #include "mongo/platform/compiler.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| enum CommonErrorCodes { | | enum CommonErrorCodes { | |
| DatabaseDifferCaseCode = 13297 , | | DatabaseDifferCaseCode = 13297 , | |
| SendStaleConfigCode = 13388 , | | SendStaleConfigCode = 13388 , | |
| RecvStaleConfigCode = 9996 | | RecvStaleConfigCode = 9996 | |
| }; | | }; | |
| | | | |
| skipping to change at line 103 | | skipping to change at line 104 | |
| DBException( const std::string& msg , int code ) : _ei(msg,code) {
traceIfNeeded(*this); } | | DBException( const std::string& msg , int code ) : _ei(msg,code) {
traceIfNeeded(*this); } | |
| virtual ~DBException() throw() { } | | virtual ~DBException() throw() { } | |
| | | | |
| virtual const char* what() const throw() { return _ei.msg.c_str();
} | | virtual const char* what() const throw() { return _ei.msg.c_str();
} | |
| virtual int getCode() const { return _ei.code; } | | virtual int getCode() const { return _ei.code; } | |
| virtual void appendPrefix( std::stringstream& ss ) const { } | | virtual void appendPrefix( std::stringstream& ss ) const { } | |
| virtual void addContext( const std::string& str ) { | | virtual void addContext( const std::string& str ) { | |
| _ei.msg = str + causedBy( _ei.msg ); | | _ei.msg = str + causedBy( _ei.msg ); | |
| } | | } | |
| | | | |
|
| | | // Utilities for the migration to Status objects | |
| | | static ErrorCodes::Error convertExceptionCode(int exCode); | |
| | | | |
| | | Status toStatus(const std::string& context) const { | |
| | | return Status(convertExceptionCode(getCode()), context + caused | |
| | | By(*this)); | |
| | | } | |
| | | Status toStatus() const { | |
| | | return Status(convertExceptionCode(getCode()), this->toString() | |
| | | ); | |
| | | } | |
| | | | |
| // context when applicable. otherwise "" | | // context when applicable. otherwise "" | |
| std::string _shard; | | std::string _shard; | |
| | | | |
| virtual std::string toString() const; | | virtual std::string toString() const; | |
| | | | |
| const ExceptionInfo& getInfo() const { return _ei; } | | const ExceptionInfo& getInfo() const { return _ei; } | |
| private: | | private: | |
| static void traceIfNeeded( const DBException& e ); | | static void traceIfNeeded( const DBException& e ); | |
| public: | | public: | |
| static bool traceExceptions; | | static bool traceExceptions; | |
| | | | |
| skipping to change at line 178 | | skipping to change at line 189 | |
| msgassertedNoTrace( msgid , msg.c_str() ); | | msgassertedNoTrace( msgid , msg.c_str() ); | |
| } | | } | |
| MONGO_COMPILER_NORETURN void msgasserted(int msgid, const char *msg); | | MONGO_COMPILER_NORETURN void msgasserted(int msgid, const char *msg); | |
| MONGO_COMPILER_NORETURN void msgasserted(int msgid, const std::string &
msg); | | MONGO_COMPILER_NORETURN void msgasserted(int msgid, const std::string &
msg); | |
| | | | |
| /* convert various types of exceptions to strings */ | | /* convert various types of exceptions to strings */ | |
| inline std::string causedBy( const char* e ){ return (std::string)" ::
caused by :: " + e; } | | inline std::string causedBy( const char* e ){ return (std::string)" ::
caused by :: " + e; } | |
| inline std::string causedBy( const DBException& e ){ return causedBy( e
.toString().c_str() ); } | | inline std::string causedBy( const DBException& e ){ return causedBy( e
.toString().c_str() ); } | |
| inline std::string causedBy( const std::exception& e ){ return causedBy
( e.what() ); } | | inline std::string causedBy( const std::exception& e ){ return causedBy
( e.what() ); } | |
| inline std::string causedBy( const std::string& e ){ return causedBy( e
.c_str() ); } | | inline std::string causedBy( const std::string& e ){ return causedBy( e
.c_str() ); } | |
|
| | | inline std::string causedBy( const std::string* e ){ | |
| | | return (e && *e != "") ? causedBy(*e) : ""; | |
| | | } | |
| | | inline std::string causedBy( const Status& e ){ return causedBy( e.reas | |
| | | on() ); } | |
| | | | |
| /** aborts on condition failure */ | | /** aborts on condition failure */ | |
| inline void fassert(int msgid, bool testOK) {if (MONGO_unlikely(!testOK
)) fassertFailed(msgid);} | | inline void fassert(int msgid, bool testOK) {if (MONGO_unlikely(!testOK
)) fassertFailed(msgid);} | |
| | | | |
| /* "user assert". if asserts, user did something wrong, not our code *
/ | | /* "user assert". if asserts, user did something wrong, not our code *
/ | |
| #define MONGO_uassert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || (
mongo::uasserted(msgid, msg), 0) ) | | #define MONGO_uassert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || (
mongo::uasserted(msgid, msg), 0) ) | |
| | | | |
|
| | | #define MONGO_uassertStatusOK(expr) do { \ | |
| | | Status status = (expr); \ | |
| | | if (!status.isOK()) \ | |
| | | uasserted(status.location() != 0 ? status.location() : status.c | |
| | | ode(), \ | |
| | | status.reason()); \ | |
| | | } while(0) | |
| | | | |
| /* warning only - keeps going */ | | /* warning only - keeps going */ | |
| #define MONGO_wassert(_Expression) (void)( MONGO_likely(!!(_Expression)) ||
(mongo::wasserted(#_Expression, __FILE__, __LINE__), 0) ) | | #define MONGO_wassert(_Expression) (void)( MONGO_likely(!!(_Expression)) ||
(mongo::wasserted(#_Expression, __FILE__, __LINE__), 0) ) | |
| | | | |
| /* display a message, no context, and throw assertionexception | | /* display a message, no context, and throw assertionexception | |
| | | | |
| easy way to throw an exception and log something without our stack t
race | | easy way to throw an exception and log something without our stack t
race | |
| display happening. | | display happening. | |
| */ | | */ | |
| #define MONGO_massert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || (
mongo::msgasserted(msgid, msg), 0) ) | | #define MONGO_massert(msgid, msg, expr) (void)( MONGO_likely(!!(expr)) || (
mongo::msgasserted(msgid, msg), 0) ) | |
| /* same as massert except no msgid */ | | /* same as massert except no msgid */ | |
| | | | |
| skipping to change at line 206 | | skipping to change at line 228 | |
| | | | |
| /* dassert is 'debug assert' -- might want to turn off for production a
s these | | /* dassert is 'debug assert' -- might want to turn off for production a
s these | |
| could be slow. | | could be slow. | |
| */ | | */ | |
| #if defined(_DEBUG) | | #if defined(_DEBUG) | |
| # define MONGO_dassert(x) fassert(16199, (x)) | | # define MONGO_dassert(x) fassert(16199, (x)) | |
| #else | | #else | |
| # define MONGO_dassert(x) | | # define MONGO_dassert(x) | |
| #endif | | #endif | |
| | | | |
|
| | | /** Allows to jump code during exeuction. */ | |
| | | inline bool debugCompare(bool inDebug, bool condition) { return inDebug | |
| | | && condition; } | |
| | | | |
| | | #if defined(_DEBUG) | |
| | | # define MONGO_debug_and(x) debugCompare(true, (x)) | |
| | | #else | |
| | | # define MONGO_debug_and(x) debugCompare(false, (x)) | |
| | | #endif | |
| | | | |
| #ifdef MONGO_EXPOSE_MACROS | | #ifdef MONGO_EXPOSE_MACROS | |
|
| | | # define dcompare MONGO_debug_and | |
| # define dassert MONGO_dassert | | # define dassert MONGO_dassert | |
| # define verify MONGO_verify | | # define verify MONGO_verify | |
| # define uassert MONGO_uassert | | # define uassert MONGO_uassert | |
|
| | | # define uassertStatusOK MONGO_uassertStatusOK | |
| # define wassert MONGO_wassert | | # define wassert MONGO_wassert | |
| # define massert MONGO_massert | | # define massert MONGO_massert | |
| #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 | |
| | | | |
| enum { ASSERT_ID_DUPKEY = 11000 }; | | enum { ASSERT_ID_DUPKEY = 11000 }; | |
| | | | |
End of changes. 7 change blocks. |
| 0 lines changed or deleted | | 38 lines changed or added | |
|
| authorization_manager.h | | authorization_manager.h | |
| | | | |
| skipping to change at line 20 | | skipping to change at line 20 | |
| * 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 <string> | | #include <string> | |
|
| | | #include <vector> | |
| | | | |
| #include "mongo/base/disallow_copying.h" | | #include "mongo/base/disallow_copying.h" | |
| #include "mongo/base/status.h" | | #include "mongo/base/status.h" | |
|
| #include "mongo/client/dbclientinterface.h" | | | |
| #include "mongo/db/auth/acquired_privilege.h" | | | |
| #include "mongo/db/auth/action_set.h" | | #include "mongo/db/auth/action_set.h" | |
| #include "mongo/db/auth/action_type.h" | | #include "mongo/db/auth/action_type.h" | |
| #include "mongo/db/auth/auth_external_state.h" | | #include "mongo/db/auth/auth_external_state.h" | |
| #include "mongo/db/auth/principal.h" | | #include "mongo/db/auth/principal.h" | |
|
| | | #include "mongo/db/auth/principal_name.h" | |
| #include "mongo/db/auth/principal_set.h" | | #include "mongo/db/auth/principal_set.h" | |
|
| | | #include "mongo/db/auth/privilege.h" | |
| #include "mongo/db/auth/privilege_set.h" | | #include "mongo/db/auth/privilege_set.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
|
| | | // --noauth cmd line option | |
| | | extern bool noauth; | |
| | | | |
| | | /** | |
| | | * Internal secret key info. | |
| | | */ | |
| | | struct AuthInfo { | |
| | | AuthInfo(); | |
| | | string user; | |
| | | string pwd; | |
| | | }; | |
| | | extern AuthInfo internalSecurity; // set at startup and not changed aft | |
| | | er initialization. | |
| | | | |
| /** | | /** | |
| * Contains all the authorization logic for a single client connection.
It contains a set of | | * Contains all the authorization logic for a single client connection.
It contains a set of | |
| * the principals which have been authenticated, as well as a set of pr
ivileges that have been | | * the principals which have been authenticated, as well as a set of pr
ivileges that have been | |
| * granted by those principals to perform various actions. | | * granted by those principals to perform various actions. | |
| * An AuthorizationManager object is present within every mongo::Client
object, therefore there | | * An AuthorizationManager object is present within every mongo::Client
object, therefore there | |
| * is one per thread that corresponds to an incoming client connection. | | * is one per thread that corresponds to an incoming client connection. | |
| */ | | */ | |
| class AuthorizationManager { | | class AuthorizationManager { | |
| MONGO_DISALLOW_COPYING(AuthorizationManager); | | MONGO_DISALLOW_COPYING(AuthorizationManager); | |
| public: | | public: | |
|
| | | | |
| | | static const std::string SERVER_RESOURCE_NAME; | |
| | | static const std::string CLUSTER_RESOURCE_NAME; | |
| | | | |
| | | static const std::string USER_NAME_FIELD_NAME; | |
| | | static const std::string USER_SOURCE_FIELD_NAME; | |
| | | static const std::string PASSWORD_FIELD_NAME; | |
| | | | |
| | | static void setSupportOldStylePrivilegeDocuments(bool enabled); | |
| | | | |
| | | // Checks to see if "doc" is a valid privilege document, assuming i | |
| | | t is stored in the | |
| | | // "system.users" collection of database "dbname". | |
| | | // | |
| | | // Returns Status::OK() if the document is good, or Status(ErrorCod | |
| | | es::BadValue), otherwise. | |
| | | static Status checkValidPrivilegeDocument(const StringData& dbname, | |
| | | const BSONObj& doc); | |
| | | | |
| // Takes ownership of the externalState. | | // Takes ownership of the externalState. | |
| explicit AuthorizationManager(AuthExternalState* externalState); | | explicit AuthorizationManager(AuthExternalState* externalState); | |
| ~AuthorizationManager(); | | ~AuthorizationManager(); | |
| | | | |
|
| // adminDBConnection is a connection that can be used to access the | | // Should be called at the beginning of every new request. This pe | |
| admin database. It is | | rforms the checks | |
| // used to determine if there are any admin users configured for th | | // necessary to determine if localhost connections should be given | |
| e cluster, and thus if | | full access. | |
| // localhost connections should be given special admin access. | | // TODO: try to eliminate the need for this call. | |
| // This function *must* be called on any new AuthorizationManager, | | void startRequest(); | |
| after the constructor but | | | |
| // before any other methods are called on the AuthorizationManager. | | | |
| Status initialize(DBClientBase* adminDBConnection); | | | |
| | | | |
|
| // Takes ownership of the principal (by putting into _authenticated
Principals). | | // Adds "principal" to the authorization manager, and takes ownersh
ip of it. | |
| void addAuthorizedPrincipal(Principal* principal); | | void addAuthorizedPrincipal(Principal* principal); | |
| | | | |
|
| // Removes and deletes the given principal from the set of authenti | | // Returns the authenticated principal with the given name. Return | |
| cated principals. | | s NULL | |
| // Return an error Status if the given principal isn't a member of | | // if no such user is found. | |
| the | | | |
| // _authenticatedPrincipals set. | | | |
| Status removeAuthorizedPrincipal(const Principal* principal); | | | |
| | | | |
| // Returns NULL if not found | | | |
| // Ownership of the returned Principal remains with _authenticatedP
rincipals | | // Ownership of the returned Principal remains with _authenticatedP
rincipals | |
|
| Principal* lookupPrincipal(const std::string& name) const; | | Principal* lookupPrincipal(const PrincipalName& name); | |
| | | | |
| | | // Gets an iterator over the names of all authenticated principals | |
| | | stored in this manager. | |
| | | PrincipalSet::NameIterator getAuthenticatedPrincipalNames(); | |
| | | | |
| | | // Removes any authenticated principals whose authorization credent | |
| | | ials came from the given | |
| | | // database, and revokes any privileges that were granted via that | |
| | | principal. | |
| | | void logoutDatabase(const std::string& dbname); | |
| | | | |
| // Grant this connection the given privilege. | | // Grant this connection the given privilege. | |
|
| Status acquirePrivilege(const AcquiredPrivilege& privilege); | | Status acquirePrivilege(const Privilege& privilege, | |
| | | const PrincipalName& authorizingPrincipal); | |
| | | | |
|
| // This should be called when the connection gets authenticated as | | // Adds a new principal with the given principal name and authorize | |
| the internal user. | | s it with full access. | |
| // This grants a privilege on all the actions for the internal role | | // Used to grant internal threads full access. | |
| , with the | | void grantInternalAuthorization(const std::string& principalName); | |
| // internalPrincipal as the principal. | | | |
| void grantInternalAuthorization(); | | // Checks if this connection has been authenticated as an internal | |
| | | user. | |
| | | bool hasInternalAuthorization(); | |
| | | | |
| // Checks if this connection has the privileges required to perform
the given action | | // Checks if this connection has the privileges required to perform
the given action | |
| // on the given resource. Contains all the authorization logic inc
luding handling things | | // on the given resource. Contains all the authorization logic inc
luding handling things | |
|
| // like the localhost exception. If it is authorized, returns the | | // like the localhost exception. Returns true if the action may pr | |
| principal that granted | | oceed on the resource. | |
| // the needed privilege. Returns NULL if not authorized. If the a | | bool checkAuthorization(const std::string& resource, ActionType act | |
| ction is authorized but | | ion); | |
| // not because of a standard user Principal but for a special reaso | | | |
| n such as the localhost | | // Same as above but takes an ActionSet instead of a single ActionT | |
| // exception, it returns a pointer to specialAdminPrincipal. | | ype. Returns true if | |
| const Principal* checkAuthorization(const std::string& resource, Ac | | // all of the actions may proceed on the resource. | |
| tionType action) const; | | bool checkAuthorization(const std::string& resource, ActionSet acti | |
| | | ons); | |
| | | | |
| | | // Parses the privilege documents and acquires all privileges that | |
| | | the privilege document | |
| | | // grants | |
| | | Status acquirePrivilegesFromPrivilegeDocument(const std::string& db | |
| | | name, | |
| | | const PrincipalName& | |
| | | principal, | |
| | | const BSONObj& privil | |
| | | egeDocument); | |
| | | | |
| // Returns the privilege document with the given user name in the g
iven database. Currently | | // Returns the privilege document with the given user name in the g
iven database. Currently | |
| // this information comes from the system.users collection in that
database. | | // this information comes from the system.users collection in that
database. | |
|
| static Status getPrivilegeDocument(DBClientBase* conn, | | Status getPrivilegeDocument(const std::string& dbname, | |
| const std::string& dbname, | | const PrincipalName& userName, | |
| const std::string& userName, | | BSONObj* result) { | |
| BSONObj* result); | | return _externalState->getPrivilegeDocument(dbname, userName, r | |
| | | esult); | |
| // Returns true if there exists at least one privilege document in | | } | |
| the given database. | | | |
| static bool hasPrivilegeDocument(DBClientBase* conn, const std::str | | // Checks if this connection has the privileges necessary to perfor | |
| ing& dbname); | | m a query on the given | |
| | | // namespace. | |
| | | Status checkAuthForQuery(const std::string& ns); | |
| | | | |
| | | // Checks if this connection has the privileges necessary to perfor | |
| | | m an update on the given | |
| | | // namespace. | |
| | | Status checkAuthForUpdate(const std::string& ns, bool upsert); | |
| | | | |
| | | // Checks if this connection has the privileges necessary to perfor | |
| | | m an insert to the given | |
| | | // namespace. | |
| | | Status checkAuthForInsert(const std::string& ns); | |
| | | | |
| | | // Checks if this connection has the privileges necessary to perfor | |
| | | m a delete on the given | |
| | | // namespace. | |
| | | Status checkAuthForDelete(const std::string& ns); | |
| | | | |
| | | // Checks if this connection has the privileges necessary to perfor | |
| | | m a getMore on the given | |
| | | // namespace. | |
| | | Status checkAuthForGetMore(const std::string& ns); | |
| | | | |
| | | // Checks if this connection is authorized for the given Privilege. | |
| | | Status checkAuthForPrivilege(const Privilege& privilege); | |
| | | | |
| | | // Checks if this connection is authorized for all the given Privil | |
| | | eges. | |
| | | Status checkAuthForPrivileges(const vector<Privilege>& privileges); | |
| | | | |
| | | // Given a database name and a readOnly flag return an ActionSet de | |
| | | scribing all the actions | |
| | | // that an old-style user with those attributes should be given. | |
| | | static ActionSet getActionsForOldStyleUser(const std::string& dbnam | |
| | | e, bool readOnly); | |
| | | | |
|
| // Parses the privilege document and returns a PrivilegeSet of all
the Capabilities that | | // Parses the privilege document and returns a PrivilegeSet of all
the Privileges that | |
| // the privilege document grants. | | // the privilege document grants. | |
| static Status buildPrivilegeSet(const std::string& dbname, | | static Status buildPrivilegeSet(const std::string& dbname, | |
|
| Principal* principal, | | const PrincipalName& principal, | |
| const BSONObj& privilegeDocument, | | const BSONObj& privilegeDocument, | |
| PrivilegeSet* result); | | PrivilegeSet* result); | |
| | | | |
|
| | | // Returns an ActionSet of all actions that can be be granted to us | |
| | | ers. This does not | |
| | | // include internal-only actions. | |
| | | static ActionSet getAllUserActions(); | |
| | | | |
| private: | | private: | |
|
| | | // Finds the set of privileges attributed to "principal" in databas | |
| | | e "dbname", | |
| | | // and adds them to the set of acquired privileges. | |
| | | void _acquirePrivilegesForPrincipalFromDatabase(const std::string& | |
| | | dbname, | |
| | | const PrincipalName | |
| | | & principal); | |
| | | | |
| | | // Checks to see if the given privilege is allowed, performing impl | |
| | | icit privilege | |
| | | // acquisition if enabled and necessary to resolve the privilege. | |
| | | Status _probeForPrivilege(const Privilege& privilege); | |
| | | | |
| // Parses the old-style (pre 2.4) privilege document and returns a
PrivilegeSet of all the | | // Parses the old-style (pre 2.4) privilege document and returns a
PrivilegeSet of all the | |
| // Privileges that the privilege document grants. | | // Privileges that the privilege document grants. | |
| static Status _buildPrivilegeSetFromOldStylePrivilegeDocument( | | static Status _buildPrivilegeSetFromOldStylePrivilegeDocument( | |
| const std::string& dbname, | | const std::string& dbname, | |
|
| Principal* principal, | | const PrincipalName& principal, | |
| | | const BSONObj& privilegeDocument, | |
| | | PrivilegeSet* result); | |
| | | | |
| | | // Parses extended-form (2.4+) privilege documents and returns a Pr | |
| | | ivilegeSet of all the | |
| | | // privileges that the document grants. | |
| | | // | |
| | | // The document, "privilegeDocument", is assumed to describe privil | |
| | | eges for "principal", and | |
| | | // to come from database "dbname". | |
| | | static Status _buildPrivilegeSetFromExtendedPrivilegeDocument( | |
| | | const std::string& dbname, | |
| | | const PrincipalName& principal, | |
| const BSONObj& privilegeDocument, | | const BSONObj& privilegeDocument, | |
| PrivilegeSet* result); | | PrivilegeSet* result); | |
| | | | |
|
| | | // Returns a new privilege that has replaced the actions needed to | |
| | | handle special casing | |
| | | // certain namespaces like system.users and system.profile. | |
| | | Privilege _modifyPrivilegeForSpecialCases(const Privilege& privileg | |
| | | e); | |
| | | | |
| | | static bool _doesSupportOldStylePrivileges; | |
| | | | |
| scoped_ptr<AuthExternalState> _externalState; | | scoped_ptr<AuthExternalState> _externalState; | |
| | | | |
| // All the privileges that have been acquired by the authenticated
principals. | | // All the privileges that have been acquired by the authenticated
principals. | |
| PrivilegeSet _acquiredPrivileges; | | PrivilegeSet _acquiredPrivileges; | |
| // All principals who have been authenticated on this connection | | // All principals who have been authenticated on this connection | |
| PrincipalSet _authenticatedPrincipals; | | PrincipalSet _authenticatedPrincipals; | |
|
| bool _initialized; | | | |
| }; | | }; | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 21 change blocks. |
| 50 lines changed or deleted | | 172 lines changed or added | |
|
| bson-inl.h | | bson-inl.h | |
| | | | |
| skipping to change at line 268 | | skipping to change at line 268 | |
| break; | | break; | |
| } | | } | |
| } | | } | |
| } | | } | |
| } | | } | |
| | | | |
| inline BSONElement BSONObj::getField(const StringData& name) const { | | inline BSONElement BSONObj::getField(const StringData& name) const { | |
| BSONObjIterator i(*this); | | BSONObjIterator i(*this); | |
| while ( i.more() ) { | | while ( i.more() ) { | |
| BSONElement e = i.next(); | | BSONElement e = i.next(); | |
|
| if ( strcmp(e.fieldName(), name.data()) == 0 ) | | if ( name == e.fieldName() ) | |
| return e; | | return e; | |
| } | | } | |
| return BSONElement(); | | return BSONElement(); | |
| } | | } | |
| | | | |
| inline int BSONObj::getIntField(const char *name) const { | | inline int BSONObj::getIntField(const char *name) const { | |
| BSONElement e = getField(name); | | BSONElement e = getField(name); | |
| return e.isNumber() ? (int) e.number() : std::numeric_limits< int >
::min(); | | return e.isNumber() ? (int) e.number() : std::numeric_limits< int >
::min(); | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 334 | | skipping to change at line 334 | |
| inline bool BSONObj::getObjectID(BSONElement& e) const { | | inline bool BSONObj::getObjectID(BSONElement& e) const { | |
| BSONElement f = getField("_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; | | | |
| _builder = builder; | | _builder = builder; | |
| } | | } | |
| | | | |
| template<class T> | | template<class T> | |
| inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<( T value )
{ | | inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<( T value )
{ | |
| _builder->append(_fieldName, value); | | _builder->append(_fieldName, value); | |
|
| _fieldName = 0; | | _fieldName = StringData(); | |
| return *_builder; | | return *_builder; | |
| } | | } | |
| | | | |
| inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<( const BSO
NElement& e ) { | | inline BSONObjBuilder& BSONObjBuilderValueStream::operator<<( const BSO
NElement& e ) { | |
| _builder->appendAs( e , _fieldName ); | | _builder->appendAs( e , _fieldName ); | |
|
| _fieldName = 0; | | _fieldName = StringData(); | |
| return *_builder; | | return *_builder; | |
| } | | } | |
| | | | |
|
| | | inline BufBuilder& BSONObjBuilderValueStream::subobjStart() { | |
| | | StringData tmp = _fieldName; | |
| | | _fieldName = StringData(); | |
| | | return _builder->subobjStart(tmp); | |
| | | } | |
| | | | |
| | | inline BufBuilder& BSONObjBuilderValueStream::subarrayStart() { | |
| | | StringData tmp = _fieldName; | |
| | | _fieldName = StringData(); | |
| | | return _builder->subarrayStart(tmp); | |
| | | } | |
| | | | |
| inline Labeler BSONObjBuilderValueStream::operator<<( const Labeler::La
bel &l ) { | | inline Labeler BSONObjBuilderValueStream::operator<<( const Labeler::La
bel &l ) { | |
| return Labeler( l, this ); | | return Labeler( l, this ); | |
| } | | } | |
| | | | |
|
| inline void BSONObjBuilderValueStream::endField( const char *nextFieldN | | inline void BSONObjBuilderValueStream::endField( const StringData& next | |
| ame ) { | | FieldName ) { | |
| if ( _fieldName && haveSubobj() ) { | | if ( haveSubobj() ) { | |
| | | verify( _fieldName.rawData() ); | |
| _builder->append( _fieldName, subobj()->done() ); | | _builder->append( _fieldName, subobj()->done() ); | |
| } | | } | |
| _subobj.reset(); | | _subobj.reset(); | |
| _fieldName = nextFieldName; | | _fieldName = nextFieldName; | |
| } | | } | |
| | | | |
| inline BSONObjBuilder *BSONObjBuilderValueStream::subobj() { | | inline BSONObjBuilder *BSONObjBuilderValueStream::subobj() { | |
| if ( !haveSubobj() ) | | if ( !haveSubobj() ) | |
| _subobj.reset( new BSONObjBuilder() ); | | _subobj.reset( new BSONObjBuilder() ); | |
| return _subobj.get(); | | return _subobj.get(); | |
| | | | |
| skipping to change at line 406 | | skipping to change at line 418 | |
| | | | |
| inline BSONObjIterator BSONObjBuilder::iterator() const { | | inline BSONObjIterator BSONObjBuilder::iterator() const { | |
| const char * s = _b.buf() + _offset; | | const char * s = _b.buf() + _offset; | |
| const char * e = _b.buf() + _b.len(); | | const char * e = _b.buf() + _b.len(); | |
| return BSONObjIterator( s , e ); | | return BSONObjIterator( s , e ); | |
| } | | } | |
| | | | |
| inline bool BSONObjBuilder::hasField( const StringData& name ) const { | | inline bool BSONObjBuilder::hasField( const StringData& name ) const { | |
| BSONObjIterator i = iterator(); | | BSONObjIterator i = iterator(); | |
| while ( i.more() ) | | while ( i.more() ) | |
|
| if ( strcmp( name.data() , i.next().fieldName() ) == 0 ) | | if ( name == i.next().fieldName() ) | |
| return true; | | return true; | |
| return false; | | return false; | |
| } | | } | |
| | | | |
| /* WARNING: nested/dotted conversions are not 100% reversible | | /* WARNING: nested/dotted conversions are not 100% reversible | |
| * nested2dotted(dotted2nested({a.b: {c:1}})) -> {a.b.c: 1} | | * nested2dotted(dotted2nested({a.b: {c:1}})) -> {a.b.c: 1} | |
| * also, dotted2nested ignores order | | * also, dotted2nested ignores order | |
| */ | | */ | |
| | | | |
| typedef std::map<std::string, BSONElement> BSONMap; | | typedef std::map<std::string, BSONElement> BSONMap; | |
| | | | |
| skipping to change at line 994 | | skipping to change at line 1006 | |
| verify( ! i.more() ); | | verify( ! i.more() ); | |
| verify( ! j.more() ); | | verify( ! j.more() ); | |
| } | | } | |
| | | | |
| inline BSONObj BSONObj::removeField(const StringData& name) const { | | inline BSONObj BSONObj::removeField(const StringData& name) const { | |
| BSONObjBuilder b; | | BSONObjBuilder b; | |
| BSONObjIterator i(*this); | | BSONObjIterator i(*this); | |
| while ( i.more() ) { | | while ( i.more() ) { | |
| BSONElement e = i.next(); | | BSONElement e = i.next(); | |
| const char *fname = e.fieldName(); | | const char *fname = e.fieldName(); | |
|
| if( strcmp(name.data(), fname) ) | | if ( name != fname ) | |
| b.append(e); | | b.append(e); | |
| } | | } | |
| return b.obj(); | | return b.obj(); | |
| } | | } | |
|
| | | | |
| | | template<typename T> bool BSONObj::coerceVector( std::vector<T>* out ) | |
| | | const { | |
| | | BSONObjIterator i( *this ); | |
| | | while ( i.more() ) { | |
| | | BSONElement e = i.next(); | |
| | | T t; | |
| | | if ( ! e.coerce<T>( &t ) ) | |
| | | return false; | |
| | | out->push_back( t ); | |
| | | } | |
| | | return true; | |
| | | } | |
| | | | |
| | | template<> inline bool BSONElement::coerce<std::string>( std::string* o | |
| | | ut ) const { | |
| | | if ( type() != mongo::String ) | |
| | | return false; | |
| | | *out = String(); | |
| | | return true; | |
| | | } | |
| | | | |
| | | template<> inline bool BSONElement::coerce<int>( int* out ) const { | |
| | | if ( !isNumber() ) | |
| | | return false; | |
| | | *out = numberInt(); | |
| | | return true; | |
| | | } | |
| | | | |
| | | template<> inline bool BSONElement::coerce<double>( double* out ) const | |
| | | { | |
| | | if ( !isNumber() ) | |
| | | return false; | |
| | | *out = numberDouble(); | |
| | | return true; | |
| | | } | |
| | | | |
| | | template<> inline bool BSONElement::coerce<bool>( bool* out ) const { | |
| | | *out = trueValue(); | |
| | | return true; | |
| | | } | |
| | | | |
| | | template<> inline bool BSONElement::coerce< std::vector<std::string> >( | |
| | | std::vector<std::string>* out ) const { | |
| | | if ( type() != mongo::Array ) | |
| | | return false; | |
| | | return Obj().coerceVector<std::string>( out ); | |
| | | } | |
| | | | |
| } | | } | |
| | | | |
End of changes. 9 change blocks. |
| 9 lines changed or deleted | | 70 lines changed or added | |
|
| bsonmisc.h | | bsonmisc.h | |
| | | | |
| skipping to change at line 20 | | skipping to change at line 20 | |
| * | | * | |
| * 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 <memory> | |
| | | | |
| #include "mongo/bson/bsonelement.h" | | #include "mongo/bson/bsonelement.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| 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 ) < 0; | | return l.woCompare( r, false ) < 0; | |
| } | | } | |
| | | | |
| skipping to change at line 97 | | skipping to change at line 99 | |
| std::cout << BSON( "created" << DATENOW ); // { created : "2009-10
-09 11:41:42" } | | std::cout << BSON( "created" << DATENOW ); // { created : "2009-10
-09 11:41:42" } | |
| */ | | */ | |
| extern struct DateNowLabeler { } DATENOW; | | extern struct DateNowLabeler { } DATENOW; | |
| | | | |
| /* Utility class to assign a NULL value to a given attribute | | /* Utility class to assign a NULL value to a given attribute | |
| Example: | | Example: | |
| std::cout << BSON( "a" << BSONNULL ); // { a : null } | | std::cout << BSON( "a" << BSONNULL ); // { a : null } | |
| */ | | */ | |
| extern struct NullLabeler { } BSONNULL; | | extern struct NullLabeler { } BSONNULL; | |
| | | | |
|
| | | /* Utility class to assign an Undefined value to a given attribute | |
| | | Example: | |
| | | std::cout << BSON( "a" << BSONUndefined ); // { a : undefined } | |
| | | */ | |
| | | extern struct UndefinedLabeler { } BSONUndefined; | |
| | | | |
| /* Utility class to add the minKey (minus infinity) to a given attribut
e | | /* Utility class to add the minKey (minus infinity) to a given attribut
e | |
| Example: | | Example: | |
| std::cout << BSON( "a" << MINKEY ); // { "a" : { "$minKey" : 1 } } | | std::cout << BSON( "a" << MINKEY ); // { "a" : { "$minKey" : 1 } } | |
| */ | | */ | |
| extern struct MinKeyLabeler { } MINKEY; | | extern struct MinKeyLabeler { } MINKEY; | |
| extern struct MaxKeyLabeler { } MAXKEY; | | extern struct MaxKeyLabeler { } MAXKEY; | |
| | | | |
| // Utility class to implement GT, GTE, etc as described above. | | // Utility class to implement GT, GTE, etc as described above. | |
| class Labeler { | | class Labeler { | |
| public: | | public: | |
| struct Label { | | struct Label { | |
|
| Label( const char *l ) : l_( l ) {} | | explicit Label( const char *l ) : l_( l ) {} | |
| const char *l_; | | const char *l_; | |
| }; | | }; | |
| Labeler( const Label &l, BSONObjBuilderValueStream *s ) : l_( l ),
s_( s ) {} | | Labeler( const Label &l, BSONObjBuilderValueStream *s ) : l_( l ),
s_( s ) {} | |
| template<class T> | | template<class T> | |
| BSONObjBuilder& operator<<( T value ); | | BSONObjBuilder& operator<<( T value ); | |
| | | | |
| /* the value of the element e is appended i.e. for | | /* the value of the element e is appended i.e. for | |
| "age" << GT << someElement | | "age" << GT << someElement | |
| one gets | | one gets | |
| { age : { $gt : someElement's value } } | | { age : { $gt : someElement's value } } | |
| */ | | */ | |
| BSONObjBuilder& operator<<( const BSONElement& e ); | | BSONObjBuilder& operator<<( const BSONElement& e ); | |
| private: | | private: | |
| const Label &l_; | | const Label &l_; | |
| BSONObjBuilderValueStream *s_; | | BSONObjBuilderValueStream *s_; | |
| }; | | }; | |
| | | | |
|
| | | // Utility class to allow adding a string to BSON as a Symbol | |
| | | struct BSONSymbol { | |
| | | explicit BSONSymbol(const StringData& sym) :symbol(sym) {} | |
| | | StringData symbol; | |
| | | }; | |
| | | | |
| | | // Utility class to allow adding a string to BSON as Code | |
| | | struct BSONCode { | |
| | | explicit BSONCode(const StringData& str) :code(str) {} | |
| | | StringData code; | |
| | | }; | |
| | | | |
| | | // Utility class to allow adding CodeWScope to BSON | |
| | | struct BSONCodeWScope { | |
| | | explicit BSONCodeWScope(const StringData& str, const BSONObj& obj) | |
| | | :code(str), scope(obj) {} | |
| | | StringData code; | |
| | | BSONObj scope; | |
| | | }; | |
| | | | |
| | | // Utility class to allow adding a RegEx to BSON | |
| | | struct BSONRegEx { | |
| | | explicit BSONRegEx(const StringData& pat, const StringData& f="") : | |
| | | pattern(pat), flags(f) {} | |
| | | StringData pattern; | |
| | | StringData flags; | |
| | | }; | |
| | | | |
| | | // Utility class to allow adding binary data to BSON | |
| | | struct BSONBinData { | |
| | | BSONBinData(const void* d, int l, BinDataType t) :data(d), length(l | |
| | | ), type(t) {} | |
| | | const void* data; | |
| | | int length; | |
| | | BinDataType type; | |
| | | }; | |
| | | | |
| | | // Utility class to allow adding deprecated DBRef type to BSON | |
| | | struct BSONDBRef { | |
| | | BSONDBRef(const StringData& nameSpace, const OID& o) :ns(nameSpace) | |
| | | , oid(o) {} | |
| | | StringData ns; | |
| | | OID oid; | |
| | | }; | |
| | | | |
| extern Labeler::Label GT; | | extern Labeler::Label GT; | |
| extern Labeler::Label GTE; | | extern Labeler::Label GTE; | |
| extern Labeler::Label LT; | | extern Labeler::Label LT; | |
| extern Labeler::Label LTE; | | extern Labeler::Label LTE; | |
| extern Labeler::Label NE; | | extern Labeler::Label NE; | |
| extern Labeler::Label NIN; | | extern Labeler::Label NIN; | |
| extern Labeler::Label BSIZE; | | extern Labeler::Label BSIZE; | |
| | | | |
| // $or helper: OR(BSON("x" << GT << 7), BSON("y" << LT << 6)); | | // $or helper: OR(BSON("x" << GT << 7), BSON("y" << LT << 6)); | |
| // becomes : {$or: [{x: {$gt: 7}}, {y: {$lt: 6}}]} | | // becomes : {$or: [{x: {$gt: 7}}, {y: {$lt: 6}}]} | |
| | | | |
| skipping to change at line 154 | | skipping to change at line 203 | |
| class BSONObjBuilderValueStream : public boost::noncopyable { | | class BSONObjBuilderValueStream : public boost::noncopyable { | |
| public: | | public: | |
| friend class Labeler; | | friend class Labeler; | |
| BSONObjBuilderValueStream( BSONObjBuilder * builder ); | | BSONObjBuilderValueStream( BSONObjBuilder * builder ); | |
| | | | |
| BSONObjBuilder& operator<<( const BSONElement& e ); | | BSONObjBuilder& operator<<( const BSONElement& e ); | |
| | | | |
| template<class T> | | template<class T> | |
| BSONObjBuilder& operator<<( T value ); | | BSONObjBuilder& operator<<( T value ); | |
| | | | |
|
| BSONObjBuilder& operator<<(DateNowLabeler& id); | | BSONObjBuilder& operator<<(const DateNowLabeler& id); | |
| | | | |
|
| BSONObjBuilder& operator<<(NullLabeler& id); | | BSONObjBuilder& operator<<(const NullLabeler& id); | |
| | | BSONObjBuilder& operator<<(const UndefinedLabeler& id); | |
| | | | |
|
| BSONObjBuilder& operator<<(MinKeyLabeler& id); | | BSONObjBuilder& operator<<(const MinKeyLabeler& id); | |
| BSONObjBuilder& operator<<(MaxKeyLabeler& id); | | BSONObjBuilder& operator<<(const MaxKeyLabeler& id); | |
| | | | |
| Labeler operator<<( const Labeler::Label &l ); | | Labeler operator<<( const Labeler::Label &l ); | |
| | | | |
|
| void endField( const char *nextFieldName = 0 ); | | void endField( const StringData& nextFieldName = StringData() ); | |
| bool subobjStarted() const { return _fieldName != 0; } | | bool subobjStarted() const { return _fieldName != 0; } | |
| | | | |
|
| | | // The following methods provide API compatibility with BSONArrayBu | |
| | | ilder | |
| | | BufBuilder& subobjStart(); | |
| | | BufBuilder& subarrayStart(); | |
| | | | |
| | | // This method should only be called from inside of implementations | |
| | | of | |
| | | // BSONObjBuilder& operator<<(BSONObjBuilderValueStream&, SOME_TYPE | |
| | | ) | |
| | | // to provide the return value. | |
| | | BSONObjBuilder& builder() { return *_builder; } | |
| private: | | private: | |
|
| const char * _fieldName; | | StringData _fieldName; | |
| BSONObjBuilder * _builder; | | BSONObjBuilder * _builder; | |
| | | | |
| bool haveSubobj() const { return _subobj.get() != 0; } | | bool haveSubobj() const { return _subobj.get() != 0; } | |
| BSONObjBuilder *subobj(); | | BSONObjBuilder *subobj(); | |
| std::auto_ptr< BSONObjBuilder > _subobj; | | std::auto_ptr< BSONObjBuilder > _subobj; | |
| }; | | }; | |
| | | | |
| /** | | /** | |
| used in conjuction with BSONObjBuilder, allows for proper buffer siz
e to prevent crazy memory usage | | used in conjuction with BSONObjBuilder, allows for proper buffer siz
e to prevent crazy memory usage | |
| */ | | */ | |
| | | | |
End of changes. 10 change blocks. |
| 7 lines changed or deleted | | 72 lines changed or added | |
|
| bsonobjbuilder.h | | bsonobjbuilder.h | |
| | | | |
| skipping to change at line 26 | | skipping to change at line 26 | |
| * 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 <boost/static_assert.hpp> | | #include <boost/static_assert.hpp> | |
|
| | | #include <map> | |
| #include <cmath> | | #include <cmath> | |
| #include <limits> | | #include <limits> | |
| | | | |
|
| | | #include "mongo/base/parse_number.h" | |
| #include "mongo/bson/bsonelement.h" | | #include "mongo/bson/bsonelement.h" | |
| #include "mongo/bson/bsonobj.h" | | #include "mongo/bson/bsonobj.h" | |
| #include "mongo/bson/bsonmisc.h" | | #include "mongo/bson/bsonmisc.h" | |
| #include "mongo/bson/bson_builder_base.h" | | #include "mongo/bson/bson_builder_base.h" | |
| #include "mongo/bson/bson_field.h" | | #include "mongo/bson/bson_field.h" | |
| | | | |
| #if defined(_DEBUG) && defined(MONGO_EXPOSE_MACROS) | | #if defined(_DEBUG) && defined(MONGO_EXPOSE_MACROS) | |
| #include "mongo/util/log.h" | | #include "mongo/util/log.h" | |
| #endif | | #endif | |
| | | | |
| | | | |
| skipping to change at line 340 | | skipping to change at line 342 | |
| @param regex options such as "i" or "g" | | @param regex options such as "i" or "g" | |
| */ | | */ | |
| BSONObjBuilder& appendRegex(const StringData& fieldName, const Stri
ngData& regex, const StringData& options = "") { | | BSONObjBuilder& appendRegex(const StringData& fieldName, const Stri
ngData& regex, const StringData& options = "") { | |
| _b.appendNum((char) RegEx); | | _b.appendNum((char) RegEx); | |
| _b.appendStr(fieldName); | | _b.appendStr(fieldName); | |
| _b.appendStr(regex); | | _b.appendStr(regex); | |
| _b.appendStr(options); | | _b.appendStr(options); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
|
| | | BSONObjBuilder& append(const StringData& fieldName, const BSONRegEx | |
| | | & regex) { | |
| | | return appendRegex(fieldName, regex.pattern, regex.flags); | |
| | | } | |
| | | | |
| BSONObjBuilder& appendCode(const StringData& fieldName, const Strin
gData& code) { | | BSONObjBuilder& appendCode(const StringData& fieldName, const Strin
gData& code) { | |
| _b.appendNum((char) Code); | | _b.appendNum((char) Code); | |
| _b.appendStr(fieldName); | | _b.appendStr(fieldName); | |
| _b.appendNum((int) code.size()+1); | | _b.appendNum((int) code.size()+1); | |
| _b.appendStr(code); | | _b.appendStr(code); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
|
| | | BSONObjBuilder& append(const StringData& fieldName, const BSONCode& | |
| | | code) { | |
| | | return appendCode(fieldName, code.code); | |
| | | } | |
| | | | |
| /** Append a string element. | | /** Append a string element. | |
| @param sz size includes terminating null character */ | | @param sz size includes terminating null character */ | |
| BSONObjBuilder& append(const StringData& fieldName, const char *str
, int sz) { | | BSONObjBuilder& append(const StringData& fieldName, const char *str
, int sz) { | |
| _b.appendNum((char) String); | | _b.appendNum((char) String); | |
| _b.appendStr(fieldName); | | _b.appendStr(fieldName); | |
| _b.appendNum((int)sz); | | _b.appendNum((int)sz); | |
| _b.appendBuf(str, sz); | | _b.appendBuf(str, sz); | |
| return *this; | | return *this; | |
| } | | } | |
| /** Append a string element */ | | /** Append a string element */ | |
| BSONObjBuilder& append(const StringData& fieldName, const char *str
) { | | BSONObjBuilder& append(const StringData& fieldName, const char *str
) { | |
| return append(fieldName, str, (int) strlen(str)+1); | | return append(fieldName, str, (int) strlen(str)+1); | |
| } | | } | |
| /** Append a string element */ | | /** Append a string element */ | |
| BSONObjBuilder& append(const StringData& fieldName, const std::stri
ng& str) { | | BSONObjBuilder& append(const StringData& fieldName, const std::stri
ng& str) { | |
| return append(fieldName, str.c_str(), (int) str.size()+1); | | return append(fieldName, str.c_str(), (int) str.size()+1); | |
| } | | } | |
| /** Append a string element */ | | /** Append a string element */ | |
| BSONObjBuilder& append(const StringData& fieldName, const StringDat
a& str) { | | BSONObjBuilder& append(const StringData& fieldName, const StringDat
a& str) { | |
|
| return append(fieldName, str.data(), (int) str.size()+1); | | _b.appendNum((char) String); | |
| | | _b.appendStr(fieldName); | |
| | | _b.appendNum((int)str.size()+1); | |
| | | _b.appendStr(str, true); | |
| | | return *this; | |
| } | | } | |
| | | | |
| BSONObjBuilder& appendSymbol(const StringData& fieldName, const Str
ingData& symbol) { | | BSONObjBuilder& appendSymbol(const StringData& fieldName, const Str
ingData& symbol) { | |
| _b.appendNum((char) Symbol); | | _b.appendNum((char) Symbol); | |
| _b.appendStr(fieldName); | | _b.appendStr(fieldName); | |
| _b.appendNum((int) symbol.size()+1); | | _b.appendNum((int) symbol.size()+1); | |
| _b.appendStr(symbol); | | _b.appendStr(symbol); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
|
| | | BSONObjBuilder& append(const StringData& fieldName, const BSONSymbo | |
| | | l& symbol) { | |
| | | return appendSymbol(fieldName, symbol.symbol); | |
| | | } | |
| | | | |
| /** Implements builder interface but no-op in ObjBuilder */ | | /** Implements builder interface but no-op in ObjBuilder */ | |
| void appendNull() { | | void appendNull() { | |
| msgasserted(16234, "Invalid call to appendNull in BSONObj Build
er."); | | msgasserted(16234, "Invalid call to appendNull in BSONObj Build
er."); | |
| } | | } | |
| | | | |
| /** Append a Null element to the object */ | | /** Append a Null element to the object */ | |
| BSONObjBuilder& appendNull( const StringData& fieldName ) { | | BSONObjBuilder& appendNull( const StringData& fieldName ) { | |
| _b.appendNum( (char) jstNULL ); | | _b.appendNum( (char) jstNULL ); | |
| _b.appendStr( fieldName ); | | _b.appendStr( fieldName ); | |
| return *this; | | return *this; | |
| | | | |
| skipping to change at line 412 | | skipping to change at line 430 | |
| | | | |
| // Append a Timestamp field -- will be updated to next OpTime on db
insert. | | // Append a Timestamp field -- will be updated to next OpTime on db
insert. | |
| BSONObjBuilder& appendTimestamp( const StringData& fieldName ) { | | BSONObjBuilder& appendTimestamp( const StringData& fieldName ) { | |
| _b.appendNum( (char) Timestamp ); | | _b.appendNum( (char) Timestamp ); | |
| _b.appendStr( fieldName ); | | _b.appendStr( fieldName ); | |
| _b.appendNum( (unsigned long long) 0 ); | | _b.appendNum( (unsigned long long) 0 ); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
| /** | | /** | |
|
| * To store an OpTime in BSON, use this function. Pass the OpTime a | | * To store an OpTime in BSON, use this function. | |
| s a Date, as follows: | | * This captures both the secs and inc fields. | |
| | | */ | |
| | | BSONObjBuilder& append(const StringData& fieldName, OpTime optime); | |
| | | | |
| | | /** | |
| | | * Alternative way to store an OpTime in BSON. Pass the OpTime as a | |
| | | Date, as follows: | |
| * | | * | |
| * builder.appendTimestamp("field", optime.asDate()); | | * builder.appendTimestamp("field", optime.asDate()); | |
| * | | * | |
| * This captures both the secs and inc fields. | | * This captures both the secs and inc fields. | |
| */ | | */ | |
| BSONObjBuilder& appendTimestamp( const StringData& fieldName , unsi
gned long long val ) { | | BSONObjBuilder& appendTimestamp( const StringData& fieldName , unsi
gned long long val ) { | |
| _b.appendNum( (char) Timestamp ); | | _b.appendNum( (char) Timestamp ); | |
| _b.appendStr( fieldName ); | | _b.appendStr( fieldName ); | |
| _b.appendNum( val ); | | _b.appendNum( val ); | |
| return *this; | | return *this; | |
| | | | |
| skipping to change at line 445 | | skipping to change at line 469 | |
| */ | | */ | |
| BSONObjBuilder& appendDBRef( const StringData& fieldName, const Str
ingData& ns, const OID &oid ) { | | BSONObjBuilder& appendDBRef( const StringData& fieldName, const Str
ingData& ns, const OID &oid ) { | |
| _b.appendNum( (char) DBRef ); | | _b.appendNum( (char) DBRef ); | |
| _b.appendStr( fieldName ); | | _b.appendStr( fieldName ); | |
| _b.appendNum( (int) ns.size() + 1 ); | | _b.appendNum( (int) ns.size() + 1 ); | |
| _b.appendStr( ns ); | | _b.appendStr( ns ); | |
| _b.appendBuf( (void *) &oid, 12 ); | | _b.appendBuf( (void *) &oid, 12 ); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
|
| | | BSONObjBuilder& append(const StringData& fieldName, const BSONDBRef | |
| | | & dbref) { | |
| | | return appendDBRef(fieldName, dbref.ns, dbref.oid); | |
| | | } | |
| | | | |
| /** Append a binary data element | | /** Append a binary data element | |
| @param fieldName name of the field | | @param fieldName name of the field | |
| @param len length of the binary data in bytes | | @param len length of the binary data in bytes | |
| @param subtype subtype information for the data. @see enum BinD
ataType in bsontypes.h. | | @param subtype subtype information for the data. @see enum BinD
ataType in bsontypes.h. | |
| Use BinDataGeneral if you don't care about the type. | | Use BinDataGeneral if you don't care about the type. | |
| @param data the byte array | | @param data the byte array | |
| */ | | */ | |
| BSONObjBuilder& appendBinData( const StringData& fieldName, int len
, BinDataType type, const void *data ) { | | BSONObjBuilder& appendBinData( const StringData& fieldName, int len
, BinDataType type, const void *data ) { | |
| _b.appendNum( (char) BinData ); | | _b.appendNum( (char) BinData ); | |
| _b.appendStr( fieldName ); | | _b.appendStr( fieldName ); | |
| _b.appendNum( len ); | | _b.appendNum( len ); | |
| _b.appendNum( (char) type ); | | _b.appendNum( (char) type ); | |
| _b.appendBuf( data, len ); | | _b.appendBuf( data, len ); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
|
| | | BSONObjBuilder& append(const StringData& fieldName, const BSONBinDa | |
| | | ta& bd) { | |
| | | return appendBinData(fieldName, bd.length, bd.type, bd.data); | |
| | | } | |
| | | | |
| /** | | /** | |
| Subtype 2 is deprecated. | | Subtype 2 is deprecated. | |
| Append a BSON bindata bytearray element. | | Append a BSON bindata bytearray element. | |
| @param data a byte array | | @param data a byte array | |
| @param len the length of data | | @param len the length of data | |
| */ | | */ | |
| BSONObjBuilder& appendBinDataArrayDeprecated( const char * fieldNam
e , const void * data , int len ) { | | BSONObjBuilder& appendBinDataArrayDeprecated( const char * fieldNam
e , const void * data , int len ) { | |
| _b.appendNum( (char) BinData ); | | _b.appendNum( (char) BinData ); | |
| _b.appendStr( fieldName ); | | _b.appendStr( fieldName ); | |
| _b.appendNum( len + 4 ); | | _b.appendNum( len + 4 ); | |
| | | | |
| skipping to change at line 490 | | skipping to change at line 522 | |
| BSONObjBuilder& appendCodeWScope( const StringData& fieldName, cons
t StringData& code, const BSONObj &scope ) { | | BSONObjBuilder& appendCodeWScope( const StringData& fieldName, cons
t StringData& code, const BSONObj &scope ) { | |
| _b.appendNum( (char) CodeWScope ); | | _b.appendNum( (char) CodeWScope ); | |
| _b.appendStr( fieldName ); | | _b.appendStr( fieldName ); | |
| _b.appendNum( ( int )( 4 + 4 + code.size() + 1 + scope.objsize(
) ) ); | | _b.appendNum( ( int )( 4 + 4 + code.size() + 1 + scope.objsize(
) ) ); | |
| _b.appendNum( ( int ) code.size() + 1 ); | | _b.appendNum( ( int ) code.size() + 1 ); | |
| _b.appendStr( code ); | | _b.appendStr( code ); | |
| _b.appendBuf( ( void * )scope.objdata(), scope.objsize() ); | | _b.appendBuf( ( void * )scope.objdata(), scope.objsize() ); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
|
| | | BSONObjBuilder& append(const StringData& fieldName, const BSONCodeW | |
| | | Scope& cws) { | |
| | | return appendCodeWScope(fieldName, cws.code, cws.scope); | |
| | | } | |
| | | | |
| void appendUndefined( const StringData& fieldName ) { | | void appendUndefined( const StringData& fieldName ) { | |
| _b.appendNum( (char) Undefined ); | | _b.appendNum( (char) Undefined ); | |
| _b.appendStr( fieldName ); | | _b.appendStr( fieldName ); | |
| } | | } | |
| | | | |
| /* helper function -- see Query::where() for primary way to do this
. */ | | /* helper function -- see Query::where() for primary way to do this
. */ | |
| void appendWhere( const StringData& code, const BSONObj &scope ) { | | void appendWhere( const StringData& code, const BSONObj &scope ) { | |
| appendCodeWScope( "$where" , code , scope ); | | appendCodeWScope( "$where" , code , scope ); | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 518 | | skipping to change at line 554 | |
| BSONObjBuilder& append( const StringData& fieldName, const std::vec
tor< T >& vals ); | | BSONObjBuilder& append( const StringData& fieldName, const std::vec
tor< T >& vals ); | |
| | | | |
| template < class T > | | template < class T > | |
| BSONObjBuilder& append( const StringData& fieldName, const std::lis
t< T >& vals ); | | BSONObjBuilder& append( const StringData& fieldName, const std::lis
t< T >& vals ); | |
| | | | |
| /** Append a set of values. */ | | /** Append a set of values. */ | |
| template < class T > | | template < class T > | |
| BSONObjBuilder& append( const StringData& fieldName, const std::set
< T >& vals ); | | BSONObjBuilder& append( const StringData& fieldName, const std::set
< T >& vals ); | |
| | | | |
| /** | | /** | |
|
| | | * Append a map of values as a sub-object. | |
| | | * Note: the keys of the map should be StringData-compatible (i.e. | |
| | | strings). | |
| | | */ | |
| | | template < class K, class T > | |
| | | BSONObjBuilder& append( const StringData& fieldName, const std::map | |
| | | < K, T >& vals ); | |
| | | | |
| | | /** | |
| * destructive | | * destructive | |
| * The returned BSONObj will free the buffer when it is finished. | | * The returned BSONObj will free the buffer when it is finished. | |
| * @return owned BSONObj | | * @return owned BSONObj | |
| */ | | */ | |
| BSONObj obj() { | | BSONObj obj() { | |
| bool own = owned(); | | bool own = owned(); | |
| massert( 10335 , "builder does not own memory", own ); | | massert( 10335 , "builder does not own memory", own ); | |
| doneFast(); | | doneFast(); | |
| BSONObj::Holder* h = (BSONObj::Holder*)_b.buf(); | | BSONObj::Holder* h = (BSONObj::Holder*)_b.buf(); | |
| decouple(); // sets _b.buf() to NULL | | decouple(); // sets _b.buf() to NULL | |
| | | | |
| skipping to change at line 556 | | skipping to change at line 599 | |
| The returned object is only valid until the next modification o
r destruction of the builder. | | 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. | | Intended use case: append a field if not already there. | |
| */ | | */ | |
| BSONObj asTempObj() { | | BSONObj asTempObj() { | |
| BSONObj temp(_done()); | | BSONObj temp(_done()); | |
| _b.setlen(_b.len()-1); //next append should overwrite the EOO | | _b.setlen(_b.len()-1); //next append should overwrite the EOO | |
| _doneCalled = false; | | _doneCalled = false; | |
| return temp; | | return temp; | |
| } | | } | |
| | | | |
|
| /* assume ownership of the buffer - you must then free it (with fre | | | |
| e()) */ | | | |
| char* decouple(int& l) { | | | |
| char *x = _done(); | | | |
| verify( x ); | | | |
| l = _b.len(); | | | |
| _b.decouple(); | | | |
| return x; | | | |
| } | | | |
| void decouple() { | | void decouple() { | |
| _b.decouple(); // post done() call version. be sure jsobj f
rees... | | _b.decouple(); // post done() call version. be sure jsobj f
rees... | |
| } | | } | |
| | | | |
| void appendKeys( const BSONObj& keyPattern , const BSONObj& values
); | | void appendKeys( const BSONObj& keyPattern , const BSONObj& values
); | |
| | | | |
| static std::string numStr( int i ) { | | static std::string numStr( int i ) { | |
| if (i>=0 && i<100 && numStrsReady) | | if (i>=0 && i<100 && numStrsReady) | |
| return numStrs[i]; | | return numStrs[i]; | |
| StringBuilder o; | | StringBuilder o; | |
| o << i; | | o << i; | |
| return o.str(); | | return o.str(); | |
| } | | } | |
| | | | |
| /** Stream oriented way to add field names and values. */ | | /** Stream oriented way to add field names and values. */ | |
|
| BSONObjBuilderValueStream &operator<<(const char * name ) { | | BSONObjBuilderValueStream &operator<<( const StringData& name ) { | |
| _s.endField( name ); | | _s.endField( name ); | |
| return _s; | | return _s; | |
| } | | } | |
| | | | |
| /** Stream oriented way to add field names and values. */ | | /** Stream oriented way to add field names and values. */ | |
| BSONObjBuilder& operator<<( GENOIDLabeler ) { return genOID(); } | | BSONObjBuilder& operator<<( GENOIDLabeler ) { return genOID(); } | |
| | | | |
|
| // prevent implicit string conversions which would allow bad things | | | |
| like BSON( BSON( "foo" << 1 ) << 2 ) | | | |
| struct ForceExplicitString { | | | |
| ForceExplicitString( const std::string &str ) : str_( str ) {} | | | |
| std::string str_; | | | |
| }; | | | |
| | | | |
| /** Stream oriented way to add field names and values. */ | | | |
| BSONObjBuilderValueStream &operator<<( const ForceExplicitString& n | | | |
| ame ) { | | | |
| return operator<<( name.str_.c_str() ); | | | |
| } | | | |
| | | | |
| Labeler operator<<( const Labeler::Label &l ) { | | Labeler operator<<( const Labeler::Label &l ) { | |
| massert( 10336 , "No subobject started", _s.subobjStarted() ); | | massert( 10336 , "No subobject started", _s.subobjStarted() ); | |
| return _s << l; | | return _s << l; | |
| } | | } | |
| | | | |
| template<typename T> | | template<typename T> | |
| BSONObjBuilderValueStream& operator<<( const BSONField<T>& f ) { | | BSONObjBuilderValueStream& operator<<( const BSONField<T>& f ) { | |
|
| _s.endField( f.name().c_str() ); | | _s.endField( f.name() ); | |
| return _s; | | return _s; | |
| } | | } | |
| | | | |
| template<typename T> | | template<typename T> | |
| BSONObjBuilder& operator<<( const BSONFieldValue<T>& v ) { | | BSONObjBuilder& operator<<( const BSONFieldValue<T>& v ) { | |
|
| append( v.name().c_str() , v.value() ); | | append( v.name(), v.value() ); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
| BSONObjBuilder& operator<<( const BSONElement& e ){ | | BSONObjBuilder& operator<<( const BSONElement& e ){ | |
| append( e ); | | append( e ); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
| bool isArray() const { | | bool isArray() const { | |
| return false; | | return false; | |
| | | | |
| skipping to change at line 685 | | skipping to change at line 709 | |
| _b.appendAs(e, num()); | | _b.appendAs(e, num()); | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
| BSONArrayBuilder& operator<<(const BSONElement& e) { | | BSONArrayBuilder& operator<<(const BSONElement& e) { | |
| return append(e); | | return append(e); | |
| } | | } | |
| | | | |
| template <typename T> | | template <typename T> | |
| BSONArrayBuilder& operator<<(const T& x) { | | BSONArrayBuilder& operator<<(const T& x) { | |
|
| return append(x); | | _b << num().c_str() << x; | |
| | | return *this; | |
| } | | } | |
| | | | |
| void appendNull() { | | void appendNull() { | |
| _b.appendNull(num()); | | _b.appendNull(num()); | |
| } | | } | |
| | | | |
| void appendUndefined() { | | void appendUndefined() { | |
| _b.appendUndefined(num()); | | _b.appendUndefined(num()); | |
| } | | } | |
| | | | |
| | | | |
| skipping to change at line 800 | | skipping to change at line 825 | |
| int len() const { return _b.len(); } | | int len() const { return _b.len(); } | |
| int arrSize() const { return _i; } | | int arrSize() const { return _i; } | |
| | | | |
| private: | | private: | |
| // These two are undefined privates to prevent their accidental | | // These two are undefined privates to prevent their accidental | |
| // use as we don't support unsigned ints in BSON | | // use as we don't support unsigned ints in BSON | |
| BSONObjBuilder& append(const StringData& fieldName, unsigned int va
l); | | BSONObjBuilder& append(const StringData& fieldName, unsigned int va
l); | |
| BSONObjBuilder& append(const StringData& fieldName, unsigned long l
ong val); | | BSONObjBuilder& append(const StringData& fieldName, unsigned long l
ong val); | |
| | | | |
| void fill( const StringData& name ) { | | void fill( const StringData& name ) { | |
|
| char *r; | | long int n; | |
| long int n = strtol( name.data(), &r, 10 ); | | Status status = parseNumberFromStringWithBase( name, 10, &n ); | |
| if ( *r ) | | uassert( 13048, | |
| uasserted( 13048, (std::string)"can't append to array using | | (string)"can't append to array using string field name | |
| string field name [" + name.data() + "]" ); | | : " + name.toString(), | |
| | | status.isOK() ); | |
| fill(n); | | fill(n); | |
| } | | } | |
| | | | |
| void fill (int upTo){ | | void fill (int upTo){ | |
| // if this is changed make sure to update error message and jst
ests/set7.js | | // if this is changed make sure to update error message and jst
ests/set7.js | |
| const int maxElems = 1500000; | | const int maxElems = 1500000; | |
| BOOST_STATIC_ASSERT(maxElems < (BSONObjMaxUserSize/10)); | | BOOST_STATIC_ASSERT(maxElems < (BSONObjMaxUserSize/10)); | |
| uassert(15891, "can't backfill array to larger than 1,500,000 e
lements", upTo <= maxElems); | | uassert(15891, "can't backfill array to larger than 1,500,000 e
lements", upTo <= maxElems); | |
| | | | |
| while( _i < upTo ) | | while( _i < upTo ) | |
| | | | |
| skipping to change at line 851 | | skipping to change at line 877 | |
| template < class T > | | template < class T > | |
| inline BSONObjBuilder& BSONObjBuilder::append( const StringData& fieldN
ame, const std::list< T >& vals ) { | | inline BSONObjBuilder& BSONObjBuilder::append( const StringData& fieldN
ame, const std::list< T >& vals ) { | |
| return _appendIt< std::list< T > >( *this, fieldName, vals ); | | return _appendIt< std::list< T > >( *this, fieldName, vals ); | |
| } | | } | |
| | | | |
| template < class T > | | template < class T > | |
| inline BSONObjBuilder& BSONObjBuilder::append( const StringData& fieldN
ame, const std::set< T >& vals ) { | | inline BSONObjBuilder& BSONObjBuilder::append( const StringData& fieldN
ame, const std::set< T >& vals ) { | |
| return _appendIt< std::set< T > >( *this, fieldName, vals ); | | return _appendIt< std::set< T > >( *this, fieldName, vals ); | |
| } | | } | |
| | | | |
|
| | | template < class K, class T > | |
| | | inline BSONObjBuilder& BSONObjBuilder::append( const StringData& fieldN | |
| | | ame, const std::map< K, T >& vals ) { | |
| | | BSONObjBuilder bob; | |
| | | for( typename std::map<K,T>::const_iterator i = vals.begin(); i != | |
| | | vals.end(); ++i ){ | |
| | | bob.append(i->first, i->second); | |
| | | } | |
| | | append(fieldName, bob.obj()); | |
| | | return *this; | |
| | | } | |
| | | | |
| template < class L > | | template < class L > | |
| inline BSONArrayBuilder& _appendArrayIt( BSONArrayBuilder& _this, const
L& vals ) { | | inline BSONArrayBuilder& _appendArrayIt( BSONArrayBuilder& _this, const
L& vals ) { | |
| for( typename L::const_iterator i = vals.begin(); i != vals.end();
i++ ) | | for( typename L::const_iterator i = vals.begin(); i != vals.end();
i++ ) | |
| _this.append( *i ); | | _this.append( *i ); | |
| return _this; | | return _this; | |
| } | | } | |
| | | | |
| template < class T > | | template < class T > | |
| inline BSONArrayBuilder& BSONArrayBuilder::append( const std::list< T >
& vals ) { | | inline BSONArrayBuilder& BSONArrayBuilder::append( const std::list< T >
& vals ) { | |
| return _appendArrayIt< std::list< T > >( *this, vals ); | | return _appendArrayIt< std::list< T > >( *this, vals ); | |
| | | | |
End of changes. 19 change blocks. |
| 34 lines changed or deleted | | 77 lines changed or added | |
|
| chunk.h | | chunk.h | |
| | | | |
| skipping to change at line 21 | | skipping to change at line 21 | |
| * 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 "mongo/pch.h" | | | |
| | | | |
| #include "mongo/bson/util/atomic_int.h" | | #include "mongo/bson/util/atomic_int.h" | |
| #include "mongo/client/distlock.h" | | #include "mongo/client/distlock.h" | |
|
| #include "mongo/s/cluster_constants.h" | | #include "mongo/s/chunk_version.h" | |
| #include "mongo/s/shard.h" | | #include "mongo/s/shard.h" | |
| #include "mongo/s/shardkey.h" | | #include "mongo/s/shardkey.h" | |
|
| #include "mongo/s/util.h" | | | |
| #include "mongo/util/concurrency/ticketholder.h" | | #include "mongo/util/concurrency/ticketholder.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| class DBConfig; | | class DBConfig; | |
| class Chunk; | | class Chunk; | |
| class ChunkRange; | | class ChunkRange; | |
| class ChunkManager; | | class ChunkManager; | |
| class ChunkObjUnitTest; | | class ChunkObjUnitTest; | |
| | | | |
| | | | |
| skipping to change at line 61 | | skipping to change at line 58 | |
| x is in a shard iff | | x is in a shard iff | |
| min <= x < max | | min <= x < max | |
| */ | | */ | |
| class Chunk : boost::noncopyable { | | class Chunk : boost::noncopyable { | |
| public: | | public: | |
| Chunk( const ChunkManager * info , BSONObj from); | | Chunk( const ChunkManager * info , BSONObj from); | |
| Chunk( const ChunkManager * info , | | Chunk( const ChunkManager * info , | |
| const BSONObj& min, | | const BSONObj& min, | |
| const BSONObj& max, | | const BSONObj& max, | |
| const Shard& shard, | | const Shard& shard, | |
|
| ShardChunkVersion lastmod = ShardChunkVersion() ); | | ChunkVersion lastmod = ChunkVersion() ); | |
| | | | |
| // | | // | |
| // serialization support | | // serialization support | |
| // | | // | |
| | | | |
|
| void serialize(BSONObjBuilder& to, ShardChunkVersion myLastMod=Shar
dChunkVersion(0,OID())); | | void serialize(BSONObjBuilder& to, ChunkVersion myLastMod=ChunkVers
ion(0,OID())); | |
| | | | |
| // | | // | |
| // chunk boundary support | | // chunk boundary support | |
| // | | // | |
| | | | |
| const BSONObj& getMin() const { return _min; } | | const BSONObj& getMin() const { return _min; } | |
| const BSONObj& getMax() const { return _max; } | | const BSONObj& getMax() const { return _max; } | |
| | | | |
| // if min/max key is pos/neg infinity | | // if min/max key is pos/neg infinity | |
| bool minIsInf() const; | | bool minIsInf() const; | |
| | | | |
| skipping to change at line 96 | | skipping to change at line 93 | |
| | | | |
| string genID() const; | | string genID() const; | |
| static string genID( const string& ns , const BSONObj& min ); | | static string genID( const string& ns , const BSONObj& min ); | |
| | | | |
| // | | // | |
| // chunk version support | | // chunk version support | |
| // | | // | |
| | | | |
| void appendShortVersion( const char * name , BSONObjBuilder& b ) co
nst; | | void appendShortVersion( const char * name , BSONObjBuilder& b ) co
nst; | |
| | | | |
|
| ShardChunkVersion getLastmod() const { return _lastmod; } | | ChunkVersion getLastmod() const { return _lastmod; } | |
| void setLastmod( ShardChunkVersion v ) { _lastmod = v; } | | void setLastmod( ChunkVersion v ) { _lastmod = v; } | |
| | | | |
| // | | // | |
| // split support | | // split support | |
| // | | // | |
| | | | |
| /** | | /** | |
| * 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 | |
| * @return if something was split | | * @return if something was split | |
| */ | | */ | |
| | | | |
| skipping to change at line 154 | | skipping to change at line 151 | |
| // | | // | |
| // migration support | | // migration support | |
| // | | // | |
| | | | |
| /** | | /** | |
| * Issues a migrate request for this chunk | | * Issues a migrate request for this chunk | |
| * | | * | |
| * @param to shard to move this chunk to | | * @param to shard to move this chunk to | |
| * @param chunSize maximum number of bytes beyond which the migrate
should no go trhough | | * @param chunSize maximum number of bytes beyond which the migrate
should no go trhough | |
| * @param secondaryThrottle whether during migrate all writes shoul
d block for repl | | * @param secondaryThrottle whether during migrate all writes shoul
d block for repl | |
|
| | | * @param waitForDelete whether chunk move should wait for cleanup
or return immediately | |
| * @param res the object containing details about the migrate execu
tion | | * @param res the object containing details about the migrate execu
tion | |
| * @return true if move was successful | | * @return true if move was successful | |
| */ | | */ | |
|
| bool moveAndCommit( const Shard& to , long long chunkSize , bool se | | bool moveAndCommit(const Shard& to, | |
| condaryThrottle, BSONObj& res ) const; | | long long chunkSize, | |
| | | bool secondaryThrottle, | |
| | | bool waitForDelete, | |
| | | BSONObj& res) const; | |
| | | | |
| /** | | /** | |
| * @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() const; | | long getPhysicalSize() const; | |
| | | | |
| /** | | /** | |
| * marks this chunk as a jumbo chunk | | * marks this chunk as a jumbo chunk | |
| * that means the chunk will be inelligble for migrates | | * that means the chunk will be inelligble for migrates | |
| | | | |
| skipping to change at line 211 | | skipping to change at line 213 | |
| | | | |
| private: | | private: | |
| | | | |
| // main shard info | | // main shard info | |
| | | | |
| const ChunkManager * _manager; | | const ChunkManager * _manager; | |
| | | | |
| BSONObj _min; | | BSONObj _min; | |
| BSONObj _max; | | BSONObj _max; | |
| Shard _shard; | | Shard _shard; | |
|
| ShardChunkVersion _lastmod; | | ChunkVersion _lastmod; | |
| mutable bool _jumbo; | | mutable bool _jumbo; | |
| | | | |
| // transient stuff | | // transient stuff | |
| | | | |
| mutable long _dataWritten; | | mutable long _dataWritten; | |
| | | | |
| // methods, etc.. | | // methods, etc.. | |
| | | | |
| /** Returns the highest or lowest existing value in the shard-key s
pace. | | /** Returns the highest or lowest existing value in the shard-key s
pace. | |
| * Warning: this assumes that the shard key is not "special"- that
is, the shardKeyPattern | | * Warning: this assumes that the shard key is not "special"- that
is, the shardKeyPattern | |
| | | | |
| skipping to change at line 318 | | skipping to change at line 320 | |
| }; | | }; | |
| | | | |
| /* config.sharding | | /* config.sharding | |
| { ns: 'alleyinsider.fs.chunks' , | | { ns: 'alleyinsider.fs.chunks' , | |
| key: { ts : 1 } , | | key: { ts : 1 } , | |
| shards: [ { min: 1, max: 100, server: a } , { min: 101, max: 200
, server : b } ] | | shards: [ { min: 1, max: 100, server: a } , { min: 101, max: 200
, server : b } ] | |
| } | | } | |
| */ | | */ | |
| class ChunkManager { | | class ChunkManager { | |
| public: | | public: | |
|
| typedef map<Shard,ShardChunkVersion> ShardVersionMap; | | typedef map<Shard,ChunkVersion> ShardVersionMap; | |
| | | | |
| // Loads a new chunk manager from a collection document | | // Loads a new chunk manager from a collection document | |
| ChunkManager( const BSONObj& collDoc ); | | ChunkManager( const BSONObj& collDoc ); | |
| | | | |
| // Creates an empty chunk manager for the namespace | | // Creates an empty chunk manager for the namespace | |
| ChunkManager( const string& ns, const ShardKeyPattern& pattern, boo
l unique ); | | ChunkManager( const string& ns, const ShardKeyPattern& pattern, boo
l unique ); | |
| | | | |
| // Updates a chunk manager based on an older manager | | // Updates a chunk manager based on an older manager | |
| ChunkManager( ChunkManagerPtr oldManager ); | | ChunkManager( ChunkManagerPtr oldManager ); | |
| | | | |
| | | | |
| skipping to change at line 392 | | skipping to change at line 394 | |
| * findChunkForDoc() on {a : "foo" , b : "bar"}, or | | * findChunkForDoc() on {a : "foo" , b : "bar"}, or | |
| * findIntersectingChunk() on {a : hash("foo") } | | * findIntersectingChunk() on {a : hash("foo") } | |
| */ | | */ | |
| ChunkPtr findIntersectingChunk( const BSONObj& point ) const; | | ChunkPtr findIntersectingChunk( const BSONObj& point ) const; | |
| | | | |
| ChunkPtr findChunkOnServer( const Shard& shard ) const; | | ChunkPtr findChunkOnServer( const Shard& shard ) const; | |
| | | | |
| void getShardsForQuery( set<Shard>& shards , const BSONObj& query )
const; | | void getShardsForQuery( set<Shard>& shards , const BSONObj& query )
const; | |
| void getAllShards( set<Shard>& all ) const; | | void getAllShards( set<Shard>& all ) const; | |
| /** @param shards set to the shards covered by the interval [min, m
ax], see SERVER-4791 */ | | /** @param shards set to the shards covered by the interval [min, m
ax], see SERVER-4791 */ | |
|
| void getShardsForRange(set<Shard>& shards, const BSONObj& min, cons
t BSONObj& max, bool fullKeyReq = true) const; | | void getShardsForRange( set<Shard>& shards, const BSONObj& min, con
st BSONObj& max ) const; | |
| | | | |
| ChunkMap getChunkMap() const { return _chunkMap; } | | ChunkMap getChunkMap() const { return _chunkMap; } | |
| | | | |
| /** | | /** | |
| * Returns true if, for this shard, the chunks are identical in bot
h chunk managers | | * Returns true if, for this shard, the chunks are identical in bot
h chunk managers | |
| */ | | */ | |
| bool compatibleWith( const ChunkManager& other, const Shard& shard
) const; | | bool compatibleWith( const ChunkManager& other, const Shard& shard
) const; | |
| bool compatibleWith( ChunkManagerPtr other, const Shard& shard ) co
nst { if( ! other ) return false; return compatibleWith( *other, shard ); } | | bool compatibleWith( ChunkManagerPtr other, const Shard& shard ) co
nst { if( ! other ) return false; return compatibleWith( *other, shard ); } | |
| | | | |
| bool compatibleWith( const Chunk& other ) const; | | bool compatibleWith( const Chunk& other ) const; | |
| bool compatibleWith( ChunkPtr other ) const { if( ! other ) return
false; return compatibleWith( *other ); } | | bool compatibleWith( ChunkPtr other ) const { if( ! other ) return
false; return compatibleWith( *other ); } | |
| | | | |
| string toString() const; | | string toString() const; | |
| | | | |
|
| ShardChunkVersion getVersion( const Shard& shard ) const; | | ChunkVersion getVersion( const Shard& shard ) const; | |
| ShardChunkVersion getVersion() const; | | ChunkVersion getVersion() const; | |
| | | | |
|
| void getInfo( BSONObjBuilder& b ) const { | | void getInfo( BSONObjBuilder& b ) const; | |
| b.append(CollectionFields::key(), _key.key()); | | | |
| b.appendBool(CollectionFields::unique(), _unique); | | | |
| _version.addEpochToBSON(b, CollectionFields::lastmod()); | | | |
| } | | | |
| | | | |
| /** | | /** | |
| * @param me - so i don't get deleted before i'm done | | * @param me - so i don't get deleted before i'm done | |
| */ | | */ | |
| void drop( ChunkManagerPtr me ) const; | | void drop( ChunkManagerPtr me ) const; | |
| | | | |
| void _printChunks() const; | | void _printChunks() const; | |
| | | | |
| int getCurrentDesiredChunkSize() const; | | int getCurrentDesiredChunkSize() const; | |
| | | | |
| ChunkManagerPtr reload(bool force=true) const; // doesn't modify se
lf! | | ChunkManagerPtr reload(bool force=true) const; // doesn't modify se
lf! | |
| | | | |
|
| void markMinorForReload( ShardChunkVersion majorVersion ) const; | | void markMinorForReload( ChunkVersion majorVersion ) const; | |
| void getMarkedMinorVersions( set<ShardChunkVersion>& minorVersions | | void getMarkedMinorVersions( set<ChunkVersion>& minorVersions ) con | |
| ) const; | | st; | |
| | | | |
| private: | | private: | |
| | | | |
| // helpers for loading | | // helpers for loading | |
| | | | |
| // returns true if load was consistent | | // returns true if load was consistent | |
| bool _load( const string& config, ChunkMap& chunks, set<Shard>& sha
rds, | | bool _load( const string& config, ChunkMap& chunks, set<Shard>& sha
rds, | |
| ShardVersionMap& shardVersions, ChunkMa
nagerPtr oldManager); | | ShardVersionMap& shardVersions, ChunkMa
nagerPtr oldManager); | |
| static bool _isValid(const ChunkMap& chunks); | | static bool _isValid(const ChunkMap& chunks); | |
| | | | |
| | | | |
| skipping to change at line 454 | | skipping to change at line 452 | |
| const bool _unique; | | const bool _unique; | |
| | | | |
| const ChunkMap _chunkMap; | | const ChunkMap _chunkMap; | |
| const ChunkRangeManager _chunkRanges; | | const ChunkRangeManager _chunkRanges; | |
| | | | |
| const set<Shard> _shards; | | const set<Shard> _shards; | |
| | | | |
| const ShardVersionMap _shardVersions; // max version per shard | | const ShardVersionMap _shardVersions; // max version per shard | |
| | | | |
| // max version of any chunk | | // max version of any chunk | |
|
| ShardChunkVersion _version; | | ChunkVersion _version; | |
| | | | |
| // the previous manager this was based on | | // the previous manager this was based on | |
| // cleared after loading chunks | | // cleared after loading chunks | |
| ChunkManagerPtr _oldManager; | | ChunkManagerPtr _oldManager; | |
| | | | |
| mutable mutex _mutex; // only used with _nsLock | | mutable mutex _mutex; // only used with _nsLock | |
| | | | |
| const unsigned long long _sequenceNumber; | | const unsigned long long _sequenceNumber; | |
| | | | |
| // | | // | |
| | | | |
| skipping to change at line 476 | | skipping to change at line 474 | |
| // | | // | |
| | | | |
| class SplitHeuristics { | | class SplitHeuristics { | |
| public: | | public: | |
| | | | |
| SplitHeuristics() : | | SplitHeuristics() : | |
| _splitTickets( maxParallelSplits ), | | _splitTickets( maxParallelSplits ), | |
| _staleMinorSetMutex( "SplitHeuristics::staleMinorSet" ), | | _staleMinorSetMutex( "SplitHeuristics::staleMinorSet" ), | |
| _staleMinorCount( 0 ) {} | | _staleMinorCount( 0 ) {} | |
| | | | |
|
| void markMinorForReload( const string& ns, ShardChunkVersion ma | | void markMinorForReload( const string& ns, ChunkVersion majorVe | |
| jorVersion ); | | rsion ); | |
| void getMarkedMinorVersions( set<ShardChunkVersion>& minorVersi | | void getMarkedMinorVersions( set<ChunkVersion>& minorVersions ) | |
| ons ); | | ; | |
| | | | |
| TicketHolder _splitTickets; | | TicketHolder _splitTickets; | |
| | | | |
| mutex _staleMinorSetMutex; | | mutex _staleMinorSetMutex; | |
| | | | |
| // mutex protects below | | // mutex protects below | |
| int _staleMinorCount; | | int _staleMinorCount; | |
|
| set<ShardChunkVersion> _staleMinorSet; | | set<ChunkVersion> _staleMinorSet; | |
| | | | |
| // Test whether we should split once data * splitTestFactor > c
hunkSize (approximately) | | // Test whether we should split once data * splitTestFactor > c
hunkSize (approximately) | |
| static const int splitTestFactor = 5; | | static const int splitTestFactor = 5; | |
| // Maximum number of parallel threads requesting a split | | // Maximum number of parallel threads requesting a split | |
| static const int maxParallelSplits = 5; | | static const int maxParallelSplits = 5; | |
| | | | |
| // The idea here is that we're over-aggressive on split testing
by a factor of | | // The idea here is that we're over-aggressive on split testing
by a factor of | |
| // splitTestFactor, so we can safely wait until we get to split
TestFactor invalid splits | | // splitTestFactor, so we can safely wait until we get to split
TestFactor invalid splits | |
| // before changing. Unfortunately, we also potentially over-re
quest the splits by a | | // before changing. Unfortunately, we also potentially over-re
quest the splits by a | |
| // factor of maxParallelSplits, but since the factors are ident
ical it works out | | // factor of maxParallelSplits, but since the factors are ident
ical it works out | |
| | | | |
| skipping to change at line 553 | | skipping to change at line 551 | |
| | | | |
| } | | } | |
| | | | |
| Chunk _c; | | Chunk _c; | |
| }; | | }; | |
| */ | | */ | |
| inline string Chunk::genID() const { return genID(_manager->getns(), _m
in); } | | inline string Chunk::genID() const { return genID(_manager->getns(), _m
in); } | |
| | | | |
| bool setShardVersion( DBClientBase & conn, | | bool setShardVersion( DBClientBase & conn, | |
| const string& ns, | | const string& ns, | |
|
| ShardChunkVersion version, | | ChunkVersion version, | |
| ChunkManagerPtr manager, | | ChunkManagerPtr manager, | |
| bool authoritative, | | bool authoritative, | |
| BSONObj& result ); | | BSONObj& result ); | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 18 change blocks. |
| 30 lines changed or deleted | | 27 lines changed or added | |
|
| chunk_diff.h | | chunk_diff.h | |
|
| // @file chunk.h | | // @file chunk_diff.h | |
| | | | |
| /** | | /** | |
| * Copyright (C) 2008 10gen Inc. | | * Copyright (C) 2008 10gen Inc. | |
| * | | * | |
| * This program is free software: you can redistribute it and/or modify | | * 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
, | | * it under the terms of the GNU Affero General Public License, version 3
, | |
| * as published by the Free Software Foundation. | | * as published by the Free Software Foundation. | |
| * | | * | |
| * This program is distributed in the hope that it will be useful, | | * This program is distributed in the hope that it will be useful, | |
| * 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 "util.h" | | #include "mongo/bson/bsonobj.h" | |
| #include "../bson/bsonobj.h" | | #include "mongo/client/dbclientcursor.h" | |
| #include "../client/dbclientcursor.h" | | #include "mongo/client/connpool.h" | |
| #include "../client/connpool.h" | | #include "mongo/s/chunk.h" | |
| | | #include "mongo/s/chunk_version.h" | |
| // TODO: Ideally wouldn't need this, but ShardNS data isn't extracted from | | | |
| config.h | | | |
| #include "config.h" | | | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| /** | | /** | |
| * This class manages and applies diffs from partial config server data
reloads. Because the | | * This class manages and applies diffs from partial config server data
reloads. Because the | |
| * config data can be large, we want to update it in small parts, not a
ll-at-once. Once a | | * config data can be large, we want to update it in small parts, not a
ll-at-once. Once a | |
| * ConfigDiffTracker is created, the current config data is *attached*
to it, and it is then | | * ConfigDiffTracker is created, the current config data is *attached*
to it, and it is then | |
| * able to modify the data. | | * able to modify the data. | |
| * | | * | |
| * The current form is templated b/c the overall algorithm is identical
between mongos and | | * The current form is templated b/c the overall algorithm is identical
between mongos and | |
| | | | |
| skipping to change at line 70 | | skipping to change at line 68 | |
| /** | | /** | |
| * The tracker attaches to a set of ranges with versions, and uses
a config server | | * The tracker attaches to a set of ranges with versions, and uses
a config server | |
| * connection to update these. Because the set of ranges and versio
ns may be large, they | | * connection to update these. Because the set of ranges and versio
ns may be large, they | |
| * aren't owned by the tracker, they're just passed in and updated.
Therefore they must all | | * aren't owned by the tracker, they're just passed in and updated.
Therefore they must all | |
| * stay in scope while the tracker is working. | | * stay in scope while the tracker is working. | |
| * | | * | |
| * TODO: Make a standard VersionedRange to encapsulate this info in
both mongod and mongos? | | * TODO: Make a standard VersionedRange to encapsulate this info in
both mongod and mongos? | |
| */ | | */ | |
| void attach( const string& ns, | | void attach( const string& ns, | |
| RangeMap& currMap, | | RangeMap& currMap, | |
|
| ShardChunkVersion& maxVersion, | | ChunkVersion& maxVersion, | |
| map<ShardType, ShardChunkVersion>& maxShardVersions ) | | map<ShardType, ChunkVersion>& maxShardVersions ) | |
| { | | { | |
| _ns = ns; | | _ns = ns; | |
| _currMap = &currMap; | | _currMap = &currMap; | |
| _maxVersion = &maxVersion; | | _maxVersion = &maxVersion; | |
| _maxShardVersions = &maxShardVersions; | | _maxShardVersions = &maxShardVersions; | |
| _validDiffs = 0; | | _validDiffs = 0; | |
| } | | } | |
| | | | |
| void detach(){ | | void detach(){ | |
| _ns = ""; | | _ns = ""; | |
| | | | |
| skipping to change at line 140 | | skipping to change at line 138 | |
| | | | |
| // Returns a subset of ranges overlapping the region min/max | | // Returns a subset of ranges overlapping the region min/max | |
| RangeOverlap overlappingRange( const BSONObj& min, const BSONObj& m
ax ); | | RangeOverlap overlappingRange( const BSONObj& min, const BSONObj& m
ax ); | |
| | | | |
| // Finds and applies the changes to a collection from the config se
rver specified | | // Finds and applies the changes to a collection from the config se
rver specified | |
| // Also includes minor version changes for particular major-version
chunks if explicitly | | // Also includes minor version changes for particular major-version
chunks if explicitly | |
| // specified. | | // specified. | |
| // Returns the number of diffs processed, or -1 if the diffs were i
nconsistent | | // Returns the number of diffs processed, or -1 if the diffs were i
nconsistent | |
| // Throws a DBException on connection errors | | // Throws a DBException on connection errors | |
| int calculateConfigDiff( string config, | | int calculateConfigDiff( string config, | |
|
| const set<ShardChunkVersion>& extraMinorVe
rsions = set<ShardChunkVersion>() ); | | const set<ChunkVersion>& extraMinorVersion
s = set<ChunkVersion>() ); | |
| | | | |
| // Applies changes to the config data from a cursor passed in | | // Applies changes to the config data from a cursor passed in | |
| // Returns the number of diffs processed, or -1 if the diffs were i
nconsistent | | // Returns the number of diffs processed, or -1 if the diffs were i
nconsistent | |
| // Throws a DBException on connection errors | | // Throws a DBException on connection errors | |
| int calculateConfigDiff( DBClientCursorInterface& diffCursor ); | | int calculateConfigDiff( DBClientCursorInterface& diffCursor ); | |
| | | | |
| // Returns the query needed to find new changes to a collection fro
m the config server | | // Returns the query needed to find new changes to a collection fro
m the config server | |
| // Needed only if a custom connection is required to the config ser
ver | | // Needed only if a custom connection is required to the config ser
ver | |
|
| Query configDiffQuery( const set<ShardChunkVersion>& extraMinorVers
ions = set<ShardChunkVersion>() ) const; | | Query configDiffQuery( const set<ChunkVersion>& extraMinorVersions
= set<ChunkVersion>() ) const; | |
| | | | |
| private: | | private: | |
| | | | |
| string _ns; | | string _ns; | |
| RangeMap* _currMap; | | RangeMap* _currMap; | |
|
| ShardChunkVersion* _maxVersion; | | ChunkVersion* _maxVersion; | |
| map<ShardType, ShardChunkVersion>* _maxShardVersions; | | map<ShardType, ChunkVersion>* _maxShardVersions; | |
| | | | |
| // Store for later use | | // Store for later use | |
| int _validDiffs; | | int _validDiffs; | |
| | | | |
| }; | | }; | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
| // Include template definition | | // Include template definition | |
| // TODO: Convert to normal .cpp file when normalized | | // TODO: Convert to normal .cpp file when normalized | |
| | | | |
End of changes. 6 change blocks. |
| 15 lines changed or deleted | | 12 lines changed or added | |
|
| chunk_diff.hpp | | chunk_diff.hpp | |
| | | | |
| skipping to change at line 22 | | skipping to change at line 22 | |
| * 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 "mongo/s/chunk_diff.h" | | #include "mongo/s/chunk_diff.h" | |
|
| #include "mongo/s/cluster_constants.h" | | #include "mongo/s/chunk_version.h" | |
| | | #include "mongo/s/type_chunk.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| template < class ValType, class ShardType > | | template < class ValType, class ShardType > | |
| bool ConfigDiffTracker<ValType,ShardType>:: | | bool ConfigDiffTracker<ValType,ShardType>:: | |
| isOverlapping( const BSONObj& min, const BSONObj& max ) | | isOverlapping( const BSONObj& min, const BSONObj& max ) | |
| { | | { | |
| RangeOverlap overlap = overlappingRange( min, max ); | | RangeOverlap overlap = overlappingRange( min, max ); | |
| | | | |
| return overlap.first != overlap.second; | | return overlap.first != overlap.second; | |
| | | | |
| skipping to change at line 78 | | skipping to change at line 79 | |
| // the next chunk cannot not overlap max | | // the next chunk cannot not overlap max | |
| high = _currMap->upper_bound( max ); | | high = _currMap->upper_bound( max ); | |
| } | | } | |
| | | | |
| return RangeOverlap( low, high ); | | return RangeOverlap( low, high ); | |
| } | | } | |
| | | | |
| template < class ValType, class ShardType > | | template < class ValType, class ShardType > | |
| int ConfigDiffTracker<ValType,ShardType>:: | | int ConfigDiffTracker<ValType,ShardType>:: | |
| calculateConfigDiff( string config, | | calculateConfigDiff( string config, | |
|
| const set<ShardChunkVersion>& extraMinorVersio
ns ) | | const set<ChunkVersion>& extraMinorVersions ) | |
| { | | { | |
| verifyAttached(); | | verifyAttached(); | |
| | | | |
| // Get the diff query required | | // Get the diff query required | |
| Query diffQuery = configDiffQuery( extraMinorVersions ); | | Query diffQuery = configDiffQuery( extraMinorVersions ); | |
| | | | |
| scoped_ptr<ScopedDbConnection> conn( | | scoped_ptr<ScopedDbConnection> conn( | |
| ScopedDbConnection::getInternalScopedDbConnection( config )
); | | ScopedDbConnection::getInternalScopedDbConnection( config )
); | |
| | | | |
| try { | | try { | |
| | | | |
| // Open a cursor for the diff chunks | | // Open a cursor for the diff chunks | |
| auto_ptr<DBClientCursor> cursor = conn->get()->query( | | auto_ptr<DBClientCursor> cursor = conn->get()->query( | |
|
| ConfigNS::chunk, diffQuery, 0, 0, 0, 0, ( DEBUG_BUILD ?
2 : 1000000 ) ); | | ChunkType::ConfigNS, diffQuery, 0, 0, 0, 0, ( DEBUG_BUI
LD ? 2 : 1000000 ) ); | |
| verify( cursor.get() ); | | verify( cursor.get() ); | |
| | | | |
| int diff = calculateConfigDiff( *cursor.get() ); | | int diff = calculateConfigDiff( *cursor.get() ); | |
| | | | |
| conn->done(); | | conn->done(); | |
| | | | |
| return diff; | | return diff; | |
| } | | } | |
| catch( DBException& e ){ | | catch( DBException& e ){ | |
| // Should only happen on connection errors | | // Should only happen on connection errors | |
| | | | |
| skipping to change at line 133 | | skipping to change at line 134 | |
| | | | |
| vector<BSONObj> newTracked; | | vector<BSONObj> newTracked; | |
| // Store epoch now so it doesn't change when we change max | | // Store epoch now so it doesn't change when we change max | |
| OID currEpoch = _maxVersion->epoch(); | | OID currEpoch = _maxVersion->epoch(); | |
| | | | |
| _validDiffs = 0; | | _validDiffs = 0; | |
| while( diffCursor.more() ){ | | while( diffCursor.more() ){ | |
| | | | |
| BSONObj diffChunkDoc = diffCursor.next(); | | BSONObj diffChunkDoc = diffCursor.next(); | |
| | | | |
|
| ShardChunkVersion chunkVersion = ShardChunkVersion::fromBSON(di
ffChunkDoc, ChunkFields::lastmod()); | | ChunkVersion chunkVersion = ChunkVersion::fromBSON(diffChunkDoc
, ChunkType::DEPRECATED_lastmod()); | |
| | | | |
|
| if( diffChunkDoc[ChunkFields::min()].type() != Object || | | if( diffChunkDoc[ChunkType::min()].type() != Object || | |
| diffChunkDoc[ChunkFields::max()].type() != Object || | | diffChunkDoc[ChunkType::max()].type() != Object || | |
| diffChunkDoc[ChunkFields::shard()].type() != String ) | | diffChunkDoc[ChunkType::shard()].type() != String ) | |
| { | | { | |
| warning() << "got invalid chunk document " << diffChunkDoc | | warning() << "got invalid chunk document " << diffChunkDoc | |
| << " when trying to load differing chunks" << end
l; | | << " when trying to load differing chunks" << end
l; | |
| continue; | | continue; | |
| } | | } | |
| | | | |
| if( ! chunkVersion.isSet() || ! chunkVersion.hasCompatibleEpoch
( currEpoch ) ){ | | if( ! chunkVersion.isSet() || ! chunkVersion.hasCompatibleEpoch
( currEpoch ) ){ | |
| | | | |
| warning() << "got invalid chunk version " << chunkVersion <
< " in document " << diffChunkDoc | | warning() << "got invalid chunk version " << chunkVersion <
< " in document " << diffChunkDoc | |
| << " when trying to load differing chunks at vers
ion " | | << " when trying to load differing chunks at vers
ion " | |
|
| << ShardChunkVersion( _maxVersion->toLong(), curr
Epoch ) << endl; | | << ChunkVersion( _maxVersion->toLong(), currEpoch
) << endl; | |
| | | | |
| // Don't keep loading, since we know we'll be broken here | | // Don't keep loading, since we know we'll be broken here | |
| return -1; | | return -1; | |
| } | | } | |
| | | | |
| _validDiffs++; | | _validDiffs++; | |
| | | | |
| // Get max changed version and chunk version | | // Get max changed version and chunk version | |
| if( chunkVersion > *_maxVersion ) *_maxVersion = chunkVersion; | | if( chunkVersion > *_maxVersion ) *_maxVersion = chunkVersion; | |
| | | | |
| // Chunk version changes | | // Chunk version changes | |
|
| ShardType shard = shardFor( diffChunkDoc[ChunkFields::shard()]. | | ShardType shard = shardFor( diffChunkDoc[ChunkType::shard()].St | |
| String() ); | | ring() ); | |
| typename map<ShardType, ShardChunkVersion>::iterator shardVersi | | typename map<ShardType, ChunkVersion>::iterator shardVersionIt | |
| onIt = _maxShardVersions->find( shard ); | | = _maxShardVersions->find( shard ); | |
| if( shardVersionIt == _maxShardVersions->end() || shardVersionI
t->second < chunkVersion ){ | | if( shardVersionIt == _maxShardVersions->end() || shardVersionI
t->second < chunkVersion ){ | |
| (*_maxShardVersions)[ shard ] = chunkVersion; | | (*_maxShardVersions)[ shard ] = chunkVersion; | |
| } | | } | |
| | | | |
| // See if we need to remove any chunks we are currently trackin
g b/c of this chunk's changes | | // See if we need to remove any chunks we are currently trackin
g b/c of this chunk's changes | |
|
| removeOverlapping(diffChunkDoc[ChunkFields::min()].Obj(), | | removeOverlapping(diffChunkDoc[ChunkType::min()].Obj(), | |
| diffChunkDoc[ChunkFields::max()].Obj()); | | diffChunkDoc[ChunkType::max()].Obj()); | |
| | | | |
| // Figure out which of the new chunks we need to track | | // Figure out which of the new chunks we need to track | |
| // Important - we need to actually own this doc, in case the cu
rsor decides to getMore or unbuffer | | // Important - we need to actually own this doc, in case the cu
rsor decides to getMore or unbuffer | |
| if( isTracked( diffChunkDoc ) ) newTracked.push_back( diffChunk
Doc.getOwned() ); | | if( isTracked( diffChunkDoc ) ) newTracked.push_back( diffChunk
Doc.getOwned() ); | |
| } | | } | |
| | | | |
| LOG(3) << "found " << _validDiffs << " new chunks for collection "
<< _ns | | LOG(3) << "found " << _validDiffs << " new chunks for collection "
<< _ns | |
| << " (tracking " << newTracked.size() << "), new version is
" << _maxVersion << endl; | | << " (tracking " << newTracked.size() << "), new version is
" << _maxVersion << endl; | |
| | | | |
| for( vector<BSONObj>::iterator it = newTracked.begin(); it != newTr
acked.end(); it++ ){ | | for( vector<BSONObj>::iterator it = newTracked.begin(); it != newTr
acked.end(); it++ ){ | |
| | | | |
| BSONObj chunkDoc = *it; | | BSONObj chunkDoc = *it; | |
| | | | |
| // Important - we need to make sure we actually own the min and
max here | | // Important - we need to make sure we actually own the min and
max here | |
|
| BSONObj min = chunkDoc[ChunkFields::min()].Obj().getOwned(); | | BSONObj min = chunkDoc[ChunkType::min()].Obj().getOwned(); | |
| BSONObj max = chunkDoc[ChunkFields::max()].Obj().getOwned(); | | BSONObj max = chunkDoc[ChunkType::max()].Obj().getOwned(); | |
| | | | |
| // Invariant enforced by sharding | | // Invariant enforced by sharding | |
| // It's possible to read inconsistent state b/c of getMore() an
d yielding, so we want | | // It's possible to read inconsistent state b/c of getMore() an
d yielding, so we want | |
| // to detect as early as possible. | | // to detect as early as possible. | |
| // TODO: This checks for overlap, we also should check for hole
s here iff we're tracking | | // TODO: This checks for overlap, we also should check for hole
s here iff we're tracking | |
| // all chunks | | // all chunks | |
| if( isOverlapping( min, max ) ) return -1; | | if( isOverlapping( min, max ) ) return -1; | |
| | | | |
| _currMap->insert( rangeFor( chunkDoc, min, max ) ); | | _currMap->insert( rangeFor( chunkDoc, min, max ) ); | |
| } | | } | |
| | | | |
| return _validDiffs; | | return _validDiffs; | |
| } | | } | |
| | | | |
| template < class ValType, class ShardType > | | template < class ValType, class ShardType > | |
| Query ConfigDiffTracker<ValType,ShardType>:: | | Query ConfigDiffTracker<ValType,ShardType>:: | |
|
| configDiffQuery( const set<ShardChunkVersion>& extraMinorVersions )
const | | configDiffQuery( const set<ChunkVersion>& extraMinorVersions ) cons
t | |
| { | | { | |
| verifyAttached(); | | verifyAttached(); | |
| | | | |
| // | | // | |
| // Basic idea behind the query is to find all the chunks $gt the cu
rrent max version, and | | // Basic idea behind the query is to find all the chunks $gt the cu
rrent max version, and | |
| // then also update chunks that we need minor versions - splits and
(2.0) max chunks on | | // then also update chunks that we need minor versions - splits and
(2.0) max chunks on | |
| // shards | | // shards | |
| // | | // | |
| | | | |
| static const int maxMinorVersionClauses = 50; | | static const int maxMinorVersionClauses = 50; | |
| BSONObjBuilder queryB; | | BSONObjBuilder queryB; | |
| | | | |
| int numStaleMinorClauses = extraMinorVersions.size() + _maxShardVer
sions->size(); | | int numStaleMinorClauses = extraMinorVersions.size() + _maxShardVer
sions->size(); | |
| | | | |
| #ifdef _DEBUG | | #ifdef _DEBUG | |
| // In debug builds, randomly trigger full reloads to exercise both
codepaths | | // In debug builds, randomly trigger full reloads to exercise both
codepaths | |
| if( rand() % 2 ) numStaleMinorClauses = maxMinorVersionClauses; | | if( rand() % 2 ) numStaleMinorClauses = maxMinorVersionClauses; | |
| #endif | | #endif | |
| | | | |
|
| queryB.append(ChunkFields::ns(), _ns); | | queryB.append(ChunkType::ns(), _ns); | |
| | | | |
| // | | // | |
| // If we have only a few minor versions to refresh, we can be more
selective in our query | | // If we have only a few minor versions to refresh, we can be more
selective in our query | |
| // | | // | |
| if( numStaleMinorClauses < maxMinorVersionClauses ){ | | if( numStaleMinorClauses < maxMinorVersionClauses ){ | |
| | | | |
| // | | // | |
| // Get any version changes higher than we know currently | | // Get any version changes higher than we know currently | |
| // | | // | |
| BSONArrayBuilder queryOrB( queryB.subarrayStart( "$or" ) ); | | BSONArrayBuilder queryOrB( queryB.subarrayStart( "$or" ) ); | |
| { | | { | |
| BSONObjBuilder queryNewB( queryOrB.subobjStart() ); | | BSONObjBuilder queryNewB( queryOrB.subobjStart() ); | |
| { | | { | |
|
| BSONObjBuilder ts(queryNewB.subobjStart(ChunkFields::la
stmod())); | | BSONObjBuilder ts(queryNewB.subobjStart(ChunkType::DEPR
ECATED_lastmod())); | |
| // We should *always* pull at least a single chunk back
, this lets us quickly | | // We should *always* pull at least a single chunk back
, this lets us quickly | |
| // detect if our collection was unsharded (and most of
the time if it was | | // detect if our collection was unsharded (and most of
the time if it was | |
| // resharded) in the meantime | | // resharded) in the meantime | |
| ts.appendTimestamp( "$gte", _maxVersion->toLong() ); | | ts.appendTimestamp( "$gte", _maxVersion->toLong() ); | |
| ts.done(); | | ts.done(); | |
| } | | } | |
| | | | |
| queryNewB.done(); | | queryNewB.done(); | |
| } | | } | |
| | | | |
| // Get any shard version changes higher than we know currently | | // Get any shard version changes higher than we know currently | |
| // Needed since there could have been a split of the max versio
n chunk of any shard | | // Needed since there could have been a split of the max versio
n chunk of any shard | |
| // TODO: Ideally, we shouldn't care about these | | // TODO: Ideally, we shouldn't care about these | |
|
| for( typename map<ShardType, ShardChunkVersion>::const_iterator
it = _maxShardVersions->begin(); it != _maxShardVersions->end(); it++ ){ | | for( typename map<ShardType, ChunkVersion>::const_iterator it =
_maxShardVersions->begin(); it != _maxShardVersions->end(); it++ ){ | |
| | | | |
| BSONObjBuilder queryShardB( queryOrB.subobjStart() ); | | BSONObjBuilder queryShardB( queryOrB.subobjStart() ); | |
|
| queryShardB.append(ChunkFields::shard(), nameFrom( it->firs
t ) ); | | queryShardB.append(ChunkType::shard(), nameFrom( it->first
) ); | |
| { | | { | |
|
| BSONObjBuilder ts(queryShardB.subobjStart(ChunkFields::
lastmod())); | | BSONObjBuilder ts(queryShardB.subobjStart(ChunkType::DE
PRECATED_lastmod())); | |
| ts.appendTimestamp( "$gt", it->second.toLong() ); | | ts.appendTimestamp( "$gt", it->second.toLong() ); | |
| ts.done(); | | ts.done(); | |
| } | | } | |
| queryShardB.done(); | | queryShardB.done(); | |
| } | | } | |
| | | | |
| // Get any minor version changes we've marked as interesting | | // Get any minor version changes we've marked as interesting | |
| // TODO: Ideally we shouldn't care about these | | // TODO: Ideally we shouldn't care about these | |
|
| for( set<ShardChunkVersion>::const_iterator it = extraMinorVers
ions.begin(); it != extraMinorVersions.end(); it++ ){ | | for( set<ChunkVersion>::const_iterator it = extraMinorVersions.
begin(); it != extraMinorVersions.end(); it++ ){ | |
| | | | |
| BSONObjBuilder queryShardB( queryOrB.subobjStart() ); | | BSONObjBuilder queryShardB( queryOrB.subobjStart() ); | |
| { | | { | |
|
| BSONObjBuilder ts(queryShardB.subobjStart(ChunkFields::
lastmod())); | | BSONObjBuilder ts(queryShardB.subobjStart(ChunkType::DE
PRECATED_lastmod())); | |
| ts.appendTimestamp( "$gt", it->toLong() ); | | ts.appendTimestamp( "$gt", it->toLong() ); | |
| ts.appendTimestamp( "$lt", | | ts.appendTimestamp( "$lt", | |
|
| ShardChunkVersion( it->majorVersion
() + 1, 0, OID() ).toLong() ); | | ChunkVersion( it->majorVersion() +
1, 0, OID() ).toLong() ); | |
| ts.done(); | | ts.done(); | |
| } | | } | |
| queryShardB.done(); | | queryShardB.done(); | |
| } | | } | |
| | | | |
| queryOrB.done(); | | queryOrB.done(); | |
| } | | } | |
| | | | |
| BSONObj query = queryB.obj(); | | BSONObj query = queryB.obj(); | |
| | | | |
| | | | |
End of changes. 18 change blocks. |
| 25 lines changed or deleted | | 26 lines changed or added | |
|
| client.h | | client.h | |
| | | | |
| skipping to change at line 29 | | skipping to change at line 29 | |
| * 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 "mongo/pch.h" | | #include "mongo/pch.h" | |
| | | | |
|
| #include "mongo/db/client_common.h" | | #include "mongo/db/client_basic.h" | |
| #include "mongo/db/d_concurrency.h" | | #include "mongo/db/d_concurrency.h" | |
| #include "mongo/db/lasterror.h" | | #include "mongo/db/lasterror.h" | |
| #include "mongo/db/lockstate.h" | | #include "mongo/db/lockstate.h" | |
| #include "mongo/db/namespace-inl.h" | | #include "mongo/db/namespace-inl.h" | |
|
| #include "mongo/db/security.h" | | | |
| #include "mongo/db/stats/top.h" | | #include "mongo/db/stats/top.h" | |
| #include "mongo/util/concurrency/rwlock.h" | | #include "mongo/util/concurrency/rwlock.h" | |
| #include "mongo/util/concurrency/threadlocal.h" | | #include "mongo/util/concurrency/threadlocal.h" | |
| #include "mongo/util/paths.h" | | #include "mongo/util/paths.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| extern class ReplSet *theReplSet; | | extern class ReplSet *theReplSet; | |
| class AuthenticationInfo; | | class AuthenticationInfo; | |
| class Database; | | class Database; | |
| | | | |
| skipping to change at line 84 | | skipping to change at line 83 | |
| return; | | return; | |
| initThread(desc); | | initThread(desc); | |
| } | | } | |
| | | | |
| /** this has to be called as the client goes away, but before threa
d termination | | /** this has to be called as the client goes away, but before threa
d termination | |
| * @return true if anything was done | | * @return true if anything was done | |
| */ | | */ | |
| bool shutdown(); | | bool shutdown(); | |
| | | | |
| string clientAddress(bool includePort=false) const; | | string clientAddress(bool includePort=false) const; | |
|
| const AuthenticationInfo * getAuthenticationInfo() const { return & | | | |
| _ai; } | | | |
| AuthenticationInfo * getAuthenticationInfo() { return &_ai; } | | | |
| bool isAdmin() { return _ai.isAuthorized( "admin" ); } | | | |
| CurOp* curop() const { return _curOp; } | | CurOp* curop() const { return _curOp; } | |
| Context* getContext() const { return _context; } | | Context* getContext() const { return _context; } | |
| Database* database() const { return _context ? _context->db() : 0;
} | | Database* database() const { return _context ? _context->db() : 0;
} | |
| const char *ns() const { return _context->ns(); } | | const char *ns() const { return _context->ns(); } | |
| const std::string desc() const { return _desc; } | | const std::string desc() const { return _desc; } | |
| void setLastOp( OpTime op ) { _lastOp = op; } | | void setLastOp( OpTime op ) { _lastOp = op; } | |
| OpTime getLastOp() const { return _lastOp; } | | OpTime getLastOp() const { return _lastOp; } | |
| | | | |
| /** caution -- use Context class instead */ | | /** caution -- use Context class instead */ | |
| void setContext(Context *c) { _context = c; } | | void setContext(Context *c) { _context = c; } | |
| | | | |
| skipping to change at line 129 | | skipping to change at line 125 | |
| private: | | private: | |
| Client(const char *desc, AbstractMessagingPort *p = 0); | | Client(const char *desc, AbstractMessagingPort *p = 0); | |
| friend class CurOp; | | friend class CurOp; | |
| ConnectionId _connectionId; // > 0 for things "conn", 0 otherwise | | ConnectionId _connectionId; // > 0 for things "conn", 0 otherwise | |
| string _threadId; // "" on non support systems | | string _threadId; // "" on non support systems | |
| CurOp * _curOp; | | CurOp * _curOp; | |
| Context * _context; | | Context * _context; | |
| bool _shutdown; // to track if Client::shutdown() gets called | | bool _shutdown; // to track if Client::shutdown() gets called | |
| std::string _desc; | | std::string _desc; | |
| bool _god; | | bool _god; | |
|
| AuthenticationInfo _ai; | | | |
| OpTime _lastOp; | | OpTime _lastOp; | |
| BSONObj _handshake; | | BSONObj _handshake; | |
| BSONObj _remoteId; | | BSONObj _remoteId; | |
| | | | |
| bool _hasWrittenThisPass; | | bool _hasWrittenThisPass; | |
| PageFaultRetryableSection *_pageFaultRetryableSection; | | PageFaultRetryableSection *_pageFaultRetryableSection; | |
| | | | |
| LockState _ls; | | LockState _ls; | |
| | | | |
| friend class PageFaultRetryableSection; // TEMP | | friend class PageFaultRetryableSection; // TEMP | |
| | | | |
| skipping to change at line 158 | | skipping to change at line 153 | |
| ~GodScope(); | | ~GodScope(); | |
| }; | | }; | |
| | | | |
| //static void assureDatabaseIsOpen(const string& ns, string path=db
path); | | //static void assureDatabaseIsOpen(const string& ns, string path=db
path); | |
| | | | |
| /** "read lock, and set my context, all in one operation" | | /** "read lock, and set my context, all in one operation" | |
| * This handles (if not recursively locked) opening an unopened da
tabase. | | * This handles (if not recursively locked) opening an unopened da
tabase. | |
| */ | | */ | |
| class ReadContext : boost::noncopyable { | | class ReadContext : boost::noncopyable { | |
| public: | | public: | |
|
| ReadContext(const std::string& ns, const std::string& path=dbpa
th, bool doauth=true ); | | ReadContext(const std::string& ns, const std::string& path=dbpa
th); | |
| Context& ctx() { return *c.get(); } | | Context& ctx() { return *c.get(); } | |
| private: | | private: | |
| scoped_ptr<Lock::DBRead> lk; | | scoped_ptr<Lock::DBRead> lk; | |
| scoped_ptr<Context> c; | | scoped_ptr<Context> c; | |
| }; | | }; | |
| | | | |
| /* 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 : boost::noncopyable { | | class Context : boost::noncopyable { | |
| public: | | public: | |
| /** this is probably what you want */ | | /** this is probably what you want */ | |
|
| Context(const string& ns, const std::string& path=dbpath, bool
doauth=true, bool doVersion=true ); | | Context(const string& ns, const std::string& path=dbpath, bool
doVersion=true); | |
| | | | |
| /** note: this does not call finishInit -- i.e., does not call | | /** note: this does not call finishInit -- i.e., does not call | |
| shardVersionOk() for example. | | shardVersionOk() for example. | |
| see also: reset(). | | see also: reset(). | |
| */ | | */ | |
|
| Context( const std::string& ns , Database * db, bool doauth=tru
e ); | | Context(const std::string& ns , Database * db); | |
| | | | |
| // used by ReadContext | | // used by ReadContext | |
|
| Context(const string& path, const string& ns, Database *db, boo
l doauth); | | Context(const string& path, const string& ns, Database *db); | |
| | | | |
| ~Context(); | | ~Context(); | |
| Client* getClient() const { return _client; } | | Client* getClient() const { return _client; } | |
| Database* db() const { return _db; } | | Database* db() const { return _db; } | |
| const char * ns() const { return _ns.c_str(); } | | const char * ns() const { return _ns.c_str(); } | |
| bool equals( const string& ns , const string& path=dbpath ) con
st { return _ns == ns && _path == path; } | | bool equals( const string& ns , const string& path=dbpath ) con
st { return _ns == ns && _path == path; } | |
| | | | |
| /** @return if the db was created by this Context */ | | /** @return if the db was created by this Context */ | |
| bool justCreated() const { return _justCreated; } | | bool justCreated() const { return _justCreated; } | |
| | | | |
| | | | |
| skipping to change at line 209 | | skipping to change at line 204 | |
| /** call before unlocking, so clear any non-thread safe state | | /** call before unlocking, so clear any non-thread safe state | |
| * _db gets restored on the relock | | * _db gets restored on the relock | |
| */ | | */ | |
| void unlocked() { _db = 0; } | | void unlocked() { _db = 0; } | |
| | | | |
| /** call after going back into the lock, will re-establish non-
thread safe stuff */ | | /** call after going back into the lock, will re-establish non-
thread safe stuff */ | |
| void relocked() { _finishInit(); } | | void relocked() { _finishInit(); } | |
| | | | |
| private: | | private: | |
| friend class CurOp; | | friend class CurOp; | |
|
| void _finishInit( bool doauth=true); | | void _finishInit(); | |
| void _auth( int lockState ); | | | |
| void checkNotStale() const; | | void checkNotStale() const; | |
| void checkNsAccess( bool doauth ); | | void checkNsAccess( bool doauth ); | |
| void checkNsAccess( bool doauth, int lockState ); | | void checkNsAccess( bool doauth, int lockState ); | |
| Client * const _client; | | Client * const _client; | |
| Context * const _oldContext; | | Context * const _oldContext; | |
| const string _path; | | const string _path; | |
| bool _justCreated; | | bool _justCreated; | |
| bool _doVersion; | | bool _doVersion; | |
| const string _ns; | | const string _ns; | |
| Database * _db; | | Database * _db; | |
| | | | |
| Timer _timer; | | Timer _timer; | |
| }; // class Client::Context | | }; // class Client::Context | |
| | | | |
| class WriteContext : boost::noncopyable { | | class WriteContext : boost::noncopyable { | |
| public: | | public: | |
|
| WriteContext(const string& ns, const std::string& path=dbpath,
bool doauth=true ); | | WriteContext(const string& ns, const std::string& path=dbpath); | |
| Context& ctx() { return _c; } | | Context& ctx() { return _c; } | |
| private: | | private: | |
| Lock::DBWrite _lk; | | Lock::DBWrite _lk; | |
| Context _c; | | Context _c; | |
| }; | | }; | |
| | | | |
| }; // class Client | | }; // class Client | |
| | | | |
| /** get the Client object for this thread. */ | | /** get the Client object for this thread. */ | |
| inline Client& cc() { | | inline Client& cc() { | |
| | | | |
End of changes. 10 change blocks. |
| 14 lines changed or deleted | | 7 lines changed or added | |
|
| cloner.h | | cloner.h | |
| | | | |
| skipping to change at line 21 | | skipping to change at line 21 | |
| * 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 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 "mongo/db/jsobj.h" | |
| | | #include "mongo/db/sort_phase_one.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
|
| | | struct CloneOptions; | |
| | | class IndexSpec; | |
| | | class DBClientBase; | |
| | | class DBClientCursor; | |
| | | class Query; | |
| | | | |
| | | class Cloner: boost::noncopyable { | |
| | | public: | |
| | | Cloner(); | |
| | | /** | |
| | | * slaveOk - if true it is ok if the source of the data is !is | |
| | | master. | |
| | | * useReplAuth - use the credentials we normally use as a replicat | |
| | | ion slave for the cloning | |
| | | * snapshot - use $snapshot mode for copying collections. note | |
| | | this should not be used | |
| | | * when it isn't required, as it will be slower. fo | |
| | | r example, | |
| | | * repairDatabase need not use it. | |
| | | */ | |
| | | void setConnection( DBClientBase *c ) { _conn.reset( c ); } | |
| | | | |
| | | /** copy the entire database */ | |
| | | bool go(const char *masterHost, string& errmsg, const string& fromd | |
| | | b, bool logForRepl, | |
| | | bool slaveOk, bool useReplAuth, bool snapshot, bool mayYiel | |
| | | d, | |
| | | bool mayBeInterrupted, int *errCode = 0); | |
| | | | |
| | | bool go(const char *masterHost, const CloneOptions& opts, set<strin | |
| | | g>& clonedColls, | |
| | | string& errmsg, int *errCode = 0); | |
| | | | |
| | | bool go(const char *masterHost, const CloneOptions& opts, string& e | |
| | | rrmsg, int *errCode = 0); | |
| | | | |
| | | bool copyCollection(const string& ns, const BSONObj& query, string& | |
| | | errmsg, | |
| | | bool mayYield, bool mayBeInterrupted, bool copy | |
| | | Indexes = true, | |
| | | bool logForRepl = true ); | |
| | | /** | |
| | | * validate the cloner query was successful | |
| | | * @param cur Cursor the query was executed on | |
| | | * @param errCode out Error code encountered during the query | |
| | | */ | |
| | | static bool validateQueryResults(const auto_ptr<DBClientCursor>& cu | |
| | | r, int32_t* errCode); | |
| | | | |
| | | /** | |
| | | * @param errmsg out - Error message (if encountered). | |
| | | * @param slaveOk - if true it is ok if the source of the data | |
| | | is !ismaster. | |
| | | * @param useReplAuth - use the credentials we normally use as a re | |
| | | plication slave for the | |
| | | * cloning. | |
| | | * @param snapshot - use $snapshot mode for copying collections. | |
| | | note this should not be | |
| | | * used when it isn't required, as it will be | |
| | | slower. for example | |
| | | * repairDatabase need not use it. | |
| | | * @param errCode out - If provided, this will be set on error to t | |
| | | he server's error code. | |
| | | * Currently this will only be set if there is | |
| | | an error in the initial | |
| | | * system.namespaces query. | |
| | | */ | |
| | | static bool cloneFrom(const char *masterHost, string& errmsg, const | |
| | | string& fromdb, | |
| | | bool logForReplication, bool slaveOk, bool us | |
| | | eReplAuth, | |
| | | bool snapshot, bool mayYield, bool mayBeInter | |
| | | rupted, | |
| | | int *errCode = 0); | |
| | | | |
| | | static bool cloneFrom(const string& masterHost, const CloneOptions& | |
| | | options, | |
| | | string& errmsg, int* errCode = 0, | |
| | | set<string>* clonedCollections = 0); | |
| | | | |
| | | /** | |
| | | * Copy a collection (and indexes) from a remote host | |
| | | */ | |
| | | static bool copyCollectionFromRemote(const string& host, const stri | |
| | | ng& ns, string& errmsg); | |
| | | | |
| | | private: | |
| | | void copy(const char *from_ns, const char *to_ns, bool isindex, boo | |
| | | l logForRepl, | |
| | | bool masterSameProcess, bool slaveOk, bool mayYield, bool | |
| | | mayBeInterrupted, | |
| | | Query q); | |
| | | | |
| | | // index presort info | |
| | | typedef struct { | |
| | | IndexSpec spec; | |
| | | SortPhaseOne preSortPhase; | |
| | | } PreSortDetails; | |
| | | | |
| | | typedef map<string, PreSortDetails> SortersForIndex; // map from in | |
| | | dex name to presorter | |
| | | typedef map<string, SortersForIndex> SortersForNS; // map from ns | |
| | | to indices/sorters | |
| | | | |
| | | struct Fun; | |
| | | auto_ptr<DBClientBase> _conn; | |
| | | SortersForNS _sortersForNS; | |
| | | }; | |
| | | | |
| struct CloneOptions { | | struct CloneOptions { | |
| | | | |
| CloneOptions() { | | CloneOptions() { | |
| logForRepl = true; | | logForRepl = true; | |
| slaveOk = false; | | slaveOk = false; | |
| useReplAuth = false; | | useReplAuth = false; | |
| snapshot = true; | | snapshot = true; | |
| mayYield = true; | | mayYield = true; | |
| mayBeInterrupted = false; | | mayBeInterrupted = false; | |
| | | | |
| | | | |
| skipping to change at line 53 | | skipping to change at line 137 | |
| bool slaveOk; | | bool slaveOk; | |
| bool useReplAuth; | | bool useReplAuth; | |
| bool snapshot; | | bool snapshot; | |
| bool mayYield; | | bool mayYield; | |
| bool mayBeInterrupted; | | bool mayBeInterrupted; | |
| | | | |
| bool syncData; | | bool syncData; | |
| bool syncIndexes; | | bool syncIndexes; | |
| }; | | }; | |
| | | | |
|
| bool cloneFrom( const string& masterHost , | | | |
| const CloneOptions& options , | | | |
| string& errmsg /* out */ , | | | |
| int* errCode = 0 /* out */ , | | | |
| set<string>* clonedCollections = 0 /* out */ ); | | | |
| | | | |
| /** | | | |
| * @param slaveOk - if true it is ok if the source of the data is ! | | | |
| ismaster. | | | |
| * @param useReplAuth - use the credentials we normally use as a replic | | | |
| ation slave for the cloning | | | |
| * @param snapshot - use $snapshot mode for copying collections. no | | | |
| te this should not be used when it isn't required, as it will be slower. | | | |
| * for example repairDatabase need not use it. | | | |
| * @param errCode - If provided, this will be set on error to the s | | | |
| erver's error code. Currently | | | |
| * this will only be set if there is an error in t | | | |
| he initial system.namespaces query. | | | |
| */ | | | |
| bool cloneFrom(const char *masterHost, string& errmsg, const string& fr | | | |
| omdb, bool logForReplication, | | | |
| bool slaveOk, bool useReplAuth, bool snapshot, bool mayY | | | |
| ield, | | | |
| bool mayBeInterrupted, int *errCode = 0); | | | |
| | | | |
| bool copyCollectionFromRemote(const string& host, const string& ns, str | | | |
| ing& errmsg); | | | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 3 change blocks. |
| 29 lines changed or deleted | | 111 lines changed or added | |
|
| cmdline.h | | cmdline.h | |
| | | | |
| skipping to change at line 35 | | skipping to change at line 35 | |
| namespace boost { | | namespace boost { | |
| namespace program_options { | | namespace program_options { | |
| class options_description; | | class options_description; | |
| class positional_options_description; | | class positional_options_description; | |
| class variables_map; | | class variables_map; | |
| } | | } | |
| } | | } | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
|
| #ifdef MONGO_SSL | | | |
| class SSLManager; | | | |
| #endif | | | |
| | | | |
| /* command line options | | /* command line options | |
| */ | | */ | |
| /* concurrency: OK/READ */ | | /* concurrency: OK/READ */ | |
| struct CmdLine { | | struct CmdLine { | |
| | | | |
| CmdLine(); | | CmdLine(); | |
| | | | |
| std::string binaryName; // mongod or mongos | | std::string binaryName; // mongod or mongos | |
| std::string cwd; // cwd of when process started | | std::string cwd; // cwd of when process started | |
| | | | |
| | | | |
| skipping to change at line 142 | | skipping to change at line 138 | |
| | | | |
| #ifndef _WIN32 | | #ifndef _WIN32 | |
| pid_t parentProc; // --fork pid of initial process | | pid_t parentProc; // --fork pid of initial process | |
| pid_t leaderProc; // --fork pid of leader process | | pid_t leaderProc; // --fork pid of leader process | |
| #endif | | #endif | |
| | | | |
| #ifdef MONGO_SSL | | #ifdef MONGO_SSL | |
| bool sslOnNormalPorts; // --sslOnNormalPorts | | bool sslOnNormalPorts; // --sslOnNormalPorts | |
| std::string sslPEMKeyFile; // --sslPEMKeyFile | | std::string sslPEMKeyFile; // --sslPEMKeyFile | |
| std::string sslPEMKeyPassword; // --sslPEMKeyPassword | | std::string sslPEMKeyPassword; // --sslPEMKeyPassword | |
|
| | | std::string sslCAFile; // --sslCAFile | |
| SSLManager* sslServerManager; // currently leaks on close | | std::string sslCRLFile; // --sslCRLFile | |
| | | bool sslForceCertificateValidation; | |
| #endif | | #endif | |
| | | | |
| /** | | /** | |
| * Switches to enable experimental (unsupported) features. | | * Switches to enable experimental (unsupported) features. | |
| */ | | */ | |
| struct ExperimentalFeatures { | | struct ExperimentalFeatures { | |
| ExperimentalFeatures() | | ExperimentalFeatures() | |
| : indexStatsCmdEnabled(false) | | : indexStatsCmdEnabled(false) | |
| , storageDetailsCmdEnabled(false) | | , storageDetailsCmdEnabled(false) | |
| {} | | {} | |
| | | | |
| skipping to change at line 194 | | skipping to change at line 191 | |
| static BSONObj getParsedOpts(); | | static BSONObj getParsedOpts(); | |
| | | | |
| time_t started; | | time_t started; | |
| }; | | }; | |
| | | | |
| // todo move to cmdline.cpp? | | // todo move to cmdline.cpp? | |
| inline CmdLine::CmdLine() : | | inline CmdLine::CmdLine() : | |
| port(DefaultDBPort), rest(false), jsonp(false), indexBuildRetry(tru
e), quiet(false), | | port(DefaultDBPort), rest(false), jsonp(false), indexBuildRetry(tru
e), quiet(false), | |
| noTableScan(false), prealloc(true), preallocj(true), smallfiles(siz
eof(int*) == 4), | | noTableScan(false), prealloc(true), preallocj(true), smallfiles(siz
eof(int*) == 4), | |
| configsvr(false), quota(false), quotaFiles(8), cpu(false), | | configsvr(false), quota(false), quotaFiles(8), cpu(false), | |
|
| durOptions(0), objcheck(false), oplogSize(0), defaultProfile(0), | | durOptions(0), objcheck(true), oplogSize(0), defaultProfile(0), | |
| slowMS(100), defaultLocalThresholdMillis(15), pretouch(0), movePara | | slowMS(100), defaultLocalThresholdMillis(15), pretouch(0), movePara | |
| noia( true ), | | noia( false ), | |
| syncdelay(60), noUnixSocket(false), doFork(0), socket("/tmp"), maxC
onns(DEFAULT_MAX_CONN), | | syncdelay(60), noUnixSocket(false), doFork(0), socket("/tmp"), maxC
onns(DEFAULT_MAX_CONN), | |
| logAppend(false), logWithSyslog(false) | | logAppend(false), logWithSyslog(false) | |
| { | | { | |
| started = time(0); | | started = time(0); | |
| | | | |
| journalCommitInterval = 0; // 0 means use default | | journalCommitInterval = 0; // 0 means use default | |
| dur = false; | | dur = false; | |
| #if defined(_DURABLEDEFAULTON) | | #if defined(_DURABLEDEFAULTON) | |
| dur = true; | | dur = true; | |
| #endif | | #endif | |
| if( sizeof(void*) == 8 ) | | if( sizeof(void*) == 8 ) | |
| dur = true; | | dur = true; | |
| #if defined(_DURABLEDEFAULTOFF) | | #if defined(_DURABLEDEFAULTOFF) | |
| dur = false; | | dur = false; | |
| #endif | | #endif | |
| | | | |
| #ifdef MONGO_SSL | | #ifdef MONGO_SSL | |
| sslOnNormalPorts = false; | | sslOnNormalPorts = false; | |
|
| sslServerManager = 0; | | | |
| #endif | | #endif | |
| } | | } | |
| | | | |
| extern CmdLine cmdLine; | | extern CmdLine cmdLine; | |
| | | | |
| void printCommandLineOpts(); | | void printCommandLineOpts(); | |
|
| | | | |
| /** | | | |
| * used for setParameter command | | | |
| * so you can write validation code that lives with code using it | | | |
| * rather than all in the command place | | | |
| * also lets you have mongos or mongod specific code | | | |
| * without pulling it all sorts of things | | | |
| */ | | | |
| class ParameterValidator { | | | |
| public: | | | |
| ParameterValidator( const std::string& name ); | | | |
| virtual ~ParameterValidator() {} | | | |
| | | | |
| virtual bool isValid( BSONElement e , std::string& errmsg ) const = | | | |
| 0; | | | |
| | | | |
| static ParameterValidator * get( const std::string& name ); | | | |
| | | | |
| private: | | | |
| const std::string _name; | | | |
| }; | | | |
| | | | |
| } | | } | |
| | | | |
End of changes. 5 change blocks. |
| 32 lines changed or deleted | | 6 lines changed or added | |
|
| commands.h | | commands.h | |
| | | | |
| skipping to change at line 22 | | skipping to change at line 22 | |
| * 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 <vector> | | #include <vector> | |
| | | | |
|
| | | #include "mongo/db/auth/action_set.h" | |
| | | #include "mongo/db/auth/action_type.h" | |
| | | #include "mongo/db/auth/authorization_manager.h" | |
| #include "mongo/db/auth/privilege.h" | | #include "mongo/db/auth/privilege.h" | |
|
| | | #include "mongo/db/client_basic.h" | |
| #include "mongo/db/jsobj.h" | | #include "mongo/db/jsobj.h" | |
| #include "mongo/util/mongoutils/str.h" | | #include "mongo/util/mongoutils/str.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| class BSONObj; | | class BSONObj; | |
| class BSONObjBuilder; | | class BSONObjBuilder; | |
| class Client; | | class Client; | |
| class Timer; | | class Timer; | |
| | | | |
| | | | |
| skipping to change at line 118 | | skipping to change at line 122 | |
| (e.g., getnonce, authenticate) can be done by anyone even unauth
orized. | | (e.g., getnonce, authenticate) can be done by anyone even unauth
orized. | |
| */ | | */ | |
| virtual bool requiresAuth() { return true; } | | virtual bool requiresAuth() { return true; } | |
| | | | |
| /** | | /** | |
| * Appends to "*out" the privileges required to run this command on
database "dbname" with | | * Appends to "*out" the privileges required to run this command on
database "dbname" with | |
| * the invocation described by "cmdObj". | | * the invocation described by "cmdObj". | |
| */ | | */ | |
| virtual void addRequiredPrivileges(const std::string& dbname, | | virtual void addRequiredPrivileges(const std::string& dbname, | |
| const BSONObj& cmdObj, | | const BSONObj& cmdObj, | |
|
| std::vector<Privilege>* out); | | std::vector<Privilege>* out) = 0
; | |
| | | | |
| /* Return true if a replica set secondary should go into "recoverin
g" | | /* Return true if a replica set secondary should go into "recoverin
g" | |
| (unreadable) state while running this command. | | (unreadable) state while running this command. | |
| */ | | */ | |
| virtual bool maintenanceMode() const { return false; } | | virtual bool maintenanceMode() const { return false; } | |
| | | | |
| /* Return true if command should be permitted when a replica set se
condary is in "recovering" | | /* Return true if command should be permitted when a replica set se
condary is in "recovering" | |
| (unreadable) state. | | (unreadable) state. | |
| */ | | */ | |
| virtual bool maintenanceOk() const { return true; /* assumed true p
rior to commit */ } | | virtual bool maintenanceOk() const { return true; /* assumed true p
rior to commit */ } | |
| | | | |
| skipping to change at line 155 | | skipping to change at line 159 | |
| | | | |
| static void logIfSlow( const Timer& cmdTimer, const string& msg); | | static void logIfSlow( const Timer& cmdTimer, const string& msg); | |
| | | | |
| static map<string,Command*> * _commands; | | static map<string,Command*> * _commands; | |
| static map<string,Command*> * _commandsByBestName; | | static map<string,Command*> * _commandsByBestName; | |
| static map<string,Command*> * _webCommands; | | static map<string,Command*> * _webCommands; | |
| | | | |
| public: | | public: | |
| static const map<string,Command*>* commandsByBestName() { return _c
ommandsByBestName; } | | static const map<string,Command*>* commandsByBestName() { return _c
ommandsByBestName; } | |
| static const map<string,Command*>* webCommands() { return _webComma
nds; } | | static const map<string,Command*>* webCommands() { return _webComma
nds; } | |
|
| /** @return if command was found and executed */ | | /** @return if command was found */ | |
| static bool runAgainstRegistered(const char *ns, BSONObj& jsobj, BS | | static void runAgainstRegistered(const char *ns, | |
| ONObjBuilder& anObjBuilder, int queryOptions = 0); | | BSONObj& jsobj, | |
| | | BSONObjBuilder& anObjBuilder, | |
| | | int queryOptions = 0); | |
| static LockType locktype( const string& name ); | | static LockType locktype( const string& name ); | |
| static Command * findCommand( const string& name ); | | static Command * findCommand( const string& name ); | |
|
| | | // For mongod and webserver. | |
| | | static void execCommand(Command* c, | |
| | | Client& client, | |
| | | int queryOptions, | |
| | | const char *ns, | |
| | | BSONObj& cmdObj, | |
| | | BSONObjBuilder& result, | |
| | | bool fromRepl ); | |
| | | // For mongos | |
| | | static void execCommandClientBasic(Command* c, | |
| | | ClientBasic& client, | |
| | | int queryOptions, | |
| | | const char *ns, | |
| | | BSONObj& cmdObj, | |
| | | BSONObjBuilder& result, | |
| | | bool fromRepl ); | |
| | | | |
| | | // Helper for setting errmsg and ok field in command result object. | |
| | | static void appendCommandStatus(BSONObjBuilder& result, bool ok, co | |
| | | nst std::string& errmsg); | |
| | | | |
| | | // Set by command line. Controls whether or not testing-only comma | |
| | | nds should be available. | |
| | | static int testCommandsEnabled; | |
| | | }; | |
| | | | |
| | | // This will be registered instead of the real implementations of any c | |
| | | ommands that don't work | |
| | | // when auth is enabled. | |
| | | class NotWithAuthCmd : public Command { | |
| | | public: | |
| | | NotWithAuthCmd(const char* cmdName) : Command(cmdName) { } | |
| | | virtual bool slaveOk() const { return true; } | |
| | | virtual LockType locktype() const { return NONE; } | |
| | | virtual bool requiresAuth() { return false; } | |
| | | virtual void addRequiredPrivileges(const std::string& dbname, | |
| | | const BSONObj& cmdObj, | |
| | | std::vector<Privilege>* out) {} | |
| | | virtual void help( stringstream &help ) const { | |
| | | help << name << " is not supported when running with authentica | |
| | | tion enabled"; | |
| | | } | |
| | | virtual bool run(const string&, | |
| | | BSONObj& cmdObj, | |
| | | int, | |
| | | string& errmsg, | |
| | | BSONObjBuilder& result, | |
| | | bool fromRepl) { | |
| | | errmsg = name + " is not supported when running with authentica | |
| | | tion enabled"; | |
| | | log() << errmsg << std::endl; | |
| | | return false; | |
| | | } | |
| }; | | }; | |
| | | | |
| class CmdShutdown : public Command { | | class CmdShutdown : public Command { | |
| public: | | public: | |
| virtual bool requiresAuth() { return true; } | | virtual bool requiresAuth() { return true; } | |
| virtual bool adminOnly() const { return true; } | | virtual bool adminOnly() const { return true; } | |
| virtual bool localHostOnlyIfNoAuth(const BSONObj& cmdObj) { return
true; } | | virtual bool localHostOnlyIfNoAuth(const BSONObj& cmdObj) { return
true; } | |
| virtual bool logTheOp() { | | virtual bool logTheOp() { | |
| return false; | | return false; | |
| } | | } | |
| virtual bool slaveOk() const { | | virtual bool slaveOk() const { | |
| return true; | | return true; | |
| } | | } | |
|
| | | virtual void addRequiredPrivileges(const std::string& dbname, | |
| | | const BSONObj& cmdObj, | |
| | | std::vector<Privilege>* out) { | |
| | | ActionSet actions; | |
| | | actions.addAction(ActionType::shutdown); | |
| | | out->push_back(Privilege(AuthorizationManager::SERVER_RESOURCE_ | |
| | | NAME, actions)); | |
| | | } | |
| virtual LockType locktype() const { return NONE; } | | virtual LockType locktype() const { return NONE; } | |
| virtual void help( stringstream& help ) const; | | virtual void help( stringstream& help ) const; | |
| CmdShutdown() : Command("shutdown") {} | | CmdShutdown() : Command("shutdown") {} | |
| bool run(const string& dbname, BSONObj& cmdObj, int options, string
& errmsg, BSONObjBuilder& result, bool fromRepl); | | bool run(const string& dbname, BSONObj& cmdObj, int options, string
& errmsg, BSONObjBuilder& result, bool fromRepl); | |
| private: | | private: | |
| bool shutdownHelper(); | | bool shutdownHelper(); | |
| }; | | }; | |
| | | | |
| bool _runCommands(const char *ns, BSONObj& jsobj, BufBuilder &b, BSONOb
jBuilder& anObjBuilder, bool fromRepl, int queryOptions); | | bool _runCommands(const char *ns, BSONObj& jsobj, BufBuilder &b, BSONOb
jBuilder& anObjBuilder, bool fromRepl, int queryOptions); | |
| | | | |
| | | | |
End of changes. 6 change blocks. |
| 4 lines changed or deleted | | 71 lines changed or added | |
|
| connpool.h | | connpool.h | |
| | | | |
| skipping to change at line 252 | | skipping to change at line 252 | |
| */ | | */ | |
| class ScopedDbConnection : public AScopedConnection { | | class ScopedDbConnection : public AScopedConnection { | |
| private: | | private: | |
| /** the main constructor you want to use | | /** the main constructor you want to use | |
| throws UserException if can't connect | | throws UserException if can't connect | |
| */ | | */ | |
| explicit ScopedDbConnection(const string& host, double socketTimeou
t = 0) : _host(host), _conn( pool.get(host, socketTimeout) ), _socketTimeou
t( socketTimeout ) { | | explicit ScopedDbConnection(const string& host, double socketTimeou
t = 0) : _host(host), _conn( pool.get(host, socketTimeout) ), _socketTimeou
t( socketTimeout ) { | |
| _setSocketTimeout(); | | _setSocketTimeout(); | |
| } | | } | |
| | | | |
|
| | | explicit ScopedDbConnection(const ConnectionString& host, double so | |
| | | cketTimeout = 0) : _host(host.toString()), _conn( pool.get(host, socketTime | |
| | | out) ), _socketTimeout( socketTimeout ) { | |
| | | _setSocketTimeout(); | |
| | | } | |
| | | | |
| ScopedDbConnection() : _host( "" ) , _conn(0), _socketTimeout( 0 )
{} | | ScopedDbConnection() : _host( "" ) , _conn(0), _socketTimeout( 0 )
{} | |
| | | | |
| /* @param conn - bind to an existing connection */ | | /* @param conn - bind to an existing connection */ | |
| ScopedDbConnection(const string& host, DBClientBase* conn, double s
ocketTimeout = 0 ) : _host( host ) , _conn( conn ), _socketTimeout( socketT
imeout ) { | | ScopedDbConnection(const string& host, DBClientBase* conn, double s
ocketTimeout = 0 ) : _host( host ) , _conn( conn ), _socketTimeout( socketT
imeout ) { | |
| _setSocketTimeout(); | | _setSocketTimeout(); | |
| } | | } | |
| public: | | public: | |
| | | | |
| // Factory functions for getting ScopedDbConnections. The caller o
wns the resulting object | | // Factory functions for getting ScopedDbConnections. The caller o
wns the resulting object | |
| // and is responsible for deleting it when finished. This should be
used when running a | | // and is responsible for deleting it when finished. This should be
used when running a | |
| // command on a shard from the mongos and the command should run wi
th the client's | | // command on a shard from the mongos and the command should run wi
th the client's | |
| // authentication. If the command should be run with full permissi
ons regardless | | // authentication. If the command should be run with full permissi
ons regardless | |
| // of whether or not the user is authorized, then use getInternalSc
opedDbConnection(). | | // of whether or not the user is authorized, then use getInternalSc
opedDbConnection(). | |
| static ScopedDbConnection* getScopedDbConnection(const string& host
, | | static ScopedDbConnection* getScopedDbConnection(const string& host
, | |
| double socketTimeo
ut = 0); | | double socketTimeo
ut = 0); | |
|
| | | static ScopedDbConnection* getScopedDbConnection(const ConnectionSt | |
| | | ring& host, | |
| | | double socketTimeo | |
| | | ut = 0); | |
| static ScopedDbConnection* getScopedDbConnection(); | | static ScopedDbConnection* getScopedDbConnection(); | |
| | | | |
|
| // Gets a ScopedDbConnection designed to be used for internal commu | | // DEPRECATED. This is now just a synonym for getScopedDbConnection | |
| nication within a cluster | | . | |
| // The mongod/mongos implementations of these set the Authenticatio | | | |
| nTable on the underlying | | | |
| // connection to the internalSecurity permissions. All commands ru | | | |
| n on the shard mongods | | | |
| // using this connection will have full access. If the command sho | | | |
| uld only be run on the | | | |
| // shard if the client has permission to do so, then use getScopedD | | | |
| bConnection(). | | | |
| // These functions should not be called by consumers of the C++ cli | | | |
| ent library. | | | |
| static ScopedDbConnection* getInternalScopedDbConnection(const stri
ng& host, | | static ScopedDbConnection* getInternalScopedDbConnection(const stri
ng& host, | |
| double soc
ketTimeout = 0); | | double soc
ketTimeout = 0); | |
|
| | | static ScopedDbConnection* getInternalScopedDbConnection(const Conn | |
| | | ectionString& host, | |
| | | double soc | |
| | | ketTimeout = 0); | |
| static ScopedDbConnection* getInternalScopedDbConnection(); | | static ScopedDbConnection* getInternalScopedDbConnection(); | |
| | | | |
| static void clearPool(); | | static void clearPool(); | |
| | | | |
| ~ScopedDbConnection(); | | ~ScopedDbConnection(); | |
| | | | |
| /** get the associated connection object */ | | /** get the associated connection object */ | |
| DBClientBase* operator->() { | | DBClientBase* operator->() { | |
| uassert( 11004 , "connection was returned to the pool already"
, _conn ); | | uassert( 11004 , "connection was returned to the pool already"
, _conn ); | |
| return _conn; | | return _conn; | |
| | | | |
| skipping to change at line 328 | | skipping to change at line 331 | |
| */ | | */ | |
| void done() { | | void done() { | |
| if ( ! _conn ) | | if ( ! _conn ) | |
| return; | | return; | |
| | | | |
| /* we could do this, but instead of assume one is using autorec
onnect mode on the connection | | /* we could do this, but instead of assume one is using autorec
onnect mode on the connection | |
| if ( _conn->isFailed() ) | | if ( _conn->isFailed() ) | |
| kill(); | | kill(); | |
| else | | else | |
| */ | | */ | |
|
| _conn->clearAuthenticationTable(); | | | |
| pool.release(_host, _conn); | | pool.release(_host, _conn); | |
| _conn = 0; | | _conn = 0; | |
| } | | } | |
| | | | |
| private: | | private: | |
| | | | |
| void _setSocketTimeout(); | | void _setSocketTimeout(); | |
| | | | |
| const string _host; | | const string _host; | |
| DBClientBase *_conn; | | DBClientBase *_conn; | |
| | | | |
End of changes. 5 change blocks. |
| 13 lines changed or deleted | | 16 lines changed or added | |
|
| d_chunk_manager.h | | d_chunk_manager.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 "mongo/pch.h" | | #include "mongo/pch.h" | |
| | | | |
|
| #include "../db/jsobj.h" | | #include "mongo/db/jsobj.h" | |
| #include "util.h" | | #include "mongo/s/chunk_version.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| class ClientCursor; | | class ClientCursor; | |
| class DBClientCursorInterface; | | class DBClientCursorInterface; | |
| | | | |
| class ShardChunkManager; | | class ShardChunkManager; | |
| typedef shared_ptr<ShardChunkManager> ShardChunkManagerPtr; | | typedef shared_ptr<ShardChunkManager> ShardChunkManagerPtr; | |
| | | | |
| /** | | /** | |
| | | | |
| skipping to change at line 80 | | skipping to change at line 80 | |
| ~ShardChunkManager() {} | | ~ShardChunkManager() {} | |
| | | | |
| /** | | /** | |
| * Generates a new manager based on 'this's state minus a given chu
nk. | | * Generates a new manager based on 'this's state minus a given chu
nk. | |
| * | | * | |
| * @param min max chunk boundaries for the chunk to subtract | | * @param min max chunk boundaries for the chunk to subtract | |
| * @param version that the resulting manager should be at. The vers
ion has to be higher than the current one. | | * @param version that the resulting manager should be at. The vers
ion has to be higher than the current one. | |
| * When cloning away the last chunk, verstion must be 0. | | * When cloning away the last chunk, verstion must be 0. | |
| * @return a new ShardChunkManager, to be owned by the caller | | * @return a new ShardChunkManager, to be owned by the caller | |
| */ | | */ | |
|
| ShardChunkManager* cloneMinus( const BSONObj& min , const BSONObj&
max , const ShardChunkVersion& version ); | | ShardChunkManager* cloneMinus( const BSONObj& min , const BSONObj&
max , const ChunkVersion& version ); | |
| | | | |
| /** | | /** | |
| * Generates a new manager based on 'this's state plus a given chun
k. | | * Generates a new manager based on 'this's state plus a given chun
k. | |
| * | | * | |
| * @param min max chunk boundaries for the chunk to add | | * @param min max chunk boundaries for the chunk to add | |
| * @param version that the resulting manager should be at. It can n
ever be 0, though (see CloneMinus). | | * @param version that the resulting manager should be at. It can n
ever be 0, though (see CloneMinus). | |
| * @return a new ShardChunkManager, to be owned by the caller | | * @return a new ShardChunkManager, to be owned by the caller | |
| */ | | */ | |
|
| ShardChunkManager* clonePlus( const BSONObj& min , const BSONObj& m
ax , const ShardChunkVersion& version ); | | ShardChunkManager* clonePlus( const BSONObj& min , const BSONObj& m
ax , const ChunkVersion& version ); | |
| | | | |
| /** | | /** | |
| * Generates a new manager by splitting an existing chunk at one or
more points. | | * Generates a new manager by splitting an existing chunk at one or
more points. | |
| * | | * | |
| * @param min max boundaries of chunk to be split | | * @param min max boundaries of chunk to be split | |
| * @param splitKeys points to split original chunk at | | * @param splitKeys points to split original chunk at | |
| * @param version to be used in first chunk. The subsequent chunks
would increment the minor version. | | * @param version to be used in first chunk. The subsequent chunks
would increment the minor version. | |
| * @return a new ShardChunkManager with the chunk split, to be owne
d by the caller | | * @return a new ShardChunkManager with the chunk split, to be owne
d by the caller | |
| */ | | */ | |
| ShardChunkManager* cloneSplit( const BSONObj& min , const BSONObj&
max , const vector<BSONObj>& splitKeys , | | ShardChunkManager* cloneSplit( const BSONObj& min , const BSONObj&
max , const vector<BSONObj>& splitKeys , | |
|
| const ShardChunkVersion& version ); | | const ChunkVersion& version ); | |
| | | | |
| /** | | /** | |
| * Checks whether a document belongs to this shard. | | * Checks whether a document belongs to this shard. | |
| * | | * | |
| * @param obj document containing sharding keys (and, optionally, o
ther attributes) | | * @param obj document containing sharding keys (and, optionally, o
ther attributes) | |
| * @return true if shards hold the object | | * @return true if shards hold the object | |
| */ | | */ | |
| bool belongsToMe( const BSONObj& doc ) const; | | bool belongsToMe( const BSONObj& doc ) const; | |
| | | | |
| /** | | /** | |
| | | | |
| skipping to change at line 131 | | skipping to change at line 131 | |
| * | | * | |
| * @param lookupKey is the min key for a previously obtained chunk
or the empty document | | * @param lookupKey is the min key for a previously obtained chunk
or the empty document | |
| * @param foundMin IN/OUT min for chunk following the one starting
at lookupKey | | * @param foundMin IN/OUT min for chunk following the one starting
at lookupKey | |
| * @param foundMax IN/OUT max for the above chunk | | * @param foundMax IN/OUT max for the above chunk | |
| * @return true if the chunk returned is the last one | | * @return true if the chunk returned is the last one | |
| */ | | */ | |
| bool getNextChunk( const BSONObj& lookupKey, BSONObj* foundMin , BS
ONObj* foundMax ) const; | | bool getNextChunk( const BSONObj& lookupKey, BSONObj* foundMin , BS
ONObj* foundMax ) const; | |
| | | | |
| // accessors | | // accessors | |
| | | | |
|
| ShardChunkVersion getVersion() const { return _version; } | | ChunkVersion getVersion() const { return _version; } | |
| ShardChunkVersion getCollVersion() const { return _collVersion; } | | ChunkVersion getCollVersion() const { return _collVersion; } | |
| BSONObj getKey() const { return _key.getOwned(); } | | BSONObj getKey() const { return _key.getOwned(); } | |
| unsigned getNumChunks() const { return _chunksMap.size(); } | | unsigned getNumChunks() const { return _chunksMap.size(); } | |
| | | | |
| string toString() const; | | string toString() const; | |
| private: | | private: | |
| void _init( const string& configServer , const string& ns , const s
tring& shardName, ShardChunkManagerPtr oldManager = ShardChunkManagerPtr()
); | | void _init( const string& configServer , const string& ns , const s
tring& shardName, ShardChunkManagerPtr oldManager = ShardChunkManagerPtr()
); | |
| | | | |
| /** | | /** | |
| * @same as belongsToMe but point is the extracted shard key | | * @same as belongsToMe but point is the extracted shard key | |
| */ | | */ | |
| bool _belongsToMe( const BSONObj& point ) const; | | bool _belongsToMe( const BSONObj& point ) const; | |
| | | | |
|
| ShardChunkVersion _collVersion; | | ChunkVersion _collVersion; | |
| // highest ShardChunkVersion for which this ShardChunkManager's inf | | // highest ChunkVersion for which this ShardChunkManager's informat | |
| ormation is accurate | | ion is accurate | |
| ShardChunkVersion _version; | | ChunkVersion _version; | |
| | | | |
| // key pattern for chunks under this range | | // key pattern for chunks under this range | |
| BSONObj _key; | | BSONObj _key; | |
| | | | |
| // a map from a min key into the chunk's (or range's) max boundary | | // a map from a min key into the chunk's (or range's) max boundary | |
| typedef map< BSONObj, BSONObj , BSONObjCmp > RangeMap; | | typedef map< BSONObj, BSONObj , BSONObjCmp > RangeMap; | |
| RangeMap _chunksMap; | | RangeMap _chunksMap; | |
| | | | |
| // a map from a min key into a range or continguous chunks | | // a map from a min key into a range or continguous chunks | |
| // redundant but we expect high chunk continguity, expecially in sm
all installations | | // redundant but we expect high chunk continguity, expecially in sm
all installations | |
| | | | |
End of changes. 6 change blocks. |
| 11 lines changed or deleted | | 11 lines changed or added | |
|
| d_logic.h | | d_logic.h | |
| | | | |
| skipping to change at line 22 | | skipping to change at line 22 | |
| * 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 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 "mongo/pch.h" | | #include "mongo/pch.h" | |
| | | | |
|
| #include "../db/jsobj.h" | | #include "mongo/db/jsobj.h" | |
| | | #include "mongo/s/d_chunk_manager.h" | |
| #include "d_chunk_manager.h" | | #include "mongo/s/chunk_version.h" | |
| #include "util.h" | | | |
| #include "mongo/util/concurrency/ticketholder.h" | | #include "mongo/util/concurrency/ticketholder.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| class Database; | | class Database; | |
| class DiskLoc; | | class DiskLoc; | |
| | | | |
|
| typedef ShardChunkVersion ConfigVersion; | | typedef ChunkVersion ConfigVersion; | |
| | | | |
| // -------------- | | // -------------- | |
| // --- global state --- | | // --- global state --- | |
| // -------------- | | // -------------- | |
| | | | |
| class ShardingState { | | class ShardingState { | |
| public: | | public: | |
| ShardingState(); | | ShardingState(); | |
| | | | |
| bool enabled() const { return _enabled; } | | bool enabled() const { return _enabled; } | |
| | | | |
| skipping to change at line 109 | | skipping to change at line 108 | |
| * Creates and installs a new chunk manager for a given collection
by "forgetting" about one of its chunks. | | * Creates and installs a new chunk manager for a given collection
by "forgetting" about one of its chunks. | |
| * The new manager uses the provided version, which has to be highe
r than the current manager's. | | * The new manager uses the provided version, which has to be highe
r than the current manager's. | |
| * One exception: if the forgotten chunk is the last one in this sh
ard for the collection, version has to be 0. | | * One exception: if the forgotten chunk is the last one in this sh
ard for the collection, version has to be 0. | |
| * | | * | |
| * If it runs successfully, clients need to grab the new version to
access the collection. | | * If it runs successfully, clients need to grab the new version to
access the collection. | |
| * | | * | |
| * @param ns the collection | | * @param ns the collection | |
| * @param min max the chunk to eliminate from the current manager | | * @param min max the chunk to eliminate from the current manager | |
| * @param version at which the new manager should be at | | * @param version at which the new manager should be at | |
| */ | | */ | |
|
| void donateChunk( const string& ns , const BSONObj& min , const BSO
NObj& max , ShardChunkVersion version ); | | void donateChunk( const string& ns , const BSONObj& min , const BSO
NObj& max , ChunkVersion version ); | |
| | | | |
| /** | | /** | |
| * Creates and installs a new chunk manager for a given collection
by reclaiming a previously donated chunk. | | * Creates and installs a new chunk manager for a given collection
by reclaiming a previously donated chunk. | |
| * The previous manager's version has to be provided. | | * The previous manager's version has to be provided. | |
| * | | * | |
| * If it runs successfully, clients that became stale by the previo
us donateChunk will be able to access the | | * If it runs successfully, clients that became stale by the previo
us donateChunk will be able to access the | |
| * collection again. | | * collection again. | |
| * | | * | |
| * @param ns the collection | | * @param ns the collection | |
| * @param min max the chunk to reclaim and add to the current manag
er | | * @param min max the chunk to reclaim and add to the current manag
er | |
| * @param version at which the new manager should be at | | * @param version at which the new manager should be at | |
| */ | | */ | |
|
| void undoDonateChunk( const string& ns , const BSONObj& min , const
BSONObj& max , ShardChunkVersion version ); | | void undoDonateChunk( const string& ns , const BSONObj& min , const
BSONObj& max , ChunkVersion version ); | |
| | | | |
| /** | | /** | |
| * Creates and installs a new chunk manager for a given collection
by splitting one of its chunks in two or more. | | * Creates and installs a new chunk manager for a given collection
by splitting one of its chunks in two or more. | |
| * The version for the first split chunk should be provided. The su
bsequent chunks' version would be the latter with the | | * The version for the first split chunk should be provided. The su
bsequent chunks' version would be the latter with the | |
| * minor portion incremented. | | * minor portion incremented. | |
| * | | * | |
| * The effect on clients will depend on the version used. If the ma
jor portion is the same as the current shards, | | * The effect on clients will depend on the version used. If the ma
jor portion is the same as the current shards, | |
| * clients shouldn't perceive the split. | | * clients shouldn't perceive the split. | |
| * | | * | |
| * @param ns the collection | | * @param ns the collection | |
| * @param min max the chunk that should be split | | * @param min max the chunk that should be split | |
| * @param splitKeys point in which to split | | * @param splitKeys point in which to split | |
| * @param version at which the new manager should be at | | * @param version at which the new manager should be at | |
| */ | | */ | |
| void splitChunk( const string& ns , const BSONObj& min , const BSON
Obj& max , const vector<BSONObj>& splitKeys , | | void splitChunk( const string& ns , const BSONObj& min , const BSON
Obj& max , const vector<BSONObj>& splitKeys , | |
|
| ShardChunkVersion version ); | | ChunkVersion version ); | |
| | | | |
| bool inCriticalMigrateSection(); | | bool inCriticalMigrateSection(); | |
| | | | |
| /** | | /** | |
| * @return true if we are NOT in the critical section | | * @return true if we are NOT in the critical section | |
| */ | | */ | |
| bool waitTillNotInCriticalSection( int maxSecondsToWait ); | | bool waitTillNotInCriticalSection( int maxSecondsToWait ); | |
| | | | |
| private: | | private: | |
| bool _enabled; | | bool _enabled; | |
| | | | |
| skipping to change at line 233 | | skipping to change at line 232 | |
| | | | |
| unsigned long long extractVersion( BSONElement e , string& errmsg ); | | unsigned long long extractVersion( BSONElement e , string& errmsg ); | |
| | | | |
| /** | | /** | |
| * @return true if we have any shard info for the ns | | * @return true if we have any shard info for the ns | |
| */ | | */ | |
| bool haveLocalShardingInfo( const string& ns ); | | bool haveLocalShardingInfo( const string& ns ); | |
| | | | |
| /** | | /** | |
| * @return true if the current threads shard version is ok, or not in s
harded version | | * @return true if the current threads shard version is ok, or not in s
harded version | |
|
| * Also returns an error message and the Config/ShardChunkVersions caus
ing conflicts | | * Also returns an error message and the Config/ChunkVersions causing c
onflicts | |
| */ | | */ | |
| bool shardVersionOk( const string& ns , string& errmsg, ConfigVersion&
received, ConfigVersion& wanted ); | | bool shardVersionOk( const string& ns , string& errmsg, ConfigVersion&
received, ConfigVersion& wanted ); | |
| | | | |
| /** | | /** | |
| * @return true if we took care of the message and nothing else should
be done | | * @return true if we took care of the message and nothing else should
be done | |
| */ | | */ | |
| struct DbResponse; | | struct DbResponse; | |
| | | | |
| bool _handlePossibleShardedMessage( Message &m, DbResponse * dbresponse
); | | bool _handlePossibleShardedMessage( Message &m, DbResponse * dbresponse
); | |
| | | | |
| | | | |
End of changes. 6 change blocks. |
| 9 lines changed or deleted | | 8 lines changed or added | |
|
| dbclientinterface.h | | dbclientinterface.h | |
| | | | |
| skipping to change at line 26 | | skipping to change at line 26 | |
| * 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 "mongo/pch.h" | | #include "mongo/pch.h" | |
| | | | |
| #include "mongo/client/authlevel.h" | | #include "mongo/client/authlevel.h" | |
|
| #include "mongo/client/authentication_table.h" | | | |
| #include "mongo/db/jsobj.h" | | #include "mongo/db/jsobj.h" | |
| #include "mongo/platform/atomic_word.h" | | #include "mongo/platform/atomic_word.h" | |
| #include "mongo/util/net/message.h" | | #include "mongo/util/net/message.h" | |
| #include "mongo/util/net/message_port.h" | | #include "mongo/util/net/message_port.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| /** the query field 'options' can have these bits set: */ | | /** the query field 'options' can have these bits set: */ | |
| enum QueryOptions { | | enum QueryOptions { | |
| /** Tailable means cursor is not closed when the last data is retri
eved. rather, the cursor marks | | /** Tailable means cursor is not closed when the last data is retri
eved. rather, the cursor marks | |
| | | | |
| skipping to change at line 174 | | skipping to change at line 173 | |
| */ | | */ | |
| ReadPreference_Nearest, | | ReadPreference_Nearest, | |
| }; | | }; | |
| | | | |
| /** | | /** | |
| * @return true if the query object contains a read preference specific
ation object. | | * @return true if the query object contains a read preference specific
ation object. | |
| */ | | */ | |
| bool hasReadPreference(const BSONObj& queryObj); | | bool hasReadPreference(const BSONObj& queryObj); | |
| | | | |
| class DBClientBase; | | class DBClientBase; | |
|
| | | class DBClientConnection; | |
| | | | |
| /** | | /** | |
| * ConnectionString handles parsing different ways to connect to mongo
and determining method | | * ConnectionString handles parsing different ways to connect to mongo
and determining method | |
| * samples: | | * samples: | |
| * server | | * server | |
| * server:port | | * server:port | |
| * foo/server:port,server:port SET | | * foo/server:port,server:port SET | |
| * server,server,server SYNC | | * server,server,server SYNC | |
| * Warning - you usually don't want
"SYNC", it's used | | * Warning - you usually don't want
"SYNC", it's used | |
| * for some special things such as s
harding config servers. | | * for some special things such as s
harding config servers. | |
| | | | |
| skipping to change at line 291 | | skipping to change at line 291 | |
| virtual DBClientBase* connect( const ConnectionString& c, | | virtual DBClientBase* connect( const ConnectionString& c, | |
| string& errmsg, | | string& errmsg, | |
| double socketTimeout ) = 0; | | double socketTimeout ) = 0; | |
| }; | | }; | |
| | | | |
| static void setConnectionHook( ConnectionHook* hook ){ | | static void setConnectionHook( ConnectionHook* hook ){ | |
| scoped_lock lk( _connectHookMutex ); | | scoped_lock lk( _connectHookMutex ); | |
| _connectHook = hook; | | _connectHook = hook; | |
| } | | } | |
| | | | |
|
| | | static ConnectionHook* getConnectionHook() { | |
| | | scoped_lock lk( _connectHookMutex ); | |
| | | return _connectHook; | |
| | | } | |
| | | | |
| private: | | private: | |
| | | | |
| void _fillServers( string s ); | | void _fillServers( string s ); | |
| void _finishInit(); | | void _finishInit(); | |
| | | | |
| ConnectionType _type; | | ConnectionType _type; | |
| vector<HostAndPort> _servers; | | vector<HostAndPort> _servers; | |
| string _string; | | string _string; | |
| string _setName; | | string _setName; | |
| | | | |
| | | | |
| skipping to change at line 564 | | skipping to change at line 569 | |
| Basically just invocations of connection.$cmd.findOne({...}); | | Basically just invocations of connection.$cmd.findOne({...}); | |
| */ | | */ | |
| class DBClientWithCommands : public DBClientInterface { | | class DBClientWithCommands : public DBClientInterface { | |
| set<string> _seenIndexes; | | set<string> _seenIndexes; | |
| public: | | public: | |
| /** controls how chatty the client is about network errors & such.
See log.h */ | | /** controls how chatty the client is about network errors & such.
See log.h */ | |
| int _logLevel; | | int _logLevel; | |
| | | | |
| DBClientWithCommands() : _logLevel(0), | | DBClientWithCommands() : _logLevel(0), | |
| _cachedAvailableOptions( (enum QueryOptions)0 ), | | _cachedAvailableOptions( (enum QueryOptions)0 ), | |
|
| _haveCachedAvailableOptions(false), | | _haveCachedAvailableOptions(false) { } | |
| _hasAuthentication(false) { } | | | |
| | | | |
| /** helper function. run a simple command where the command expres
sion is simply | | /** helper function. run a simple command where the command expres
sion is simply | |
| { command : 1 } | | { command : 1 } | |
| @param info -- where to put result object. may be null if call
er doesn't need that info | | @param info -- where to put result object. may be null if call
er doesn't need that info | |
| @param command -- command name | | @param command -- command name | |
| @return true if the command returned "ok". | | @return true if the command returned "ok". | |
| */ | | */ | |
| bool simpleCommand(const string &dbname, BSONObj *info, const strin
g &command); | | bool simpleCommand(const string &dbname, BSONObj *info, const strin
g &command); | |
| | | | |
| /** Run a database command. Database commands are represented as B
SON objects. Common database | | /** Run a database command. Database commands are represented as B
SON objects. Common database | |
| commands have prebuilt helper functions -- see below. If a hel
per is not available you can | | commands have prebuilt helper functions -- see below. If a hel
per is not available you can | |
|
| directly call runCommand. If _authTable has been set, will app | | directly call runCommand. | |
| end a BSON representation of | | | |
| that AuthenticationTable to the command object, unless an Authe | | | |
| nticationTable object has been | | | |
| passed to this method directly, in which case it will use that | | | |
| instead of _authTable. | | | |
| | | | |
| @param dbname database name. Use "admin" for global administra
tive commands. | | @param dbname database name. Use "admin" for global administra
tive commands. | |
| @param cmd the command object to execute. For example, { isma
ster : 1 } | | @param cmd the command object to execute. For example, { isma
ster : 1 } | |
| @param info the result object the database returns. Typically h
as { ok : ..., errmsg : ... } fields | | @param info the result object the database returns. Typically h
as { ok : ..., errmsg : ... } fields | |
| set. | | set. | |
| @param options see enum QueryOptions - normally not needed to r
un a command | | @param options see enum QueryOptions - normally not needed to r
un a command | |
| @param auth if set, the BSONObj representation will be appended
to the command object sent | | @param auth if set, the BSONObj representation will be appended
to the command object sent | |
| | | | |
| @return true if the command returned "ok". | | @return true if the command returned "ok". | |
| */ | | */ | |
| virtual bool runCommand(const string &dbname, const BSONObj& cmd, B
SONObj &info, | | virtual bool runCommand(const string &dbname, const BSONObj& cmd, B
SONObj &info, | |
|
| int options=0, const AuthenticationTable* a
uth = NULL); | | int options=0); | |
| | | | |
| /** Authorize access to a particular database. | | /** Authorize access to a particular database. | |
| Authentication is separate for each database on the server -- y
ou may authenticate for any | | Authentication is separate for each database on the server -- y
ou may authenticate for any | |
| number of databases on a single connection. | | number of databases on a single connection. | |
| The "admin" database is special and once authenticated provides
access to all databases on the | | The "admin" database is special and once authenticated provides
access to all databases on the | |
| server. | | server. | |
| @param digestPassword if password is plain text, set this
to true. otherwise assumed to be pre-digested | | @param digestPassword if password is plain text, set this
to true. otherwise assumed to be pre-digested | |
| @param[out] authLevel level of authentication for the giv
en user | | @param[out] authLevel level of authentication for the giv
en user | |
| @return true if successful | | @return true if successful | |
| */ | | */ | |
| | | | |
| skipping to change at line 859 | | skipping to change at line 861 | |
| */ | | */ | |
| list<string> getDatabaseNames(); | | list<string> getDatabaseNames(); | |
| | | | |
| /** | | /** | |
| get a list of all the current collections in db | | get a list of all the current collections in db | |
| */ | | */ | |
| list<string> getCollectionNames( const string& db ); | | list<string> getCollectionNames( const string& db ); | |
| | | | |
| bool exists( const string& ns ); | | bool exists( const string& ns ); | |
| | | | |
|
| virtual void setAuthenticationTable( const AuthenticationTable& aut | | | |
| h ); | | | |
| virtual void clearAuthenticationTable(); | | | |
| | | | |
| /** Create an index if it does not already exist. | | /** Create an index if it does not already exist. | |
| ensureIndex calls are remembered so it is safe/fast to call thi
s function many | | ensureIndex calls are remembered so it is safe/fast to call thi
s function many | |
| times in your code. | | times in your code. | |
| @param ns collection to be indexed | | @param ns collection to be indexed | |
| @param keys the "key pattern" for the index. e.g., { name : 1 } | | @param keys the "key pattern" for the index. e.g., { name : 1 } | |
| @param unique if true, indicates that key uniqueness should be e
nforced for this index | | @param unique if true, indicates that key uniqueness should be e
nforced for this index | |
| @param name if not specified, it will be created from the keys a
utomatically (which is recommended) | | @param name if not specified, it will be created from the keys a
utomatically (which is recommended) | |
| @param cache if set to false, the index cache for the connection
won't remember this call | | @param cache if set to false, the index cache for the connection
won't remember this call | |
| @param background build index in the background (see mongodb doc
s/wiki for details) | | @param background build index in the background (see mongodb doc
s/wiki for details) | |
| @param v index version. leave at default value. (unit tests set
this parameter.) | | @param v index version. leave at default value. (unit tests set
this parameter.) | |
| | | | |
| skipping to change at line 929 | | skipping to change at line 928 | |
| BSONObj _countCmd(const string &ns, const BSONObj& query, int optio
ns, int limit, int skip ); | | BSONObj _countCmd(const string &ns, const BSONObj& query, int optio
ns, int limit, int skip ); | |
| | | | |
| /** | | /** | |
| * Look up the options available on this client. Caches the answer
from | | * Look up the options available on this client. Caches the answer
from | |
| * _lookupAvailableOptions(), below. | | * _lookupAvailableOptions(), below. | |
| */ | | */ | |
| QueryOptions availableOptions(); | | QueryOptions availableOptions(); | |
| | | | |
| virtual QueryOptions _lookupAvailableOptions(); | | virtual QueryOptions _lookupAvailableOptions(); | |
| | | | |
|
| bool hasAuthenticationTable(); | | | |
| AuthenticationTable& getAuthenticationTable(); | | | |
| | | | |
| private: | | private: | |
| enum QueryOptions _cachedAvailableOptions; | | enum QueryOptions _cachedAvailableOptions; | |
| bool _haveCachedAvailableOptions; | | bool _haveCachedAvailableOptions; | |
|
| AuthenticationTable _authTable; | | | |
| bool _hasAuthentication; | | | |
| }; | | }; | |
| | | | |
| /** | | /** | |
| abstract class that implements the core db operations | | abstract class that implements the core db operations | |
| */ | | */ | |
| class DBClientBase : public DBClientWithCommands, public DBConnector { | | class DBClientBase : public DBClientWithCommands, public DBConnector { | |
| protected: | | protected: | |
| static AtomicInt64 ConnectionIdSequence; | | static AtomicInt64 ConnectionIdSequence; | |
| long long _connectionId; // unique connection id for this connectio
n | | long long _connectionId; // unique connection id for this connectio
n | |
| WriteConcern _writeConcern; | | WriteConcern _writeConcern; | |
| | | | |
| skipping to change at line 1138 | | skipping to change at line 1132 | |
| | | | |
| virtual unsigned long long query( boost::function<void(DBClientCurs
orBatchIterator &)> f, | | virtual unsigned long long query( boost::function<void(DBClientCurs
orBatchIterator &)> f, | |
| const string& ns, | | const string& ns, | |
| Query query, | | Query query, | |
| const BSONObj *fieldsToReturn, | | const BSONObj *fieldsToReturn, | |
| int queryOptions ); | | int queryOptions ); | |
| | | | |
| virtual bool runCommand(const string &dbname, | | virtual bool runCommand(const string &dbname, | |
| const BSONObj& cmd, | | const BSONObj& cmd, | |
| BSONObj &info, | | BSONObj &info, | |
|
| int options=0, | | int options=0); | |
| const AuthenticationTable* auth=NULL); | | | |
| | | | |
| /** | | /** | |
| @return true if this connection is currently in a failed state.
When autoreconnect is on, | | @return true if this connection is currently in a failed state.
When autoreconnect is on, | |
| a connection will transition back to an ok state after r
econnecting. | | a connection will transition back to an ok state after r
econnecting. | |
| */ | | */ | |
| bool isFailed() const { return _failed; } | | bool isFailed() const { return _failed; } | |
| | | | |
| MessagingPort& port() { verify(p); return *p; } | | MessagingPort& port() { verify(p); return *p; } | |
| | | | |
| string toStringLong() const { | | string toStringLong() const { | |
| | | | |
| skipping to change at line 1177 | | skipping to change at line 1170 | |
| virtual ConnectionString::ConnectionType type() const { return Conn
ectionString::MASTER; } | | virtual ConnectionString::ConnectionType type() const { return Conn
ectionString::MASTER; } | |
| void setSoTimeout(double timeout); | | void setSoTimeout(double timeout); | |
| double getSoTimeout() const { return _so_timeout; } | | double getSoTimeout() const { return _so_timeout; } | |
| | | | |
| virtual bool lazySupported() const { return true; } | | virtual bool lazySupported() const { return true; } | |
| | | | |
| static int getNumConnections() { | | static int getNumConnections() { | |
| return _numConnections; | | return _numConnections; | |
| } | | } | |
| | | | |
|
| | | /** | |
| | | * Primarily used for notifying the replica set client that the ser | |
| | | ver | |
| | | * it is talking to is not primary anymore. | |
| | | * | |
| | | * @param rsClient caller is responsible for managing the life of r | |
| | | sClient | |
| | | * and making sure that it lives longer than this object. | |
| | | * | |
| | | * Warning: This is only for internal use and will eventually be re | |
| | | moved in | |
| | | * the future. | |
| | | */ | |
| | | void setReplSetClientCallback(DBClientReplicaSet* rsClient); | |
| | | | |
| static void setLazyKillCursor( bool lazy ) { _lazyKillCursor = lazy
; } | | static void setLazyKillCursor( bool lazy ) { _lazyKillCursor = lazy
; } | |
| static bool getLazyKillCursor() { return _lazyKillCursor; } | | static bool getLazyKillCursor() { return _lazyKillCursor; } | |
| | | | |
| uint64_t getSockCreationMicroSec() const; | | uint64_t getSockCreationMicroSec() const; | |
| | | | |
| protected: | | protected: | |
| friend class SyncClusterConnection; | | friend class SyncClusterConnection; | |
| virtual void sayPiggyBack( Message &toSend ); | | virtual void sayPiggyBack( Message &toSend ); | |
| | | | |
| DBClientReplicaSet *clientSet; | | DBClientReplicaSet *clientSet; | |
| | | | |
| skipping to change at line 1207 | | skipping to change at line 1212 | |
| void checkConnection() { if( _failed ) _checkConnection(); } | | void checkConnection() { if( _failed ) _checkConnection(); } | |
| | | | |
| map< string, pair<string,string> > authCache; | | map< string, pair<string,string> > authCache; | |
| double _so_timeout; | | double _so_timeout; | |
| bool _connect( string& errmsg ); | | bool _connect( string& errmsg ); | |
| | | | |
| static AtomicUInt _numConnections; | | static AtomicUInt _numConnections; | |
| static bool _lazyKillCursor; // lazy means we piggy back kill curso
rs on next op | | static bool _lazyKillCursor; // lazy means we piggy back kill curso
rs on next op | |
| | | | |
| #ifdef MONGO_SSL | | #ifdef MONGO_SSL | |
|
| static SSLManager* sslManager(); | | SSLManager* sslManager(); | |
| static SSLManager* _sslManager; | | | |
| #endif | | #endif | |
| }; | | }; | |
| | | | |
| /** pings server to check if it's up | | /** pings server to check if it's up | |
| */ | | */ | |
| bool serverAlive( const string &uri ); | | bool serverAlive( const string &uri ); | |
| | | | |
| DBClientBase * createDirectClient(); | | DBClientBase * createDirectClient(); | |
| | | | |
| BSONElement getErrField( const BSONObj& result ); | | BSONElement getErrField( const BSONObj& result ); | |
| | | | |
End of changes. 12 change blocks. |
| 23 lines changed or deleted | | 26 lines changed or added | |
|
| dbhelpers.h | | dbhelpers.h | |
| | | | |
| skipping to change at line 107 | | skipping to change at line 107 | |
| /** | | /** | |
| * you have to lock | | * you have to lock | |
| * you do not have to have Context set | | * you do not have to have Context set | |
| * o has to have an _id field or will assert | | * o has to have an _id field or will assert | |
| */ | | */ | |
| static void upsert( const string& ns , const BSONObj& o, bool fromM
igrate = false ); | | static void upsert( const string& ns , const BSONObj& o, bool fromM
igrate = false ); | |
| | | | |
| /** You do not need to set the database before calling. | | /** You do not need to set the database before calling. | |
| @return true if collection is empty. | | @return true if collection is empty. | |
| */ | | */ | |
|
| static bool isEmpty(const char *ns, bool doAuth=true); | | static bool isEmpty(const char *ns); | |
| | | | |
| // TODO: this should be somewhere else probably | | // TODO: this should be somewhere else probably | |
| /* Takes object o, and returns a new object with the | | /* Takes object o, and returns a new object with the | |
|
| * same field elements but the names stripped out. Also, | | * same field elements but the names stripped out. | |
| * fills in "key" with an ascending keyPattern that matches o | | | |
| * Example: | | * Example: | |
|
| * o = {a : 5 , b : 6} --> | | * o = {a : 5 , b : 6} --> {"" : 5, "" : 6} | |
| * sets key= {a : 1, b :1}, returns {"" : 5, "" : 6} | | | |
| */ | | */ | |
|
| static BSONObj toKeyFormat( const BSONObj& o , BSONObj& key ); | | static BSONObj toKeyFormat( const BSONObj& o ); | |
| | | | |
|
| /* Takes a BSONObj indicating the min or max boundary of a range, | | /* Takes object o, and infers an ascending keyPattern with the same | |
| * and a keyPattern corresponding to an index that is useful | | fields as o | |
| * for locating items in the range, and returns an "extension" | | * Example: | |
| * of the bound, modified to fit the given pattern. In other words | | * o = {a : 5 , b : 6} --> {a : 1 , b : 1 } | |
| , | | | |
| * it appends MinKey or MaxKey values to the bound, so that the ext | | | |
| ension | | | |
| * has the same number of fields as keyPattern. | | | |
| * minOrMax should be -1/+1 to indicate whether the extension | | | |
| * corresponds to the min or max bound for the range. | | | |
| * Also, strips out the field names to put the bound in key format. | | | |
| * Examples: | | | |
| * {a : 55}, {a :1}, -1 --> {"" : 55} | | | |
| * {a : 55}, {a : 1, b : 1}, -1 -> {"" : 55, "" : minKey} | | | |
| * {a : 55}, {a : 1, b : 1}, 1 -> {"" : 55, "" : maxKey} | | | |
| * {a : 55}, {a : 1, b : -1}, -1 -> {"" : 55, "" : maxKey} | | | |
| * {a : 55}, {a : 1, b : -1}, 1 -> {"" : 55, "" : minKey} | | | |
| * | | | |
| * This function is useful for modifying chunk ranges in sharding, | | | |
| * when the shard key is a prefix of the index actually used | | | |
| * (also useful when the shard key is equal to the index used, | | | |
| * since it strips out the field names). | | | |
| */ | | */ | |
|
| static BSONObj modifiedRangeBound( const BSONObj& bound , | | static BSONObj inferKeyPattern( const BSONObj& o ); | |
| const BSONObj& keyPattern , | | | |
| int minOrMax ); | | | |
| | | | |
| class RemoveCallback { | | class RemoveCallback { | |
| public: | | public: | |
| virtual ~RemoveCallback() {} | | virtual ~RemoveCallback() {} | |
| virtual void goingToDelete( const BSONObj& o ) = 0; | | virtual void goingToDelete( const BSONObj& o ) = 0; | |
| }; | | }; | |
| | | | |
| /** | | /** | |
| * Takes a range, specified by a min and max, and an index, specifi
ed by | | * Takes a range, specified by a min and max, and an index, specifi
ed by | |
| * keyPattern, and removes all the documents in that range found by
iterating | | * keyPattern, and removes all the documents in that range found by
iterating | |
| * over the given index. Caller is responsible for insuring that mi
n/max are | | * over the given index. Caller is responsible for insuring that mi
n/max are | |
| * compatible with the given keyPattern (e.g min={a:100} is compati
ble with | | * compatible with the given keyPattern (e.g min={a:100} is compati
ble with | |
| * keyPattern={a:1,b:1} since it can be extended to {a:100,b:minKey
}, but | | * keyPattern={a:1,b:1} since it can be extended to {a:100,b:minKey
}, but | |
| * min={b:100} is not compatible). | | * min={b:100} is not compatible). | |
| * | | * | |
| * Caller must hold a write lock on 'ns' | | * Caller must hold a write lock on 'ns' | |
| * | | * | |
| * Does oplog the individual document deletions. | | * Does oplog the individual document deletions. | |
|
| | | * // TODO: Refactor this mechanism, it is growing too large | |
| */ | | */ | |
| static long long removeRange( const string& ns , | | static long long removeRange( const string& ns , | |
| const BSONObj& min , | | const BSONObj& min , | |
| const BSONObj& max , | | const BSONObj& max , | |
| const BSONObj& keyPattern , | | const BSONObj& keyPattern , | |
| bool maxInclusive = false , | | bool maxInclusive = false , | |
| bool secondaryThrottle = false , | | bool secondaryThrottle = false , | |
| RemoveCallback * callback = 0, | | RemoveCallback * callback = 0, | |
|
| bool fromMigrate = false ); | | bool fromMigrate = false, | |
| | | bool onlyRemoveOrphanedDocs = false ) | |
| | | ; | |
| | | | |
| /** | | /** | |
| * Remove all documents from a collection. | | * Remove all documents from a collection. | |
| * You do not need to set the database before calling. | | * You do not need to set the database before calling. | |
| * Does not oplog the operation. | | * Does not oplog the operation. | |
| */ | | */ | |
| static void emptyCollection(const char *ns); | | static void emptyCollection(const char *ns); | |
| | | | |
| }; | | }; | |
| | | | |
| | | | |
End of changes. 8 change blocks. |
| 32 lines changed or deleted | | 13 lines changed or added | |
|
| document.h | | document.h | |
| | | | |
| skipping to change at line 112 | | skipping to change at line 112 | |
| * the fields in order. The comparison is done in roughly the sam
e way | | * the fields in order. The comparison is done in roughly the sam
e way | |
| * as strings are compared, but comparing one field at a time inst
ead | | * as strings are compared, but comparing one field at a time inst
ead | |
| * of one character at a time. | | * of one character at a time. | |
| * | | * | |
| * @returns an integer less than zero, zero, or an integer greater
than | | * @returns an integer less than zero, zero, or an integer greater
than | |
| * zero, depending on whether lhs < rhs, lhs == rhs, or l
hs > rhs | | * zero, depending on whether lhs < rhs, lhs == rhs, or l
hs > rhs | |
| * Warning: may return values other than -1, 0, or 1 | | * Warning: may return values other than -1, 0, or 1 | |
| */ | | */ | |
| static int compare(const Document& lhs, const Document& rhs); | | static int compare(const Document& lhs, const Document& rhs); | |
| | | | |
|
| string toString() const; // TODO support streams | | string toString() const; | |
| | | | |
| | | friend | |
| | | ostream& operator << (ostream& out, const Document& doc) { return o | |
| | | ut << doc.toString(); } | |
| | | | |
| /** Calculate a hash value. | | /** Calculate a hash value. | |
| * | | * | |
| * Meant to be used to create composite hashes suitable for | | * Meant to be used to create composite hashes suitable for | |
| * hashed container classes such as unordered_map. | | * hashed container classes such as unordered_map. | |
| */ | | */ | |
| void hash_combine(size_t &seed) const; | | void hash_combine(size_t &seed) const; | |
| | | | |
| /// Add this document to the BSONObj under construction with the gi
ven BSONObjBuilder. | | /// Add this document to the BSONObj under construction with the gi
ven BSONObjBuilder. | |
| void toBson(BSONObjBuilder *pBsonObjBuilder) const; | | void toBson(BSONObjBuilder *pBsonObjBuilder) const; | |
| | | | |
|
| | | // Support BSONObjBuilder and BSONArrayBuilder "stream" API | |
| | | friend BSONObjBuilder& operator << (BSONObjBuilderValueStream& buil | |
| | | der, const Document& d); | |
| | | | |
| /** Return the abstract Position of a field, suitable to pass to op
erator[] or getField(). | | /** Return the abstract Position of a field, suitable to pass to op
erator[] or getField(). | |
| * This can potentially save time if you need to refer to a field
multiple times. | | * This can potentially save time if you need to refer to a field
multiple times. | |
| */ | | */ | |
| Position positionOf(StringData fieldName) const { return storage().
findField(fieldName); } | | Position positionOf(StringData fieldName) const { return storage().
findField(fieldName); } | |
| | | | |
| /** Clone a document. | | /** Clone a document. | |
| * | | * | |
| * This should only be called by MutableDocument and tests | | * This should only be called by MutableDocument and tests | |
| * | | * | |
| * The new document shares all the fields' values with the origina
l. | | * The new document shares all the fields' values with the origina
l. | |
| | | | |
| skipping to change at line 281 | | skipping to change at line 287 | |
| /// Update field by Position. Must already be a valid Position. | | /// Update field by Position. Must already be a valid Position. | |
| MutableValue operator[] (Position pos) { return getField(pos); } | | MutableValue operator[] (Position pos) { return getField(pos); } | |
| void setField(Position pos, const Value& val) { getField(pos) = val
; } | | void setField(Position pos, const Value& val) { getField(pos) = val
; } | |
| MutableValue getField(Position pos) { | | MutableValue getField(Position pos) { | |
| return MutableValue(storage().getField(pos).val); | | return MutableValue(storage().getField(pos).val); | |
| } | | } | |
| | | | |
| /// Logically remove a field. Note that memory usage does not decre
ase. | | /// Logically remove a field. Note that memory usage does not decre
ase. | |
| void remove(StringData key) { getField(key) = Value(); } | | void remove(StringData key) { getField(key) = Value(); } | |
| | | | |
|
| /// Takes positions vector from Document::getNestedField. | | /** Gets/Sets a nested field given a path. | |
| | | * | |
| | | * All fields along path are created as empty Documents if they do | |
| | | n't exist | |
| | | * or are any other type. | |
| | | */ | |
| | | MutableValue getNestedField(const FieldPath& dottedField); | |
| | | void setNestedField(const FieldPath& dottedField, const Value& val) | |
| | | { | |
| | | getNestedField(dottedField) = val; | |
| | | } | |
| | | | |
| | | /// Takes positions vector from Document::getNestedField. All field | |
| | | s in path must exist. | |
| MutableValue getNestedField(const vector<Position>& positions); | | MutableValue getNestedField(const vector<Position>& positions); | |
| void setNestedField(const vector<Position>& positions, const Value&
val) { | | void setNestedField(const vector<Position>& positions, const Value&
val) { | |
| getNestedField(positions) = val; | | getNestedField(positions) = val; | |
| } | | } | |
| | | | |
| /** Convert to a read-only document and release reference. | | /** Convert to a read-only document and release reference. | |
| * | | * | |
| * Call this to indicate that you are done with this Document and
will | | * Call this to indicate that you are done with this Document and
will | |
| * not be making further changes from this MutableDocument. | | * not be making further changes from this MutableDocument. | |
| * | | * | |
| * TODO: there are some optimizations that may make sense at freez
e time. | | * TODO: there are some optimizations that may make sense at freez
e time. | |
| */ | | */ | |
| Document freeze() { | | Document freeze() { | |
|
| Document ret(storagePtr()); | | // This essentially moves _storage into a new Document by way o | |
| reset(NULL); | | f temp. | |
| | | Document ret; | |
| | | intrusive_ptr<const DocumentStorage> temp (storagePtr(), /*inc_ | |
| | | ref_count=*/false); | |
| | | temp.swap(ret._storage); | |
| | | _storage = NULL; | |
| return ret; | | return ret; | |
| } | | } | |
| | | | |
| /** Borrow a readable reference to this Document. | | /** Borrow a readable reference to this Document. | |
| * | | * | |
| * Note that unlike freeze(), this indicates intention to continue | | * Note that unlike freeze(), this indicates intention to continue | |
| * modifying this document. The returned Document will not observe | | * modifying this document. The returned Document will not observe | |
| * future changes to this MutableDocument. | | * future changes to this MutableDocument. | |
| */ | | */ | |
| Document peek() { | | Document peek() { | |
| | | | |
| skipping to change at line 343 | | skipping to change at line 362 | |
| } | | } | |
| DocumentStorage& newStorage() { | | DocumentStorage& newStorage() { | |
| reset(new DocumentStorage); | | reset(new DocumentStorage); | |
| return const_cast<DocumentStorage&>(*storagePtr()); | | return const_cast<DocumentStorage&>(*storagePtr()); | |
| } | | } | |
| DocumentStorage& clonedStorage() { | | DocumentStorage& clonedStorage() { | |
| reset(storagePtr()->clone().get()); | | reset(storagePtr()->clone().get()); | |
| return const_cast<DocumentStorage&>(*storagePtr()); | | return const_cast<DocumentStorage&>(*storagePtr()); | |
| } | | } | |
| | | | |
|
| MutableValue getNestedFieldHelper(MutableDocument& md, | | // recursive helpers for same-named public methods | |
| const vector<Position>& positions | | MutableValue getNestedFieldHelper(const FieldPath& dottedField, siz | |
| , | | e_t level); | |
| size_t level); | | MutableValue getNestedFieldHelper(const vector<Position>& positions | |
| | | , size_t level); | |
| | | | |
| // this should only be called by storage methods and peek/freeze | | // this should only be called by storage methods and peek/freeze | |
| const DocumentStorage* storagePtr() const { | | const DocumentStorage* storagePtr() const { | |
| dassert(!_storage || typeid(*_storage) == typeid(const Document
Storage)); | | dassert(!_storage || typeid(*_storage) == typeid(const Document
Storage)); | |
| return static_cast<const DocumentStorage*>(_storage); | | return static_cast<const DocumentStorage*>(_storage); | |
| } | | } | |
| | | | |
| // These are both const to prevent modifications bypassing storage(
) method. | | // These are both const to prevent modifications bypassing storage(
) method. | |
| // They always point to NULL or an object with dynamic type Documen
tStorage. | | // They always point to NULL or an object with dynamic type Documen
tStorage. | |
| const RefCountable* _storageHolder; // Only used in constructors an
d destructor | | const RefCountable* _storageHolder; // Only used in constructors an
d destructor | |
| | | | |
End of changes. 5 change blocks. |
| 8 lines changed or deleted | | 35 lines changed or added | |
|
| document_internal.h | | document_internal.h | |
| | | | |
| skipping to change at line 58 | | skipping to change at line 58 | |
| | | | |
| #pragma pack(1) | | #pragma pack(1) | |
| /** This is how values are stored in the DocumentStorage buffer | | /** This is how values are stored in the DocumentStorage buffer | |
| * Internal class. Consumers shouldn't care about this. | | * Internal class. Consumers shouldn't care about this. | |
| */ | | */ | |
| class ValueElement : boost::noncopyable { | | class ValueElement : boost::noncopyable { | |
| public: | | public: | |
| Value val; | | Value val; | |
| Position nextCollision; // Position of next field with same hashBuc
ket | | Position nextCollision; // Position of next field with same hashBuc
ket | |
| const int nameLen; // doesn't include '\0' | | const int nameLen; // doesn't include '\0' | |
|
| const char name[1]; // pointer to start of name | | const char _name[1]; // pointer to start of name (use nameSD instea
d) | |
| | | | |
| ValueElement* next() { | | ValueElement* next() { | |
| return align(plusBytes(sizeof(ValueElement) + nameLen)); | | return align(plusBytes(sizeof(ValueElement) + nameLen)); | |
| } | | } | |
| | | | |
| const ValueElement* next() const { | | const ValueElement* next() const { | |
| return align(plusBytes(sizeof(ValueElement) + nameLen)); | | return align(plusBytes(sizeof(ValueElement) + nameLen)); | |
| } | | } | |
| | | | |
|
| StringData nameSD() const { return StringData(name, nameLen); } | | StringData nameSD() const { return StringData(_name, nameLen); } | |
| | | | |
| // helpers for doing pointer arithmetic with this class | | // helpers for doing pointer arithmetic with this class | |
| // Note: These don't dereference 'this' so they are safe to use wit
h NULL | | // Note: These don't dereference 'this' so they are safe to use wit
h NULL | |
| char* ptr() { return reinterpret_cast<char*>(this); } | | char* ptr() { return reinterpret_cast<char*>(this); } | |
| const char* ptr() const { return reinterpret_cast<const char*>(this
); } | | const char* ptr() const { return reinterpret_cast<const char*>(this
); } | |
| const ValueElement* plusBytes(size_t bytes) const { | | const ValueElement* plusBytes(size_t bytes) const { | |
| return reinterpret_cast<const ValueElement*>(ptr() + bytes); | | return reinterpret_cast<const ValueElement*>(ptr() + bytes); | |
| } | | } | |
| ValueElement* plusBytes(size_t bytes) { | | ValueElement* plusBytes(size_t bytes) { | |
| return reinterpret_cast<ValueElement*>(ptr() + bytes); | | return reinterpret_cast<ValueElement*>(ptr() + bytes); | |
| | | | |
| skipping to change at line 111 | | skipping to change at line 111 | |
| class DocumentStorageIterator { | | class DocumentStorageIterator { | |
| public: | | public: | |
| // DocumentStorage::iterator() and iteratorAll() are easier to use | | // DocumentStorage::iterator() and iteratorAll() are easier to use | |
| DocumentStorageIterator(const ValueElement* first, | | DocumentStorageIterator(const ValueElement* first, | |
| const ValueElement* end, | | const ValueElement* end, | |
| bool includeMissing) | | bool includeMissing) | |
| : _first(first) | | : _first(first) | |
| , _it(first) | | , _it(first) | |
| , _end(end) | | , _end(end) | |
| , _includeMissing(includeMissing) { | | , _includeMissing(includeMissing) { | |
|
| skipMissing(); | | if (!_includeMissing) | |
| | | skipMissing(); | |
| } | | } | |
| | | | |
| bool atEnd() const { return _it == _end; } | | bool atEnd() const { return _it == _end; } | |
| | | | |
| const ValueElement& get() const { return *_it; } | | const ValueElement& get() const { return *_it; } | |
| | | | |
| Position position() const { return Position(_it->ptr() - _first->pt
r()); } | | Position position() const { return Position(_it->ptr() - _first->pt
r()); } | |
| | | | |
| void advance() { | | void advance() { | |
| advanceOne(); | | advanceOne(); | |
|
| skipMissing(); | | if (!_includeMissing) | |
| | | skipMissing(); | |
| } | | } | |
| | | | |
| const ValueElement* operator-> () { return _it; } | | const ValueElement* operator-> () { return _it; } | |
| const ValueElement& operator* () { return *_it; } | | const ValueElement& operator* () { return *_it; } | |
| | | | |
| private: | | private: | |
| void advanceOne() { | | void advanceOne() { | |
| _it = _it->next(); | | _it = _it->next(); | |
| } | | } | |
| | | | |
| void skipMissing() { | | void skipMissing() { | |
|
| if (!_includeMissing) { | | while (!atEnd() && _it->val.missing()) { | |
| while (!atEnd() && _it->val.missing()) { | | advanceOne(); | |
| advanceOne(); | | | |
| } | | | |
| } | | } | |
| } | | } | |
| | | | |
| const ValueElement* _first; | | const ValueElement* _first; | |
| const ValueElement* _it; | | const ValueElement* _it; | |
| const ValueElement* _end; | | const ValueElement* _end; | |
| bool _includeMissing; | | bool _includeMissing; | |
| }; | | }; | |
| | | | |
| /// Storage class used by both Document and MutableDocument | | /// Storage class used by both Document and MutableDocument | |
| | | | |
| skipping to change at line 251 | | skipping to change at line 251 | |
| | | | |
| /// rehash on buffer growth if load-factor > .5 (attempt to keep lf
< 1 when full) | | /// rehash on buffer growth if load-factor > .5 (attempt to keep lf
< 1 when full) | |
| bool needRehash() const { return _numFields*2 > hashTabBuckets(); } | | bool needRehash() const { return _numFields*2 > hashTabBuckets(); } | |
| | | | |
| /// Initialize empty hash table | | /// Initialize empty hash table | |
| void hashTabInit() { memset(_hashTab, -1, hashTabBytes()); } | | void hashTabInit() { memset(_hashTab, -1, hashTabBytes()); } | |
| | | | |
| static unsigned hashKey(StringData name) { | | static unsigned hashKey(StringData name) { | |
| // TODO consider FNV-1a once we have a better benchmark corpus | | // TODO consider FNV-1a once we have a better benchmark corpus | |
| unsigned out; | | unsigned out; | |
|
| MurmurHash3_x86_32(name.data(), name.size(), 0, &out); | | MurmurHash3_x86_32(name.rawData(), name.size(), 0, &out); | |
| return out; | | return out; | |
| } | | } | |
| | | | |
| unsigned bucketForKey(StringData name) const { | | unsigned bucketForKey(StringData name) const { | |
| return hashKey(name) & _hashTabMask; | | return hashKey(name) & _hashTabMask; | |
| } | | } | |
| | | | |
| /// Adds all fields to the hash table | | /// Adds all fields to the hash table | |
| void rehash() { | | void rehash() { | |
| hashTabInit(); | | hashTabInit(); | |
| | | | |
End of changes. 6 change blocks. |
| 9 lines changed or deleted | | 9 lines changed or added | |
|
| document_source.h | | document_source.h | |
| | | | |
| skipping to change at line 41 | | skipping to change at line 41 | |
| #include "mongo/s/shard.h" | | #include "mongo/s/shard.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| class Accumulator; | | class Accumulator; | |
| class Cursor; | | class Cursor; | |
| class Document; | | class Document; | |
| class Expression; | | class Expression; | |
| class ExpressionContext; | | class ExpressionContext; | |
| class ExpressionFieldPath; | | class ExpressionFieldPath; | |
| class ExpressionObject; | | class ExpressionObject; | |
|
| | | class DocumentSourceLimit; | |
| class Matcher; | | class Matcher; | |
| | | | |
| class DocumentSource : | | class DocumentSource : | |
| public IntrusiveCounterUnsigned, | | public IntrusiveCounterUnsigned, | |
| public StringWriter { | | public StringWriter { | |
| public: | | public: | |
| virtual ~DocumentSource(); | | virtual ~DocumentSource(); | |
| | | | |
| // virtuals from StringWriter | | // virtuals from StringWriter | |
| virtual void writeString(stringstream &ss) const; | | virtual void writeString(stringstream &ss) const; | |
| | | | |
| skipping to change at line 182 | | skipping to change at line 183 | |
| */ | | */ | |
| virtual GetDepsReturn getDependencies(set<string>& deps) const { | | virtual GetDepsReturn getDependencies(set<string>& deps) const { | |
| return NOT_SUPPORTED; | | return NOT_SUPPORTED; | |
| } | | } | |
| | | | |
| /** This takes dependencies from getDependencies and | | /** This takes dependencies from getDependencies and | |
| * returns a projection that includes all of them | | * returns a projection that includes all of them | |
| */ | | */ | |
| static BSONObj depsToProjection(const set<string>& deps); | | static BSONObj depsToProjection(const set<string>& deps); | |
| | | | |
|
| | | /** These functions take the same input as depsToProjection but are | |
| | | able to | |
| | | * produce a Document from a BSONObj with the needed fields much f | |
| | | aster. | |
| | | */ | |
| | | typedef Document ParsedDeps; // See implementation for structure | |
| | | static ParsedDeps parseDeps(const set<string>& deps); | |
| | | static Document documentFromBsonWithDeps(const BSONObj& object, con | |
| | | st ParsedDeps& deps); | |
| | | | |
| /** | | /** | |
| Add the DocumentSource to the array builder. | | Add the DocumentSource to the array builder. | |
| | | | |
| The default implementation calls sourceToBson() in order to | | The default implementation calls sourceToBson() in order to | |
| convert the inner part of the object which will be added to the | | convert the inner part of the object which will be added to the | |
| array being built here. | | array being built here. | |
| | | | |
|
| | | A subclass may choose to overwrite this rather than addToBsonArra | |
| | | y | |
| | | if it should output multiple stages. | |
| | | | |
| @param pBuilder the array builder to add the operation to. | | @param pBuilder the array builder to add the operation to. | |
| @param explain create explain output | | @param explain create explain output | |
| */ | | */ | |
|
| virtual void addToBsonArray(BSONArrayBuilder *pBuilder, | | virtual void addToBsonArray(BSONArrayBuilder *pBuilder, bool explai | |
| bool explain = false) const; | | n=false) const; | |
| | | | |
| protected: | | protected: | |
| /** | | /** | |
| Base constructor. | | Base constructor. | |
| */ | | */ | |
| DocumentSource(const intrusive_ptr<ExpressionContext> &pExpCtx); | | DocumentSource(const intrusive_ptr<ExpressionContext> &pExpCtx); | |
| | | | |
| /** | | /** | |
| Create an object that represents the document source. The object | | Create an object that represents the document source. The object | |
| will have a single field whose name is the source's name. This | | will have a single field whose name is the source's name. This | |
| | | | |
| skipping to change at line 432 | | skipping to change at line 442 | |
| | | | |
| This should be captured after any optimizations are applied to | | This should be captured after any optimizations are applied to | |
| the pipeline so that it reflects what is really used. | | the pipeline so that it reflects what is really used. | |
| | | | |
| This gets used for explain output. | | This gets used for explain output. | |
| | | | |
| @param pBsonObj the sort to record | | @param pBsonObj the sort to record | |
| */ | | */ | |
| void setSort(const shared_ptr<BSONObj> &pBsonObj); | | void setSort(const shared_ptr<BSONObj> &pBsonObj); | |
| | | | |
|
| void setProjection(BSONObj projection); | | void setProjection(const BSONObj& projection, const ParsedDeps& dep
s); | |
| protected: | | protected: | |
| // virtuals from DocumentSource | | // virtuals from DocumentSource | |
| virtual void sourceToBson(BSONObjBuilder *pBuilder, bool explain) c
onst; | | virtual void sourceToBson(BSONObjBuilder *pBuilder, bool explain) c
onst; | |
| | | | |
| private: | | private: | |
| DocumentSourceCursor( | | DocumentSourceCursor( | |
| const shared_ptr<CursorWithContext>& cursorWithContext, | | const shared_ptr<CursorWithContext>& cursorWithContext, | |
| const intrusive_ptr<ExpressionContext> &pExpCtx); | | const intrusive_ptr<ExpressionContext> &pExpCtx); | |
| | | | |
| void findNext(); | | void findNext(); | |
| | | | |
| skipping to change at line 458 | | skipping to change at line 468 | |
| string ns; // namespace | | string ns; // namespace | |
| | | | |
| /* | | /* | |
| The bson dependencies must outlive the Cursor wrapped by this | | The bson dependencies must outlive the Cursor wrapped by this | |
| source. Therefore, bson dependencies must appear before pCursor | | source. Therefore, bson dependencies must appear before pCursor | |
| in order cause its destructor to be called *after* pCursor's. | | in order cause its destructor to be called *after* pCursor's. | |
| */ | | */ | |
| shared_ptr<BSONObj> pQuery; | | shared_ptr<BSONObj> pQuery; | |
| shared_ptr<BSONObj> pSort; | | shared_ptr<BSONObj> pSort; | |
| shared_ptr<Projection> _projection; // shared with pClientCursor | | shared_ptr<Projection> _projection; // shared with pClientCursor | |
|
| | | ParsedDeps _dependencies; | |
| | | | |
| shared_ptr<CursorWithContext> _cursorWithContext; | | shared_ptr<CursorWithContext> _cursorWithContext; | |
| | | | |
| ClientCursor::Holder& cursor(); | | ClientCursor::Holder& cursor(); | |
| const ShardChunkManager* chunkMgr() { return _cursorWithContext->_c
hunkMgr.get(); } | | const ShardChunkManager* chunkMgr() { return _cursorWithContext->_c
hunkMgr.get(); } | |
| | | | |
| bool canUseCoveredIndex(); | | bool canUseCoveredIndex(); | |
| | | | |
| /* | | /* | |
| Yield the cursor sometimes. | | Yield the cursor sometimes. | |
| | | | |
| skipping to change at line 597 | | skipping to change at line 608 | |
| class DocumentSourceGroup : | | class DocumentSourceGroup : | |
| public SplittableDocumentSource { | | public SplittableDocumentSource { | |
| public: | | public: | |
| // virtuals from DocumentSource | | // virtuals from DocumentSource | |
| virtual ~DocumentSourceGroup(); | | virtual ~DocumentSourceGroup(); | |
| virtual bool eof(); | | virtual bool eof(); | |
| virtual bool advance(); | | virtual bool advance(); | |
| virtual const char *getSourceName() const; | | virtual const char *getSourceName() const; | |
| virtual Document getCurrent(); | | virtual Document getCurrent(); | |
| virtual GetDepsReturn getDependencies(set<string>& deps) const; | | virtual GetDepsReturn getDependencies(set<string>& deps) const; | |
|
| | | virtual void dispose(); | |
| | | | |
| /** | | /** | |
| Create a new grouping DocumentSource. | | Create a new grouping DocumentSource. | |
| | | | |
| @param pExpCtx the expression context for the pipeline | | @param pExpCtx the expression context for the pipeline | |
| @returns the DocumentSource | | @returns the DocumentSource | |
| */ | | */ | |
| static intrusive_ptr<DocumentSourceGroup> create( | | static intrusive_ptr<DocumentSourceGroup> create( | |
| const intrusive_ptr<ExpressionContext> &pExpCtx); | | const intrusive_ptr<ExpressionContext> &pExpCtx); | |
| | | | |
| | | | |
| skipping to change at line 698 | | skipping to change at line 710 | |
| These three vectors parallel each other. | | These three vectors parallel each other. | |
| */ | | */ | |
| vector<string> vFieldName; | | vector<string> vFieldName; | |
| vector<intrusive_ptr<Accumulator> (*)( | | vector<intrusive_ptr<Accumulator> (*)( | |
| const intrusive_ptr<ExpressionContext> &)> vpAccumulatorFactory
; | | const intrusive_ptr<ExpressionContext> &)> vpAccumulatorFactory
; | |
| vector<intrusive_ptr<Expression> > vpExpression; | | vector<intrusive_ptr<Expression> > vpExpression; | |
| | | | |
| Document makeDocument(const GroupsType::iterator &rIter); | | Document makeDocument(const GroupsType::iterator &rIter); | |
| | | | |
| GroupsType::iterator groupsIterator; | | GroupsType::iterator groupsIterator; | |
|
| Document pCurrent; | | | |
| }; | | }; | |
| | | | |
| class DocumentSourceMatch : | | class DocumentSourceMatch : | |
| public DocumentSourceFilterBase { | | public DocumentSourceFilterBase { | |
| public: | | public: | |
| // virtuals from DocumentSource | | // virtuals from DocumentSource | |
| virtual ~DocumentSourceMatch(); | | virtual ~DocumentSourceMatch(); | |
| virtual const char *getSourceName() const; | | virtual const char *getSourceName() const; | |
| | | | |
| /** | | /** | |
| | | | |
| skipping to change at line 840 | | skipping to change at line 851 | |
| | | | |
| class DocumentSourceSort : | | class DocumentSourceSort : | |
| public SplittableDocumentSource { | | public SplittableDocumentSource { | |
| public: | | public: | |
| // virtuals from DocumentSource | | // virtuals from DocumentSource | |
| virtual ~DocumentSourceSort(); | | virtual ~DocumentSourceSort(); | |
| virtual bool eof(); | | virtual bool eof(); | |
| virtual bool advance(); | | virtual bool advance(); | |
| virtual const char *getSourceName() const; | | virtual const char *getSourceName() const; | |
| virtual Document getCurrent(); | | virtual Document getCurrent(); | |
|
| | | virtual void addToBsonArray(BSONArrayBuilder *pBuilder, bool explai | |
| virtual GetDepsReturn getDependencies(set<string>& deps) const; | | n=false) const; | |
| | | | |
| /* | | | |
| TODO | | | |
| Adjacent sorts should reduce to the last sort. | | | |
| virtual bool coalesce(const intrusive_ptr<DocumentSource> &pNextSou
rce); | | virtual bool coalesce(const intrusive_ptr<DocumentSource> &pNextSou
rce); | |
|
| */ | | virtual void dispose(); | |
| | | | |
| /** | | | |
| Create a new sorting DocumentSource. | | | |
| | | | |
|
| @param pExpCtx the expression context for the pipeline | | virtual GetDepsReturn getDependencies(set<string>& deps) const; | |
| @returns the DocumentSource | | | |
| */ | | | |
| static intrusive_ptr<DocumentSourceSort> create( | | | |
| const intrusive_ptr<ExpressionContext> &pExpCtx); | | | |
| | | | |
| // Virtuals for SplittableDocumentSource | | // Virtuals for SplittableDocumentSource | |
|
| // All work for sort is done in router currently | | // All work for sort is done in router currently if there is no lim | |
| // TODO: do partial sorts on the shards then merge in the router | | it. | |
| // Not currently possible due to DocumentSource's cursor-like | | // If there is a limit, the $sort/$limit combination is performed o | |
| interface | | n the | |
| virtual intrusive_ptr<DocumentSource> getShardSource() { return NUL | | // shards, then the results are resorted and limited on mongos | |
| L; } | | virtual intrusive_ptr<DocumentSource> getShardSource() { return lim | |
| | | itSrc ? this : NULL; } | |
| virtual intrusive_ptr<DocumentSource> getRouterSource() { return th
is; } | | virtual intrusive_ptr<DocumentSource> getRouterSource() { return th
is; } | |
| | | | |
| /** | | /** | |
| Add sort key field. | | Add sort key field. | |
| | | | |
| Adds a sort key field to the key being built up. A concatenated | | Adds a sort key field to the key being built up. A concatenated | |
| key is built up by calling this repeatedly. | | key is built up by calling this repeatedly. | |
| | | | |
| @param fieldPath the field path to the key component | | @param fieldPath the field path to the key component | |
| @param ascending if true, use the key for an ascending sort, | | @param ascending if true, use the key for an ascending sort, | |
| | | | |
| skipping to change at line 900 | | skipping to change at line 899 | |
| element named $group. | | element named $group. | |
| | | | |
| @param pBsonElement the BSONELement that defines the group | | @param pBsonElement the BSONELement that defines the group | |
| @param pExpCtx the expression context for the pipeline | | @param pExpCtx the expression context for the pipeline | |
| @returns the grouping DocumentSource | | @returns the grouping DocumentSource | |
| */ | | */ | |
| static intrusive_ptr<DocumentSource> createFromBson( | | static intrusive_ptr<DocumentSource> createFromBson( | |
| BSONElement *pBsonElement, | | BSONElement *pBsonElement, | |
| const intrusive_ptr<ExpressionContext> &pExpCtx); | | const intrusive_ptr<ExpressionContext> &pExpCtx); | |
| | | | |
|
| static const char sortName[]; | | /// Create a DocumentSourceSort with a given sort and (optional) li | |
| | | mit | |
| | | static intrusive_ptr<DocumentSourceSort> create( | |
| | | const intrusive_ptr<ExpressionContext> &pExpCtx, | |
| | | BSONObj sortOrder, | |
| | | long long limit=-1); | |
| | | | |
|
| | | /// returns -1 for no limit | |
| | | long long getLimit() const; | |
| | | | |
| | | intrusive_ptr<DocumentSourceLimit> getLimitSrc() const { return lim | |
| | | itSrc; } | |
| | | | |
| | | static const char sortName[]; | |
| protected: | | protected: | |
| // virtuals from DocumentSource | | // virtuals from DocumentSource | |
|
| virtual void sourceToBson(BSONObjBuilder *pBuilder, bool explain) c | | virtual void sourceToBson(BSONObjBuilder *pBuilder, bool explain) c | |
| onst; | | onst { | |
| | | verify(false); // should call addToBsonArray instead | |
| | | } | |
| | | | |
| private: | | private: | |
| DocumentSourceSort(const intrusive_ptr<ExpressionContext> &pExpCtx)
; | | DocumentSourceSort(const intrusive_ptr<ExpressionContext> &pExpCtx)
; | |
| | | | |
| /* | | /* | |
| Before returning anything, this source must fetch everything from | | Before returning anything, this source must fetch everything from | |
| the underlying source and group it. populate() is used to do tha
t | | the underlying source and group it. populate() is used to do tha
t | |
| on the first call to any method on this source. The populated | | on the first call to any method on this source. The populated | |
| boolean indicates that this has been done. | | boolean indicates that this has been done. | |
| */ | | */ | |
| void populate(); | | void populate(); | |
| bool populated; | | bool populated; | |
| | | | |
|
| | | // These are called by populate() | |
| | | void populateAll(); // no limit | |
| | | void populateOne(); // limit == 1 | |
| | | void populateTopK(); // limit > 1 | |
| | | | |
| /* these two parallel each other */ | | /* these two parallel each other */ | |
| typedef vector<intrusive_ptr<ExpressionFieldPath> > SortPaths; | | typedef vector<intrusive_ptr<ExpressionFieldPath> > SortPaths; | |
| SortPaths vSortKey; | | SortPaths vSortKey; | |
|
| vector<bool> vAscending; | | vector<char> vAscending; // used like vector<bool> but without spec
ialization | |
| | | | |
|
| /* | | struct KeyAndDoc { | |
| Compare two documents according to the specified sort key. | | explicit KeyAndDoc(const Document& d, const SortPaths& sp); // | |
| | | extracts sort key | |
| | | Value key; // array of keys if vSortKey.size() > 1 | |
| | | Document doc; | |
| | | }; | |
| | | friend void swap(KeyAndDoc& l, KeyAndDoc& r); | |
| | | | |
|
| @param rL reference to the left document | | /// Compare two KeyAndDocs according to the specified sort key. | |
| @param rR reference to the right document | | int compare(const KeyAndDoc& lhs, const KeyAndDoc& rhs) const; | |
| @returns a number less than, equal to, or greater than zero, | | | |
| indicating pL < pR, pL == pR, or pL > pR, respectively | | | |
| */ | | | |
| int compare(const Document& pL, const Document& pR); | | | |
| | | | |
| /* | | /* | |
| This is a utility class just for the STL sort that is done | | This is a utility class just for the STL sort that is done | |
| inside. | | inside. | |
| */ | | */ | |
| class Comparator { | | class Comparator { | |
| public: | | public: | |
|
| bool operator()(const Document& pL, const Document& pR) { | | explicit Comparator(const DocumentSourceSort& source): _source( | |
| return (pSort->compare(pL, pR) < 0); | | source) {} | |
| } | | bool operator()(const KeyAndDoc& lhs, const KeyAndDoc& rhs) con | |
| | | st { | |
| inline Comparator(DocumentSourceSort *pS): | | return (_source.compare(lhs, rhs) < 0); | |
| pSort(pS) { | | | |
| } | | } | |
|
| | | | |
| private: | | private: | |
|
| DocumentSourceSort *pSort; | | const DocumentSourceSort& _source; | |
| }; | | }; | |
| | | | |
|
| typedef vector<Document> VectorType; | | deque<KeyAndDoc> documents; | |
| VectorType documents; | | | |
| | | | |
|
| VectorType::iterator docIterator; | | intrusive_ptr<DocumentSourceLimit> limitSrc; | |
| Document pCurrent; | | | |
| }; | | }; | |
|
| | | inline void swap(DocumentSourceSort::KeyAndDoc& l, DocumentSourceSort:: | |
| | | KeyAndDoc& r) { | |
| | | l.key.swap(r.key); | |
| | | l.doc.swap(r.doc); | |
| | | } | |
| | | | |
| class DocumentSourceLimit : | | class DocumentSourceLimit : | |
| public SplittableDocumentSource { | | public SplittableDocumentSource { | |
| public: | | public: | |
| // virtuals from DocumentSource | | // virtuals from DocumentSource | |
| virtual ~DocumentSourceLimit(); | | virtual ~DocumentSourceLimit(); | |
| virtual bool eof(); | | virtual bool eof(); | |
| virtual bool advance(); | | virtual bool advance(); | |
| virtual Document getCurrent(); | | virtual Document getCurrent(); | |
| virtual const char *getSourceName() const; | | virtual const char *getSourceName() const; | |
| | | | |
| skipping to change at line 980 | | skipping to change at line 994 | |
| return SEE_NEXT; // This doesn't affect needed fields | | return SEE_NEXT; // This doesn't affect needed fields | |
| } | | } | |
| | | | |
| /** | | /** | |
| Create a new limiting DocumentSource. | | Create a new limiting DocumentSource. | |
| | | | |
| @param pExpCtx the expression context for the pipeline | | @param pExpCtx the expression context for the pipeline | |
| @returns the DocumentSource | | @returns the DocumentSource | |
| */ | | */ | |
| static intrusive_ptr<DocumentSourceLimit> create( | | static intrusive_ptr<DocumentSourceLimit> create( | |
|
| const intrusive_ptr<ExpressionContext> &pExpCtx); | | const intrusive_ptr<ExpressionContext> &pExpCtx, | |
| | | long long limit); | |
| | | | |
| // Virtuals for SplittableDocumentSource | | // Virtuals for SplittableDocumentSource | |
| // Need to run on rounter. Running on shard as well is an optimizat
ion. | | // Need to run on rounter. Running on shard as well is an optimizat
ion. | |
| virtual intrusive_ptr<DocumentSource> getShardSource() { return thi
s; } | | virtual intrusive_ptr<DocumentSource> getShardSource() { return thi
s; } | |
| virtual intrusive_ptr<DocumentSource> getRouterSource() { return th
is; } | | virtual intrusive_ptr<DocumentSource> getRouterSource() { return th
is; } | |
| | | | |
| long long getLimit() const { return limit; } | | long long getLimit() const { return limit; } | |
| void setLimit(long long newLimit) { limit = newLimit; } | | void setLimit(long long newLimit) { limit = newLimit; } | |
| | | | |
| /** | | /** | |
| | | | |
| skipping to change at line 1012 | | skipping to change at line 1027 | |
| BSONElement *pBsonElement, | | BSONElement *pBsonElement, | |
| const intrusive_ptr<ExpressionContext> &pExpCtx); | | const intrusive_ptr<ExpressionContext> &pExpCtx); | |
| | | | |
| static const char limitName[]; | | static const char limitName[]; | |
| | | | |
| protected: | | protected: | |
| // virtuals from DocumentSource | | // virtuals from DocumentSource | |
| virtual void sourceToBson(BSONObjBuilder *pBuilder, bool explain) c
onst; | | virtual void sourceToBson(BSONObjBuilder *pBuilder, bool explain) c
onst; | |
| | | | |
| private: | | private: | |
|
| DocumentSourceLimit( | | DocumentSourceLimit(const intrusive_ptr<ExpressionContext> &pExpCtx | |
| const intrusive_ptr<ExpressionContext> &pExpCtx); | | , | |
| | | long long limit); | |
| | | | |
| long long limit; | | long long limit; | |
| long long count; | | long long count; | |
| }; | | }; | |
| | | | |
| class DocumentSourceSkip : | | class DocumentSourceSkip : | |
| public SplittableDocumentSource { | | public SplittableDocumentSource { | |
| public: | | public: | |
| // virtuals from DocumentSource | | // virtuals from DocumentSource | |
| virtual ~DocumentSourceSkip(); | | virtual ~DocumentSourceSkip(); | |
| | | | |
| skipping to change at line 1143 | | skipping to change at line 1158 | |
| void unwindPath(const FieldPath &fieldPath); | | void unwindPath(const FieldPath &fieldPath); | |
| | | | |
| // Configuration state. | | // Configuration state. | |
| scoped_ptr<FieldPath> _unwindPath; | | scoped_ptr<FieldPath> _unwindPath; | |
| | | | |
| // Iteration state. | | // Iteration state. | |
| class Unwinder; | | class Unwinder; | |
| scoped_ptr<Unwinder> _unwinder; | | scoped_ptr<Unwinder> _unwinder; | |
| }; | | }; | |
| | | | |
|
| | | class DocumentSourceGeoNear : public SplittableDocumentSource { | |
| | | public: | |
| | | // virtuals from DocumentSource | |
| | | virtual ~DocumentSourceGeoNear(); | |
| | | virtual bool eof(); | |
| | | virtual bool advance(); | |
| | | virtual Document getCurrent(); | |
| | | virtual const char *getSourceName() const; | |
| | | virtual void setSource(DocumentSource *pSource); // errors out sinc | |
| | | e this must be first | |
| | | virtual bool coalesce(const intrusive_ptr<DocumentSource> &pNextSou | |
| | | rce); | |
| | | | |
| | | // Virtuals for SplittableDocumentSource | |
| | | virtual intrusive_ptr<DocumentSource> getShardSource(); | |
| | | virtual intrusive_ptr<DocumentSource> getRouterSource(); | |
| | | | |
| | | static intrusive_ptr<DocumentSource> createFromBson( | |
| | | BSONElement *pBsonElement, | |
| | | const intrusive_ptr<ExpressionContext> &pCtx); | |
| | | | |
| | | static char geoNearName[]; | |
| | | | |
| | | long long getLimit() { return limit; } | |
| | | | |
| | | // this should only be used for testing | |
| | | static intrusive_ptr<DocumentSourceGeoNear> create( | |
| | | const intrusive_ptr<ExpressionContext> &pCtx); | |
| | | | |
| | | protected: | |
| | | // virtuals from DocumentSource | |
| | | virtual void sourceToBson(BSONObjBuilder *pBuilder, bool explain) c | |
| | | onst; | |
| | | | |
| | | private: | |
| | | DocumentSourceGeoNear(const intrusive_ptr<ExpressionContext> &pExpC | |
| | | tx); | |
| | | | |
| | | void parseOptions(BSONObj options); | |
| | | BSONObj buildGeoNearCmd(const StringData& collection) const; | |
| | | void runCommand(); | |
| | | | |
| | | // These fields describe the command to run. | |
| | | // coords and distanceField are required, rest are optional | |
| | | BSONObj coords; // "near" option, but near is a reserved keyword on | |
| | | windows | |
| | | bool coordsIsArray; | |
| | | scoped_ptr<FieldPath> distanceField; // Using scoped_ptr because Fi | |
| | | eldPath can't be empty | |
| | | long long limit; | |
| | | double maxDistance; | |
| | | BSONObj query; | |
| | | bool spherical; | |
| | | double distanceMultiplier; | |
| | | scoped_ptr<FieldPath> includeLocs; | |
| | | bool uniqueDocs; | |
| | | | |
| | | // These fields are injected by PipelineD. This division of labor a | |
| | | llows the | |
| | | // DocumentSourceGeoNear class to be linked into both mongos and mo | |
| | | ngod while | |
| | | // allowing it to run a command using DBDirectClient when in mongod | |
| | | . | |
| | | string db; | |
| | | string collection; | |
| | | boost::scoped_ptr<DBClientWithCommands> client; // either NULL or a | |
| | | DBDirectClient | |
| | | friend class PipelineD; | |
| | | | |
| | | // these fields are used while processing the results | |
| | | BSONObj cmdOutput; | |
| | | boost::scoped_ptr<BSONObjIterator> resultsIterator; // iterator ove | |
| | | r cmdOutput["results"] | |
| | | Document currentDoc; | |
| | | bool hasCurrent; | |
| | | }; | |
| } | | } | |
| | | | |
| /* ======================= INLINED IMPLEMENTATIONS ========================
== */ | | /* ======================= INLINED IMPLEMENTATIONS ========================
== */ | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| inline void DocumentSource::setPipelineStep(int s) { | | inline void DocumentSource::setPipelineStep(int s) { | |
| step = s; | | step = s; | |
| } | | } | |
| | | | |
| | | | |
End of changes. 28 change blocks. |
| 52 lines changed or deleted | | 157 lines changed or added | |
|
| engine.h | | engine.h | |
| | | | |
| skipping to change at line 23 | | skipping to change at line 23 | |
| * 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 "mongo/db/jsobj.h" | | #include "mongo/db/jsobj.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
|
| | | typedef unsigned long long ScriptingFunction; | |
| | | typedef BSONObj (*NativeFunction)(const BSONObj& args, void* data); | |
| | | | |
| | | class DBClientWithCommands; | |
| | | | |
| | | static const unsigned kMaxJsFileLength = std::numeric_limits<unsigned>: | |
| | | :max() - 1; | |
| | | | |
| struct JSFile { | | struct JSFile { | |
| const char* name; | | const char* name; | |
| const StringData& source; | | const StringData& source; | |
| }; | | }; | |
| | | | |
|
| typedef unsigned long long ScriptingFunction; | | | |
| typedef BSONObj (*NativeFunction) ( const BSONObj &args, void* data ); | | | |
| | | | |
| class Scope : boost::noncopyable { | | class Scope : boost::noncopyable { | |
| public: | | public: | |
| Scope(); | | Scope(); | |
| virtual ~Scope(); | | virtual ~Scope(); | |
| | | | |
| virtual void reset() = 0; | | virtual void reset() = 0; | |
|
| virtual void init( const BSONObj * data ) = 0; | | virtual void init(const BSONObj* data) = 0; | |
| void init( const char * data ) { | | void init(const char* data) { | |
| BSONObj o( data ); | | BSONObj o(data); | |
| init( &o ); | | init(&o); | |
| } | | } | |
| | | | |
|
| virtual void localConnect( const char * dbName ) = 0; | | virtual void localConnect(const char* dbName) = 0; | |
| virtual void externalSetup() = 0; | | virtual void externalSetup() = 0; | |
| | | | |
|
| class NoDBAccess { | | virtual BSONObj getObject(const char* field) = 0; | |
| Scope * _s; | | virtual string getString(const char* field) = 0; | |
| public: | | virtual bool getBoolean(const char* field) = 0; | |
| NoDBAccess( Scope * s ) { | | virtual double getNumber(const char* field) = 0; | |
| _s = s; | | virtual int getNumberInt(const char* field) { return (int)getNumber | |
| } | | (field); } | |
| ~NoDBAccess() { | | virtual long long getNumberLongLong(const char* field) { | |
| _s->rename( "____db____" , "db" ); | | return static_cast<long long>(getNumber(field)); | |
| } | | } | |
| }; | | | |
| NoDBAccess disableDBAccess( const char * why ) { | | virtual void setElement(const char* field, const BSONElement& e) = | |
| rename( "db" , "____db____" ); | | 0; | |
| return NoDBAccess( this ); | | virtual void setNumber(const char* field, double val) = 0; | |
| } | | virtual void setString(const char* field, const char* val) = 0; | |
| | | virtual void setObject(const char* field, const BSONObj& obj, bool | |
| | | readOnly=true) = 0; | |
| | | virtual void setBoolean(const char* field, bool val) = 0; | |
| | | virtual void setFunction(const char* field, const char* code) = 0; | |
| | | | |
| | | virtual int type(const char* field) = 0; | |
| | | | |
|
| virtual double getNumber( const char *field ) = 0; | | virtual void append(BSONObjBuilder& builder, const char* fieldName, | |
| virtual int getNumberInt( const char *field ) { return (int)getNumb | | const char* scopeName); | |
| er( field ); } | | | |
| virtual long long getNumberLongLong( const char *field ) { return ( | | | |
| long long)getNumber( field ); } | | | |
| virtual string getString( const char *field ) = 0; | | | |
| virtual bool getBoolean( const char *field ) = 0; | | | |
| virtual BSONObj getObject( const char *field ) = 0; | | | |
| | | | |
|
| virtual int type( const char *field ) = 0; | | virtual void rename(const char* from, const char* to) = 0; | |
| | | | |
|
| virtual void append( BSONObjBuilder & builder , const char * fieldN | | virtual string getError() = 0; | |
| ame , const char * scopeName ); | | | |
| | | virtual bool hasOutOfMemoryException() = 0; | |
| | | | |
|
| virtual void setElement( const char *field , const BSONElement& e ) | | virtual bool isKillPending() const = 0; | |
| = 0; | | | |
| virtual void setNumber( const char *field , double val ) = 0; | | | |
| virtual void setString( const char *field , const char * val ) = 0; | | | |
| virtual void setObject( const char *field , const BSONObj& obj , bo | | | |
| ol readOnly=true ) = 0; | | | |
| virtual void setBoolean( const char *field , bool val ) = 0; | | | |
| virtual void setFunction( const char *field , const char * code ) = | | | |
| 0; | | | |
| // virtual void setThis( const BSONObj * obj ) = 0; | | | |
| | | | |
|
| virtual ScriptingFunction createFunction( const char * code ); | | virtual void gc() = 0; | |
| | | | |
| | | virtual ScriptingFunction createFunction(const char* code); | |
| | | | |
|
| virtual void rename( const char * from , const char * to ) = 0; | | | |
| /** | | /** | |
| * @return 0 on success | | * @return 0 on success | |
| */ | | */ | |
|
| virtual int invoke( ScriptingFunction func , const BSONObj* args, c | | int invoke(const char* code, const BSONObj* args, const BSONObj* re | |
| onst BSONObj* recv, int timeoutMs = 0 , bool ignoreReturn = false, bool rea | | cv, int timeoutMs = 0); | |
| dOnlyArgs = false, bool readOnlyRecv = false ) = 0; | | | |
| void invokeSafe( ScriptingFunction func , const BSONObj* args, cons | | virtual int invoke(ScriptingFunction func, const BSONObj* args, con | |
| t BSONObj* recv, int timeoutMs = 0 , bool ignoreReturn = false, bool readOn | | st BSONObj* recv, | |
| lyArgs = false, bool readOnlyRecv = false ) { | | int timeoutMs = 0, bool ignoreReturn = false, bo | |
| int res = invoke( func , args , recv, timeoutMs, ignoreReturn, | | ol readOnlyArgs = false, | |
| readOnlyArgs, readOnlyRecv ); | | bool readOnlyRecv = false) = 0; | |
| if ( res == 0 ) | | | |
| | | void invokeSafe(ScriptingFunction func, const BSONObj* args, const | |
| | | BSONObj* recv, | |
| | | int timeoutMs = 0, bool ignoreReturn = false, bool | |
| | | readOnlyArgs = false, | |
| | | bool readOnlyRecv = false) { | |
| | | int res = invoke(func, args, recv, timeoutMs, ignoreReturn, | |
| | | readOnlyArgs, readOnlyRecv); | |
| | | if (res == 0) | |
| return; | | return; | |
|
| throw UserException( 9004 , (string)"invoke failed: " + getErro
r() ); | | uasserted(9004, string("invoke failed: ") + getError()); | |
| } | | } | |
|
| virtual string getError() = 0; | | | |
| virtual bool hasOutOfMemoryException() = 0; | | | |
| | | | |
|
| int invoke( const char* code , const BSONObj* args, const BSONObj* | | void invokeSafe(const char* code, const BSONObj* args, const BSONOb | |
| recv, int timeoutMs = 0 ); | | j* recv, | |
| void invokeSafe( const char* code , const BSONObj* args, const BSON | | int timeoutMs = 0) { | |
| Obj* recv, int timeoutMs = 0 ) { | | if (invoke(code, args, recv, timeoutMs) == 0) | |
| if ( invoke( code , args , recv, timeoutMs ) == 0 ) | | | |
| return; | | return; | |
|
| throw UserException( 9005 , (string)"invoke failed: " + getErro
r() ); | | uasserted(9005, string("invoke failed: ") + getError()); | |
| } | | } | |
| | | | |
|
| virtual bool exec( const StringData& code , const string& name , bo | | virtual void injectNative(const char* field, NativeFunction func, v | |
| ol printResult , bool reportError , bool assertOnError, int timeoutMs = 0 ) | | oid* data = 0) = 0; | |
| = 0; | | | |
| virtual void execSetup( const StringData& code , const string& name | | virtual bool exec(const StringData& code, const string& name, bool | |
| = "setup" ) { | | printResult, | |
| exec( code , name , false , true , true , 0 ); | | bool reportError, bool assertOnError, int timeout | |
| | | Ms = 0) = 0; | |
| | | | |
| | | virtual void execSetup(const StringData& code, const string& name = | |
| | | "setup") { | |
| | | exec(code, name, false, true, true, 0); | |
| } | | } | |
| | | | |
|
| void execSetup( const JSFile& file) { | | void execSetup(const JSFile& file) { | |
| execSetup(file.source, file.name); | | execSetup(file.source, file.name); | |
| } | | } | |
| | | | |
|
| void execCoreFiles(); | | virtual bool execFile(const string& filename, bool printResult, boo | |
| | | l reportError, | |
| | | int timeoutMs = 0); | |
| | | | |
|
| virtual bool execFile( const string& filename , bool printResult , | | void execCoreFiles(); | |
| bool reportError , bool assertOnError, int timeoutMs = 0 ); | | | |
| | | | |
| virtual void injectNative( const char *field, NativeFunction func, | | | |
| void* data = 0 ) = 0; | | | |
| | | | |
| virtual void gc() = 0; | | | |
| | | | |
|
| void loadStored( bool ignoreNotConnected = false ); | | void loadStored(bool ignoreNotConnected = false); | |
| | | | |
| /** | | /** | |
|
| if any changes are made to .system.js, call this | | * if any changes are made to .system.js, call this | |
| right now its just global - slightly inefficient, but a lot simple | | * right now its just global - slightly inefficient, but a lot simp | |
| r | | ler | |
| */ | | */ | |
| static void storedFuncMod(); | | static void storedFuncMod(); | |
| | | | |
|
| static int getNumScopes() { | | static void validateObjectIdString(const string& str); | |
| return _numScopes; | | | |
| } | | | |
| | | | |
| static void validateObjectIdString( const string &str ); | | | |
| | | | |
| /** increments the number of times a scope was used */ | | /** increments the number of times a scope was used */ | |
| void incTimeUsed() { ++_numTimeUsed; } | | void incTimeUsed() { ++_numTimeUsed; } | |
|
| | | | |
| /** gets the number of times a scope was used */ | | /** gets the number of times a scope was used */ | |
| int getTimeUsed() { return _numTimeUsed; } | | int getTimeUsed() { return _numTimeUsed; } | |
| | | | |
|
| protected: | | class NoDBAccess { | |
| | | Scope* _s; | |
| | | public: | |
| | | NoDBAccess(Scope* s) : _s(s) { | |
| | | } | |
| | | ~NoDBAccess() { | |
| | | _s->rename("____db____", "db"); | |
| | | } | |
| | | }; | |
| | | NoDBAccess disableDBAccess(const char* why) { | |
| | | rename("db", "____db____"); | |
| | | return NoDBAccess(this); | |
| | | } | |
| | | | |
|
| virtual ScriptingFunction _createFunction( const char * code ) = 0; | | protected: | |
| | | virtual ScriptingFunction _createFunction(const char* code) = 0; | |
| | | | |
| string _localDBName; | | string _localDBName; | |
| long long _loadedVersion; | | long long _loadedVersion; | |
| set<string> _storedNames; | | set<string> _storedNames; | |
| static long long _lastVersion; | | static long long _lastVersion; | |
|
| map<string,ScriptingFunction> _cachedFunctions; | | map<string, ScriptingFunction> _cachedFunctions; | |
| int _numTimeUsed; | | int _numTimeUsed; | |
|
| | | | |
| static int _numScopes; | | | |
| }; | | }; | |
| | | | |
|
| void installGlobalUtils( Scope& scope ); | | | |
| | | | |
| class DBClientWithCommands; | | | |
| | | | |
| 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(); | | return createScope(); | |
| if ( s && _scopeInitCallback ) | | | |
| _scopeInitCallback( *s ); | | | |
| installGlobalUtils( *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(); | |
| | | | |
| /** gets a scope from the pool or a new one if pool is empty | | /** gets a scope from the pool or a new one if pool is empty | |
| * @param pool An identifier for the pool, usually the db name | | * @param pool An identifier for the pool, usually the db name | |
|
| * @return the scope */ | | * @return the scope | |
| auto_ptr<Scope> getPooledScope( const string& pool ); | | */ | |
| | | auto_ptr<Scope> getPooledScope(const string& pool); | |
| | | | |
|
| /** call this method to release some JS resources when a thread is | | /** | |
| done */ | | * call this method to release some JS resources when a thread is d | |
| | | one | |
| | | */ | |
| void threadDone(); | | void threadDone(); | |
| | | | |
|
| void setScopeInitCallback( void ( *func )( Scope & ) ) { _scopeInit | | void setScopeInitCallback(void (*func)(Scope&)) { _scopeInitCallbac | |
| Callback = func; } | | k = func; } | |
| static void setConnectCallback( void ( *func )( DBClientWithCommand | | static void setConnectCallback(void (*func)(DBClientWithCommands&)) | |
| s& ) ) { _connectCallback = func; } | | { | |
| static void runConnectCallback( DBClientWithCommands &c ) { | | _connectCallback = func; | |
| if ( _connectCallback ) | | } | |
| _connectCallback( c ); | | static void runConnectCallback(DBClientWithCommands& c) { | |
| | | if (_connectCallback) | |
| | | _connectCallback(c); | |
| } | | } | |
| | | | |
| // engine implementation may either respond to interrupt events or | | // engine implementation may either respond to interrupt events or | |
|
| // poll for interrupts | | // poll for interrupts. the interrupt functions must not wait inde | |
| | | finitely on a lock. | |
| // the interrupt functions must not wait indefinitely on a lock | | virtual void interrupt(unsigned opId) {} | |
| virtual void interrupt( unsigned opSpec ) {} | | | |
| virtual void interruptAll() {} | | virtual void interruptAll() {} | |
|
| | | static void setGetCurrentOpIdCallback(unsigned (*func)()) { | |
| static void setGetInterruptSpecCallback( unsigned ( *func )() ) { _ | | _getCurrentOpIdCallback = func; | |
| getInterruptSpecCallback = func; } | | } | |
| static bool haveGetInterruptSpecCallback() { return _getInterruptSp | | static bool haveGetCurrentOpIdCallback() { return _getCurrentOpIdCa | |
| ecCallback; } | | llback; } | |
| static unsigned getInterruptSpec() { | | static unsigned getCurrentOpId() { | |
| massert( 13474, "no _getInterruptSpecCallback", _getInterruptSp | | massert(13474, "no _getCurrentOpIdCallback", _getCurrentOpIdCal | |
| ecCallback ); | | lback); | |
| return _getInterruptSpecCallback(); | | return _getCurrentOpIdCallback(); | |
| | | } | |
| | | static void setCheckInterruptCallback(const char* (*func)()) { | |
| | | _checkInterruptCallback = func; | |
| } | | } | |
|
| | | | |
| static void setCheckInterruptCallback( const char * ( *func )() ) { | | | |
| _checkInterruptCallback = func; } | | | |
| static bool haveCheckInterruptCallback() { return _checkInterruptCa
llback; } | | static bool haveCheckInterruptCallback() { return _checkInterruptCa
llback; } | |
|
| static const char * checkInterrupt() { | | static const char* checkInterrupt() { | |
| return _checkInterruptCallback ? _checkInterruptCallback() : ""
; | | return _checkInterruptCallback ? _checkInterruptCallback() : ""
; | |
| } | | } | |
| static bool interrupted() { | | static bool interrupted() { | |
|
| const char *r = checkInterrupt(); | | const char* r = checkInterrupt(); | |
| return r && r[ 0 ]; | | return r && r[0]; | |
| } | | } | |
|
| | | | |
| static std::string getInterpreterVersionString(); | | static std::string getInterpreterVersionString(); | |
| | | | |
| protected: | | protected: | |
|
| virtual Scope * createScope() = 0; | | virtual Scope* createScope() = 0; | |
| | | void (*_scopeInitCallback)(Scope&); | |
| | | | |
| private: | | private: | |
|
| void ( *_scopeInitCallback )( Scope & ); | | static void (*_connectCallback)(DBClientWithCommands&); | |
| static void ( *_connectCallback )( DBClientWithCommands & ); | | static const char* (*_checkInterruptCallback)(); | |
| static const char * ( *_checkInterruptCallback )(); | | static unsigned (*_getCurrentOpIdCallback)(); | |
| static unsigned ( *_getInterruptSpecCallback )(); | | | |
| }; | | }; | |
| | | | |
|
| bool hasJSReturn( const string& s ); | | void installGlobalUtils(Scope& scope); | |
| | | bool hasJSReturn(const string& s); | |
| const char * jsSkipWhiteSpace( const char * raw ); | | const char* jsSkipWhiteSpace(const char* raw); | |
| | | | |
|
| extern ScriptEngine * globalScriptEngine; | | extern ScriptEngine* globalScriptEngine; | |
| } | | } | |
| | | | |
End of changes. 43 change blocks. |
| 142 lines changed or deleted | | 150 lines changed or added | |
|
| engine_v8.h | | engine_v8.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 | |
| | | | |
| #include <v8.h> | | #include <v8.h> | |
| #include <vector> | | #include <vector> | |
| | | | |
| #include "mongo/scripting/engine.h" | | #include "mongo/scripting/engine.h" | |
| | | | |
|
| using namespace v8; | | #include "mongo/base/disallow_copying.h" | |
| | | | |
| | | /** | |
| | | * V8_SIMPLE_HEADER must be placed in any function called from a public API | |
| | | * that work with v8 handles (and/or must be within the V8Scope's isolate | |
| | | * and context). Be sure to close the handle_scope if returning a v8::Hand | |
| | | le! | |
| | | */ | |
| | | #define V8_SIMPLE_HEADER | |
| | | \ | |
| | | v8::Locker v8lock(_isolate); /* acquire isolate lock */ | |
| | | \ | |
| | | v8::Isolate::Scope iscope(_isolate); /* enter the isolate; exit wh | |
| | | en out of scope */ \ | |
| | | v8::HandleScope handle_scope; /* make the current scope own | |
| | | local handles */ \ | |
| | | v8::Context::Scope context_scope(_context); /* enter the context; e | |
| | | xit when out of scope */ | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| class V8ScriptEngine; | | class V8ScriptEngine; | |
| class V8Scope; | | class V8Scope; | |
| | | | |
|
| typedef Handle< Value > (*v8Function) ( V8Scope* scope, const v8::Argum | | typedef v8::Handle<v8::Value> (*v8Function)(V8Scope* scope, const v8::A | |
| ents& args ); | | rguments& args); | |
| | | | |
| // Preemption is going to be allowed for the v8 mutex, and some of our | | | |
| v8 | | | |
| // usage is not preemption safe. So we are using an additional mutex t | | | |
| hat | | | |
| // will not be preempted. The V8Lock should be used in place of v8::Lo | | | |
| cker | | | |
| // except in certain special cases involving interrupts. | | | |
| namespace v8Locks { | | | |
| struct InterruptLock { | | | |
| InterruptLock(); | | | |
| ~InterruptLock(); | | | |
| }; | | | |
| | | | |
| // the implementations are quite simple - objects must be destroyed | | | |
| in | | | |
| // reverse of the order created, and should not be shared between t | | | |
| hreads | | | |
| struct RecursiveLock { | | | |
| RecursiveLock(); | | | |
| ~RecursiveLock(); | | | |
| bool _unlock; | | | |
| }; | | | |
| struct RecursiveUnlock { | | | |
| RecursiveUnlock(); | | | |
| ~RecursiveUnlock(); | | | |
| bool _lock; | | | |
| }; | | | |
| } // namespace v8Locks | | | |
| | | | |
| class V8Lock { | | | |
| public: | | | |
| V8Lock() : _preemptionLock(Isolate::GetCurrent()){} | | | |
| | | | |
| private: | | | |
| v8Locks::RecursiveLock _noPreemptionLock; | | | |
| v8::Locker _preemptionLock; | | | |
| }; | | | |
| | | | |
| struct V8Unlock { | | | |
| public: | | | |
| V8Unlock() : _preemptionUnlock(Isolate::GetCurrent()){} | | | |
| | | | |
| private: | | | |
| v8::Unlocker _preemptionUnlock; | | | |
| v8Locks::RecursiveUnlock _noPreemptionUnlock; | | | |
| }; | | | |
| | | | |
| class BSONHolder { | | class BSONHolder { | |
| public: | | public: | |
|
| | | BSONHolder(BSONObj obj) { | |
| BSONHolder( BSONObj obj ) { | | | |
| _obj = obj.getOwned(); | | _obj = obj.getOwned(); | |
| _modified = false; | | _modified = false; | |
|
| | | v8::V8::AdjustAmountOfExternalAllocatedMemory(_obj.objsize()); | |
| } | | } | |
|
| | | | |
| ~BSONHolder() { | | ~BSONHolder() { | |
|
| | | v8::V8::AdjustAmountOfExternalAllocatedMemory(-_obj.objsize()); | |
| } | | } | |
|
| | | | |
| BSONObj _obj; | | BSONObj _obj; | |
| bool _modified; | | bool _modified; | |
| list<string> _extra; | | list<string> _extra; | |
| set<string> _removed; | | set<string> _removed; | |
|
| | | | |
| }; | | }; | |
| | | | |
|
| | | /** | |
| | | * A V8Scope represents a unit of javascript execution environment; spe | |
| | | cifically a single | |
| | | * isolate and a single context executing in a single mongo thread. A | |
| | | V8Scope can be reused | |
| | | * in another thread only after reset() has been called. | |
| | | * | |
| | | * NB: | |
| | | * - v8 objects/handles/etc. cannot be shared between V8Scopes | |
| | | * - in mongod, each scope is associated with an opId (for KillOp sup | |
| | | port) | |
| | | * - any public functions that call the v8 API should use a V8_SIMPLE | |
| | | _HEADER | |
| | | * - the caller of any public function that returns a v8 type or has | |
| | | a v8 handle argument | |
| | | * must enter the isolate, context, and set up the appropriate | |
| | | handle scope | |
| | | */ | |
| class V8Scope : public Scope { | | class V8Scope : public Scope { | |
| public: | | public: | |
| | | | |
|
| V8Scope( V8ScriptEngine * engine ); | | V8Scope(V8ScriptEngine* engine); | |
| ~V8Scope(); | | ~V8Scope(); | |
| | | | |
|
| | | virtual void init(const BSONObj* data); | |
| | | | |
| | | /** | |
| | | * Reset the state of this scope for use by another thread or opera | |
| | | tion | |
| | | */ | |
| virtual void reset(); | | virtual void reset(); | |
|
| virtual void init( const BSONObj * data ); | | | |
| | | | |
|
| virtual void localConnect( const char * dbName ); | | /** | |
| | | * Terminate this scope | |
| | | */ | |
| | | virtual void kill(); | |
| | | | |
| | | /** check if there is a pending killOp request */ | |
| | | bool isKillPending() const; | |
| | | | |
| | | virtual void localConnect(const char* dbName); | |
| | | | |
| virtual void externalSetup(); | | virtual void externalSetup(); | |
| | | | |
|
| v8::Handle<v8::Value> get( const char * field ); // caller must cre | | | |
| ate context and handle scopes | | | |
| virtual double getNumber( const char *field ); | | | |
| virtual int getNumberInt( const char *field ); | | | |
| virtual long long getNumberLongLong( const char *field ); | | | |
| virtual string getString( const char *field ); | | | |
| virtual bool getBoolean( const char *field ); | | | |
| virtual BSONObj getObject( const char *field ); | | | |
| Handle<v8::Object> getGlobalObject() { return _global; }; | | | |
| | | | |
| virtual int type( const char *field ); | | | |
| | | | |
| virtual void setNumber( const char *field , double val ); | | | |
| virtual void setString( const char *field , const char * val ); | | | |
| virtual void setBoolean( const char *field , bool val ); | | | |
| virtual void setElement( const char *field , const BSONElement& e ) | | | |
| ; | | | |
| virtual void setObject( const char *field , const BSONObj& obj , bo | | | |
| ol readOnly); | | | |
| virtual void setFunction( const char *field , const char * code ); | | | |
| // virtual void setThis( const BSONObj * obj ); | | | |
| | | | |
| virtual void rename( const char * from , const char * to ); | | | |
| | | | |
| virtual ScriptingFunction _createFunction( const char * code ); | | | |
| Local< v8::Function > __createFunction( const char * code ); | | | |
| virtual int invoke( ScriptingFunction func , const BSONObj* args, c | | | |
| onst BSONObj* recv, int timeoutMs = 0 , bool ignoreReturn = false, bool rea | | | |
| dOnlyArgs = false, bool readOnlyRecv = false ); | | | |
| virtual bool exec( const StringData& code , const string& name , bo | | | |
| ol printResult , bool reportError , bool assertOnError, int timeoutMs ); | | | |
| virtual string getError() { return _error; } | | virtual string getError() { return _error; } | |
|
| virtual bool hasOutOfMemoryException(); | | | |
| | | | |
|
| virtual void injectNative( const char *field, NativeFunction func, | | virtual bool hasOutOfMemoryException(); | |
| void* data = 0 ); | | | |
| void injectNative( const char *field, NativeFunction func, Handle<v | | | |
| 8::Object>& obj, void* data = 0 ); | | | |
| void injectV8Function( const char *field, v8Function func ); | | | |
| void injectV8Function( const char *field, v8Function func, Handle<v | | | |
| 8::Object>& obj ); | | | |
| void injectV8Function( const char *field, v8Function func, Handle<v | | | |
| 8::Template>& t ); | | | |
| Handle<v8::FunctionTemplate> createV8Function( v8Function func ); | | | |
| | | | |
|
| | | /** | |
| | | * Run the garbage collector on this scope (native function). @see | |
| | | GCV8 for the | |
| | | * javascript binding version. | |
| | | */ | |
| void gc(); | | void gc(); | |
| | | | |
|
| Handle< Context > context() const { return _context; } | | /** | |
| | | * get a global property. caller must set up the v8 state. | |
| v8::Local<v8::Object> mongoToV8( const mongo::BSONObj & m , bool ar | | */ | |
| ray = 0 , bool readOnly = false ); | | v8::Handle<v8::Value> get(const char* field); | |
| v8::Handle<v8::Object> mongoToLZV8( const mongo::BSONObj & m , bool | | | |
| array = 0 , bool readOnly = false ); | | virtual double getNumber(const char* field); | |
| mongo::BSONObj v8ToMongo( v8::Handle<v8::Object> o , int depth = 0 | | virtual int getNumberInt(const char* field); | |
| ); | | virtual long long getNumberLongLong(const char* field); | |
| | | virtual string getString(const char* field); | |
| // v8 to mongo/BSON conversion functions | | virtual bool getBoolean(const char* field); | |
| | | virtual BSONObj getObject(const char* field); | |
| | | | |
| | | virtual void setNumber(const char* field, double val); | |
| | | virtual void setString(const char* field, const char* val); | |
| | | virtual void setBoolean(const char* field, bool val); | |
| | | virtual void setElement(const char* field, const BSONElement& e); | |
| | | virtual void setObject(const char* field, const BSONObj& obj, bool | |
| | | readOnly); | |
| | | virtual void setFunction(const char* field, const char* code); | |
| | | | |
| | | virtual int type(const char* field); | |
| | | | |
| | | virtual void rename(const char* from, const char* to); | |
| | | | |
| | | virtual int invoke(ScriptingFunction func, const BSONObj* args, con | |
| | | st BSONObj* recv, | |
| | | int timeoutMs = 0, bool ignoreReturn = false, | |
| | | bool readOnlyArgs = false, bool readOnlyRecv = f | |
| | | alse); | |
| | | | |
| | | virtual bool exec(const StringData& code, const string& name, bool | |
| | | printResult, | |
| | | bool reportError, bool assertOnError, int timeout | |
| | | Ms); | |
| | | | |
| | | // functions to create v8 object and function templates | |
| | | virtual void injectNative(const char* field, NativeFunction func, v | |
| | | oid* data = 0); | |
| | | void injectNative(const char* field, NativeFunction func, v8::Handl | |
| | | e<v8::Object>& obj, | |
| | | void* data = 0); | |
| | | void injectV8Function(const char* field, v8Function func); | |
| | | void injectV8Function(const char* field, v8Function func, v8::Handl | |
| | | e<v8::Object>& obj); | |
| | | void injectV8Function(const char* field, v8Function func, v8::Handl | |
| | | e<v8::Template>& t); | |
| | | v8::Handle<v8::FunctionTemplate> createV8Function(v8Function func); | |
| | | virtual ScriptingFunction _createFunction(const char* code); | |
| | | v8::Local<v8::Function> __createFunction(const char* code); | |
| | | | |
| | | /** | |
| | | * Convert BSON types to v8 Javascript types | |
| | | */ | |
| | | v8::Local<v8::Object> mongoToV8(const mongo::BSONObj& m, bool array | |
| | | = 0, | |
| | | bool readOnly = false); | |
| | | v8::Persistent<v8::Object> mongoToLZV8(const mongo::BSONObj& m, boo | |
| | | l readOnly = false); | |
| | | v8::Handle<v8::Value> mongoToV8Element(const BSONElement& f, bool r | |
| | | eadOnly = false); | |
| | | | |
| | | /** | |
| | | * Convert v8 Javascript types to BSON types | |
| | | */ | |
| | | mongo::BSONObj v8ToMongo(v8::Handle<v8::Object> obj, int depth = 0) | |
| | | ; | |
| void v8ToMongoElement(BSONObjBuilder& b, | | void v8ToMongoElement(BSONObjBuilder& b, | |
| const string& sname, | | const string& sname, | |
| v8::Handle<v8::Value> value, | | v8::Handle<v8::Value> value, | |
| int depth = 0, | | int depth = 0, | |
| BSONObj* originalParent = 0); | | BSONObj* originalParent = 0); | |
| void v8ToMongoObject(BSONObjBuilder& b, | | void v8ToMongoObject(BSONObjBuilder& b, | |
| const string& sname, | | const string& sname, | |
| v8::Handle<v8::Value> value, | | v8::Handle<v8::Value> value, | |
| int depth, | | int depth, | |
| BSONObj* originalParent); | | BSONObj* originalParent); | |
| | | | |
| skipping to change at line 183 | | skipping to change at line 194 | |
| void v8ToMongoDBRef(BSONObjBuilder& b, | | void v8ToMongoDBRef(BSONObjBuilder& b, | |
| const string& elementName, | | const string& elementName, | |
| v8::Handle<v8::Object> obj); | | v8::Handle<v8::Object> obj); | |
| void v8ToMongoBinData(BSONObjBuilder& b, | | void v8ToMongoBinData(BSONObjBuilder& b, | |
| const string& elementName, | | const string& elementName, | |
| v8::Handle<v8::Object> obj); | | v8::Handle<v8::Object> obj); | |
| void v8ToMongoObjectID(BSONObjBuilder& b, | | void v8ToMongoObjectID(BSONObjBuilder& b, | |
| const string& elementName, | | const string& elementName, | |
| v8::Handle<v8::Object> obj); | | v8::Handle<v8::Object> obj); | |
| | | | |
|
| v8::Handle<v8::Value> mongoToV8Element( const BSONElement &f, bool | | v8::Function* getNamedCons(const char* name); | |
| readOnly = false ); | | | |
| virtual void append( BSONObjBuilder & builder , const char * fieldN | | | |
| ame , const char * scopeName ); | | | |
| | | | |
|
| v8::Function * getNamedCons( const char * name ); | | v8::Function* getObjectIdCons(); | |
| v8::Function * getObjectIdCons(); | | | |
| Local< v8::Value > newId( const OID &id ); | | | |
| | | | |
|
| Persistent<v8::Object> wrapBSONObject(Local<v8::Object> obj, BSONHo | | v8::Local<v8::Value> newId(const OID& id); | |
| lder* data); | | | |
| Persistent<v8::Object> wrapArrayObject(Local<v8::Object> obj, char* | | | |
| data); | | | |
| | | | |
|
| | | /** | |
| | | * GC callback for weak references to BSON objects (via BSONHolder) | |
| | | */ | |
| | | v8::Persistent<v8::Object> wrapBSONObject(v8::Local<v8::Object> obj | |
| | | , BSONHolder* data); | |
| | | v8::Persistent<v8::Object> wrapArrayObject(v8::Local<v8::Object> ob | |
| | | j, char* data); | |
| | | | |
| | | /** | |
| | | * Get a V8 string from the scope's cache, creating one if needed ( | |
| | | NOTE: this may be | |
| | | * dangerous due to use in multiple threads without changing the v8 | |
| | | Locker) | |
| | | */ | |
| v8::Handle<v8::String> getV8Str(string str); | | v8::Handle<v8::String> getV8Str(string str); | |
|
| // inline v8::Handle<v8::String> getV8Str(string str) { return v8::S | | | |
| tring::New(str.c_str()); } | | | |
| inline v8::Handle<v8::String> getLocalV8Str(string str) { return v8 | | | |
| ::String::New(str.c_str()); } | | | |
| | | | |
|
| | | /** | |
| | | * Create a V8 string with a local handle | |
| | | */ | |
| | | inline v8::Handle<v8::String> getLocalV8Str(string str) { | |
| | | return v8::String::New(str.c_str()); | |
| | | } | |
| | | | |
| | | /** | |
| | | * Get the isolate this scope belongs to (can be called from any th | |
| | | read, but v8 requires | |
| | | * the new thread enter the isolate and context. Only one thread | |
| | | can enter the isolate. | |
| | | */ | |
| v8::Isolate* getIsolate() { return _isolate; } | | v8::Isolate* getIsolate() { return _isolate; } | |
|
| Persistent<Context> getContext() { return _context; } | | | |
| | | | |
|
| // call with v8 mutex: | | /** | |
| void enableV8Interrupt(); | | * Get the JS context this scope executes within. | |
| void disableV8Interrupt(); | | */ | |
| bool pauseV8Interrupt(); | | v8::Persistent<v8::Context> getContext() { return _context; } | |
| bool resumeV8Interrupt(); | | | |
| | | /** | |
| Handle<v8::String> V8STR_CONN; | | * Static v8 strings for various identifiers | |
| Handle<v8::String> V8STR_ID; | | */ | |
| Handle<v8::String> V8STR_LENGTH; | | v8::Handle<v8::String> V8STR_CONN; | |
| Handle<v8::String> V8STR_LEN; | | v8::Handle<v8::String> V8STR_ID; | |
| Handle<v8::String> V8STR_TYPE; | | v8::Handle<v8::String> V8STR_LENGTH; | |
| Handle<v8::String> V8STR_ISOBJECTID; | | v8::Handle<v8::String> V8STR_LEN; | |
| Handle<v8::String> V8STR_NATIVE_FUNC; | | v8::Handle<v8::String> V8STR_TYPE; | |
| Handle<v8::String> V8STR_NATIVE_DATA; | | v8::Handle<v8::String> V8STR_ISOBJECTID; | |
| Handle<v8::String> V8STR_V8_FUNC; | | v8::Handle<v8::String> V8STR_NATIVE_FUNC; | |
| Handle<v8::String> V8STR_RETURN; | | v8::Handle<v8::String> V8STR_NATIVE_DATA; | |
| Handle<v8::String> V8STR_ARGS; | | v8::Handle<v8::String> V8STR_V8_FUNC; | |
| Handle<v8::String> V8STR_T; | | v8::Handle<v8::String> V8STR_RETURN; | |
| Handle<v8::String> V8STR_I; | | v8::Handle<v8::String> V8STR_ARGS; | |
| Handle<v8::String> V8STR_EMPTY; | | v8::Handle<v8::String> V8STR_T; | |
| Handle<v8::String> V8STR_MINKEY; | | v8::Handle<v8::String> V8STR_I; | |
| Handle<v8::String> V8STR_MAXKEY; | | v8::Handle<v8::String> V8STR_EMPTY; | |
| Handle<v8::String> V8STR_NUMBERLONG; | | v8::Handle<v8::String> V8STR_MINKEY; | |
| Handle<v8::String> V8STR_NUMBERINT; | | v8::Handle<v8::String> V8STR_MAXKEY; | |
| Handle<v8::String> V8STR_DBPTR; | | v8::Handle<v8::String> V8STR_NUMBERLONG; | |
| Handle<v8::String> V8STR_BINDATA; | | v8::Handle<v8::String> V8STR_NUMBERINT; | |
| Handle<v8::String> V8STR_WRAPPER; | | v8::Handle<v8::String> V8STR_DBPTR; | |
| Handle<v8::String> V8STR_RO; | | v8::Handle<v8::String> V8STR_BINDATA; | |
| Handle<v8::String> V8STR_FULLNAME; | | v8::Handle<v8::String> V8STR_WRAPPER; | |
| Handle<v8::String> V8STR_BSON; | | v8::Handle<v8::String> V8STR_RO; | |
| | | v8::Handle<v8::String> V8STR_FULLNAME; | |
| | | v8::Handle<v8::String> V8STR_BSON; | |
| | | | |
| private: | | private: | |
|
| void _startCall(); | | | |
| | | | |
| static Handle< Value > nativeCallback( V8Scope* scope, const Argume | | | |
| nts &args ); | | | |
| static v8::Handle< v8::Value > v8Callback( const v8::Arguments &arg | | | |
| s ); | | | |
| static Handle< Value > load( V8Scope* scope, const Arguments &args | | | |
| ); | | | |
| static Handle< Value > Print(V8Scope* scope, const v8::Arguments& a | | | |
| rgs); | | | |
| static Handle< Value > Version(V8Scope* scope, const v8::Arguments& | | | |
| args); | | | |
| static Handle< Value > GCV8(V8Scope* scope, const v8::Arguments& ar | | | |
| gs); | | | |
| | | | |
|
| V8ScriptEngine * _engine; | | /** | |
| | | * Trampoline to call a c++ function with a specific signature (V8S | |
| | | cope*, v8::Arguments&). | |
| | | * Handles interruption, exceptions, etc. | |
| | | */ | |
| | | static v8::Handle<v8::Value> v8Callback(const v8::Arguments& args); | |
| | | | |
| | | /** | |
| | | * Interpreter agnostic 'Native Callback' trampoline. Note this is | |
| | | only called | |
| | | * from v8Callback(). | |
| | | */ | |
| | | static v8::Handle<v8::Value> nativeCallback(V8Scope* scope, const v | |
| | | 8::Arguments& args); | |
| | | | |
| | | /** | |
| | | * v8-specific implementations of basic global functions | |
| | | */ | |
| | | static v8::Handle<v8::Value> load(V8Scope* scope, const v8::Argumen | |
| | | ts& args); | |
| | | static v8::Handle<v8::Value> Print(V8Scope* scope, const v8::Argume | |
| | | nts& args); | |
| | | static v8::Handle<v8::Value> Version(V8Scope* scope, const v8::Argu | |
| | | ments& args); | |
| | | static v8::Handle<v8::Value> GCV8(V8Scope* scope, const v8::Argumen | |
| | | ts& args); | |
| | | | |
| | | /** Signal that this scope has entered a native (C++) execution con | |
| | | text. | |
| | | * @return false if execution has been interrupted | |
| | | */ | |
| | | bool nativePrologue(); | |
| | | | |
| | | /** Signal that this scope has completed native execution and is re | |
| | | turning to v8. | |
| | | * @return false if execution has been interrupted | |
| | | */ | |
| | | bool nativeEpilogue(); | |
| | | | |
| | | /** | |
| | | * Register this scope with the mongo op id. If executing outside | |
| | | the | |
| | | * context of a mongo operation (e.g. from the shell), killOp will | |
| | | not | |
| | | * be supported. | |
| | | */ | |
| | | void registerOpId(); | |
| | | | |
| | | /** | |
| | | * Unregister this scope with the mongo op id. | |
| | | */ | |
| | | void unregisterOpId(); | |
| | | | |
| | | /** | |
| | | * Create a new function; primarily used for BSON/V8 conversion. | |
| | | */ | |
| | | v8::Local<v8::Value> newFunction(const char *code); | |
| | | | |
|
| Persistent<Context> _context; | | V8ScriptEngine* _engine; | |
| Persistent<v8::Object> _global; | | | |
| | | | |
|
| | | v8::Persistent<v8::Context> _context; | |
| | | v8::Persistent<v8::Object> _global; | |
| string _error; | | string _error; | |
|
| vector< Persistent<Value> > _funcs; | | vector<v8::Persistent<v8::Value> > _funcs; | |
| v8::Persistent<v8::Object> _emptyObj; | | | |
| | | | |
|
| v8::Persistent<v8::Function> _wrapper; | | enum ConnectState { NOT, LOCAL, EXTERNAL }; | |
| | | | |
| enum ConnectState { NOT , LOCAL , EXTERNAL }; | | | |
| ConnectState _connectState; | | ConnectState _connectState; | |
| | | | |
|
| std::map <string, v8::Persistent <v8::String> > _strCache; | | std::map <string, v8::Persistent<v8::String> > _strCache; | |
| | | | |
| | | v8::Persistent<v8::FunctionTemplate> lzFunctionTemplate; | |
| | | v8::Persistent<v8::ObjectTemplate> lzObjectTemplate; | |
| | | v8::Persistent<v8::ObjectTemplate> roObjectTemplate; | |
| | | v8::Persistent<v8::ObjectTemplate> lzArrayTemplate; | |
| | | v8::Persistent<v8::ObjectTemplate> internalFieldObjects; | |
| | | | |
|
| Persistent<v8::FunctionTemplate> lzFunctionTemplate; | | | |
| Persistent<v8::ObjectTemplate> lzObjectTemplate; | | | |
| Persistent<v8::ObjectTemplate> roObjectTemplate; | | | |
| Persistent<v8::ObjectTemplate> lzArrayTemplate; | | | |
| Persistent<v8::ObjectTemplate> internalFieldObjects; | | | |
| v8::Isolate* _isolate; | | v8::Isolate* _isolate; | |
|
| | | | |
| | | mongo::mutex _interruptLock; // protects interruption-related flags | |
| | | bool _inNativeExecution; // protected by _interruptLock | |
| | | bool _pendingKill; // protected by _interruptLock | |
| | | int _opId; // op id for this scope | |
| }; | | }; | |
| | | | |
| class V8ScriptEngine : public ScriptEngine { | | class V8ScriptEngine : public ScriptEngine { | |
| public: | | public: | |
| V8ScriptEngine(); | | V8ScriptEngine(); | |
| virtual ~V8ScriptEngine(); | | virtual ~V8ScriptEngine(); | |
|
| | | virtual Scope* createScope() { return new V8Scope(this); } | |
| virtual Scope * createScope() { return new V8Scope( this ); } | | | |
| | | | |
| virtual void runTest() {} | | virtual void runTest() {} | |
|
| | | | |
| bool utf8Ok() const { return true; } | | bool utf8Ok() const { return true; } | |
| | | | |
|
| virtual void interrupt( unsigned opSpec ); | | /** | |
| | | * Interrupt a single active v8 execution context | |
| | | * NB: To interrupt a context, we must acquire the following locks | |
| | | (in order): | |
| | | * - mutex to protect the the map of all scopes (_globalInter | |
| | | ruptLock) | |
| | | * - mutex to protect the scope that's being interrupted (_in | |
| | | terruptLock) | |
| | | * The scope will be removed from the map upon destruction, and the | |
| | | op id | |
| | | * will be updated if the scope is ever reused from a pool. | |
| | | */ | |
| | | virtual void interrupt(unsigned opId); | |
| | | | |
| | | /** | |
| | | * Interrupt all v8 contexts (and isolates). @see interrupt(). | |
| | | */ | |
| virtual void interruptAll(); | | virtual void interruptAll(); | |
| | | | |
| private: | | private: | |
| friend class V8Scope; | | friend class V8Scope; | |
|
| }; | | | |
| | | | |
| class ExternalString : public v8::String::ExternalAsciiStringResource { | | | |
| public: | | | |
| ExternalString(std::string str) : _data(str) { | | | |
| } | | | |
| | | | |
|
| ~ExternalString() { | | std::string printKnownOps_inlock(); | |
| } | | | |
| | | | |
|
| const char* data () const { return _data.c_str(); } | | typedef map<unsigned, V8Scope*> OpIdToScopeMap; | |
| size_t length () const { return _data.length(); } | | mongo::mutex _globalInterruptLock; // protects map of all operatio | |
| private: | | n ids -> scope | |
| // string _str; | | OpIdToScopeMap _opToScopeMap; // map of mongo op ids to scope | |
| // const char* _data; | | s (protected by | |
| std::string _data; | | // _globalInterruptLock). | |
| // size_t _len; | | | |
| }; | | }; | |
| | | | |
|
| extern ScriptEngine * globalScriptEngine; | | extern ScriptEngine* globalScriptEngine; | |
| | | | |
| } | | } | |
| | | | |
End of changes. 42 change blocks. |
| 205 lines changed or deleted | | 292 lines changed or added | |
|
| expression.h | | expression.h | |
| | | | |
| skipping to change at line 409 | | skipping to change at line 409 | |
| static intrusive_ptr<ExpressionNary> createLt(); | | static intrusive_ptr<ExpressionNary> createLt(); | |
| static intrusive_ptr<ExpressionNary> createLte(); | | static intrusive_ptr<ExpressionNary> createLte(); | |
| | | | |
| private: | | private: | |
| friend class ExpressionFieldRange; | | friend class ExpressionFieldRange; | |
| ExpressionCompare(CmpOp cmpOp); | | ExpressionCompare(CmpOp cmpOp); | |
| | | | |
| CmpOp cmpOp; | | CmpOp cmpOp; | |
| }; | | }; | |
| | | | |
|
| class ExpressionCond : | | class ExpressionConcat : public ExpressionNary { | |
| public ExpressionNary { | | public: | |
| | | // virtuals from ExpressionNary | |
| | | virtual ~ExpressionConcat(); | |
| | | virtual Value evaluate(const Document& input) const; | |
| | | virtual const char *getOpName() const; | |
| | | | |
| | | static intrusive_ptr<ExpressionNary> create(); | |
| | | }; | |
| | | | |
| | | class ExpressionCond : public ExpressionNary { | |
| public: | | public: | |
| // virtuals from ExpressionNary | | // virtuals from ExpressionNary | |
| virtual ~ExpressionCond(); | | virtual ~ExpressionCond(); | |
| virtual Value evaluate(const Document& pDocument) const; | | virtual Value evaluate(const Document& pDocument) const; | |
| virtual const char *getOpName() const; | | virtual const char *getOpName() const; | |
| virtual void addOperand(const intrusive_ptr<Expression> &pExpressio
n); | | virtual void addOperand(const intrusive_ptr<Expression> &pExpressio
n); | |
| | | | |
| static intrusive_ptr<ExpressionNary> create(); | | static intrusive_ptr<ExpressionNary> create(); | |
| | | | |
| private: | | private: | |
| | | | |
| skipping to change at line 573 | | skipping to change at line 582 | |
| /* | | /* | |
| Internal implementation of evaluate(), used recursively. | | Internal implementation of evaluate(), used recursively. | |
| | | | |
| The internal implementation doesn't just use a loop because of | | The internal implementation doesn't just use a loop because of | |
| the possibility that we need to skip over an array. If the path | | the possibility that we need to skip over an array. If the path | |
| is "a.b.c", and a is an array, then we fan out from there, and | | is "a.b.c", and a is an array, then we fan out from there, and | |
| traverse "b.c" for each element of a:[...]. This requires that | | traverse "b.c" for each element of a:[...]. This requires that | |
| a be an array of objects in order to navigate more deeply. | | a be an array of objects in order to navigate more deeply. | |
| | | | |
| @param index current path field index to extract | | @param index current path field index to extract | |
|
| @param pathLength maximum number of fields on field path | | @param input current document traversed to (not the top-level one | |
| @param pDocument current document traversed to (not the top-level | | ) | |
| one) | | | |
| @returns the field found; could be an array | | @returns the field found; could be an array | |
| */ | | */ | |
|
| Value evaluatePath( | | Value evaluatePath(size_t index, const Document& input) const; | |
| size_t index, const size_t pathLength, | | | |
| Document pDocument) const; | | // Helper for evaluatePath to handle Array case | |
| | | Value evaluatePathArray(size_t index, const Value& input) const; | |
| | | | |
| FieldPath fieldPath; | | FieldPath fieldPath; | |
| }; | | }; | |
| | | | |
| class ExpressionFieldRange : | | class ExpressionFieldRange : | |
| public Expression { | | public Expression { | |
| public: | | public: | |
| // virtuals from expression | | // virtuals from expression | |
| virtual ~ExpressionFieldRange(); | | virtual ~ExpressionFieldRange(); | |
| virtual intrusive_ptr<Expression> optimize(); | | virtual intrusive_ptr<Expression> optimize(); | |
| | | | |
| skipping to change at line 705 | | skipping to change at line 714 | |
| virtual Value evaluate(const Document& pDocument) const; | | virtual Value evaluate(const Document& pDocument) const; | |
| virtual const char *getOpName() const; | | virtual const char *getOpName() const; | |
| virtual void addOperand(const intrusive_ptr<Expression> &pExpressio
n); | | virtual void addOperand(const intrusive_ptr<Expression> &pExpressio
n); | |
| | | | |
| static intrusive_ptr<ExpressionNary> create(); | | static intrusive_ptr<ExpressionNary> create(); | |
| | | | |
| private: | | private: | |
| ExpressionIfNull(); | | ExpressionIfNull(); | |
| }; | | }; | |
| | | | |
|
| | | class ExpressionMillisecond : | |
| | | public ExpressionNary { | |
| | | public: | |
| | | // virtuals from ExpressionNary | |
| | | virtual ~ExpressionMillisecond(); | |
| | | virtual Value evaluate(const Document& document) const; | |
| | | virtual const char* getOpName() const; | |
| | | virtual void addOperand(const intrusive_ptr<Expression>& pExpressio | |
| | | n); | |
| | | | |
| | | static intrusive_ptr<ExpressionNary> create(); | |
| | | | |
| | | private: | |
| | | ExpressionMillisecond(); | |
| | | }; | |
| | | | |
| class ExpressionMinute : | | class ExpressionMinute : | |
| public ExpressionNary { | | public ExpressionNary { | |
| public: | | public: | |
| // virtuals from ExpressionNary | | // virtuals from ExpressionNary | |
| virtual ~ExpressionMinute(); | | virtual ~ExpressionMinute(); | |
| virtual Value evaluate(const Document& pDocument) const; | | virtual Value evaluate(const Document& pDocument) const; | |
| virtual const char *getOpName() const; | | virtual const char *getOpName() const; | |
| virtual void addOperand(const intrusive_ptr<Expression> &pExpressio
n); | | virtual void addOperand(const intrusive_ptr<Expression> &pExpressio
n); | |
| | | | |
| static intrusive_ptr<ExpressionNary> create(); | | static intrusive_ptr<ExpressionNary> create(); | |
| | | | |
| skipping to change at line 904 | | skipping to change at line 928 | |
| | | | |
| // mapping from fieldname to Expression to generate the value | | // mapping from fieldname to Expression to generate the value | |
| // NULL expression means include from source document | | // NULL expression means include from source document | |
| typedef map<string, intrusive_ptr<Expression> > ExpressionMap; | | typedef map<string, intrusive_ptr<Expression> > ExpressionMap; | |
| ExpressionMap _expressions; | | ExpressionMap _expressions; | |
| | | | |
| // this is used to maintain order for generated fields not in the s
ource document | | // this is used to maintain order for generated fields not in the s
ource document | |
| vector<string> _order; | | vector<string> _order; | |
| | | | |
| bool _excludeId; | | bool _excludeId; | |
|
| | | | |
| /* | | | |
| Utility object for collecting emitPaths() results in a BSON | | | |
| object. | | | |
| */ | | | |
| class BuilderPathSink : | | | |
| public PathSink { | | | |
| public: | | | |
| // virtuals from PathSink | | | |
| virtual void path(const string &path, bool include); | | | |
| | | | |
| /* | | | |
| Create a PathSink that writes paths to a BSONObjBuilder, | | | |
| to create an object in the form of { path:is_included,...} | | | |
| | | | |
| This object uses a builder pointer that won't guarantee the | | | |
| lifetime of the builder, so make sure it outlasts the use of | | | |
| this for an emitPaths() call. | | | |
| | | | |
| @param pBuilder to the builder to write paths to | | | |
| */ | | | |
| BuilderPathSink(BSONObjBuilder *pBuilder); | | | |
| | | | |
| private: | | | |
| BSONObjBuilder *pBuilder; | | | |
| }; | | | |
| | | | |
| /* utility class used by emitPaths() */ | | | |
| class PathPusher : | | | |
| boost::noncopyable { | | | |
| public: | | | |
| PathPusher(vector<string> *pvPath, const string &s); | | | |
| ~PathPusher(); | | | |
| | | | |
| private: | | | |
| vector<string> *pvPath; | | | |
| }; | | | |
| }; | | }; | |
| | | | |
| class ExpressionOr : | | class ExpressionOr : | |
| public ExpressionNary { | | public ExpressionNary { | |
| public: | | public: | |
| // virtuals from Expression | | // virtuals from Expression | |
| virtual ~ExpressionOr(); | | virtual ~ExpressionOr(); | |
| virtual intrusive_ptr<Expression> optimize(); | | virtual intrusive_ptr<Expression> optimize(); | |
| virtual Value evaluate(const Document& pDocument) const; | | virtual Value evaluate(const Document& pDocument) const; | |
| virtual const char *getOpName() const; | | virtual const char *getOpName() const; | |
| | | | |
| skipping to change at line 1120 | | skipping to change at line 1107 | |
| } | | } | |
| | | | |
| inline void ExpressionFieldPath::writeFieldPath( | | inline void ExpressionFieldPath::writeFieldPath( | |
| ostream &outStream, bool fieldPrefix) const { | | ostream &outStream, bool fieldPrefix) const { | |
| return fieldPath.writePath(outStream, fieldPrefix); | | return fieldPath.writePath(outStream, fieldPrefix); | |
| } | | } | |
| | | | |
| inline size_t ExpressionObject::getFieldCount() const { | | inline size_t ExpressionObject::getFieldCount() const { | |
| return _expressions.size(); | | return _expressions.size(); | |
| } | | } | |
|
| | | | |
| inline ExpressionObject::BuilderPathSink::BuilderPathSink( | | | |
| BSONObjBuilder *pB): | | | |
| pBuilder(pB) { | | | |
| } | | | |
| | | | |
| inline ExpressionObject::PathPusher::PathPusher( | | | |
| vector<string> *pTheVPath, const string &s): | | | |
| pvPath(pTheVPath) { | | | |
| pvPath->push_back(s); | | | |
| } | | | |
| | | | |
| inline ExpressionObject::PathPusher::~PathPusher() { | | | |
| pvPath->pop_back(); | | | |
| } | | | |
| | | | |
| } | | } | |
| | | | |
End of changes. 6 change blocks. |
| 61 lines changed or deleted | | 33 lines changed or added | |
|
| file.h | | file.h | |
| | | | |
| skipping to change at line 20 | | skipping to change at line 20 | |
| * | | * | |
| * 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 | |
| | | | |
|
| #if !defined(_WIN32) | | #include <boost/cstdint.hpp> | |
| #include "errno.h" | | #include <string> | |
| #include <sys/mman.h> | | | |
| #include <sys/types.h> | | #include "mongo/platform/basic.h" | |
| #include <sys/stat.h> | | #include "mongo/platform/cstdint.h" | |
| #include <fcntl.h> | | | |
| #include <sys/statvfs.h> | | | |
| #endif | | | |
| #include "text.h" | | | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
|
| #ifndef __sunos__ | | | |
| typedef uint64_t fileofs; | | typedef uint64_t fileofs; | |
|
| #else | | | |
| typedef boost::uint64_t fileofs; | | | |
| #endif | | | |
| | | | |
|
| /* NOTE: not thread-safe. (at least the windows implementation isn't. *
/ | | // NOTE: not thread-safe. (at least the windows implementation isn't) | |
| | | | |
|
| class FileInterface { | | class File { | |
| public: | | | |
| void open(const char *fn) {} | | | |
| void write(fileofs o, const char *data, unsigned len) {} | | | |
| void read(fileofs o, char *data, unsigned len) {} | | | |
| bool bad() {return false;} | | | |
| bool is_open() {return false;} | | | |
| fileofs len() { return 0; } | | | |
| void fsync() { verify(false); } | | | |
| | | | |
|
| // shrink file to size bytes. No-op if file already smaller. | | | |
| void truncate(fileofs size); | | | |
| | | | |
| /** @return -1 if error or unavailable */ | | | |
| static boost::intmax_t freeSpace(const string &path) { verify(false | | | |
| ); return -1; } | | | |
| }; | | | |
| | | | |
| #if defined(_WIN32) | | | |
| #include <io.h> | | | |
| | | | |
| class File : public FileInterface { | | | |
| HANDLE fd; | | | |
| bool _bad; | | | |
| string _name; | | | |
| void err(BOOL b=false) { /* false = error happened */ | | | |
| if( !b && !_bad ) { | | | |
| _bad = true; | | | |
| log() << "File " << _name << "I/O error " << GetLastError() | | | |
| << endl; | | | |
| } | | | |
| } | | | |
| public: | | public: | |
|
| File() { | | File(); | |
| fd = INVALID_HANDLE_VALUE; | | ~File(); | |
| _bad = true; | | | |
| } | | | |
| ~File() { | | | |
| if( is_open() ) CloseHandle(fd); | | | |
| fd = INVALID_HANDLE_VALUE; | | | |
| } | | | |
| void open(const char *filename, bool readOnly=false , bool direct=f | | | |
| alse) { | | | |
| _name = filename; | | | |
| fd = CreateFile( | | | |
| toNativeString(filename).c_str(), | | | |
| ( readOnly ? 0 : GENERIC_WRITE ) | GENERIC_READ, FILE_ | | | |
| SHARE_WRITE|FILE_SHARE_READ, | | | |
| NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); | | | |
| if( !is_open() ) { | | | |
| DWORD e = GetLastError(); | | | |
| log() << "Create/Open File failed " << filename << ' ' << e | | | |
| rrnoWithDescription(e) << endl; | | | |
| } | | | |
| else | | | |
| _bad = false; | | | |
| } | | | |
| static boost::intmax_t freeSpace(const string &path) { | | | |
| ULARGE_INTEGER avail; | | | |
| if( GetDiskFreeSpaceEx(toNativeString(path.c_str()).c_str(), &a | | | |
| vail, NULL, NULL) ) { | | | |
| return avail.QuadPart; | | | |
| } | | | |
| DWORD e = GetLastError(); | | | |
| log() << "GetDiskFreeSpaceEx fails errno: " << e << endl; | | | |
| return -1; | | | |
| } | | | |
| void write(fileofs o, const char *data, unsigned len) { | | | |
| LARGE_INTEGER li; | | | |
| li.QuadPart = o; | | | |
| SetFilePointerEx(fd, li, NULL, FILE_BEGIN); | | | |
| DWORD written; | | | |
| err( WriteFile(fd, data, len, &written, NULL) ); | | | |
| } | | | |
| void read(fileofs o, char *data, unsigned len) { | | | |
| DWORD read; | | | |
| LARGE_INTEGER li; | | | |
| li.QuadPart = o; | | | |
| SetFilePointerEx(fd, li, NULL, FILE_BEGIN); | | | |
| int ok = ReadFile(fd, data, len, &read, 0); | | | |
| if( !ok ) | | | |
| err(ok); | | | |
| else | | | |
| massert( 10438 , "ReadFile error - truncated file?", read = | | | |
| = len); | | | |
| } | | | |
| bool bad() { return _bad; } | | | |
| bool is_open() { return fd != INVALID_HANDLE_VALUE; } | | | |
| fileofs len() { | | | |
| LARGE_INTEGER li; | | | |
| li.LowPart = GetFileSize(fd, (DWORD *) &li.HighPart); | | | |
| if( li.HighPart == 0 && li.LowPart == INVALID_FILE_SIZE ) { | | | |
| err( false ); | | | |
| return 0; | | | |
| } | | | |
| return li.QuadPart; | | | |
| } | | | |
| void fsync() { FlushFileBuffers(fd); } | | | |
| | | | |
| void truncate(fileofs size) { | | | |
| if (len() <= size) | | | |
| return; | | | |
| | | | |
| LARGE_INTEGER li; | | | |
| li.QuadPart = size; | | | |
| if (SetFilePointerEx(fd, li, NULL, FILE_BEGIN) == 0){ | | | |
| err(false); | | | |
| return; //couldn't seek | | | |
| } | | | |
| | | | |
|
| err(SetEndOfFile(fd)); | | bool bad() const { return _bad; } | |
| } | | void fsync() const; | |
| }; | | bool is_open() const; | |
| | | fileofs len(); | |
| | | void open(const char* filename, bool readOnly = false, bool direct | |
| | | = false); | |
| | | void read(fileofs o, char* data, unsigned len); | |
| | | void truncate(fileofs size); | |
| | | void write(fileofs o, const char* data, unsigned len); | |
| | | | |
|
| #else | | static boost::intmax_t freeSpace(const std::string& path); | |
| | | | |
|
| class File : public FileInterface { | | | |
| public: | | | |
| int fd; | | | |
| private: | | private: | |
| bool _bad; | | bool _bad; | |
|
| void err(bool ok) { | | #ifdef _WIN32 | |
| if( !ok && !_bad ) { | | HANDLE _handle; | |
| _bad = true; | | #else | |
| log() << "File I/O " << errnoWithDescription() << endl; | | int _fd; | |
| } | | | |
| } | | | |
| public: | | | |
| File() { | | | |
| fd = -1; | | | |
| _bad = true; | | | |
| } | | | |
| ~File() { | | | |
| if( is_open() ) ::close(fd); | | | |
| fd = -1; | | | |
| } | | | |
| | | | |
| #ifndef O_NOATIME | | | |
| #define O_NOATIME 0 | | | |
| #endif | | | |
| | | | |
| void open(const char *filename, bool readOnly=false , bool direct=f | | | |
| alse) { | | | |
| fd = ::open(filename, | | | |
| O_CREAT | ( readOnly ? 0 : ( O_RDWR | O_NOATIME ) ) | | | |
| #if defined(O_DIRECT) | | | |
| | ( direct ? O_DIRECT : 0 ) | | | |
| #endif | | #endif | |
|
| , | | std::string _name; | |
| S_IRUSR | S_IWUSR); | | | |
| if ( fd <= 0 ) { | | | |
| out() << "couldn't open " << filename << ' ' << errnoWithDe | | | |
| scription() << endl; | | | |
| return; | | | |
| } | | | |
| _bad = false; | | | |
| } | | | |
| void write(fileofs o, const char *data, unsigned len) { | | | |
| err( ::pwrite(fd, data, len, o) == (int) len ); | | | |
| } | | | |
| void read(fileofs o, char *data, unsigned len) { | | | |
| ssize_t s = ::pread(fd, data, len, o); | | | |
| if( s == -1 ) { | | | |
| err(false); | | | |
| } | | | |
| else if( s != (int) len ) { | | | |
| _bad = true; | | | |
| log() << "File error read:" << s << " bytes, wanted:" << le | | | |
| n << " ofs:" << o << endl; | | | |
| } | | | |
| } | | | |
| bool bad() { return _bad; } | | | |
| bool is_open() { return fd > 0; } | | | |
| fileofs len() { | | | |
| off_t o = lseek(fd, 0, SEEK_END); | | | |
| if( o != (off_t) -1 ) | | | |
| return o; | | | |
| err(false); | | | |
| return 0; | | | |
| } | | | |
| void fsync() { ::fsync(fd); } | | | |
| static boost::intmax_t freeSpace ( const string &path ) { | | | |
| struct statvfs info; | | | |
| verify( !statvfs( path.c_str() , &info ) ); | | | |
| return boost::intmax_t( info.f_bavail ) * info.f_frsize; | | | |
| } | | | |
| | | | |
| void truncate(fileofs size) { | | | |
| if (len() <= size) | | | |
| return; | | | |
| | | | |
|
| err(ftruncate(fd, size) == 0); | | | |
| } | | | |
| }; | | }; | |
| | | | |
|
| #endif | | | |
| | | | |
| } | | } | |
| | | | |
End of changes. 14 change blocks. |
| 200 lines changed or deleted | | 24 lines changed or added | |
|
| indexkey.h | | indexkey.h | |
| | | | |
| skipping to change at line 37 | | skipping to change at line 37 | |
| | | | |
| extern const int DefaultIndexVersionNumber; | | extern const int DefaultIndexVersionNumber; | |
| | | | |
| const int ParallelArraysCode = 10088; | | const int ParallelArraysCode = 10088; | |
| | | | |
| class Cursor; | | class Cursor; | |
| class IndexSpec; | | class IndexSpec; | |
| class IndexType; // TODO: this name sucks | | class IndexType; // TODO: this name sucks | |
| class IndexPlugin; | | class IndexPlugin; | |
| class IndexDetails; | | class IndexDetails; | |
|
| | | class FieldRangeSet; | |
| | | | |
| enum IndexSuitability { USELESS = 0 , HELPFUL = 1 , OPTIMAL = 2 }; | | enum IndexSuitability { USELESS = 0 , HELPFUL = 1 , OPTIMAL = 2 }; | |
| | | | |
| /** | | /** | |
| * this represents an instance of a index plugin | | * this represents an instance of a index plugin | |
| * done this way so parsing, etc... can be cached | | * done this way so parsing, etc... can be cached | |
| * so if there is a FTS IndexPlugin, for each index using FTS | | * so if there is a FTS IndexPlugin, for each index using FTS | |
| * there will be 1 of these, and it can have things pre-parsed, etc... | | * there will be 1 of these, and it can have things pre-parsed, etc... | |
| */ | | */ | |
| class IndexType : boost::noncopyable { | | class IndexType : boost::noncopyable { | |
| | | | |
| skipping to change at line 65 | | skipping to change at line 66 | |
| virtual BSONObj fixKey( const BSONObj& in ) { return in; } | | virtual BSONObj fixKey( const BSONObj& in ) { return in; } | |
| | | | |
| /** optional op : compare 2 objects with regards to this index */ | | /** optional op : compare 2 objects with regards to this index */ | |
| virtual int compare( const BSONObj& l , const BSONObj& r ) const; | | virtual int compare( const BSONObj& l , const BSONObj& r ) const; | |
| | | | |
| /** @return plugin */ | | /** @return plugin */ | |
| const IndexPlugin * getPlugin() const { return _plugin; } | | const IndexPlugin * getPlugin() const { return _plugin; } | |
| | | | |
| const BSONObj& keyPattern() const; | | const BSONObj& keyPattern() const; | |
| | | | |
|
| virtual IndexSuitability suitability( const BSONObj& query , const | | /* Determines the suitability level of this index for answering a g | |
| BSONObj& order ) const ; | | iven query. The query is | |
| | | * represented as a set of constraints given by a FieldRangeSet, an | |
| | | d a desired ordering of | |
| | | * the output. | |
| | | * | |
| | | * Note: it is the responsibility of the caller to pass in the corr | |
| | | ect FieldRangeSet, which | |
| | | * may depend upon whether this is a single or multi-key index at t | |
| | | he time of calling. | |
| | | */ | |
| | | virtual IndexSuitability suitability( const FieldRangeSet& queryCon | |
| | | straints , | |
| | | const BSONObj& order ) const; | |
| | | | |
| virtual bool scanAndOrderRequired( const BSONObj& query , const BSO
NObj& order ) const ; | | virtual bool scanAndOrderRequired( const BSONObj& query , const BSO
NObj& order ) const ; | |
| | | | |
| protected: | | protected: | |
| const IndexPlugin * _plugin; | | const IndexPlugin * _plugin; | |
| const IndexSpec * _spec; | | const IndexSpec * _spec; | |
| }; | | }; | |
| | | | |
| /** | | /** | |
| * this represents a plugin | | * this represents a plugin | |
| | | | |
| skipping to change at line 164 | | skipping to change at line 173 | |
| } | | } | |
| | | | |
| IndexType* getType() const { | | IndexType* getType() const { | |
| return _indexType.get(); | | return _indexType.get(); | |
| } | | } | |
| | | | |
| const IndexDetails * getDetails() const { | | const IndexDetails * getDetails() const { | |
| return _details; | | return _details; | |
| } | | } | |
| | | | |
|
| IndexSuitability suitability( const BSONObj& query , const BSONObj& | | IndexSuitability suitability( const FieldRangeSet& queryConstraints | |
| order ) const ; | | , | |
| | | const BSONObj& order ) const ; | |
| | | | |
| bool isSparse() const { return _sparse; } | | bool isSparse() const { return _sparse; } | |
| | | | |
|
| | | string toString() const; | |
| | | | |
| protected: | | protected: | |
| | | | |
| int indexVersion() const; | | int indexVersion() const; | |
| | | | |
|
| IndexSuitability _suitability( const BSONObj& query , const BSONObj | | IndexSuitability _suitability( const FieldRangeSet& queryConstraint | |
| & order ) const ; | | s , | |
| | | const BSONObj& order ) const ; | |
| | | | |
| BSONSizeTracker _sizeTracker; | | BSONSizeTracker _sizeTracker; | |
| vector<const char*> _fieldNames; | | vector<const char*> _fieldNames; | |
| vector<BSONElement> _fixed; | | vector<BSONElement> _fixed; | |
| | | | |
| BSONObj _nullKey; // a full key with all fields null | | BSONObj _nullKey; // a full key with all fields null | |
| BSONObj _nullObj; // only used for _nullElt | | BSONObj _nullObj; // only used for _nullElt | |
| BSONElement _nullElt; // jstNull | | BSONElement _nullElt; // jstNull | |
| | | | |
| BSONObj _undefinedObj; // only used for _undefinedElt | | BSONObj _undefinedObj; // only used for _undefinedElt | |
| | | | |
End of changes. 5 change blocks. |
| 6 lines changed or deleted | | 23 lines changed or added | |
|
| json.h | | json.h | |
|
| /** @file json.h */ | | | |
| | | | |
| /** | | /** | |
| * Copyright (C) 2008 10gen Inc. | | * Copyright (C) 2008 10gen Inc. | |
| * | | * | |
| * This program is free software: you can redistribute it and/or modify | | * 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
, | | * it under the terms of the GNU Affero General Public License, version 3
, | |
| * as published by the Free Software Foundation. | | * as published by the Free Software Foundation. | |
| * | | * | |
| * This program is distributed in the hope that it will be useful, | | * This program is distributed in the hope that it will be useful, | |
| * 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 | |
| | | | |
| skipping to change at line 24 | | 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 <string> | | #include <string> | |
| | | | |
| #include "mongo/bson/bsonobj.h" | | #include "mongo/bson/bsonobj.h" | |
|
| | | #include "mongo/base/status.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
|
| /** Create a BSONObj from a JSON <http://www.json.org> string. In addi | | /** | |
| tion | | * Create a BSONObj from a JSON <http://www.json.org>, | |
| to the JSON extensions extensions described here | | * <http://www.ietf.org/rfc/rfc4627.txt> string. In addition to the JS | |
| <http://mongodb.onconfluence.com/display/DOCS/Mongo+Extended+JSON>, | | ON | |
| this function accepts certain unquoted field names and allows single q | | * extensions extensions described here | |
| uotes | | * <http://mongodb.onconfluence.com/display/DOCS/Mongo+Extended+JSON>, | |
| to optionally be used when specifying field names and string values in | | this | |
| stead | | * function accepts unquoted field names and allows single quotes to | |
| of double quotes. JSON unicode escape sequences (of the form \uXXXX) | | * optionally be used when specifying field names and string values ins | |
| are | | tead | |
| converted to utf8. | | * of double quotes. JSON unicode escape sequences (of the form \uXXXX | |
| \throws MsgAssertionException if parsing fails. The message included | | ) are | |
| with | | * converted to utf8. | |
| this assertion includes a rough indication of where parsing failed. | | * | |
| */ | | * @throws MsgAssertionException if parsing fails. The message include | |
| BSONObj fromjson(const std::string &str); | | d with | |
| | | * this assertion includes the character offset where parsing failed. | |
| | | */ | |
| | | BSONObj fromjson(const std::string& str); | |
| | | | |
| | | /** @param len will be size of JSON object in text chars. */ | |
| | | BSONObj fromjson(const char* str, int* len=NULL); | |
| | | | |
| | | /** | |
| | | * Parser class. A BSONObj is constructed incrementally by passing a | |
| | | * BSONObjBuilder to the recursive parsing methods. The grammar for th | |
| | | e | |
| | | * element parsed is described before each function. | |
| | | */ | |
| | | class JParse { | |
| | | public: | |
| | | explicit JParse(const char*); | |
| | | | |
| | | /* | |
| | | * Notation: All-uppercase symbols denote non-terminals; all ot | |
| | | her | |
| | | * symbols are literals. | |
| | | */ | |
| | | | |
| | | /* | |
| | | * VALUE : | |
| | | * STRING | |
| | | * | NUMBER | |
| | | * | OBJECT | |
| | | * | ARRAY | |
| | | * | |
| | | * | true | |
| | | * | false | |
| | | * | null | |
| | | * | undefined | |
| | | * | |
| | | * | NaN | |
| | | * | Infinity | |
| | | * | -Infinity | |
| | | * | |
| | | * | DATE | |
| | | * | TIMESTAMP | |
| | | * | REGEX | |
| | | * | OBJECTID | |
| | | * | DBREF | |
| | | * | |
| | | * | new CONSTRUCTOR | |
| | | */ | |
| | | private: | |
| | | Status value(const StringData& fieldName, BSONObjBuilder&); | |
| | | | |
| | | /* | |
| | | * OBJECT : | |
| | | * {} | |
| | | * | { MEMBERS } | |
| | | * | SPECIALOBJECT | |
| | | * | |
| | | * MEMBERS : | |
| | | * PAIR | |
| | | * | PAIR , MEMBERS | |
| | | * | |
| | | * PAIR : | |
| | | * FIELD : VALUE | |
| | | * | |
| | | * SPECIALOBJECT : | |
| | | * OIDOBJECT | |
| | | * | BINARYOBJECT | |
| | | * | DATEOBJECT | |
| | | * | TIMESTAMPOBJECT | |
| | | * | REGEXOBJECT | |
| | | * | REFOBJECT | |
| | | * | UNDEFINEDOBJECT | |
| | | * | |
| | | */ | |
| | | public: | |
| | | Status object(const StringData& fieldName, BSONObjBuilder&, boo | |
| | | l subObj=true); | |
| | | | |
| | | private: | |
| | | /* The following functions are called with the '{' and the firs | |
| | | t | |
| | | * field already parsed since they are both implied given the | |
| | | * context. */ | |
| | | /* | |
| | | * OIDOBJECT : | |
| | | * { FIELD("$oid") : <24 character hex string> } | |
| | | */ | |
| | | Status objectIdObject(const StringData& fieldName, BSONObjBuild | |
| | | er&); | |
| | | | |
| | | /* | |
| | | * BINARYOBJECT : | |
| | | * { FIELD("$binary") : <base64 representation of a binary | |
| | | string>, | |
| | | * FIELD("$type") : <hexadecimal representation of a s | |
| | | ingle byte | |
| | | * indicating the data type> } | |
| | | */ | |
| | | Status binaryObject(const StringData& fieldName, BSONObjBuilder | |
| | | &); | |
| | | | |
| | | /* | |
| | | * DATEOBJECT : | |
| | | * { FIELD("$date") : <64 bit signed integer for millisecon | |
| | | ds since epoch> } | |
| | | */ | |
| | | Status dateObject(const StringData& fieldName, BSONObjBuilder&) | |
| | | ; | |
| | | | |
| | | /* | |
| | | * TIMESTAMPOBJECT : | |
| | | * { FIELD("$timestamp") : { | |
| | | * FIELD("t") : <32 bit unsigned integer for seconds si | |
| | | nce epoch>, | |
| | | * FIELD("i") : <32 bit unsigned integer for the increm | |
| | | ent> } } | |
| | | */ | |
| | | Status timestampObject(const StringData& fieldName, BSONObjBuil | |
| | | der&); | |
| | | | |
| | | /* | |
| | | * NOTE: the rules for the body of the regex are different | |
| | | here, | |
| | | * since it is quoted instead of surrounded by slashes. | |
| | | * REGEXOBJECT : | |
| | | * { FIELD("$regex") : <string representing body of regex> | |
| | | } | |
| | | * | { FIELD("$regex") : <string representing body of regex>, | |
| | | * FIELD("$options") : <string representing regex opti | |
| | | ons> } | |
| | | */ | |
| | | Status regexObject(const StringData& fieldName, BSONObjBuilder& | |
| | | ); | |
| | | | |
| | | /* | |
| | | * REFOBJECT : | |
| | | * { FIELD("$ref") : <string representing collection name>, | |
| | | * FIELD("$id") : <24 character hex string> } | |
| | | * | { FIELD("$ref") : STRING , FIELD("$id") : OBJECTID } | |
| | | * | { FIELD("$ref") : STRING , FIELD("$id") : OIDOBJECT } | |
| | | */ | |
| | | Status dbRefObject(const StringData& fieldName, BSONObjBuilder& | |
| | | ); | |
| | | | |
| | | /* | |
| | | * UNDEFINEDOBJECT : | |
| | | * { FIELD("$undefined") : true } | |
| | | */ | |
| | | Status undefinedObject(const StringData& fieldName, BSONObjBuil | |
| | | der&); | |
| | | | |
| | | /* | |
| | | * ARRAY : | |
| | | * [] | |
| | | * | [ ELEMENTS ] | |
| | | * | |
| | | * ELEMENTS : | |
| | | * VALUE | |
| | | * | VALUE , ELEMENTS | |
| | | */ | |
| | | Status array(const StringData& fieldName, BSONObjBuilder&); | |
| | | | |
| | | /* | |
| | | * NOTE: Currently only Date can be preceded by the "new" keywo | |
| | | rd | |
| | | * CONSTRUCTOR : | |
| | | * DATE | |
| | | */ | |
| | | Status constructor(const StringData& fieldName, BSONObjBuilder& | |
| | | ); | |
| | | | |
| | | /* The following functions only parse the body of the construct | |
| | | or | |
| | | * between the parentheses, not including the constructor name | |
| | | */ | |
| | | /* | |
| | | * DATE : | |
| | | * Date( <64 bit signed integer for milliseconds since epoc | |
| | | h> ) | |
| | | */ | |
| | | Status date(const StringData& fieldName, BSONObjBuilder&); | |
| | | | |
| | | /* | |
| | | * TIMESTAMP : | |
| | | * Timestamp( <32 bit unsigned integer for seconds since ep | |
| | | och>, | |
| | | * <32 bit unsigned integer for the increment> ) | |
| | | */ | |
| | | Status timestamp(const StringData& fieldName, BSONObjBuilder&); | |
| | | | |
| | | /* | |
| | | * OBJECTID : | |
| | | * ObjectId( <24 character hex string> ) | |
| | | */ | |
| | | Status objectId(const StringData& fieldName, BSONObjBuilder&); | |
| | | | |
| | | /* | |
| | | * DBREF : | |
| | | * Dbref( <namespace string> , <24 character hex string> ) | |
| | | */ | |
| | | Status dbRef(const StringData& fieldName, BSONObjBuilder&); | |
| | | | |
| | | /* | |
| | | * REGEX : | |
| | | * / REGEXCHARS / REGEXOPTIONS | |
| | | * | |
| | | * REGEXCHARS : | |
| | | * REGEXCHAR | |
| | | * | REGEXCHAR REGEXCHARS | |
| | | * | |
| | | * REGEXCHAR : | |
| | | * any-Unicode-character-except-/-or-\-or-CONTROLCHAR | |
| | | * | \" | |
| | | * | \' | |
| | | * | \\ | |
| | | * | \/ | |
| | | * | \b | |
| | | * | \f | |
| | | * | \n | |
| | | * | \r | |
| | | * | \t | |
| | | * | \v | |
| | | * | \u HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT | |
| | | * | \any-Unicode-character-except-x-or-[0-7] | |
| | | * | |
| | | * REGEXOPTIONS : | |
| | | * REGEXOPTION | |
| | | * | REGEXOPTION REGEXOPTIONS | |
| | | * | |
| | | * REGEXOPTION : | |
| | | * g | i | m | s | |
| | | */ | |
| | | Status regex(const StringData& fieldName, BSONObjBuilder&); | |
| | | Status regexPat(std::string* result); | |
| | | Status regexOpt(std::string* result); | |
| | | Status regexOptCheck(const StringData& opt); | |
| | | | |
| | | /* | |
| | | * NUMBER : | |
| | | * | |
| | | * NOTE: Number parsing is based on standard library functions, | |
| | | not | |
| | | * necessarily on the JSON numeric grammar. | |
| | | * | |
| | | * Number as value - strtoll and strtod | |
| | | * Date - strtoll | |
| | | * Timestamp - strtoul for both timestamp and increment and '-' | |
| | | * before a number explicity disallowed | |
| | | */ | |
| | | Status number(const StringData& fieldName, BSONObjBuilder&); | |
| | | | |
| | | /* | |
| | | * FIELD : | |
| | | * STRING | |
| | | * | [a-zA-Z$_] FIELDCHARS | |
| | | * | |
| | | * FIELDCHARS : | |
| | | * [a-zA-Z0-9$_] | |
| | | * | [a-zA-Z0-9$_] FIELDCHARS | |
| | | */ | |
| | | Status field(std::string* result); | |
| | | | |
| | | /* | |
| | | * STRING : | |
| | | * " " | |
| | | * | ' ' | |
| | | * | " CHARS " | |
| | | * | ' CHARS ' | |
| | | */ | |
| | | Status quotedString(std::string* result); | |
| | | | |
| | | /* | |
| | | * CHARS : | |
| | | * CHAR | |
| | | * | CHAR CHARS | |
| | | * | |
| | | * Note: " or ' may be allowed depending on whether the string | |
| | | is | |
| | | * double or single quoted | |
| | | * | |
| | | * CHAR : | |
| | | * any-Unicode-character-except-"-or-'-or-\-or-CONTROLCHAR | |
| | | * | \" | |
| | | * | \' | |
| | | * | \\ | |
| | | * | \/ | |
| | | * | \b | |
| | | * | \f | |
| | | * | \n | |
| | | * | \r | |
| | | * | \t | |
| | | * | \v | |
| | | * | \u HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT | |
| | | * | \any-Unicode-character-except-x-or-[0-9] | |
| | | * | |
| | | * HEXDIGIT : [0..9a..fA..F] | |
| | | * | |
| | | * per http://www.ietf.org/rfc/rfc4627.txt, control characters | |
| | | are | |
| | | * (U+0000 through U+001F). U+007F is not mentioned as a contr | |
| | | ol | |
| | | * character. | |
| | | * CONTROLCHAR : [0x00..0x1F] | |
| | | * | |
| | | * If there is not an error, result will contain a null termina | |
| | | ted | |
| | | * string, but there is no guarantee that it will not contain o | |
| | | ther | |
| | | * null characters. | |
| | | */ | |
| | | Status chars(std::string* result, const char* terminalSet, cons | |
| | | t char* allowedSet=NULL); | |
| | | | |
| | | /** | |
| | | * Converts the two byte Unicode code point to its UTF8 charact | |
| | | er | |
| | | * encoding representation. This function returns a string bec | |
| | | ause | |
| | | * UTF8 encodings for code points from 0x0000 to 0xFFFF can ran | |
| | | ge | |
| | | * from one to three characters. | |
| | | */ | |
| | | std::string encodeUTF8(unsigned char first, unsigned char secon | |
| | | d) const; | |
| | | | |
| | | /** | |
| | | * @return true if the given token matches the next non whitesp | |
| | | ace | |
| | | * sequence in our buffer, and false if the token doesn't match | |
| | | or | |
| | | * we reach the end of our buffer. Do not update the pointer t | |
| | | o our | |
| | | * buffer if advance is false. | |
| | | */ | |
| | | bool accept(const char* token, bool advance=true); | |
| | | | |
| | | /** | |
| | | * @return true if the next field in our stream matches field. | |
| | | * Handles single quoted, double quoted, and unquoted field nam | |
| | | es | |
| | | */ | |
| | | bool acceptField(const StringData& field); | |
| | | | |
| | | /** | |
| | | * @return true if matchChar is in matchSet | |
| | | * @return true if matchSet is NULL and false if it is an empty | |
| | | string | |
| | | */ | |
| | | bool match(char matchChar, const char* matchSet) const; | |
| | | | |
| | | /** | |
| | | * @return true if every character in the string is a hex digit | |
| | | */ | |
| | | bool isHexString(const StringData&) const; | |
| | | | |
| | | /** | |
| | | * @return true if every character in the string is a valid bas | |
| | | e64 | |
| | | * character | |
| | | */ | |
| | | bool isBase64String(const StringData&) const; | |
| | | | |
| | | /** | |
| | | * @return FailedToParse status with the given message and some | |
| | | * additional context information | |
| | | */ | |
| | | Status parseError(const StringData& msg); | |
| | | public: | |
| | | inline int offset() { return (_input - _buf); } | |
| | | | |
|
| /** len will be size of JSON object in text chars. */ | | private: | |
| BSONObj fromjson(const char *str, int* len=NULL); | | /* | |
| | | * _buf - start of our input buffer | |
| | | * _input - cursor we advance in our input buffer | |
| | | * _input_end - sentinel for the end of our input buffer | |
| | | * | |
| | | * _buf is the null terminated buffer containing the JSON strin | |
| | | g we | |
| | | * are parsing. _input_end points to the null byte at the end | |
| | | of | |
| | | * the buffer. strtoll, strtol, and strtod will access the nul | |
| | | l | |
| | | * byte at the end of the buffer because they are assuming a c- | |
| | | style | |
| | | * string. | |
| | | */ | |
| | | const char* const _buf; | |
| | | const char* _input; | |
| | | const char* const _input_end; | |
| | | }; | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 4 change blocks. |
| 20 lines changed or deleted | | 405 lines changed or added | |
|
| keypattern.h | | keypattern.h | |
| | | | |
| skipping to change at line 21 | | skipping to change at line 21 | |
| * 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 "mongo/base/string_data.h" | |
| #include "mongo/db/jsobj.h" | | #include "mongo/db/jsobj.h" | |
| #include "mongo/util/mongoutils/str.h" | | #include "mongo/util/mongoutils/str.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| struct FieldInterval; | | struct FieldInterval; | |
| class FieldRangeSet; | | class FieldRangeSet; | |
| | | | |
| /** | | /** | |
| * A BoundList contains intervals specified by inclusive start | | * A BoundList contains intervals specified by inclusive start | |
| | | | |
| skipping to change at line 60 | | skipping to change at line 61 | |
| | | | |
| /* | | /* | |
| * Returns a BSON representation of this KeyPattern. | | * Returns a BSON representation of this KeyPattern. | |
| */ | | */ | |
| BSONObj toBSON() const { return _pattern; } | | BSONObj toBSON() const { return _pattern; } | |
| | | | |
| /* | | /* | |
| * Returns true if the given fieldname is the name of one element o
f the (potentially) | | * Returns true if the given fieldname is the name of one element o
f the (potentially) | |
| * compound key described by this KeyPattern. | | * compound key described by this KeyPattern. | |
| */ | | */ | |
|
| bool hasField( const char* fieldname ) const { return _pattern.hasF
ield( fieldname ); } | | bool hasField( const StringData& fieldname ) const { return _patter
n.hasField( fieldname ); } | |
| | | | |
| /* | | /* | |
| * Gets the element of this pattern corresponding to the given fiel
dname. | | * Gets the element of this pattern corresponding to the given fiel
dname. | |
| * Returns eoo if none exists. | | * Returns eoo if none exists. | |
| */ | | */ | |
| BSONElement getField( const char* fieldname ) const { return _patte
rn[ fieldname ]; } | | BSONElement getField( const char* fieldname ) const { return _patte
rn[ fieldname ]; } | |
| | | | |
| /* | | /* | |
| * Returns true if the key described by this KeyPattern is a prefix
of | | * Returns true if the key described by this KeyPattern is a prefix
of | |
| * the (potentially) compound key described by 'other' | | * the (potentially) compound key described by 'other' | |
| */ | | */ | |
| bool isPrefixOf( const KeyPattern& other ) const { | | bool isPrefixOf( const KeyPattern& other ) const { | |
| return _pattern.isPrefixOf( other.toBSON() ); | | return _pattern.isPrefixOf( other.toBSON() ); | |
| } | | } | |
| | | | |
|
| | | /* Takes a BSONObj whose field names are a prefix of the fields in | |
| | | this keyPattern, and | |
| | | * outputs a new bound with MinKey values appended to match the fie | |
| | | lds in this keyPattern | |
| | | * (or MaxKey values for descending -1 fields). This is useful in s | |
| | | harding for | |
| | | * calculating chunk boundaries when tag ranges are specified on a | |
| | | prefix of the actual | |
| | | * shard key, or for calculating index bounds when the shard key is | |
| | | a prefix of the actual | |
| | | * index used. | |
| | | * | |
| | | * @param makeUpperInclusive If true, then MaxKeys instead of MinKe | |
| | | ys will be appended, so | |
| | | * that the output bound will compare *greater* than the bound bein | |
| | | g extended (note that | |
| | | * -1's in the keyPattern will swap MinKey/MaxKey vals. See example | |
| | | s). | |
| | | * | |
| | | * Examples: | |
| | | * If this keyPattern is {a : 1} | |
| | | * extendRangeBound( {a : 55}, false) --> {a : 55} | |
| | | * | |
| | | * If this keyPattern is {a : 1, b : 1} | |
| | | * extendRangeBound( {a : 55}, false) --> {a : 55, b : MinKey} | |
| | | * extendRangeBound( {a : 55}, true ) --> {a : 55, b : MaxKey} | |
| | | * | |
| | | * If this keyPattern is {a : 1, b : -1} | |
| | | * extendRangeBound( {a : 55}, false) --> {a : 55, b : MaxKey} | |
| | | * extendRangeBound( {a : 55}, true ) --> {a : 55, b : MinKey} | |
| | | */ | |
| | | BSONObj extendRangeBound( const BSONObj& bound , bool makeUpperIncl | |
| | | usive ) const; | |
| | | | |
| /** | | /** | |
| * Returns true if this KeyPattern contains any computed values, (e
.g. {a : "hashed"}), | | * Returns true if this KeyPattern contains any computed values, (e
.g. {a : "hashed"}), | |
| * and false if this KeyPattern consists of only ascending/descendi
ng fields | | * and false if this KeyPattern consists of only ascending/descendi
ng fields | |
| * (e.g. {a : 1, b : -1}). With our current index expression langua
ge, "special" patterns | | * (e.g. {a : 1, b : -1}). With our current index expression langua
ge, "special" patterns | |
| * are any patterns that are not a simple list of field names and 1
/-1 values. | | * are any patterns that are not a simple list of field names and 1
/-1 values. | |
| */ | | */ | |
| bool isSpecial() const; | | bool isSpecial() const; | |
| | | | |
| /** | | /** | |
| * Returns true if the quantities stored in this KeyPattern can be
used to compute all the | | * Returns true if the quantities stored in this KeyPattern can be
used to compute all the | |
| | | | |
End of changes. 3 change blocks. |
| 1 lines changed or deleted | | 36 lines changed or added | |
|
| log.h | | log.h | |
| | | | |
| skipping to change at line 28 | | skipping to change at line 28 | |
| #pragma once | | #pragma once | |
| | | | |
| #include <string.h> | | #include <string.h> | |
| #include <sstream> | | #include <sstream> | |
| #include <errno.h> | | #include <errno.h> | |
| #include <vector> | | #include <vector> | |
| #include <boost/shared_ptr.hpp> | | #include <boost/shared_ptr.hpp> | |
| #include <boost/scoped_ptr.hpp> | | #include <boost/scoped_ptr.hpp> | |
| #include <boost/thread/tss.hpp> | | #include <boost/thread/tss.hpp> | |
| | | | |
|
| | | #include "mongo/base/status.h" | |
| #include "mongo/bson/util/builder.h" | | #include "mongo/bson/util/builder.h" | |
| #include "mongo/util/concurrency/mutex.h" | | #include "mongo/util/concurrency/mutex.h" | |
| #include "mongo/util/debug_util.h" | | #include "mongo/util/debug_util.h" | |
| #include "mongo/util/exit_code.h" | | #include "mongo/util/exit_code.h" | |
| | | | |
| #ifndef _WIN32 | | #ifndef _WIN32 | |
| #include <syslog.h> | | #include <syslog.h> | |
| #endif | | #endif | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| skipping to change at line 250 | | skipping to change at line 251 | |
| static mongo::mutex mutex; | | static mongo::mutex mutex; | |
| static int doneSetup; | | static int doneSetup; | |
| std::stringstream ss; | | std::stringstream ss; | |
| int indent; | | int indent; | |
| LogLevel logLevel; | | LogLevel logLevel; | |
| static FILE* logfile; | | static FILE* logfile; | |
| static boost::scoped_ptr<std::ostream> stream; | | static boost::scoped_ptr<std::ostream> stream; | |
| static std::vector<Tee*> * globalTees; | | static std::vector<Tee*> * globalTees; | |
| static bool isSyslog; | | static bool isSyslog; | |
| public: | | public: | |
|
| | | // Type for optional function for inserting context information in | |
| | | log messages. See | |
| | | // registerExtraLogContextFn, below. | |
| | | typedef void (*ExtraLogContextFn)(BufBuilder& builder); | |
| | | | |
| static void logLockless( const StringData& s ); | | static void logLockless( const StringData& s ); | |
| | | | |
| static void setLogFile(FILE* f); | | static void setLogFile(FILE* f); | |
| #ifndef _WIN32 | | #ifndef _WIN32 | |
| static void useSyslog(const char * name) { | | static void useSyslog(const char * name) { | |
| std::cout << "using syslog ident: " << name << std::endl; | | std::cout << "using syslog ident: " << name << std::endl; | |
| | | | |
| // openlog requires heap allocated non changing pointer | | // openlog requires heap allocated non changing pointer | |
| // this should only be called once per pragram execution | | // this should only be called once per pragram execution | |
| | | | |
| | | | |
| skipping to change at line 291 | | skipping to change at line 296 | |
| void flush(Tee *t = 0); | | void flush(Tee *t = 0); | |
| | | | |
| inline Nullstream& setLogLevel(LogLevel l) { | | inline Nullstream& setLogLevel(LogLevel l) { | |
| logLevel = l; | | logLevel = l; | |
| return *this; | | return *this; | |
| } | | } | |
| | | | |
| /** note these are virtual */ | | /** note these are virtual */ | |
| Logstream& operator<<(const char *x) { ss << x; return *this; } | | Logstream& operator<<(const char *x) { ss << x; return *this; } | |
| Logstream& operator<<(const string& x) { ss << x; return *this; } | | Logstream& operator<<(const string& x) { ss << x; return *this; } | |
|
| Logstream& operator<<(const StringData& x) { ss << x.data(); return
*this; } | | Logstream& operator<<(const StringData& x) { ss << x; return *this;
} | |
| Logstream& operator<<(char *x) { ss << x; return *this; } | | Logstream& operator<<(char *x) { ss << x; return *this; } | |
| Logstream& operator<<(char x) { ss << x; return *this; } | | Logstream& operator<<(char x) { ss << x; return *this; } | |
| Logstream& operator<<(int x) { ss << x; return *this; } | | Logstream& operator<<(int x) { ss << x; return *this; } | |
| Logstream& operator<<(ExitCode x) { ss << x; return *this; } | | Logstream& operator<<(ExitCode x) { ss << x; return *this; } | |
| Logstream& operator<<(long x) { ss << x; return *this; } | | Logstream& operator<<(long x) { ss << x; return *this; } | |
| Logstream& operator<<(unsigned long x) { ss << x; return *this; } | | Logstream& operator<<(unsigned long x) { ss << x; return *this; } | |
| Logstream& operator<<(unsigned x) { ss << x; return *this; } | | Logstream& operator<<(unsigned x) { ss << x; return *this; } | |
| Logstream& operator<<(unsigned short x){ ss << x; return *this; } | | Logstream& operator<<(unsigned short x){ ss << x; return *this; } | |
| Logstream& operator<<(double x) { ss << x; return *this; } | | Logstream& operator<<(double x) { ss << x; return *this; } | |
| Logstream& operator<<(void *x) { ss << x; return *this; } | | Logstream& operator<<(void *x) { ss << x; return *this; } | |
| | | | |
| skipping to change at line 342 | | skipping to change at line 347 | |
| globalTees = new std::vector<Tee*>(); | | globalTees = new std::vector<Tee*>(); | |
| globalTees->push_back( t ); | | globalTees->push_back( t ); | |
| } | | } | |
| | | | |
| void removeGlobalTee( Tee * tee ); | | void removeGlobalTee( Tee * tee ); | |
| | | | |
| void indentInc(){ indent++; } | | void indentInc(){ indent++; } | |
| void indentDec(){ indent--; } | | void indentDec(){ indent--; } | |
| int getIndent() const { return indent; } | | int getIndent() const { return indent; } | |
| | | | |
|
| | | // Replace any pre-existing function for appending context informat | |
| | | ion to log lines with | |
| | | // "contextFn". Returns Status::OK on first call, and ErrorCodes:: | |
| | | AlreadyInitialized if | |
| | | // called more than once. Returns ErrorCodes::BadValue if contextF | |
| | | n is NULL. | |
| | | static Status registerExtraLogContextFn(ExtraLogContextFn contextFn | |
| | | ); | |
| | | | |
| private: | | private: | |
| static boost::thread_specific_ptr<Logstream> tsp; | | static boost::thread_specific_ptr<Logstream> tsp; | |
| Logstream() { | | Logstream() { | |
| indent = 0; | | indent = 0; | |
| _init(); | | _init(); | |
| } | | } | |
| void _init() { | | void _init() { | |
| ss.str(""); | | ss.str(""); | |
| logLevel = LL_INFO; | | logLevel = LL_INFO; | |
| } | | } | |
|
| | | | |
| public: | | public: | |
| static Logstream& get(); | | static Logstream& get(); | |
| }; | | }; | |
| | | | |
| extern int logLevel; | | extern int logLevel; | |
| extern int tlogLevel; | | extern int tlogLevel; | |
| | | | |
| inline Nullstream& out( int level = 0 ) { | | inline Nullstream& out( int level = 0 ) { | |
| if ( level > logLevel ) | | if ( level > logLevel ) | |
| return nullstream; | | return nullstream; | |
| | | | |
End of changes. 5 change blocks. |
| 1 lines changed or deleted | | 17 lines changed or added | |
|
| matcher.h | | matcher.h | |
| | | | |
| skipping to change at line 25 | | skipping to change at line 25 | |
| * 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 "jsobj.h" | | #include "jsobj.h" | |
| #include "pcrecpp.h" | | #include "pcrecpp.h" | |
|
| | | #include "mongo/db/geo/geoparser.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| class Cursor; | | class Cursor; | |
| class CoveredIndexMatcher; | | class CoveredIndexMatcher; | |
| class ElementMatcher; | | class ElementMatcher; | |
| class Matcher; | | class Matcher; | |
| class FieldRangeVector; | | class FieldRangeVector; | |
| | | | |
| class RegexMatcher { | | class RegexMatcher { | |
| | | | |
| skipping to change at line 52 | | skipping to change at line 53 | |
| | | | |
| const char *_fieldName; | | const char *_fieldName; | |
| const char *_regex; | | const char *_regex; | |
| const char *_flags; | | const char *_flags; | |
| string _prefix; | | string _prefix; | |
| shared_ptr< pcrecpp::RE > _re; | | shared_ptr< pcrecpp::RE > _re; | |
| bool _isNot; | | bool _isNot; | |
| RegexMatcher() : _isNot() {} | | RegexMatcher() : _isNot() {} | |
| }; | | }; | |
| | | | |
|
| | | class GeoMatcher { | |
| | | private: | |
| | | GeoMatcher(const string& field, bool isNot) : _isBox(false), _isCir | |
| | | cle(false), | |
| | | _isPolygon(false), _f | |
| | | ieldName(field), | |
| | | _isNot(isNot) {} | |
| | | bool _isBox; | |
| | | Box _box; | |
| | | | |
| | | bool _isCircle; | |
| | | Point _center; | |
| | | double _radius; | |
| | | | |
| | | bool _isPolygon; | |
| | | Polygon _polygon; | |
| | | | |
| | | string _fieldName; | |
| | | bool _isNot; | |
| | | public: | |
| | | const string& getFieldName() const { return _fieldName; } | |
| | | | |
| | | static GeoMatcher makeBoxMatcher(const string& field, const BSONObj | |
| | | &obj, bool isNot) { | |
| | | GeoMatcher m(field, isNot); | |
| | | m._isBox = true; | |
| | | GeoParser::parseLegacyBox(obj, &m._box); | |
| | | return m; | |
| | | } | |
| | | | |
| | | static GeoMatcher makeCircleMatcher(const string& field, const BSON | |
| | | Obj &obj, bool isNot) { | |
| | | GeoMatcher m(field, isNot); | |
| | | m._isCircle = true; | |
| | | GeoParser::parseLegacyCenter(obj, &m._center, &m._radius); | |
| | | return m; | |
| | | } | |
| | | | |
| | | static GeoMatcher makePolygonMatcher(const string& field, const BSO | |
| | | NObj &obj, bool isNot) { | |
| | | GeoMatcher m(field, isNot); | |
| | | m._isPolygon = true; | |
| | | GeoParser::parseLegacyPolygon(obj, &m._polygon); | |
| | | return m; | |
| | | } | |
| | | | |
| | | bool containsPoint(Point p) const { | |
| | | bool ret; | |
| | | if (_isBox) { | |
| | | ret = _box.inside(p, 0); | |
| | | } else if (_isCircle) { | |
| | | ret = distance(p, _center) <= _radius; | |
| | | } else if (_isPolygon) { | |
| | | ret = _polygon.contains(p); | |
| | | } else { | |
| | | ret = false; | |
| | | } | |
| | | return _isNot ? !ret : ret; | |
| | | } | |
| | | | |
| | | string toString() const { | |
| | | stringstream ss; | |
| | | if (_isBox) { | |
| | | ss << "GeoMatcher Box: " << _box.toString(); | |
| | | } else if (_isCircle) { | |
| | | ss << "GeoMatcher Circle @ " << _center.toString() << " r = | |
| | | " << _radius; | |
| | | } else { | |
| | | ss << "GeoMatcher UNKNOWN"; | |
| | | } | |
| | | return ss.str(); | |
| | | } | |
| | | | |
| | | static bool pointFrom(const BSONObj o, Point *p) { | |
| | | if (!GeoParser::isLegacyPoint(o)) { return false; } | |
| | | GeoParser::parseLegacyPoint(o, p); | |
| | | return true; | |
| | | } | |
| | | }; | |
| | | | |
| struct element_lt { | | struct element_lt { | |
| bool operator()(const BSONElement& l, const BSONElement& r) const { | | bool operator()(const BSONElement& l, const BSONElement& r) const { | |
| int x = (int) l.canonicalType() - (int) r.canonicalType(); | | int x = (int) l.canonicalType() - (int) r.canonicalType(); | |
| if ( x < 0 ) return true; | | if ( x < 0 ) return true; | |
| else if ( x > 0 ) return false; | | else if ( x > 0 ) return false; | |
| return compareElementValues(l,r) < 0; | | return compareElementValues(l,r) < 0; | |
| } | | } | |
| }; | | }; | |
| | | | |
| /** | | /** | |
| | | | |
| skipping to change at line 225 | | skipping to change at line 300 | |
| return _jsobj.toString(); | | return _jsobj.toString(); | |
| } | | } | |
| | | | |
| /** | | /** | |
| * @return true if this key matcher will return the same true/false | | * @return true if this key matcher will return the same true/false | |
| * value as the provided doc matcher. | | * value as the provided doc matcher. | |
| */ | | */ | |
| bool keyMatch( const Matcher &docMatcher ) const; | | bool keyMatch( const Matcher &docMatcher ) const; | |
| | | | |
| bool singleSimpleCriterion() const { | | bool singleSimpleCriterion() const { | |
|
| return false; // TODO SERVER-958 | | if ( _where || | |
| // // TODO Really check, especially if all basics are ok. | | _basics.size() > 1 || | |
| // // $all, etc | | _haveNeg || | |
| // // _orConstraints? | | _haveSize || | |
| // return ( ( basics.size() + nRegex ) < 2 ) && !where && !_orMa | | _regexs.size() > 0 ) | |
| tchers.size() && !_norMatchers.size(); | | return false; | |
| | | | |
| | | if ( _jsobj.nFields() > 1 ) | |
| | | return false; | |
| | | | |
| | | if ( _basics.size() != 1 ) | |
| | | return false; | |
| | | | |
| | | if ( strchr( _jsobj.firstElement().fieldName(), '.' ) ) | |
| | | return false; | |
| | | | |
| | | return _basics[0]._compareOp == BSONObj::Equality; | |
| } | | } | |
| | | | |
| const BSONObj *getQuery() const { return &_jsobj; }; | | const BSONObj *getQuery() const { return &_jsobj; }; | |
| | | | |
| private: | | private: | |
| /** | | /** | |
| * Generate a matcher for the provided index key format using the | | * Generate a matcher for the provided index key format using the | |
| * provided full doc matcher. | | * provided full doc matcher. | |
| */ | | */ | |
| Matcher( const Matcher &docMatcher, const BSONObj &constrainIndexKe
y ); | | Matcher( const Matcher &docMatcher, const BSONObj &constrainIndexKe
y ); | |
| | | | |
| skipping to change at line 276 | | skipping to change at line 363 | |
| bool _haveNeg; | | bool _haveNeg; | |
| | | | |
| /* $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://dochub.mongodb.org/core/remove | | http://dochub.mongodb.org/core/remove | |
| */ | | */ | |
| bool _atomic; | | bool _atomic; | |
| | | | |
| vector<RegexMatcher> _regexs; | | vector<RegexMatcher> _regexs; | |
|
| | | vector<GeoMatcher> _geo; | |
| | | | |
| // so we delete the mem when we're done: | | // so we delete the mem when we're done: | |
| vector< shared_ptr< BSONObjBuilder > > _builders; | | vector< shared_ptr< BSONObjBuilder > > _builders; | |
| list< shared_ptr< Matcher > > _andMatchers; | | list< shared_ptr< Matcher > > _andMatchers; | |
| list< shared_ptr< Matcher > > _orMatchers; | | list< shared_ptr< Matcher > > _orMatchers; | |
| list< shared_ptr< Matcher > > _norMatchers; | | list< shared_ptr< Matcher > > _norMatchers; | |
| | | | |
| friend class CoveredIndexMatcher; | | friend class CoveredIndexMatcher; | |
| }; | | }; | |
| | | | |
| | | | |
End of changes. 4 change blocks. |
| 6 lines changed or deleted | | 99 lines changed or added | |
|
| mock_dbclient_connection.h | | mock_dbclient_connection.h | |
| | | | |
| skipping to change at line 19 | | skipping to change at line 19 | |
| * 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 <boost/shared_ptr.hpp> | | #include <boost/shared_ptr.hpp> | |
|
| #include <map> | | | |
| #include <string> | | #include <string> | |
| #include <vector> | | #include <vector> | |
| | | | |
| #include "mongo/client/dbclientinterface.h" | | #include "mongo/client/dbclientinterface.h" | |
| #include "mongo/dbtests/mock/mock_remote_db_server.h" | | #include "mongo/dbtests/mock/mock_remote_db_server.h" | |
| | | | |
|
| namespace mongo_test { | | namespace mongo { | |
| /** | | /** | |
| * A simple class for mocking mongo::DBClientConnection. | | * A simple class for mocking mongo::DBClientConnection. | |
| * | | * | |
| * Also check out sample usage in dbtests/mock_dbclient_conn_test.cpp | | * Also check out sample usage in dbtests/mock_dbclient_conn_test.cpp | |
| */ | | */ | |
| class MockDBClientConnection : public mongo::DBClientConnection { | | class MockDBClientConnection : public mongo::DBClientConnection { | |
| public: | | public: | |
| /** | | /** | |
| * Create a mock connection to a mock server. | | * Create a mock connection to a mock server. | |
| * | | * | |
| * @param remoteServer the remote server to connect to. The caller
is | | * @param remoteServer the remote server to connect to. The caller
is | |
| * responsible for making sure that the life of remoteServer is | | * responsible for making sure that the life of remoteServer is | |
| * longer than this connection. | | * longer than this connection. | |
|
| | | * @param autoReconnect will automatically re-establish connection | |
| | | the | |
| | | * next time an operation is requested when the last operation | |
| | | caused | |
| | | * this connection to fall into a failed state. | |
| */ | | */ | |
|
| MockDBClientConnection(MockRemoteDBServer* remoteServer); | | MockDBClientConnection(MockRemoteDBServer* remoteServer, bool autoR
econnect = false); | |
| virtual ~MockDBClientConnection(); | | virtual ~MockDBClientConnection(); | |
| | | | |
| // | | // | |
| // DBClientBase methods | | // DBClientBase methods | |
| // | | // | |
| | | | |
|
| | | bool connect(const char* hostName, std::string& errmsg); | |
| | | | |
| | | inline bool connect(const HostAndPort& host, std::string& errmsg) { | |
| | | return connect(host.toString().c_str(), errmsg); | |
| | | } | |
| | | | |
| bool runCommand(const std::string& dbname, const mongo::BSONObj& cm
dObj, | | bool runCommand(const std::string& dbname, const mongo::BSONObj& cm
dObj, | |
|
| mongo::BSONObj &info, int options = 0, | | mongo::BSONObj &info, int options = 0); | |
| const mongo::AuthenticationTable* auth = NULL); | | | |
| | | | |
| std::auto_ptr<mongo::DBClientCursor> query(const std::string &ns, | | std::auto_ptr<mongo::DBClientCursor> query(const std::string &ns, | |
| mongo::Query query = mongo::Query(), | | mongo::Query query = mongo::Query(), | |
| int nToReturn = 0, | | int nToReturn = 0, | |
| int nToSkip = 0, | | int nToSkip = 0, | |
| const mongo::BSONObj* fieldsToReturn = 0, | | const mongo::BSONObj* fieldsToReturn = 0, | |
| int queryOptions = 0, | | int queryOptions = 0, | |
| int batchSize = 0); | | int batchSize = 0); | |
| | | | |
| uint64_t getSockCreationMicroSec() const; | | uint64_t getSockCreationMicroSec() const; | |
| | | | |
|
| | | virtual void insert(const string& ns, BSONObj obj, int flags = 0); | |
| | | | |
| | | virtual void insert(const string& ns, const vector<BSONObj>& objLis | |
| | | t, int flags = 0); | |
| | | | |
| | | virtual void remove(const string& ns, Query query, bool justOne = f | |
| | | alse); | |
| | | | |
| | | virtual void remove(const string& ns, Query query, int flags = 0); | |
| | | | |
| // | | // | |
| // Getters | | // Getters | |
| // | | // | |
| | | | |
| mongo::ConnectionString::ConnectionType type() const; | | mongo::ConnectionString::ConnectionType type() const; | |
| bool isFailed() const; | | bool isFailed() const; | |
| double getSoTimeout() const; | | double getSoTimeout() const; | |
| std::string getServerAddress() const; | | std::string getServerAddress() const; | |
| std::string toString(); | | std::string toString(); | |
| | | | |
| | | | |
| skipping to change at line 97 | | skipping to change at line 112 | |
| | | | |
| void killCursor(long long cursorID); | | void killCursor(long long cursorID); | |
| bool callRead(mongo::Message& toSend , mongo::Message& response); | | bool callRead(mongo::Message& toSend , mongo::Message& response); | |
| bool call(mongo::Message& toSend, mongo::Message& response, bool as
sertOk = true, | | bool call(mongo::Message& toSend, mongo::Message& response, bool as
sertOk = true, | |
| std::string* actualServer = 0); | | std::string* actualServer = 0); | |
| void say(mongo::Message& toSend, bool isRetry = false, std::string*
actualServer = 0); | | void say(mongo::Message& toSend, bool isRetry = false, std::string*
actualServer = 0); | |
| void sayPiggyBack(mongo::Message& toSend); | | void sayPiggyBack(mongo::Message& toSend); | |
| bool lazySupported() const; | | bool lazySupported() const; | |
| | | | |
| private: | | private: | |
|
| const MockRemoteDBServer::InstanceID _remoteServerInstanceID; | | void checkConnection(); | |
| | | | |
| | | MockRemoteDBServer::InstanceID _remoteServerInstanceID; | |
| MockRemoteDBServer* _remoteServer; | | MockRemoteDBServer* _remoteServer; | |
| bool _isFailed; | | bool _isFailed; | |
| uint64_t _sockCreationTime; | | uint64_t _sockCreationTime; | |
|
| | | bool _autoReconnect; | |
| }; | | }; | |
| } | | } | |
| | | | |
End of changes. 9 change blocks. |
| 6 lines changed or deleted | | 28 lines changed or added | |
|
| mock_remote_db_server.h | | mock_remote_db_server.h | |
| | | | |
| skipping to change at line 19 | | skipping to change at line 19 | |
| * 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 <boost/shared_ptr.hpp> | | #include <boost/shared_ptr.hpp> | |
|
| #include <map> | | | |
| #include <string> | | #include <string> | |
| #include <vector> | | #include <vector> | |
| | | | |
|
| | | #include "mongo/bson/bsonobjbuilder.h" | |
| #include "mongo/client/dbclientinterface.h" | | #include "mongo/client/dbclientinterface.h" | |
|
| | | #include "mongo/platform/unordered_map.h" | |
| #include "mongo/util/concurrency/spin_lock.h" | | #include "mongo/util/concurrency/spin_lock.h" | |
| | | | |
|
| namespace mongo_test { | | namespace mongo { | |
| /** | | /** | |
| * A very simple mock that acts like a database server. Every object ke
eps track of its own | | * A very simple mock that acts like a database server. Every object ke
eps track of its own | |
| * InstanceID, which initially starts at zero and increments every time
it is restarted. | | * InstanceID, which initially starts at zero and increments every time
it is restarted. | |
| * This is primarily used for simulating the state of which old connect
ions won't be able | | * This is primarily used for simulating the state of which old connect
ions won't be able | |
| * to talk to the sockets that has already been closed on this server. | | * to talk to the sockets that has already been closed on this server. | |
| * | | * | |
| * Note: All operations on this server are protected by a lock. | | * Note: All operations on this server are protected by a lock. | |
| */ | | */ | |
| class MockRemoteDBServer { | | class MockRemoteDBServer { | |
| public: | | public: | |
| typedef size_t InstanceID; | | typedef size_t InstanceID; | |
| | | | |
| /** | | /** | |
|
| * Creates a new mock server. This also setups a hook to this serve | | * Creates a new mock server. This can also be setup to work with t | |
| r that can be used | | he | |
| * to allow clients using the ConnectionString::connect interface t | | * ConnectionString class by using mongo::MockConnRegistry as follo | |
| o create connections | | ws: | |
| * to this server. The requirements to make this hook fully functio | | | |
| nal are: | | | |
| * | | * | |
|
| * 1. hostName of this server should start with $. | | * ConnectionString::setConnectionHook(MockConnRegistry::get()->get | |
| * 2. No other instance has the same hostName as this. | | ConnStrHook()); | |
| | | * MockRemoteDBServer server("$a:27017"); | |
| | | * MockConnRegistry::get()->addServer(&server); | |
| * | | * | |
|
| * To register the hook, simply call setConnectionHook: | | * This allows clients using the ConnectionString::connect interfac | |
| | | e to create | |
| | | * connections to this server. The requirements to make this hook f | |
| | | ully functional are: | |
| * | | * | |
|
| * MockRemoteDBServer mockServer; | | * 1. hostAndPort of this server should start with $. | |
| * ConnectionString::setConnectionHook(mockServer.getConnectionHook | | * 2. No other instance has the same hostAndPort as this. | |
| ()); | | | |
| * | | * | |
|
| * @param hostName the host name for this server. | | * @param hostAndPort the host name with port for this server. | |
| | | * | |
| | | * @see MockConnRegistry | |
| */ | | */ | |
|
| MockRemoteDBServer(const std::string& hostName); | | MockRemoteDBServer(const std::string& hostAndPort); | |
| virtual ~MockRemoteDBServer(); | | virtual ~MockRemoteDBServer(); | |
| | | | |
|
| /** | | | |
| * @return the hook that can be used with ConnectionString. | | | |
| */ | | | |
| mongo::ConnectionString::ConnectionHook* getConnectionHook(); | | | |
| | | | |
| // | | // | |
| // Connectivity methods | | // Connectivity methods | |
| // | | // | |
| | | | |
| /** | | /** | |
| * Set a delay for calls to query and runCommand | | * Set a delay for calls to query and runCommand | |
| */ | | */ | |
| void setDelay(long long milliSec); | | void setDelay(long long milliSec); | |
| | | | |
| /** | | /** | |
| | | | |
| skipping to change at line 113 | | skipping to change at line 112 | |
| * | | * | |
| * @param cmdName the name of the command. | | * @param cmdName the name of the command. | |
| * @param replySequence the sequence of replies to cycle through ev
ery time | | * @param replySequence the sequence of replies to cycle through ev
ery time | |
| * the given command is requested. This is useful for setting u
p a | | * the given command is requested. This is useful for setting u
p a | |
| * sequence of response when the command can be called more tha
n once | | * sequence of response when the command can be called more tha
n once | |
| * that requires different results when calling a method. | | * that requires different results when calling a method. | |
| */ | | */ | |
| void setCommandReply(const std::string& cmdName, | | void setCommandReply(const std::string& cmdName, | |
| const std::vector<mongo::BSONObj>& replySequence); | | const std::vector<mongo::BSONObj>& replySequence); | |
| | | | |
|
| | | /** | |
| | | * Inserts a single document to this server. | |
| | | * | |
| | | * @param ns the namespace to insert the document to. | |
| | | * @param obj the document to insert. | |
| | | * @param flags ignored. | |
| | | */ | |
| | | void insert(const string& ns, BSONObj obj, int flags = 0); | |
| | | | |
| | | /** | |
| | | * Removes documents from this server. | |
| | | * | |
| | | * @param ns the namespace to remove documents from. | |
| | | * @param query ignored. | |
| | | * @param flags ignored. | |
| | | */ | |
| | | void remove(const string& ns, Query query, int flags = 0); | |
| | | | |
| // | | // | |
| // DBClientBase methods | | // DBClientBase methods | |
| // | | // | |
| bool runCommand(InstanceID id, const std::string& dbname, | | bool runCommand(InstanceID id, const std::string& dbname, | |
| const mongo::BSONObj& cmdObj, | | const mongo::BSONObj& cmdObj, | |
|
| mongo::BSONObj &info, int options = 0, | | mongo::BSONObj &info, int options = 0); | |
| const mongo::AuthenticationTable* auth = NULL); | | | |
| | | | |
|
| std::auto_ptr<mongo::DBClientCursor> query(InstanceID id, | | mongo::BSONArray query(InstanceID id, | |
| const std::string &ns, | | const std::string &ns, | |
| mongo::Query query = mongo::Query(), | | mongo::Query query = mongo::Query(), | |
| int nToReturn = 0, | | int nToReturn = 0, | |
| int nToSkip = 0, | | int nToSkip = 0, | |
| const mongo::BSONObj* fieldsToReturn = 0, | | const mongo::BSONObj* fieldsToReturn = 0, | |
| int queryOptions = 0, | | int queryOptions = 0, | |
| int batchSize = 0); | | int batchSize = 0); | |
| | | | |
| // | | // | |
| // Getters | | // Getters | |
| // | | // | |
| | | | |
| InstanceID getInstanceID() const; | | InstanceID getInstanceID() const; | |
| mongo::ConnectionString::ConnectionType type() const; | | mongo::ConnectionString::ConnectionType type() const; | |
| double getSoTimeout() const; | | double getSoTimeout() const; | |
|
| | | | |
| | | /** | |
| | | * @return the exact string address passed to hostAndPort parameter | |
| | | of the | |
| | | * constructor. In other words, doesn't automatically append a | |
| | | * 'default' port if none is specified. | |
| | | */ | |
| std::string getServerAddress() const; | | std::string getServerAddress() const; | |
| std::string toString(); | | std::string toString(); | |
| | | | |
| // | | // | |
| // Call counters | | // Call counters | |
| // | | // | |
| | | | |
| size_t getCmdCount() const; | | size_t getCmdCount() const; | |
| size_t getQueryCount() const; | | size_t getQueryCount() const; | |
| void clearCounters(); | | void clearCounters(); | |
| | | | |
| skipping to change at line 166 | | skipping to change at line 188 | |
| */ | | */ | |
| CircularBSONIterator(const std::vector<mongo::BSONObj>& replyVe
ctor); | | CircularBSONIterator(const std::vector<mongo::BSONObj>& replyVe
ctor); | |
| mongo::BSONObj next(); | | mongo::BSONObj next(); | |
| | | | |
| private: | | private: | |
| std::vector<mongo::BSONObj>::iterator _iter; | | std::vector<mongo::BSONObj>::iterator _iter; | |
| std::vector<mongo::BSONObj> _replyObjs; | | std::vector<mongo::BSONObj> _replyObjs; | |
| }; | | }; | |
| | | | |
| /** | | /** | |
|
| * Custom connection hook that can be used with ConnectionString. | | | |
| */ | | | |
| class MockDBClientConnStrHook: public mongo::ConnectionString::Conn | | | |
| ectionHook { | | | |
| public: | | | |
| /** | | | |
| * Creates a new connection hook for the ConnectionString class | | | |
| that | | | |
| * can create mock connections to this server. | | | |
| * | | | |
| * @param replSet the mock replica set. Caller is responsible f | | | |
| or managing | | | |
| * mockServer and making sure that it lives longer than thi | | | |
| s object. | | | |
| */ | | | |
| MockDBClientConnStrHook(MockRemoteDBServer* mockServer); | | | |
| ~MockDBClientConnStrHook(); | | | |
| | | | |
| mongo::DBClientBase* connect( | | | |
| const mongo::ConnectionString& connString, | | | |
| std::string& errmsg, double socketTimeout); | | | |
| | | | |
| private: | | | |
| MockRemoteDBServer* _mockServer; | | | |
| }; | | | |
| | | | |
| /** | | | |
| * Checks whether the instance of the server is still up. | | * Checks whether the instance of the server is still up. | |
| * | | * | |
| * @throws mongo::SocketException if this server is down | | * @throws mongo::SocketException if this server is down | |
| */ | | */ | |
| void checkIfUp(InstanceID id) const; | | void checkIfUp(InstanceID id) const; | |
| | | | |
|
| typedef std::map<std::string, boost::shared_ptr<CircularBSONIterato | | typedef unordered_map<std::string, boost::shared_ptr<CircularBSONIt | |
| r> > CmdToReplyObj; | | erator> > CmdToReplyObj; | |
| | | typedef unordered_map<std::string, mongo::BSONArrayBuilder*> MockDa | |
| | | taMgr; | |
| | | | |
| bool _isRunning; | | bool _isRunning; | |
| | | | |
|
| std::string _hostName; | | const std::string _hostAndPort; | |
| long long _delayMilliSec; | | long long _delayMilliSec; | |
| | | | |
|
| | | // | |
| | | // Mock replies | |
| | | // | |
| CmdToReplyObj _cmdMap; | | CmdToReplyObj _cmdMap; | |
|
| | | MockDataMgr _dataMgr; | |
| | | | |
| // | | // | |
| // Op Counters | | // Op Counters | |
| // | | // | |
| size_t _cmdCount; | | size_t _cmdCount; | |
| size_t _queryCount; | | size_t _queryCount; | |
| | | | |
| // Unique id for every restart of this server used for rejecting re
quests from | | // Unique id for every restart of this server used for rejecting re
quests from | |
| // connections that are still "connected" to the old instance | | // connections that are still "connected" to the old instance | |
| InstanceID _instanceID; | | InstanceID _instanceID; | |
| | | | |
| // protects this entire instance | | // protects this entire instance | |
| mutable mongo::SpinLock _lock; | | mutable mongo::SpinLock _lock; | |
|
| | | | |
| MockDBClientConnStrHook _connStrHook; | | | |
| }; | | }; | |
| } | | } | |
| | | | |
End of changes. 21 change blocks. |
| 56 lines changed or deleted | | 57 lines changed or added | |
|
| mock_replica_set.h | | mock_replica_set.h | |
| | | | |
| skipping to change at line 25 | | skipping to change at line 25 | |
| | | | |
| #pragma once | | #pragma once | |
| | | | |
| #include "mongo/dbtests/mock/mock_remote_db_server.h" | | #include "mongo/dbtests/mock/mock_remote_db_server.h" | |
| #include "mongo/db/repl/rs_config.h" | | #include "mongo/db/repl/rs_config.h" | |
| | | | |
| #include <string> | | #include <string> | |
| #include <map> | | #include <map> | |
| #include <vector> | | #include <vector> | |
| | | | |
|
| namespace mongo_test { | | namespace mongo { | |
| /** | | /** | |
| * This is a helper class for managing a replica set consisting of | | * This is a helper class for managing a replica set consisting of | |
| * MockRemoteDBServer instances. | | * MockRemoteDBServer instances. | |
| * | | * | |
|
| | | * Note: Be sure to call ScopedDbConnection::clearPool() after every te | |
| | | st | |
| | | * when doing tests that involves the ReplicaSetMonitor. This is becaus | |
| | | e | |
| | | * it uses ScopedDbConnection which means you can have a residue connec | |
| | | tions | |
| | | * that was created from previous tests and can cause a seg fault if th | |
| | | e | |
| | | * MockRemoteDBServer instances were already destroyed. | |
| | | * | |
| * Warning: Not thread-safe | | * Warning: Not thread-safe | |
| */ | | */ | |
| class MockReplicaSet { | | class MockReplicaSet { | |
| public: | | public: | |
|
| | | typedef std::map<std::string, ReplSetConfig::MemberCfg> ReplConfigM | |
| | | ap; | |
| | | | |
| /** | | /** | |
| * Creates a mock replica set and automatically mocks the isMaster | | * Creates a mock replica set and automatically mocks the isMaster | |
| * and replSetGetStatus commands based on the default replica set | | * and replSetGetStatus commands based on the default replica set | |
| * configuration. | | * configuration. | |
| * | | * | |
| * @param setName The name for this replica set | | * @param setName The name for this replica set | |
| * @param nodes The initial number of nodes for this replica set | | * @param nodes The initial number of nodes for this replica set | |
| */ | | */ | |
| MockReplicaSet(const std::string& setName, size_t nodes); | | MockReplicaSet(const std::string& setName, size_t nodes); | |
| ~MockReplicaSet(); | | ~MockReplicaSet(); | |
| | | | |
| // | | // | |
| // getters | | // getters | |
| // | | // | |
| | | | |
| std::string getSetName() const; | | std::string getSetName() const; | |
| std::string getConnectionString() const; | | std::string getConnectionString() const; | |
|
| std::vector<mongo::HostAndPort> getHosts() const; | | std::vector<HostAndPort> getHosts() const; | |
| mongo::ConnectionString::ConnectionHook* getConnectionHook(); | | ReplConfigMap getReplConfig() const; | |
| const std::vector<mongo::ReplSetConfig::MemberCfg>& getReplConfig() | | | |
| const; | | | |
| std::string getPrimary() const; | | std::string getPrimary() const; | |
|
| const std::vector<std::string>& getSecondaries() const; | | std::vector<std::string> getSecondaries() const; | |
| | | | |
| /** | | /** | |
| * Sets the configuration for this replica sets. This also has a si
de effect | | * Sets the configuration for this replica sets. This also has a si
de effect | |
| * of mocking the ismaster and replSetGetStatus command responses b
ased on | | * of mocking the ismaster and replSetGetStatus command responses b
ased on | |
| * the new config. | | * the new config. | |
|
| | | * | |
| | | * Note: does not automatically select a new primary. Can be done m | |
| | | anually by | |
| | | * calling setPrimary. | |
| */ | | */ | |
|
| void setConfig(const std::vector<mongo::ReplSetConfig::MemberCfg>& | | void setConfig(const ReplConfigMap& newConfig); | |
| newConfig); | | | |
| | | void setPrimary(const std::string& hostAndPort); | |
| | | | |
| /** | | /** | |
| * @return pointer to the mocked remote server with the given hostN
ame. | | * @return pointer to the mocked remote server with the given hostN
ame. | |
| * NULL if host doesn't exists. | | * NULL if host doesn't exists. | |
| */ | | */ | |
|
| MockRemoteDBServer* getNode(const std::string& hostName); | | MockRemoteDBServer* getNode(const std::string& hostAndPort); | |
| | | | |
| /** | | /** | |
|
| * Kills a node. | | * Kills a node belonging to this set. | |
| * | | * | |
| * @param hostName the name of the replica node to kill. | | * @param hostName the name of the replica node to kill. | |
| */ | | */ | |
|
| void kill(const std::string& hostName); | | void kill(const std::string& hostAndPort); | |
| | | | |
| | | /** | |
| | | * Kills a set of host belonging to this set. | |
| | | * | |
| | | * @param hostList the list of host names of the servers to kill. | |
| | | */ | |
| | | void kill(const std::vector<std::string>& hostList); | |
| | | | |
| /** | | /** | |
| * Reboots a node. | | * Reboots a node. | |
| * | | * | |
| * @param hostName the name of the host to reboot. | | * @param hostName the name of the host to reboot. | |
| */ | | */ | |
| void restore(const std::string& hostName); | | void restore(const std::string& hostName); | |
| | | | |
| private: | | private: | |
|
| class ReplSetConnHook: public mongo::ConnectionString::ConnectionHo | | typedef std::map<std::string, MockRemoteDBServer*> ReplNodeMap; | |
| ok { | | | |
| public: | | | |
| /** | | | |
| * Creates a new connection hook for the ConnectionString class | | | |
| that | | | |
| * can create mock connections to mock replica set members usin | | | |
| g their | | | |
| * pseudo host names. | | | |
| * | | | |
| * @param replSet the mock replica set. Caller is responsible f | | | |
| or managing | | | |
| * replSet and making sure that it lives longer than this o | | | |
| bject. | | | |
| */ | | | |
| ReplSetConnHook(MockReplicaSet* replSet); | | | |
| ~ReplSetConnHook(); | | | |
| | | | |
| mongo::DBClientBase* connect( | | | |
| const mongo::ConnectionString& connString, | | | |
| std::string& errmsg, double socketTimeout); | | | |
| | | | |
| private: | | | |
| MockReplicaSet* _replSet; | | | |
| }; | | | |
| | | | |
| /** | | /** | |
| * Mocks the ismaster command based on the information on the curre
nt | | * Mocks the ismaster command based on the information on the curre
nt | |
| * replica set configuration. | | * replica set configuration. | |
| */ | | */ | |
| void mockIsMasterCmd(); | | void mockIsMasterCmd(); | |
| | | | |
| /** | | /** | |
| * Mocks the replSetGetStatus command based on the current states o
f the | | * Mocks the replSetGetStatus command based on the current states o
f the | |
| * mocked servers. | | * mocked servers. | |
| */ | | */ | |
| void mockReplSetGetStatusCmd(); | | void mockReplSetGetStatusCmd(); | |
| | | | |
| /** | | /** | |
| * @return the replica set state of the given host | | * @return the replica set state of the given host | |
| */ | | */ | |
|
| int getState(const std::string& host) const; | | int getState(const std::string& hostAndPort) const; | |
| | | | |
| const std::string _setName; | | const std::string _setName; | |
|
| std::map<std::string, MockRemoteDBServer*> _nodeMap; | | ReplNodeMap _nodeMap; | |
| ReplSetConnHook _connStringHook; | | ReplConfigMap _replConfig; | |
| std::vector<mongo::ReplSetConfig::MemberCfg> _replConfig; | | | |
| | | | |
| std::string _primaryHost; | | std::string _primaryHost; | |
|
| std::vector<std::string> _secondaryHosts; | | | |
| }; | | }; | |
| } | | } | |
| | | | |
End of changes. 14 change blocks. |
| 41 lines changed or deleted | | 38 lines changed or added | |
|
| mutable_bson.h | | mutable_bson.h | |
| | | | |
| skipping to change at line 32 | | skipping to change at line 32 | |
| #include "mongo/base/status.h" | | #include "mongo/base/status.h" | |
| #include "mongo/db/jsobj.h" | | #include "mongo/db/jsobj.h" | |
| #include "mongo/platform/cstdint.h" | | #include "mongo/platform/cstdint.h" | |
| #include "mongo/util/safe_num.h" | | #include "mongo/util/safe_num.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| namespace mutablebson { | | namespace mutablebson { | |
| | | | |
| class Document; | | class Document; | |
| class ElementVector; | | class ElementVector; | |
|
| class FilterIterator; | | | |
| class Heap; | | class Heap; | |
| class SiblingIterator; | | class SiblingIterator; | |
| struct ElementRep; | | struct ElementRep; | |
| | | | |
| /* | | /* | |
| * The Element class represents one node in the document tree. A docume
nt is | | * The Element class represents one node in the document tree. A docume
nt is | |
| * identified with its root node. | | * identified with its root node. | |
| * | | * | |
| * Elements are created with the help of the Document class. Once creat
ed, an | | * Elements are created with the help of the Document class. Once creat
ed, an | |
| * element can be introduced in any position in a document tree with me
thods | | * element can be introduced in any position in a document tree with me
thods | |
| | | | |
| skipping to change at line 60 | | skipping to change at line 59 | |
| * // Document is: {} | | * // Document is: {} | |
| * | | * | |
| * mutablebson::Element e0 = doc.makeObjElement("e0"); | | * mutablebson::Element e0 = doc.makeObjElement("e0"); | |
| * doc.root().addChild(e0); | | * doc.root().addChild(e0); | |
| * // Document is: { e0 : {} } | | * // Document is: { e0 : {} } | |
| * | | * | |
| * mutablebson::Element e1 = doc.makeObjElement("e1"); | | * mutablebson::Element e1 = doc.makeObjElement("e1"); | |
| * e0.addChild(e1); | | * e0.addChild(e1); | |
| * // Document is: { e0 : { e1 : {} } } | | * // Document is: { e0 : { e1 : {} } } | |
| * | | * | |
|
| * // traversal | | * TODO: Add iteration and search examples | |
| * mutablebson::SubtreeIterator it(&doc, e0); | | | |
| * while (!it.done()) { | | | |
| * cout << mutablebson::Element(&doc, it.getRep()).fieldName()) | | | |
| << endl; | | | |
| * } | | | |
| * | | * | |
|
| * // look up | | | |
| * mutablebson::FilterIterator it = e0.find("e1"); | | | |
| * if (!it.done()) { | | | |
| * cout << mongo::mutablebson::Element(&doc, it.getRep()).field | | | |
| Name( ) << endl; | | | |
| * } | | | |
| */ | | */ | |
| class Element { | | class Element { | |
| public: | | public: | |
| Element(Document* doc, uint32_t rep) | | Element(Document* doc, uint32_t rep) | |
| : _doc(doc) | | : _doc(doc) | |
| , _rep(rep) {} | | , _rep(rep) {} | |
| | | | |
| ~Element() {} | | ~Element() {} | |
| | | | |
| // | | // | |
| // navigation API | | // navigation API | |
| // | | // | |
| | | | |
| Element leftChild() const; | | Element leftChild() const; | |
| Element rightChild() const; | | Element rightChild() const; | |
| Element leftSibling() const; | | Element leftSibling() const; | |
| Element rightSibling() const; | | Element rightSibling() const; | |
| Element parent() const; | | Element parent() const; | |
| | | | |
|
| /** Find subtree nodes with a given name */ | | | |
| FilterIterator find(const std::string& fieldName) const; | | | |
| | | | |
| /** Iterate children of this node */ | | /** Iterate children of this node */ | |
| SiblingIterator children(); | | SiblingIterator children(); | |
| | | | |
| // | | // | |
| // update API | | // update API | |
| // | | // | |
| | | | |
| Status addChild(Element e); | | Status addChild(Element e); | |
| Status addSiblingBefore(Element e); | | Status addSiblingBefore(Element e); | |
| Status addSiblingAfter(Element e); | | Status addSiblingAfter(Element e); | |
| Status remove(); | | Status remove(); | |
|
| Status rename(const std::string& newName); | | Status rename(const StringData& newName); | |
| Status move(Element newParent); | | Status move(Element newParent); | |
| | | | |
| // | | // | |
| // array API | | // array API | |
| // | | // | |
| | | | |
| Status arraySize(uint32_t* size); | | Status arraySize(uint32_t* size); | |
| Status peekBack(Element* ep); | | Status peekBack(Element* ep); | |
| Status pushBack(Element e); | | Status pushBack(Element e); | |
| Status popBack(); | | Status popBack(); | |
| | | | |
| skipping to change at line 160 | | skipping to change at line 147 | |
| void setBoolValue(bool boolVal); | | void setBoolValue(bool boolVal); | |
| void setIntValue(int32_t intVal); | | void setIntValue(int32_t intVal); | |
| void setLongValue(int64_t longVal); | | void setLongValue(int64_t longVal); | |
| void setTSValue(OpTime tsVal); | | void setTSValue(OpTime tsVal); | |
| void setDateValue(int64_t millis); | | void setDateValue(int64_t millis); | |
| void setDoubleValue(double doubleVal); | | void setDoubleValue(double doubleVal); | |
| void setOIDValue(const OID& oid); | | void setOIDValue(const OID& oid); | |
| void setStringValue(const StringData& stringVal); | | void setStringValue(const StringData& stringVal); | |
| void setRegexValue(const StringData& re); | | void setRegexValue(const StringData& re); | |
| void setSafeNumValue(const SafeNum& safeNum); | | void setSafeNumValue(const SafeNum& safeNum); | |
|
| | | void setMinKey(); | |
| | | void setMaxKey(); | |
| | | void setUndefined(); | |
| | | void setNull(); | |
| | | void setSymbol(const StringData& symbolVal); | |
| | | | |
| | | /** Set the value of this element to equal the value of the | |
| | | * provided BSONElement 'val'. The name of this Element is | |
| | | * not modified. | |
| | | */ | |
| | | void setValueFromBSONElement(const BSONElement& val); | |
| | | | |
| // additional methods needed for BSON decoding | | // additional methods needed for BSON decoding | |
| Status prefix(std::string* result, char delim) const; | | Status prefix(std::string* result, char delim) const; | |
| Status suffix(std::string* result, char delim) const; | | Status suffix(std::string* result, char delim) const; | |
| Status regex(std::string* result) const; | | Status regex(std::string* result) const; | |
| Status regexFlags(std::string* result) const; | | Status regexFlags(std::string* result) const; | |
| Status dbrefNS(std::string* result) const; | | Status dbrefNS(std::string* result) const; | |
| Status dbrefOID(std::string* result) const; | | Status dbrefOID(std::string* result) const; | |
| Status codeWScopeCode(std::string* result) const; | | Status codeWScopeCode(std::string* result) const; | |
| Status codeWScopeScope(std::string* result) const; | | Status codeWScopeScope(std::string* result) const; | |
| | | | |
| skipping to change at line 208 | | skipping to change at line 206 | |
| Status appendRegex( | | Status appendRegex( | |
| const StringData& fieldName, const StringData& re, const String
Data& flags); | | const StringData& fieldName, const StringData& re, const String
Data& flags); | |
| Status appendCodeWScope( | | Status appendCodeWScope( | |
| const StringData& fieldName, const StringData& code, const Stri
ngData& scope); | | const StringData& fieldName, const StringData& code, const Stri
ngData& scope); | |
| Status appendBinary( | | Status appendBinary( | |
| const StringData& fieldName, uint32_t len, BinDataType t, const
void* bin); | | const StringData& fieldName, uint32_t len, BinDataType t, const
void* bin); | |
| | | | |
| Status appendSafeNum(const StringData& fieldName, const SafeNum num
); | | Status appendSafeNum(const StringData& fieldName, const SafeNum num
); | |
| | | | |
| // | | // | |
|
| // operator overloading | | | |
| // | | | |
| | | | |
| friend std::ostream& operator<<(std::ostream&, const Element&); | | | |
| | | | |
| // | | | |
| // encapsulate state | | // encapsulate state | |
| // | | // | |
| | | | |
|
| uint32_t getRep() const; | | uint32_t getRep() const { return _rep; }; | |
| void setRep(uint32_t rep); | | Document* getDocument() const { return _doc; } | |
| | | | |
| Document* getDocument() const; | | | |
| void setDocument(Document* doc); | | | |
| | | | |
| std::string fieldName() const; | | | |
| int fieldNameSize() const; | | | |
| | | | |
| // | | | |
| // output : mainly for debugging | | | |
| // | | | |
| | | | |
| std::ostream& put(std::ostream& os, uint32_t depth) const; | | | |
| std::ostream& putValue(std::ostream& os) const; | | | |
| std::string putType() const; | | | |
| | | | |
| // | | | |
| // For testing/debugging only: treat as private | | | |
| // | | | |
| | | | |
| ElementRep& getElementRep(); | | | |
| ElementRep& getElementRep() const; | | | |
| | | | |
|
| // | | StringData getFieldName() const; | |
| // helper methods | | | |
| // | | | |
| Status checkSubtreeIsClean(Element e); | | | |
| | | | |
| private: | | private: | |
|
| | | inline Status checkSubtreeIsClean(Element e); | |
| | | | |
| // We carry the document in every element. The document determines
the element: | | // We carry the document in every element. The document determines
the element: | |
| // '_rep' is resolved through the document ElementVector and Heap | | // '_rep' is resolved through the document ElementVector and Heap | |
| Document* _doc; | | Document* _doc; | |
| uint32_t _rep; | | uint32_t _rep; | |
| }; | | }; | |
| | | | |
| /** | | /** | |
| * Document contains the root node, and factory methods for | | * Document contains the root node, and factory methods for | |
| * creating new nodes. Storage is allocated for the nodes within | | * creating new nodes. Storage is allocated for the nodes within | |
| * the Content heap, and the document tree structure is stored in | | * the Content heap, and the document tree structure is stored in | |
| | | | |
| skipping to change at line 274 | | skipping to change at line 244 | |
| public: | | public: | |
| explicit Document(Heap* heap); | | explicit Document(Heap* heap); | |
| ~Document(); | | ~Document(); | |
| | | | |
| // | | // | |
| // getters, (setters?) | | // getters, (setters?) | |
| // | | // | |
| | | | |
| Heap* getHeap() { return _heap; } | | Heap* getHeap() { return _heap; } | |
| const Heap* getHeap() const { return _heap; } | | const Heap* getHeap() const { return _heap; } | |
|
| std::string getString(uint32_t offset) const; | | | |
| char* getStringBuffer(uint32_t offset) const; | | | |
| uint32_t elementVectorSize() const; | | | |
| | | | |
| // | | // | |
| // The distinguished root Element of the document, which is | | // The distinguished root Element of the document, which is | |
| // always an Object element. | | // always an Object element. | |
| // | | // | |
| Element& root() { return _root; } | | Element& root() { return _root; } | |
| const Element& root() const { return _root; } | | const Element& root() const { return _root; } | |
| | | | |
| // | | // | |
| // factory methods | | // factory methods | |
| | | | |
| skipping to change at line 317 | | skipping to change at line 284 | |
| const StringData& fieldName, const StringData& regex, const Str
ingData& flags); | | const StringData& fieldName, const StringData& regex, const Str
ingData& flags); | |
| Element makeCodeWScopeElement( | | Element makeCodeWScopeElement( | |
| const StringData& fieldName, const StringData& code, const Stri
ngData& scope); | | const StringData& fieldName, const StringData& code, const Stri
ngData& scope); | |
| Element makeDBRefElement( | | Element makeDBRefElement( | |
| const StringData& fieldName, const StringData& ns, const mongo:
:OID& oid); | | const StringData& fieldName, const StringData& ns, const mongo:
:OID& oid); | |
| Element makeBinaryElement( | | Element makeBinaryElement( | |
| const StringData& fieldName, uint32_t len, BinDataType binType,
const void* data); | | const StringData& fieldName, uint32_t len, BinDataType binType,
const void* data); | |
| | | | |
| private: | | private: | |
| friend class Element; | | friend class Element; | |
|
| friend class SubtreeIterator; | | | |
| friend class SiblingIterator; | | friend class SiblingIterator; | |
| | | | |
| Heap* const _heap; | | Heap* const _heap; | |
| boost::scoped_ptr<ElementVector> _elements; | | boost::scoped_ptr<ElementVector> _elements; | |
| Element _root; | | Element _root; | |
| }; | | }; | |
| | | | |
| // | | // | |
| // iteration support | | // iteration support | |
| // | | // | |
| | | | |
| class Iterator { | | class Iterator { | |
| public: | | public: | |
|
| virtual ~Iterator() {} | | | |
| Iterator(); | | Iterator(); | |
|
| Iterator(Element e); | | | |
| Iterator(const Iterator& it); | | explicit Iterator(Element e) | |
| | | : _doc(e.getDocument()) | |
| | | , _theRep(e.getRep()) {} | |
| | | | |
| | | virtual ~Iterator() {} | |
| | | | |
| // iterator interface | | // iterator interface | |
| virtual Iterator& operator++() = 0; | | virtual Iterator& operator++() = 0; | |
| virtual bool done() const = 0; | | virtual bool done() const = 0; | |
|
| Element operator*(); | | | |
| Element operator->(); | | Element operator*() { return Element(getDocument(), getRep()); } | |
| | | | |
| // acessors | | // acessors | |
|
| Document* getDocument() const; | | Document* getDocument() const { return _doc; } | |
| uint32_t getRep() const; | | uint32_t getRep() const { return _theRep; } | |
| | | | |
| protected: | | protected: | |
| Document* _doc; | | Document* _doc; | |
| uint32_t _theRep; | | uint32_t _theRep; | |
| }; | | }; | |
| | | | |
|
| /** implementation: subtree pre-order traversal */ | | | |
| class SubtreeIterator : public Iterator { | | | |
| public: | | | |
| virtual ~SubtreeIterator(); | | | |
| SubtreeIterator(); | | | |
| SubtreeIterator(Element e); | | | |
| SubtreeIterator(const SubtreeIterator& it); | | | |
| | | | |
| // iterator interface | | | |
| virtual Iterator& operator++(); | | | |
| virtual bool done() const; | | | |
| | | | |
| protected: | | | |
| bool advance(); | | | |
| | | | |
| protected: // state | | | |
| bool _theDoneBit; | | | |
| }; | | | |
| | | | |
| /** implementation: sibling iterator */ | | /** implementation: sibling iterator */ | |
| class SiblingIterator : public Iterator { | | class SiblingIterator : public Iterator { | |
| public: | | public: | |
|
| ~SiblingIterator(); | | SiblingIterator() | |
| SiblingIterator(); | | : Iterator() {} | |
| SiblingIterator(Element e); | | | |
| SiblingIterator(const SiblingIterator& it); | | | |
| | | | |
|
| // iterator interface | | explicit SiblingIterator(Element e) | |
| Iterator& operator++(); | | : Iterator(e) {} | |
| bool done() const; | | | |
| | | | |
| protected: // state | | | |
| bool advance(); | | | |
| }; | | | |
| | | | |
|
| /** interface: generic node filter - used by FilterIterator */ | | virtual ~SiblingIterator() {} | |
| class Filter { | | | |
| public: | | | |
| virtual ~Filter() {} | | | |
| | | | |
|
| // filter interface | | virtual SiblingIterator& operator++() { | |
| virtual bool match(Element) const = 0; | | advance(); | |
| }; | | return *this; | |
| | | } | |
| | | | |
|
| /** implementation: field name filter */ | | virtual bool done() const; | |
| class FieldNameFilter : public Filter { | | | |
| public: | | | |
| FieldNameFilter(const std::string& fieldName); | | | |
| ~FieldNameFilter(); | | | |
| | | | |
| // filter interface | | | |
| bool match(Element e) const; | | | |
| | | | |
| private: | | | |
| std::string _fieldName; | | | |
| }; | | | |
| | | | |
| /** implementation: filtered subtree pre-order traversal */ | | | |
| class FilterIterator : public SubtreeIterator { | | | |
| | | | |
| public: | | | |
| ~FilterIterator(); | | | |
| FilterIterator(); | | | |
| FilterIterator(Element e, const Filter* filt); | | | |
| FilterIterator(const FilterIterator& it); | | | |
| | | | |
| // iterator interface | | | |
| Iterator& operator++(); | | | |
| bool done() const; | | | |
| | | | |
| private: | | private: | |
|
| const Filter* _filter; | | bool advance(); | |
| }; | | }; | |
| | | | |
| } // namespace mutablebson | | } // namespace mutablebson | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 23 change blocks. |
| 124 lines changed or deleted | | 39 lines changed or added | |
|
| namespace_details.h | | namespace_details.h | |
| | | | |
| skipping to change at line 84 | | skipping to change at line 84 | |
| long long nrecords; | | long long nrecords; | |
| } stats; | | } stats; | |
| int lastExtentSize; | | int lastExtentSize; | |
| int nIndexes; | | int nIndexes; | |
| private: | | private: | |
| // ofs 192 | | // ofs 192 | |
| IndexDetails _indexes[NIndexesBase]; | | IndexDetails _indexes[NIndexesBase]; | |
| | | | |
| // ofs 352 (16 byte aligned) | | // ofs 352 (16 byte aligned) | |
| int _isCapped; // there is wasted space her
e if I'm right (ERH) | | int _isCapped; // there is wasted space her
e if I'm right (ERH) | |
|
| int _maxDocsInCapped; // max # of objects for a ca
pped table. TODO: should this be 64 bit? | | int _maxDocsInCapped; // max # of objects for a ca
pped table, -1 for inf. | |
| | | | |
| double _paddingFactor; // 1.0 = no padding. | | double _paddingFactor; // 1.0 = no padding. | |
| // ofs 386 (16) | | // ofs 386 (16) | |
| int _systemFlags; // things that the system sets/cares about | | int _systemFlags; // things that the system sets/cares about | |
| public: | | public: | |
| DiskLoc capExtent; // the "current" extent we're writing too for a
capped collection | | DiskLoc capExtent; // the "current" extent we're writing too for a
capped collection | |
| DiskLoc capFirstNewRecord; | | DiskLoc capFirstNewRecord; | |
| unsigned short dataFileVersion; // NamespaceDetails version.
So we can do backward compatibility in the future. See filever.h | | unsigned short dataFileVersion; // NamespaceDetails version.
So we can do backward compatibility in the future. See filever.h | |
| unsigned short indexFileVersion; | | unsigned short indexFileVersion; | |
| unsigned long long multiKeyIndexBits; | | unsigned long long multiKeyIndexBits; | |
| private: | | private: | |
| // ofs 400 (16) | | // ofs 400 (16) | |
| unsigned long long reservedA; | | unsigned long long reservedA; | |
| long long extraOffset; // where the $extra info is l
ocated (bytes relative to this) | | long long extraOffset; // where the $extra info is l
ocated (bytes relative to this) | |
| public: | | public: | |
|
| int indexBuildInProgress; // 1 if in prog | | int indexBuildsInProgress; // Number of indexes currentl
y being built | |
| private: | | private: | |
| int _userFlags; | | int _userFlags; | |
| char reserved[72]; | | char reserved[72]; | |
| /*-------- end data 496 bytes */ | | /*-------- end data 496 bytes */ | |
| public: | | public: | |
| explicit NamespaceDetails( const DiskLoc &loc, bool _capped ); | | explicit NamespaceDetails( const DiskLoc &loc, bool _capped ); | |
| | | | |
| class Extra { | | class Extra { | |
| long long _next; | | long long _next; | |
| public: | | public: | |
| | | | |
| skipping to change at line 158 | | skipping to change at line 158 | |
| Extent *theCapExtent() const { return capExtent.ext(); } | | Extent *theCapExtent() const { return capExtent.ext(); } | |
| void advanceCapExtent( const char *ns ); | | void advanceCapExtent( const char *ns ); | |
| DiskLoc __capAlloc(int len); | | DiskLoc __capAlloc(int len); | |
| DiskLoc cappedAlloc(const char *ns, int len); | | DiskLoc cappedAlloc(const char *ns, int len); | |
| DiskLoc &cappedFirstDeletedInCurExtent(); | | DiskLoc &cappedFirstDeletedInCurExtent(); | |
| bool nextIsInCapExtent( const DiskLoc &dl ) const; | | bool nextIsInCapExtent( const DiskLoc &dl ) const; | |
| | | | |
| public: | | public: | |
| | | | |
| bool isCapped() const { return _isCapped; } | | bool isCapped() const { return _isCapped; } | |
|
| long long maxCappedDocs() const { verify( isCapped() ); return _max
DocsInCapped; } | | long long maxCappedDocs() const; | |
| void setMaxCappedDocs( long long max ); | | void setMaxCappedDocs( long long max ); | |
|
| | | /** | |
| | | * @param max in and out, will be adjusted | |
| | | * @return if the value is valid at all | |
| | | */ | |
| | | static bool validMaxCappedDocs( long long* max ); | |
| | | | |
| DiskLoc& cappedListOfAllDeletedRecords() { return deletedList[0]; } | | DiskLoc& cappedListOfAllDeletedRecords() { return deletedList[0]; } | |
| DiskLoc& cappedLastDelRecLastExtent() { return deletedList[1]; } | | DiskLoc& cappedLastDelRecLastExtent() { return deletedList[1]; } | |
| void cappedDumpDelInfo(); | | void cappedDumpDelInfo(); | |
| bool capLooped() const { return _isCapped && capFirstNewRecord.isVa
lid(); } | | bool capLooped() const { return _isCapped && capFirstNewRecord.isVa
lid(); } | |
| bool inCapExtent( const DiskLoc &dl ) const; | | bool inCapExtent( const DiskLoc &dl ) const; | |
| void cappedCheckMigrate(); | | void cappedCheckMigrate(); | |
| /** | | /** | |
| * Truncate documents newer than the document at 'end' from the cap
ped | | * Truncate documents newer than the document at 'end' from the cap
ped | |
| * collection. The collection cannot be completely emptied using t
his | | * collection. The collection cannot be completely emptied using t
his | |
| * function. An assertion will be thrown if that is attempted. | | * function. An assertion will be thrown if that is attempted. | |
| * @param inclusive - Truncate 'end' as well iff true | | * @param inclusive - Truncate 'end' as well iff true | |
| */ | | */ | |
| void cappedTruncateAfter(const char *ns, DiskLoc end, bool inclusiv
e); | | void cappedTruncateAfter(const char *ns, DiskLoc end, bool inclusiv
e); | |
| /** Remove all documents from the capped collection */ | | /** Remove all documents from the capped collection */ | |
| void emptyCappedCollection(const char *ns); | | void emptyCappedCollection(const char *ns); | |
| | | | |
| /* when a background index build is in progress, we don't count the
index in nIndexes until | | /* 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. | | complete, yet need to still use it in _indexRecord() - thus we u
se this function for that. | |
| */ | | */ | |
|
| int nIndexesBeingBuilt() const { return nIndexes + indexBuildInProg
ress; } | | int getTotalIndexCount() const { return nIndexes + indexBuildsInPro
gress; } | |
| | | | |
| /* 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 SystemFlags { | | enum SystemFlags { | |
| Flag_HaveIdIndex = 1 << 0 // set when we have _id index (ONLY i
f ensureIdIndex was called -- 0 if that has never been called) | | Flag_HaveIdIndex = 1 << 0 // set when we have _id index (ONLY i
f ensureIdIndex was called -- 0 if that has never been called) | |
| }; | | }; | |
| | | | |
| enum UserFlags { | | enum UserFlags { | |
| Flag_UsePowerOf2Sizes = 1 << 0 | | Flag_UsePowerOf2Sizes = 1 << 0 | |
| }; | | }; | |
| | | | |
| IndexDetails& idx(int idxNo, bool missingExpected = false ); | | IndexDetails& idx(int idxNo, bool missingExpected = false ); | |
| | | | |
|
| /** get the IndexDetails for the index currently being built in the | | | |
| background. (there is at most one) */ | | | |
| IndexDetails& inProgIdx() { | | | |
| DEV verify(indexBuildInProgress); | | | |
| return idx(nIndexes); | | | |
| } | | | |
| | | | |
| class IndexIterator { | | class IndexIterator { | |
| public: | | public: | |
| int pos() { return i; } // note this is the next one to come | | int pos() { return i; } // note this is the next one to come | |
| bool more() { return i < n; } | | bool more() { return i < n; } | |
| IndexDetails& next() { return d->idx(i++); } | | IndexDetails& next() { return d->idx(i++); } | |
| private: | | private: | |
| friend class NamespaceDetails; | | friend class NamespaceDetails; | |
| int i, n; | | int i, n; | |
| NamespaceDetails *d; | | NamespaceDetails *d; | |
| IndexIterator(NamespaceDetails *_d); | | IndexIterator(NamespaceDetails *_d); | |
| | | | |
| skipping to change at line 223 | | skipping to change at line 222 | |
| IndexIterator ii() { return IndexIterator(this); } | | IndexIterator ii() { return IndexIterator(this); } | |
| | | | |
| /* hackish - find our index # in the indexes array */ | | /* hackish - find our index # in the indexes array */ | |
| int idxNo(const IndexDetails& idx); | | int idxNo(const IndexDetails& idx); | |
| | | | |
| /* multikey indexes are indexes where there are more than one key i
n the index | | /* multikey indexes are indexes where there are more than one key i
n the index | |
| for a single document. see multikey in wiki. | | for a single document. see multikey in wiki. | |
| for these, we have to do some dedup work on queries. | | for these, we have to do some dedup work on queries. | |
| */ | | */ | |
| bool isMultikey(int i) const { return (multiKeyIndexBits & (((unsig
ned long long) 1) << i)) != 0; } | | bool isMultikey(int i) const { return (multiKeyIndexBits & (((unsig
ned long long) 1) << i)) != 0; } | |
|
| void setIndexIsMultikey(const char *thisns, int i); | | void setIndexIsMultikey(const char *thisns, int i, bool multikey =
true); | |
| | | | |
| /** | | /** | |
| * This fetches the IndexDetails for the next empty index slot. The
caller must populate | | * This fetches the IndexDetails for the next empty index slot. The
caller must populate | |
| * returned object. This handles allocating extra index space, if
necessary. | | * returned object. This handles allocating extra index space, if
necessary. | |
| */ | | */ | |
| IndexDetails& getNextIndexDetails(const char* thisns); | | IndexDetails& getNextIndexDetails(const char* thisns); | |
| | | | |
| /** | | /** | |
| * Add a new index. This does not add it to system.indexes etc. -
just to NamespaceDetails. | | * Add a new index. This does not add it to system.indexes etc. -
just to NamespaceDetails. | |
| * This resets the transient namespace details. | | * This resets the transient namespace details. | |
| | | | |
| skipping to change at line 312 | | skipping to change at line 311 | |
| } | | } | |
| } | | } | |
| | | | |
| /* Returns the index entry for the first index whose prefix contain
s | | /* Returns the index entry for the first index whose prefix contain
s | |
| * 'keyPattern'. If 'requireSingleKey' is true, skip indices that c
ontain | | * 'keyPattern'. If 'requireSingleKey' is true, skip indices that c
ontain | |
| * array attributes. Otherwise, returns NULL. | | * array attributes. Otherwise, returns NULL. | |
| */ | | */ | |
| const IndexDetails* findIndexByPrefix( const BSONObj &keyPattern , | | const IndexDetails* findIndexByPrefix( const BSONObj &keyPattern , | |
| bool requireSingleKey ); | | bool requireSingleKey ); | |
| | | | |
|
| | | /* Updates the expireAfterSeconds field of the given index to the v | |
| | | alue in newExpireSecs. | |
| | | * The specified index must already contain an expireAfterSeconds f | |
| | | ield, and the value in | |
| | | * that field and newExpireSecs must both be numeric. | |
| | | */ | |
| | | void updateTTLIndex( int idxNo , const BSONElement& newExpireSecs ) | |
| | | ; | |
| | | | |
| const int systemFlags() const { return _systemFlags; } | | const int systemFlags() const { return _systemFlags; } | |
| bool isSystemFlagSet( int flag ) const { return _systemFlags & flag
; } | | bool isSystemFlagSet( int flag ) const { return _systemFlags & flag
; } | |
| void setSystemFlag( int flag ); | | void setSystemFlag( int flag ); | |
| void clearSystemFlag( int flag ); | | void clearSystemFlag( int flag ); | |
| | | | |
| const int userFlags() const { return _userFlags; } | | const int userFlags() const { return _userFlags; } | |
| bool isUserFlagSet( int flag ) const { return _userFlags & flag; } | | bool isUserFlagSet( int flag ) const { return _userFlags & flag; } | |
| | | | |
| /** | | /** | |
| * these methods only modify NamespaceDetails and do not | | * these methods only modify NamespaceDetails and do not | |
| | | | |
| skipping to change at line 370 | | skipping to change at line 375 | |
| /* @return the size for an allocated record quantized to 1/16th of
the BucketSize | | /* @return the size for an allocated record quantized to 1/16th of
the BucketSize | |
| @param allocSize requested size to allocate | | @param allocSize requested size to allocate | |
| */ | | */ | |
| static int quantizeAllocationSpace(int allocSize); | | static int quantizeAllocationSpace(int allocSize); | |
| | | | |
| /* predetermine location of the next alloc without actually doing i
t. | | /* predetermine location of the next alloc without actually doing i
t. | |
| if cannot predetermine returns null (so still call alloc() then) | | if cannot predetermine returns null (so still call alloc() then) | |
| */ | | */ | |
| DiskLoc allocWillBeAt(const char *ns, int lenToAlloc); | | DiskLoc allocWillBeAt(const char *ns, int lenToAlloc); | |
| | | | |
|
| /* allocate a new record. lenToAlloc includes headers. */ | | /** allocate space for a new record from deleted lists. | |
| | | @param lenToAlloc is WITH header | |
| | | @return null diskloc if no room - allocate a new extent then | |
| | | */ | |
| DiskLoc alloc(const char* ns, int lenToAlloc); | | DiskLoc alloc(const char* ns, int lenToAlloc); | |
| | | | |
| /* add a given record to the deleted chains for this NS */ | | /* add a given record to the deleted chains for this NS */ | |
| void addDeletedRec(DeletedRecord *d, DiskLoc dloc); | | void addDeletedRec(DeletedRecord *d, DiskLoc dloc); | |
| void dumpDeleted(set<DiskLoc> *extents = 0); | | void dumpDeleted(set<DiskLoc> *extents = 0); | |
| // 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; | |
| long long storageSize( int * numExtents = 0 , BSONArrayBuilder * ex
tentInfo = 0 ) const; | | long long storageSize( int * numExtents = 0 , BSONArrayBuilder * ex
tentInfo = 0 ) const; | |
| | | | |
| skipping to change at line 502 | | skipping to change at line 510 | |
| * The returned cursor may @throw inside of advance() or recoverFro
mYield() in certain error | | * The returned cursor may @throw inside of advance() or recoverFro
mYield() in certain error | |
| * cases, for example if a capped overrun occurred during a yield.
This indicates that the | | * cases, for example if a capped overrun occurred during a yield.
This indicates that the | |
| * cursor was unable to perform a complete scan. | | * cursor was unable to perform a complete scan. | |
| * | | * | |
| * This is a work in progress. Partial list of features not yet im
plemented through this | | * This is a work in progress. Partial list of features not yet im
plemented through this | |
| * interface: | | * interface: | |
| * | | * | |
| * - covered indexes | | * - covered indexes | |
| * - in memory sorting | | * - in memory sorting | |
| */ | | */ | |
|
| static shared_ptr<Cursor> getCursor( const char* ns, | | static shared_ptr<Cursor> getCursor( const StringData& ns, | |
| const BSONObj& query, | | const BSONObj& query, | |
| const BSONObj& order = BSONObj
(), | | const BSONObj& order = BSONObj
(), | |
| const QueryPlanSelectionPolicy
& planPolicy = | | const QueryPlanSelectionPolicy
& planPolicy = | |
| QueryPlanSelectionPolicy::
any(), | | QueryPlanSelectionPolicy::
any(), | |
| const shared_ptr<const ParsedQ
uery>& parsedQuery = | | const shared_ptr<const ParsedQ
uery>& parsedQuery = | |
| shared_ptr<const ParsedQue
ry>(), | | shared_ptr<const ParsedQue
ry>(), | |
| bool requireOrder = true, | | bool requireOrder = true, | |
| QueryPlanSummary* singlePlanSu
mmary = NULL ); | | QueryPlanSummary* singlePlanSu
mmary = NULL ); | |
| | | | |
| /** | | /** | |
| | | | |
| skipping to change at line 628 | | skipping to change at line 636 | |
| bool exists() const; | | bool exists() const; | |
| | | | |
| void init() { | | void init() { | |
| if( !ht ) | | if( !ht ) | |
| _init(); | | _init(); | |
| } | | } | |
| | | | |
| void add_ns(const char *ns, DiskLoc& loc, bool capped); | | void add_ns(const char *ns, DiskLoc& loc, bool capped); | |
| void add_ns( const char *ns, const NamespaceDetails &details ); | | void add_ns( const char *ns, const NamespaceDetails &details ); | |
| | | | |
|
| NamespaceDetails* details(const char *ns) { | | NamespaceDetails* details(const StringData& ns) { | |
| if ( !ht ) | | if ( !ht ) | |
| return 0; | | return 0; | |
| Namespace n(ns); | | Namespace n(ns); | |
| NamespaceDetails *d = ht->get(n); | | NamespaceDetails *d = ht->get(n); | |
| if ( d && d->isCapped() ) | | if ( d && d->isCapped() ) | |
| d->cappedCheckMigrate(); | | d->cappedCheckMigrate(); | |
| return d; | | return d; | |
| } | | } | |
| | | | |
| void kill_ns(const char *ns); | | void kill_ns(const char *ns); | |
| | | | |
End of changes. 11 change blocks. |
| 15 lines changed or deleted | | 25 lines changed or added | |
|
| pdfile.h | | pdfile.h | |
| | | | |
| skipping to change at line 46 | | skipping to change at line 46 | |
| #include "mongo/platform/cstdint.h" | | #include "mongo/platform/cstdint.h" | |
| #include "mongo/util/log.h" | | #include "mongo/util/log.h" | |
| #include "mongo/util/mmap.h" | | #include "mongo/util/mmap.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| // pdfile versions | | // pdfile versions | |
| const int PDFILE_VERSION = 4; | | const int PDFILE_VERSION = 4; | |
| const int PDFILE_VERSION_MINOR = 5; | | const int PDFILE_VERSION_MINOR = 5; | |
| | | | |
|
| | | class Cursor; | |
| class DataFileHeader; | | class DataFileHeader; | |
| class Extent; | | class Extent; | |
|
| class Record; | | | |
| class Cursor; | | | |
| class OpDebug; | | class OpDebug; | |
|
| | | class Record; | |
| | | struct SortPhaseOne; | |
| | | | |
| void dropDatabase(const std::string& db); | | void dropDatabase(const std::string& db); | |
| bool repairDatabase(string db, string &errmsg, bool preserveClonedFiles
OnFailure = false, bool backupOriginalFiles = false); | | bool repairDatabase(string db, string &errmsg, bool preserveClonedFiles
OnFailure = false, bool backupOriginalFiles = false); | |
| | | | |
| /* low level - only drops this ns */ | | /* low level - only drops this ns */ | |
| void dropNS(const string& dropNs); | | void dropNS(const string& dropNs); | |
| | | | |
| /* deletes this ns, indexes and cursors */ | | /* deletes this ns, indexes and cursors */ | |
| void dropCollection( const string &name, string &errmsg, BSONObjBuilder
&result ); | | void dropCollection( const string &name, string &errmsg, BSONObjBuilder
&result ); | |
| bool userCreateNS(const char *ns, BSONObj j, string& err, bool logForRe
plication, bool *deferIdIndex = 0); | | bool userCreateNS(const char *ns, BSONObj j, string& err, bool logForRe
plication, bool *deferIdIndex = 0); | |
| | | | |
| skipping to change at line 118 | | skipping to change at line 119 | |
| DataFileHeader* header() { return (DataFileHeader*) _mb; } | | DataFileHeader* header() { return (DataFileHeader*) _mb; } | |
| | | | |
| MongoMMF mmf; | | MongoMMF mmf; | |
| void *_mb; // the memory mapped view | | void *_mb; // the memory mapped view | |
| int fileNo; | | int fileNo; | |
| }; | | }; | |
| | | | |
| class DataFileMgr { | | class DataFileMgr { | |
| friend class BasicCursor; | | friend class BasicCursor; | |
| public: | | public: | |
|
| | | DataFileMgr(); | |
| 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 */ | |
| // changedId should be initialized to false | | // changedId should be initialized to false | |
| const DiskLoc updateRecord( | | const DiskLoc updateRecord( | |
| const char *ns, | | const char *ns, | |
| NamespaceDetails *d, | | NamespaceDetails *d, | |
| NamespaceDetailsTransient *nsdt, | | NamespaceDetailsTransient *nsdt, | |
| Record *toupdate, const DiskLoc& dl, | | Record *toupdate, const DiskLoc& dl, | |
| const char *buf, int len, OpDebug& debug, bool god=false); | | const char *buf, int len, OpDebug& debug, bool god=false); | |
| | | | |
| // 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, bool fromMigrate = false ); | | void insertAndLog( const char *ns, const BSONObj &o, bool god = fal
se, bool fromMigrate = false ); | |
| | | | |
| /** | | /** | |
| * insert() will add an _id to the object if not present. If you w
ould like to see the | | * insert() will add an _id to the object if not present. If you w
ould like to see the | |
| * final object after such an addition, use this method. | | * final object after such an addition, use this method. | |
|
| | | * note: does NOT put on oplog | |
| * @param o both and in and out param | | * @param o both and in and out param | |
| * @param mayInterrupt When true, killop may interrupt the function
call. | | * @param mayInterrupt When true, killop may interrupt the function
call. | |
| */ | | */ | |
| DiskLoc insertWithObjMod(const char* ns, | | DiskLoc insertWithObjMod(const char* ns, | |
| BSONObj& /*out*/o, | | BSONObj& /*out*/o, | |
| bool mayInterrupt = false, | | bool mayInterrupt = false, | |
| bool god = false); | | bool god = false); | |
| | | | |
|
| /** @param obj in value only for this version. */ | | | |
| void insertNoReturnVal(const char *ns, BSONObj o, bool god = false) | | | |
| ; | | | |
| | | | |
| /** | | /** | |
| * Insert the contents of @param buf with length @param len into na
mespace @param ns. | | * Insert the contents of @param buf with length @param len into na
mespace @param ns. | |
|
| | | * note: does NOT put on oplog | |
| * @param mayInterrupt When true, killop may interrupt the function
call. | | * @param mayInterrupt When true, killop may interrupt the function
call. | |
| * @param god if true, you may pass in obuf of NULL and then popula
te the returned DiskLoc | | * @param god if true, you may pass in obuf of NULL and then popula
te the returned DiskLoc | |
| * after the call -- that will prevent a double buffer copy in
some cases (btree.cpp). | | * after the call -- that will prevent a double buffer copy in
some cases (btree.cpp). | |
| * @param mayAddIndex almost always true, except for invocation fro
m rename namespace | | * @param mayAddIndex almost always true, except for invocation fro
m rename namespace | |
| * command. | | * command. | |
| * @param addedID if not null, set to true if adding _id element.
You must assure false | | * @param addedID if not null, set to true if adding _id element.
You must assure false | |
| * before calling if using. | | * before calling if using. | |
| */ | | */ | |
| DiskLoc insert(const char* ns, | | DiskLoc insert(const char* ns, | |
| const void* buf, | | const void* buf, | |
| int32_t len, | | int32_t len, | |
| bool mayInterrupt = false, | | bool mayInterrupt = false, | |
| bool god = false, | | bool god = false, | |
| bool mayAddIndex = true, | | bool mayAddIndex = true, | |
| bool* addedID = 0); | | bool* addedID = 0); | |
|
| static shared_ptr<Cursor> findAll(const char *ns, const DiskLoc &st
artLoc = DiskLoc()); | | static shared_ptr<Cursor> findAll(const StringData& ns, const DiskL
oc &startLoc = DiskLoc()); | |
| | | | |
| /* special version of insert for transaction logging -- streamlined
a bit. | | /* special version of insert for transaction logging -- streamlined
a bit. | |
| assumes ns is capped and no indexes | | assumes ns is capped and no indexes | |
| no _id field check | | no _id field check | |
| */ | | */ | |
| Record* fast_oplog_insert(NamespaceDetails *d, const char *ns, int
len); | | Record* fast_oplog_insert(NamespaceDetails *d, const char *ns, int
len); | |
| | | | |
| static Extent* getExtent(const DiskLoc& dl); | | static Extent* getExtent(const DiskLoc& dl); | |
| static Record* getRecord(const DiskLoc& dl); | | static Record* getRecord(const DiskLoc& dl); | |
| static DeletedRecord* getDeletedRecord(const DiskLoc& dl); | | static DeletedRecord* getDeletedRecord(const DiskLoc& dl); | |
| | | | |
| void deleteRecord(const char *ns, Record *todelete, const DiskLoc&
dl, bool cappedOK = false, bool noWarn = false, bool logOp=false); | | void deleteRecord(const char *ns, Record *todelete, const DiskLoc&
dl, bool cappedOK = false, bool noWarn = false, bool logOp=false); | |
| | | | |
| void deleteRecord(NamespaceDetails* d, const char *ns, Record *tode
lete, const DiskLoc& dl, bool cappedOK = false, bool noWarn = false, bool l
ogOp=false); | | void deleteRecord(NamespaceDetails* d, const char *ns, Record *tode
lete, const DiskLoc& dl, bool cappedOK = false, bool noWarn = false, bool l
ogOp=false); | |
| | | | |
| /* does not clean up indexes, etc. : just deletes the record in the
pdfile. use deleteRecord() to unindex */ | | /* does not clean up indexes, etc. : just deletes the record in the
pdfile. use deleteRecord() to unindex */ | |
| void _deleteRecord(NamespaceDetails *d, const char *ns, Record *tod
elete, const DiskLoc& dl); | | void _deleteRecord(NamespaceDetails *d, const char *ns, Record *tod
elete, const DiskLoc& dl); | |
| | | | |
|
| | | /** | |
| | | * accessor/mutator for the 'precalced' keys (that is, sorted index | |
| | | keys) | |
| | | * | |
| | | * NB: 'precalced' is accessed from fastBuildIndex(), which is call | |
| | | ed from insert-related | |
| | | * methods like insertWithObjMod(). It is mutated from various cal | |
| | | lers of the insert | |
| | | * methods, which assume 'precalced' will not change while in the i | |
| | | nsert method. This | |
| | | * should likely be refactored so theDataFileMgr takes full respons | |
| | | ibility. | |
| | | */ | |
| | | SortPhaseOne* getPrecalced() const; | |
| | | void setPrecalced(SortPhaseOne* precalced); | |
| | | mongo::mutex _precalcedMutex; | |
| | | | |
| private: | | private: | |
| vector<MongoDataFile *> files; | | vector<MongoDataFile *> files; | |
|
| | | SortPhaseOne* _precalced; | |
| }; | | }; | |
| | | | |
| extern DataFileMgr theDataFileMgr; | | extern DataFileMgr theDataFileMgr; | |
| | | | |
| #pragma pack(1) | | #pragma pack(1) | |
| | | | |
| class DeletedRecord { | | class DeletedRecord { | |
| public: | | public: | |
| | | | |
| int lengthWithHeaders() const { _accessing(); return _lengthWithHea
ders; } | | int lengthWithHeaders() const { _accessing(); return _lengthWithHea
ders; } | |
| | | | |
| skipping to change at line 546 | | skipping to change at line 560 | |
| while ( 1 ) { | | while ( 1 ) { | |
| if ( e->xnext.isNull() ) | | if ( e->xnext.isNull() ) | |
| return DiskLoc(); // end of table. | | return DiskLoc(); // end of table. | |
| e = e->xnext.ext(); | | e = e->xnext.ext(); | |
| if ( !e->firstRecord.isNull() ) | | if ( !e->firstRecord.isNull() ) | |
| break; | | break; | |
| // entire extent could be empty, keep looking | | // entire extent could be empty, keep looking | |
| } | | } | |
| return e->firstRecord; | | return e->firstRecord; | |
| } | | } | |
|
| | | | |
| inline DiskLoc Record::getPrev(const DiskLoc& myLoc) { | | inline DiskLoc Record::getPrev(const DiskLoc& myLoc) { | |
| _accessing(); | | _accessing(); | |
|
| if ( _prevOfs != DiskLoc::NullOfs ) | | | |
| | | // Check if we still have records on our current extent | |
| | | if ( _prevOfs != DiskLoc::NullOfs ) { | |
| return DiskLoc(myLoc.a(), _prevOfs); | | return DiskLoc(myLoc.a(), _prevOfs); | |
|
| | | } | |
| | | | |
| | | // Get the current extent | |
| Extent *e = myExtent(myLoc); | | Extent *e = myExtent(myLoc); | |
|
| if ( e->xprev.isNull() ) | | while ( 1 ) { | |
| return DiskLoc(); | | if ( e->xprev.isNull() ) { | |
| return e->xprev.ext()->lastRecord; | | // There are no more extents before this one | |
| | | return DiskLoc(); | |
| | | } | |
| | | | |
| | | // Move to the extent before this one | |
| | | e = e->xprev.ext(); | |
| | | | |
| | | if ( !e->lastRecord.isNull() ) { | |
| | | // We have found a non empty extent | |
| | | break; | |
| | | } | |
| | | } | |
| | | | |
| | | // Return the last record in our new extent | |
| | | return e->lastRecord; | |
| } | | } | |
| | | | |
| inline BSONObj DiskLoc::obj() const { | | inline BSONObj DiskLoc::obj() const { | |
| return BSONObj::make(rec()->accessed()); | | return BSONObj::make(rec()->accessed()); | |
| } | | } | |
| inline DeletedRecord* DiskLoc::drec() const { | | inline DeletedRecord* DiskLoc::drec() const { | |
| verify( _a != -1 ); | | verify( _a != -1 ); | |
| DeletedRecord* dr = (DeletedRecord*) rec(); | | DeletedRecord* dr = (DeletedRecord*) rec(); | |
| memconcept::is(dr, memconcept::concept::deletedrecord); | | memconcept::is(dr, memconcept::concept::deletedrecord); | |
| return dr; | | return dr; | |
| | | | |
| skipping to change at line 587 | | skipping to change at line 621 | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
| #include "database.h" | | #include "database.h" | |
| #include "memconcept.h" | | #include "memconcept.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| boost::intmax_t dbSize( const char *database ); | | boost::intmax_t dbSize( const char *database ); | |
| | | | |
|
| inline NamespaceIndex* nsindex(const char *ns) { | | inline NamespaceIndex* nsindex(const StringData& ns) { | |
| Database *database = cc().database(); | | Database *database = cc().database(); | |
| verify( database ); | | verify( database ); | |
| memconcept::is(database, memconcept::concept::database, ns, sizeof(
Database)); | | memconcept::is(database, memconcept::concept::database, ns, sizeof(
Database)); | |
| DEV { | | DEV { | |
|
| char buf[256]; | | StringData dbname = nsToDatabaseSubstring( ns ); | |
| nsToDatabase(ns, buf); | | if ( database->name != dbname ) { | |
| if ( database->name != buf ) { | | | |
| out() << "ERROR: attempt to write to wrong database\n"; | | out() << "ERROR: attempt to write to wrong database\n"; | |
| out() << " ns:" << ns << '\n'; | | out() << " ns:" << ns << '\n'; | |
| out() << " database->name:" << database->name << endl; | | out() << " database->name:" << database->name << endl; | |
|
| verify( database->name == buf ); | | verify( database->name == dbname ); | |
| } | | } | |
| } | | } | |
| return &database->namespaceIndex; | | return &database->namespaceIndex; | |
| } | | } | |
| | | | |
|
| inline NamespaceDetails* nsdetails(const char *ns) { | | inline NamespaceDetails* nsdetails(const StringData& ns) { | |
| // if this faults, did you set the current db first? (Client::Cont
ext + dblock) | | // if this faults, did you set the current db first? (Client::Cont
ext + dblock) | |
| NamespaceDetails *d = nsindex(ns)->details(ns); | | NamespaceDetails *d = nsindex(ns)->details(ns); | |
| if( d ) { | | if( d ) { | |
| memconcept::is(d, memconcept::concept::nsdetails, ns, sizeof(Na
mespaceDetails)); | | memconcept::is(d, memconcept::concept::nsdetails, ns, sizeof(Na
mespaceDetails)); | |
| } | | } | |
| return d; | | return d; | |
| } | | } | |
| | | | |
| inline Extent* DataFileMgr::getExtent(const DiskLoc& dl) { | | inline Extent* DataFileMgr::getExtent(const DiskLoc& dl) { | |
| verify( dl.a() != -1 ); | | verify( dl.a() != -1 ); | |
| | | | |
| skipping to change at line 640 | | skipping to change at line 673 | |
| return BSONObj( r->data() ); | | return BSONObj( r->data() ); | |
| } | | } | |
| | | | |
| DiskLoc allocateSpaceForANewRecord(const char* ns, | | DiskLoc allocateSpaceForANewRecord(const char* ns, | |
| NamespaceDetails* d, | | NamespaceDetails* d, | |
| int32_t lenWHdr, | | int32_t lenWHdr, | |
| bool god); | | bool god); | |
| | | | |
| void addRecordToRecListInExtent(Record* r, DiskLoc loc); | | void addRecordToRecListInExtent(Record* r, DiskLoc loc); | |
| | | | |
|
| | | /** | |
| | | * Static helpers to manipulate the list of unfinished index builds. | |
| | | */ | |
| | | class IndexBuildsInProgress { | |
| | | public: | |
| | | /** | |
| | | * Find an unfinished index build by name. Does not search finishe | |
| | | d index builds. | |
| | | */ | |
| | | static int get(const char* ns, const std::string& indexName); | |
| | | | |
| | | /** | |
| | | * Remove an unfinished index build from the list of index builds a | |
| | | nd move every subsequent | |
| | | * unfinished index build back one. E.g., if x, y, z, and w are bu | |
| | | ilding and someone kills | |
| | | * y, this method would rearrange the list to be x, z, w, (empty), | |
| | | etc. | |
| | | */ | |
| | | static void remove(const char* ns, int offset); | |
| | | }; | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 19 change blocks. |
| 17 lines changed or deleted | | 76 lines changed or added | |
|
| pipeline.h | | pipeline.h | |
| | | | |
| skipping to change at line 100 | | skipping to change at line 100 | |
| | | | |
| @param the builder to write the command to | | @param the builder to write the command to | |
| */ | | */ | |
| void toBson(BSONObjBuilder *pBuilder) const; | | void toBson(BSONObjBuilder *pBuilder) const; | |
| | | | |
| /** | | /** | |
| Run the Pipeline on the given source. | | Run the Pipeline on the given source. | |
| | | | |
| @param result builder to write the result to | | @param result builder to write the result to | |
| @param errmsg place to put error messages, if any | | @param errmsg place to put error messages, if any | |
|
| @param pSource the document source to use at the head of the chai
n | | | |
| @returns true on success, false if an error occurs | | @returns true on success, false if an error occurs | |
| */ | | */ | |
|
| bool run(BSONObjBuilder &result, string &errmsg, | | bool run(BSONObjBuilder &result, string &errmsg); | |
| const intrusive_ptr<DocumentSource> &pSource); | | | |
| | | | |
| /** | | /** | |
| Debugging: should the processing pipeline be split within | | Debugging: should the processing pipeline be split within | |
| mongod, simulating the real mongos/mongod split? This is determi
ned | | mongod, simulating the real mongos/mongod split? This is determi
ned | |
| by setting the splitMongodPipeline field in an "aggregate" | | by setting the splitMongodPipeline field in an "aggregate" | |
| command. | | command. | |
| | | | |
| The split itself is handled by the caller, which is currently | | The split itself is handled by the caller, which is currently | |
| pipeline_command.cpp. | | pipeline_command.cpp. | |
| | | | |
| | | | |
| skipping to change at line 126 | | skipping to change at line 124 | |
| */ | | */ | |
| bool getSplitMongodPipeline() const; | | bool getSplitMongodPipeline() const; | |
| | | | |
| /** | | /** | |
| Ask if this is for an explain request. | | Ask if this is for an explain request. | |
| | | | |
| @returns true if this is an explain | | @returns true if this is an explain | |
| */ | | */ | |
| bool isExplain() const; | | bool isExplain() const; | |
| | | | |
|
| | | /// The initial source is special since it varies between mongos an | |
| | | d mongod. | |
| | | void addInitialSource(intrusive_ptr<DocumentSource> source); | |
| | | | |
| /** | | /** | |
| The aggregation command name. | | The aggregation command name. | |
| */ | | */ | |
| static const char commandName[]; | | static const char commandName[]; | |
| | | | |
| /* | | /* | |
| PipelineD is a "sister" class that has additional functionality | | PipelineD is a "sister" class that has additional functionality | |
| for the Pipeline. It exists because of linkage requirements. | | for the Pipeline. It exists because of linkage requirements. | |
| Pipeline needs to function in mongod and mongos. PipelineD | | Pipeline needs to function in mongod and mongos. PipelineD | |
| contains extra functionality required in mongod, and which can't | | contains extra functionality required in mongod, and which can't | |
| | | | |
| skipping to change at line 169 | | skipping to change at line 170 | |
| | | | |
| /* | | /* | |
| Write the pipeline's operators to the given result document, | | Write the pipeline's operators to the given result document, | |
| for a shard server (or regular server, in an unsharded setup). | | for a shard server (or regular server, in an unsharded setup). | |
| | | | |
| This uses writeExplainOps() and adds that array to the result | | This uses writeExplainOps() and adds that array to the result | |
| with the serverPipelineName. That will be preceded by explain | | with the serverPipelineName. That will be preceded by explain | |
| information for the input source. | | information for the input source. | |
| | | | |
| @param result the object to add the explain information to | | @param result the object to add the explain information to | |
|
| @param pInputSource source for the pipeline | | | |
| */ | | */ | |
|
| void writeExplainShard(BSONObjBuilder &result, | | void writeExplainShard(BSONObjBuilder &result) const; | |
| const intrusive_ptr<DocumentSource> &pInputSource) const; | | | |
| | | | |
| /* | | /* | |
| Write the pipeline's operators to the given result document, | | Write the pipeline's operators to the given result document, | |
| for a mongos instance. | | for a mongos instance. | |
| | | | |
| This first adds the serverPipeline obtained from the input | | This first adds the serverPipeline obtained from the input | |
| source. | | source. | |
| | | | |
| Then this uses writeExplainOps() and adds that array to the resul
t | | Then this uses writeExplainOps() and adds that array to the resul
t | |
| with the serverPipelineName. That will be preceded by explain | | with the serverPipelineName. That will be preceded by explain | |
| information for the input source. | | information for the input source. | |
| | | | |
| @param result the object to add the explain information to | | @param result the object to add the explain information to | |
|
| @param pInputSource source for the pipeline; expected to be the | | | |
| output of a shard | | | |
| */ | | */ | |
|
| void writeExplainMongos(BSONObjBuilder &result, | | void writeExplainMongos(BSONObjBuilder &result) const; | |
| const intrusive_ptr<DocumentSource> &pInputSource) const; | | | |
| | | | |
| string collectionName; | | string collectionName; | |
|
| typedef vector<intrusive_ptr<DocumentSource> > SourceVector; | | typedef deque<intrusive_ptr<DocumentSource> > SourceContainer; | |
| SourceVector sourceVector; | | SourceContainer sources; | |
| bool explain; | | bool explain; | |
| | | | |
| bool splitMongodPipeline; | | bool splitMongodPipeline; | |
| intrusive_ptr<ExpressionContext> pCtx; | | intrusive_ptr<ExpressionContext> pCtx; | |
| }; | | }; | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
| /* ======================= INLINED IMPLEMENTATIONS ========================
== */ | | /* ======================= INLINED IMPLEMENTATIONS ========================
== */ | |
| | | | |
| | | | |
End of changes. 8 change blocks. |
| 12 lines changed or deleted | | 9 lines changed or added | |
|
| principal_set.h | | principal_set.h | |
|
| /** | | /* Copyright 2012 10gen Inc. | |
| * Copyright (C) 2012 10gen Inc. | | * | |
| * | | * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * This program is free software: you can redistribute it and/or modify | | * you may not use this file except in compliance with the License. | |
| * it under the terms of the GNU Affero General Public License, version 3 | | * You may obtain a copy of the License at | |
| , | | * | |
| * as published by the Free Software Foundation. | | * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | | * | |
| * This program is distributed in the hope that it will be useful, | | * Unless required by applicable law or agreed to in writing, software | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | | * distributed under the License is distributed on an "AS IS" BASIS, | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli | |
| * GNU Affero General Public License for more details. | | ed. | |
| * | | * See the License for the specific language governing permissions and | |
| * You should have received a copy of the GNU Affero General Public Licen | | * limitations under the License. | |
| se | | */ | |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. | | | |
| */ | | | |
| | | | |
| #pragma once | | #pragma once | |
| | | | |
| #include <string> | | #include <string> | |
|
| | | #include <vector> | |
| | | | |
| #include "mongo/base/disallow_copying.h" | | #include "mongo/base/disallow_copying.h" | |
|
| #include "mongo/base/status.h" | | #include "mongo/base/string_data.h" | |
| #include "mongo/db/auth/principal.h" | | #include "mongo/db/auth/principal.h" | |
|
| #include "mongo/platform/unordered_map.h" | | #include "mongo/db/auth/principal_name.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| /** | | /** | |
| * A collection of authenticated principals. | | * A collection of authenticated principals. | |
| * This class does not do any locking/synchronization, the consumer wil
l be responsible for | | * This class does not do any locking/synchronization, the consumer wil
l be responsible for | |
| * synchronizing access. | | * synchronizing access. | |
| */ | | */ | |
| class PrincipalSet { | | class PrincipalSet { | |
| MONGO_DISALLOW_COPYING(PrincipalSet); | | MONGO_DISALLOW_COPYING(PrincipalSet); | |
| public: | | public: | |
|
| | | typedef std::vector<Principal*>::const_iterator iterator; | |
| | | | |
| | | /** | |
| | | * Forward iterator over the names of the principals stored in a Pr | |
| | | incipalSet. | |
| | | * | |
| | | * Instances are valid until the underlying vector<Principal*> is m | |
| | | odified. | |
| | | * | |
| | | * more() must be the first method called after construction, and m | |
| | | ust be checked | |
| | | * after each call to next() before calling any other methods. | |
| | | */ | |
| | | class NameIterator { | |
| | | public: | |
| | | explicit NameIterator(const std::vector<Principal*>& principals | |
| | | ) : | |
| | | _curr(principals.begin()), | |
| | | _end(principals.end()) { | |
| | | } | |
| | | | |
| | | NameIterator() {} | |
| | | | |
| | | bool more() { return _curr != _end; } | |
| | | const PrincipalName& next() { | |
| | | const PrincipalName& ret = get(); | |
| | | ++_curr; | |
| | | return ret; | |
| | | } | |
| | | | |
| | | const PrincipalName& get() const { return (*_curr)->getName(); | |
| | | } | |
| | | | |
| | | const PrincipalName& operator*() const { return get(); } | |
| | | const PrincipalName* operator->() const { return &get(); } | |
| | | | |
| | | private: | |
| | | std::vector<Principal*>::const_iterator _curr; | |
| | | std::vector<Principal*>::const_iterator _end; | |
| | | }; | |
| | | | |
| PrincipalSet(); | | PrincipalSet(); | |
| ~PrincipalSet(); | | ~PrincipalSet(); | |
| | | | |
| // If the principal is already present, this will replace the exist
ing entry. | | // If the principal is already present, this will replace the exist
ing entry. | |
| // The PrincipalSet takes ownership of the passed-in principal and
is responsible for | | // The PrincipalSet takes ownership of the passed-in principal and
is responsible for | |
| // deleting it eventually | | // deleting it eventually | |
| void add(Principal* principal); | | void add(Principal* principal); | |
|
| Status removeByName(const std::string& name); | | | |
| // Returns NULL if not found | | // Removes all principals whose authentication credentials came fro | |
| | | m dbname. | |
| | | void removeByDBName(const StringData& dbname); | |
| | | | |
| | | // Returns the Principal with the given name, or NULL if not found. | |
| // Ownership of the returned Principal remains with the PrincipalSe
t. The pointer | | // Ownership of the returned Principal remains with the PrincipalSe
t. The pointer | |
| // returned is only guaranteed to remain valid until the next non-c
onst method is called | | // returned is only guaranteed to remain valid until the next non-c
onst method is called | |
| // on the PrincipalSet. | | // on the PrincipalSet. | |
|
| Principal* lookup(const std::string& name) const; | | Principal* lookup(const PrincipalName& name) const; | |
| | | | |
| | | // Gets the principal whose authentication credentials came from db | |
| | | name, or NULL if none | |
| | | // exist. There should be at most one such principal. | |
| | | Principal* lookupByDBName(const StringData& dbname) const; | |
| | | | |
| | | // Gets an iterator over the names of the principals stored in the | |
| | | set. The iterator is | |
| | | // valid until the next non-const method is called on the Principal | |
| | | Set. | |
| | | NameIterator getNames() const { return NameIterator(_principals); } | |
| | | | |
| | | iterator begin() const { return _principals.begin(); } | |
| | | iterator end() const { return _principals.end(); } | |
| | | | |
| private: | | private: | |
|
| // Key is principal name. | | | |
| // The PrincipalSet maintains ownership of the Principals in it, an
d is responsible for | | // The PrincipalSet maintains ownership of the Principals in it, an
d is responsible for | |
| // deleting them when done with them. | | // deleting them when done with them. | |
|
| unordered_map<std::string, Principal*> _principals; | | std::vector<Principal*> _principals; | |
| }; | | }; | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 9 change blocks. |
| 24 lines changed or deleted | | 81 lines changed or added | |
|
| privilege_set.h | | privilege_set.h | |
|
| /** | | /* Copyright 2012 10gen Inc. | |
| * Copyright (C) 2012 10gen Inc. | | * | |
| * | | * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * This program is free software: you can redistribute it and/or modify | | * you may not use this file except in compliance with the License. | |
| * it under the terms of the GNU Affero General Public License, version 3 | | * You may obtain a copy of the License at | |
| , | | * | |
| * as published by the Free Software Foundation. | | * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | | * | |
| * This program is distributed in the hope that it will be useful, | | * Unless required by applicable law or agreed to in writing, software | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | | * distributed under the License is distributed on an "AS IS" BASIS, | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli | |
| * GNU Affero General Public License for more details. | | ed. | |
| * | | * See the License for the specific language governing permissions and | |
| * You should have received a copy of the GNU Affero General Public Licen | | * limitations under the License. | |
| se | | */ | |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. | | | |
| */ | | | |
| | | | |
| #pragma once | | #pragma once | |
| | | | |
| #include <map> | | #include <map> | |
| #include <string> | | #include <string> | |
| | | | |
| #include "mongo/base/disallow_copying.h" | | #include "mongo/base/disallow_copying.h" | |
|
| #include "mongo/db/auth/acquired_privilege.h" | | | |
| #include "mongo/db/auth/action_set.h" | | #include "mongo/db/auth/action_set.h" | |
| #include "mongo/db/auth/action_type.h" | | #include "mongo/db/auth/action_type.h" | |
| #include "mongo/db/auth/privilege.h" | | #include "mongo/db/auth/privilege.h" | |
|
| #include "mongo/db/auth/principal.h" | | #include "mongo/db/auth/principal_name.h" | |
| | | #include "mongo/util/string_map.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| /** | | /** | |
|
| * A collection of privileges describing which authenticated principals | | * A collection of privileges describing which authenticated principals | |
| bestow the client | | bestow the client the | |
| * the ability to perform various actions on specific resources. Since | | * ability to perform various actions on specific resources. Since eve | |
| every privilege | | ry privilege comes from | |
| * comes from an authenticated principal, removing that principal can r | | * an authenticated principal, removing that principal removes all priv | |
| emove all privileges | | ileges granted by that | |
| * that that principal granted. | | * principal. | |
| | | * | |
| | | * Resources are arranged hierarchically, with a wildcard resource, | |
| | | * PrivilegeSet::WILDCARD_RESOURCE, matching any resource. In the curr | |
| | | ent implementation, the | |
| | | * only two levels of the hierarchy are the wildcard and one level belo | |
| | | w, which is analagous to | |
| | | * the name of a database. It is future work to support collection or | |
| | | other sub-database | |
| | | * resources. | |
| | | * | |
| * This class does not do any locking/synchronization, the consumer wil
l be responsible for | | * This class does not do any locking/synchronization, the consumer wil
l be responsible for | |
| * synchronizing access. | | * synchronizing access. | |
| */ | | */ | |
| class PrivilegeSet { | | class PrivilegeSet { | |
| MONGO_DISALLOW_COPYING(PrivilegeSet); | | MONGO_DISALLOW_COPYING(PrivilegeSet); | |
| public: | | public: | |
|
| PrivilegeSet(){} | | static const std::string WILDCARD_RESOURCE; | |
| ~PrivilegeSet(){} | | | |
| | | | |
|
| void grantPrivilege(const AcquiredPrivilege& privilege); | | PrivilegeSet(); | |
| void revokePrivilegesFromPrincipal(Principal* principal); | | ~PrivilegeSet(); | |
| | | | |
|
| // Returns the first privilege found that grants the given action o | | /** | |
| n the given resource. | | * Adds the specified privilege to the set, associating it with the | |
| // Returns NULL if there is no such privilege. | | named principal. | |
| // Ownership of the returned Privilege remains with the PrivilegeSe | | * | |
| t. The pointer | | * The privilege should be on a specific resource, or on the WILDCA | |
| // returned is only guaranteed to remain valid until the next non-c | | RD_RESOURCE. | |
| onst method is called | | */ | |
| // on the PrivilegeSet. | | void grantPrivilege(const Privilege& privilege, const PrincipalName | |
| const AcquiredPrivilege* getPrivilegeForAction(const std::string& r | | & authorizingPrincipal); | |
| esource, | | | |
| const ActionType& ac | | /** | |
| tion) const; | | * Adds the specified privileges to the set, associating them with | |
| | | the named principal. | |
| | | */ | |
| | | void grantPrivileges(const std::vector<Privilege>& privileges, | |
| | | const PrincipalName& authorizingPrincipal); | |
| | | | |
| | | /** | |
| | | * Removes from the set all privileges associated with the given pr | |
| | | incipal. | |
| | | * | |
| | | * If multiple princpals enable the same privilege, the set will co | |
| | | ntinue to | |
| | | * contain those privileges until all authorizing principals have h | |
| | | ad their | |
| | | * privileges revoked from the set. | |
| | | */ | |
| | | void revokePrivilegesFromPrincipal(const PrincipalName& principal); | |
| | | | |
| | | /** | |
| | | * Returns true if the set authorizes "desiredPrivilege". | |
| | | * | |
| | | * The set is considered to authorize "desiredPrivilege" if each ac | |
| | | tion in | |
| | | * "desiredPrivilege" is satisfied either on the database component | |
| | | of | |
| | | * "desiredPrivilege.getResource()" or on WILDCARD_RESOURCE. | |
| | | * | |
| | | * TODO: Support checking for the privilege on the full resource na | |
| | | me as well as the | |
| | | * database component, to support sub-database granularity privileg | |
| | | e assignment. | |
| | | */ | |
| | | bool hasPrivilege(const Privilege& desiredPrivilege); | |
| | | | |
| | | /** | |
| | | * Same as hasPrivilege, except checks all the privileges in a vect | |
| | | or. | |
| | | */ | |
| | | bool hasPrivileges(const std::vector<Privilege>& desiredPrivileges) | |
| | | ; | |
| | | | |
| private: | | private: | |
| | | | |
|
| // Key is the resource the privilege is on. | | /** | |
| typedef std::multimap<const std::string, AcquiredPrivilege> Privile | | * Information about privileges held on a resource. | |
| geMap; | | * | |
| typedef PrivilegeMap::iterator PrivilegeRangeIterator; | | * Instances are stored in the _byResource map, and accelerate the | |
| typedef std::pair<PrivilegeRangeIterator, PrivilegeRangeIterator> P | | fast path of | |
| rivilegeSetRange; | | * hasPrivilege(). Privilege revocations via revokePrivilegesFromP | |
| typedef PrivilegeMap::const_iterator PrivilegeRangeConstIterator; | | rincipal() can make these | |
| typedef std::pair<PrivilegeRangeConstIterator, PrivilegeRangeConstI | | * entries invalid, at which point they are marked "dirty". Dirty | |
| terator> | | entries are rebuilt via | |
| PrivilegeSetConstRange; | | * _rebuildEntry(), below, during execution of hasPrivilege(). | |
| | | */ | |
| | | class ResourcePrivilegeCacheEntry { | |
| | | public: | |
| | | ResourcePrivilegeCacheEntry() : actions(), dirty(false) {} | |
| | | | |
| | | // All actions enabled on the associated resource, provided tha | |
| | | t "dirty" is false. | |
| | | ActionSet actions; | |
| | | | |
| | | // False if this data is consistent with the full privilege inf | |
| | | ormation, stored in the | |
| | | // _byPrincipal map. | |
| | | bool dirty; | |
| | | }; | |
| | | | |
| | | /** | |
| | | * Type of map from resource names to authorized actions. | |
| | | */ | |
| | | typedef StringMap<ResourcePrivilegeCacheEntry> ResourcePrivilegeCac | |
| | | he; | |
| | | | |
| | | /** | |
| | | * Type of map from principal identity to information about the pri | |
| | | ncipal's privileges. The | |
| | | * values in the map are themselves maps from resource names to ass | |
| | | ociated actions. | |
| | | */ | |
| | | typedef std::map<PrincipalName, StringMap<ActionSet> > PrincipalPri | |
| | | vilegeMap; | |
| | | | |
| | | void _rebuildEntry(const StringData& resource, ResourcePrivilegeCac | |
| | | heEntry* summary); | |
| | | | |
| | | ResourcePrivilegeCacheEntry* _lookupEntry(const StringData& resourc | |
| | | e); | |
| | | ResourcePrivilegeCacheEntry* _lookupOrInsertEntry(const StringData& | |
| | | resource); | |
| | | | |
| | | // Information about privileges available on all resources. | |
| | | ResourcePrivilegeCacheEntry _globalPrivilegeEntry; | |
| | | | |
| | | // Cache of privilege information, by resource. | |
| | | ResourcePrivilegeCache _byResource; | |
| | | | |
|
| // Maps resource to privileges | | // Directory of privilege information, by principal. | |
| PrivilegeMap _privileges; | | PrincipalPrivilegeMap _byPrincipal; | |
| }; | | }; | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 9 change blocks. |
| 55 lines changed or deleted | | 143 lines changed or added | |
|
| queryutil.h | | queryutil.h | |
| | | | |
| skipping to change at line 261 | | skipping to change at line 261 | |
| struct FieldBound { | | struct FieldBound { | |
| BSONElement _bound; | | BSONElement _bound; | |
| bool _inclusive; | | bool _inclusive; | |
| bool operator==( const FieldBound &other ) const { | | bool operator==( const FieldBound &other ) const { | |
| return _bound.woCompare( other._bound ) == 0 && | | return _bound.woCompare( other._bound ) == 0 && | |
| _inclusive == other._inclusive; | | _inclusive == other._inclusive; | |
| } | | } | |
| void flipInclusive() { _inclusive = !_inclusive; } | | void flipInclusive() { _inclusive = !_inclusive; } | |
| }; | | }; | |
| | | | |
|
| | | // Keep track of what special indices we're using. This can be nontriv | |
| | | ial | |
| | | // because an index could be required by one operator but not by anothe | |
| | | r. | |
| | | struct SpecialIndices { | |
| | | // Unlike true/false, this is readable. :) | |
| | | enum IndexRequired { | |
| | | INDEX_REQUIRED, | |
| | | NO_INDEX_REQUIRED, | |
| | | }; | |
| | | map<string, bool> _indexRequired; | |
| | | | |
| | | bool has(const string& name) const { | |
| | | return _indexRequired.end() != _indexRequired.find(name); | |
| | | } | |
| | | | |
| | | SpecialIndices combineWith(const SpecialIndices& other) { | |
| | | SpecialIndices ret = *this; | |
| | | for (map<string, bool>::const_iterator it = other._indexRequire | |
| | | d.begin(); | |
| | | it != other._indexRequired.end(); ++it) { | |
| | | ret._indexRequired[it->first] = ret._indexRequired[it->firs | |
| | | t] || it->second; | |
| | | } | |
| | | return ret; | |
| | | } | |
| | | | |
| | | void add(const string& name, IndexRequired req) { | |
| | | _indexRequired[name] = _indexRequired[name] || (req == INDEX_RE | |
| | | QUIRED); | |
| | | } | |
| | | | |
| | | bool allRequireIndex() const { | |
| | | for (map<string, bool>::const_iterator it = _indexRequired.begi | |
| | | n(); | |
| | | it != _indexRequired.end(); ++it) { | |
| | | if (!it->second) { return false; } | |
| | | } | |
| | | return true; | |
| | | } | |
| | | | |
| | | bool empty() const { return _indexRequired.empty(); } | |
| | | string toString() const { | |
| | | stringstream ss; | |
| | | for (map<string, bool>::const_iterator it = _indexRequired.begi | |
| | | n(); | |
| | | it != _indexRequired.end(); ++it) { | |
| | | ss << it->first; | |
| | | ss << (it->second ? " (needs index)" : " (no index needed)" | |
| | | ); | |
| | | ss << ", "; | |
| | | } | |
| | | return ss.str(); | |
| | | } | |
| | | }; | |
| | | | |
| /** An interval defined between a lower and an upper FieldBound. */ | | /** An interval defined between a lower and an upper FieldBound. */ | |
| struct FieldInterval { | | struct FieldInterval { | |
| FieldInterval() : _cachedEquality( -1 ) {} | | FieldInterval() : _cachedEquality( -1 ) {} | |
| FieldInterval( const BSONElement& e ) : _cachedEquality( -1 ) { | | FieldInterval( const BSONElement& e ) : _cachedEquality( -1 ) { | |
| _lower._bound = _upper._bound = e; | | _lower._bound = _upper._bound = e; | |
| _lower._inclusive = _upper._inclusive = true; | | _lower._inclusive = _upper._inclusive = true; | |
| } | | } | |
| FieldBound _lower; | | FieldBound _lower; | |
| FieldBound _upper; | | FieldBound _upper; | |
| /** | | /** | |
| | | | |
| skipping to change at line 359 | | skipping to change at line 407 | |
| * FieldRange( { a:{ $in:[ 1, 2 ] } } ), isPointIntervalSet() -> t
rue | | * FieldRange( { a:{ $in:[ 1, 2 ] } } ), isPointIntervalSet() -> t
rue | |
| * FieldRange( { a:{ $gt:5 } } ), isPointIntervalSet() -> false | | * FieldRange( { a:{ $gt:5 } } ), isPointIntervalSet() -> false | |
| * FieldRange( {} ), isPointIntervalSet() -> false | | * FieldRange( {} ), isPointIntervalSet() -> false | |
| */ | | */ | |
| bool isPointIntervalSet() const; | | bool isPointIntervalSet() const; | |
| const BSONElement& elemMatchContext() const { return _elemMatchCont
ext; } | | const BSONElement& elemMatchContext() const { return _elemMatchCont
ext; } | |
| | | | |
| /** Empty the range so it includes no BSONElements. */ | | /** Empty the range so it includes no BSONElements. */ | |
| void makeEmpty() { _intervals.clear(); } | | void makeEmpty() { _intervals.clear(); } | |
| const vector<FieldInterval> &intervals() const { return _intervals;
} | | const vector<FieldInterval> &intervals() const { return _intervals;
} | |
|
| const set<string>& getSpecial() const { return _special; } | | const SpecialIndices& getSpecial() const { return _special; } | |
| /** Make component intervals noninclusive. */ | | /** Make component intervals noninclusive. */ | |
| void setExclusiveBounds(); | | void setExclusiveBounds(); | |
| /** | | /** | |
| * Constructs a range where all FieldIntervals and FieldBounds are
in | | * Constructs a range where all FieldIntervals and FieldBounds are
in | |
| * the opposite order of the current range. | | * the opposite order of the current range. | |
| * NOTE the resulting intervals might not be strictValid(). | | * NOTE the resulting intervals might not be strictValid(). | |
| */ | | */ | |
| void reverse( FieldRange &ret ) const; | | void reverse( FieldRange &ret ) const; | |
| | | | |
| string toString() const; | | string toString() const; | |
| private: | | private: | |
| BSONObj addObj( const BSONObj &o ); | | BSONObj addObj( const BSONObj &o ); | |
| void finishOperation( const vector<FieldInterval> &newIntervals, co
nst FieldRange &other, | | void finishOperation( const vector<FieldInterval> &newIntervals, co
nst FieldRange &other, | |
| bool exactMatchRepresentation ); | | bool exactMatchRepresentation ); | |
| vector<FieldInterval> _intervals; | | vector<FieldInterval> _intervals; | |
| // Owns memory for our BSONElements. | | // Owns memory for our BSONElements. | |
| vector<BSONObj> _objData; | | vector<BSONObj> _objData; | |
|
| set<string> _special; // Index type name of a non standard (eg '2d'
) index required by a | | SpecialIndices _special; // Index type name of a non standard (eg '
2d') index required by a | |
| // parsed query operator (eg '$near'). Could
be >1. | | // parsed query operator (eg '$near'). Could
be >1. | |
| bool _exactMatchRepresentation; | | bool _exactMatchRepresentation; | |
| BSONElement _elemMatchContext; // Parent $elemMatch object of the f
ield constraint that | | BSONElement _elemMatchContext; // Parent $elemMatch object of the f
ield constraint that | |
| // generated this FieldRange. For e
xample if the query is | | // generated this FieldRange. For e
xample if the query is | |
| // { a:{ $elemMatch:{ b:1, c:1 } } }
, then the | | // { a:{ $elemMatch:{ b:1, c:1 } } }
, then the | |
| // _elemMatchContext for the FieldRa
nge on 'a.b' is the query | | // _elemMatchContext for the FieldRa
nge on 'a.b' is the query | |
| // element having field name '$elemM
atch'. | | // element having field name '$elemM
atch'. | |
| }; | | }; | |
| | | | |
| class QueryPattern; | | class QueryPattern; | |
| | | | |
| skipping to change at line 454 | | skipping to change at line 502 | |
| * | | * | |
| * Used in determining "suitability" for hashedindexes, and also in | | * Used in determining "suitability" for hashedindexes, and also in | |
| * sharding for determining the relevant shards for a query. | | * sharding for determining the relevant shards for a query. | |
| * | | * | |
| * TODO: move this into FieldRange instead of FieldRangeSet | | * TODO: move this into FieldRange instead of FieldRangeSet | |
| */ | | */ | |
| bool isPointIntervalSet( const string& fieldname ) const; | | bool isPointIntervalSet( const string& fieldname ) const; | |
| | | | |
| const char *ns() const { return _ns.c_str(); } | | const char *ns() const { return _ns.c_str(); } | |
| | | | |
|
| /** | | | |
| * @return a simplified query from the extreme values of the non un | | | |
| iversal | | | |
| * fields. | | | |
| * @param fields If specified, the fields of the returned object ar | | | |
| e | | | |
| * ordered to match those of 'fields'. | | | |
| */ | | | |
| BSONObj simplifiedQuery( const BSONObj &fields = BSONObj() ) const; | | | |
| | | | |
| QueryPattern pattern( const BSONObj &sort = BSONObj() ) const; | | QueryPattern pattern( const BSONObj &sort = BSONObj() ) const; | |
|
| set<string> getSpecial() const; | | SpecialIndices getSpecial() const; | |
| | | | |
| /** | | /** | |
| * @return a FieldRangeSet approximation of the documents in 'this'
but | | * @return a FieldRangeSet approximation of the documents in 'this'
but | |
| * not in 'other'. The approximation will be a superset of the doc
uments | | * not in 'other'. The approximation will be a superset of the doc
uments | |
| * in 'this' but not 'other'. | | * in 'this' but not 'other'. | |
| */ | | */ | |
| const FieldRangeSet &operator-=( const FieldRangeSet &other ); | | const FieldRangeSet &operator-=( const FieldRangeSet &other ); | |
| /** @return intersection of 'this' with 'other'. */ | | /** @return intersection of 'this' with 'other'. */ | |
| const FieldRangeSet &operator&=( const FieldRangeSet &other ); | | const FieldRangeSet &operator&=( const FieldRangeSet &other ); | |
| | | | |
| | | | |
| skipping to change at line 572 | | skipping to change at line 612 | |
| /** @return false if a match is impossible regardless of index. */ | | /** @return false if a match is impossible regardless of index. */ | |
| bool matchPossible() const { return _multiKey.matchPossible(); } | | bool matchPossible() const { return _multiKey.matchPossible(); } | |
| /** | | /** | |
| * @return false if a match is impossible on the specified index. | | * @return false if a match is impossible on the specified index. | |
| * @param idxNo -1 for non index scan. | | * @param idxNo -1 for non index scan. | |
| */ | | */ | |
| bool matchPossibleForIndex( NamespaceDetails *d, int idxNo, const B
SONObj &keyPattern ) const; | | bool matchPossibleForIndex( NamespaceDetails *d, int idxNo, const B
SONObj &keyPattern ) const; | |
| | | | |
| const char *ns() const { return _singleKey.ns(); } | | const char *ns() const { return _singleKey.ns(); } | |
| | | | |
|
| set<string> getSpecial() const { return _singleKey.getSpecial(); } | | SpecialIndices getSpecial() const { return _singleKey.getSpecial();
} | |
| | | | |
| /** Intersect with another FieldRangeSetPair. */ | | /** Intersect with another FieldRangeSetPair. */ | |
| FieldRangeSetPair &operator&=( const FieldRangeSetPair &other ); | | FieldRangeSetPair &operator&=( const FieldRangeSetPair &other ); | |
| /** | | /** | |
| * Subtract a FieldRangeSet, generally one expressing a range that
has | | * Subtract a FieldRangeSet, generally one expressing a range that
has | |
| * already been scanned. | | * already been scanned. | |
| */ | | */ | |
| FieldRangeSetPair &operator-=( const FieldRangeSet &scanned ); | | FieldRangeSetPair &operator-=( const FieldRangeSet &scanned ); | |
| | | | |
| bool matchPossibleForSingleKeyFRS( const BSONObj &keyPattern ) cons
t { | | bool matchPossibleForSingleKeyFRS( const BSONObj &keyPattern ) cons
t { | |
| | | | |
| skipping to change at line 598 | | skipping to change at line 638 | |
| const FieldRangeSet getSingleKeyFRS() const { return _singleKey; } | | const FieldRangeSet getSingleKeyFRS() const { return _singleKey; } | |
| const FieldRangeSet getMultiKeyFRS() const { return _singleKey; } | | const FieldRangeSet getMultiKeyFRS() const { return _singleKey; } | |
| | | | |
| string toString() const; | | string toString() const; | |
| private: | | private: | |
| FieldRangeSetPair( const FieldRangeSet &singleKey, const FieldRange
Set &multiKey ) | | FieldRangeSetPair( const FieldRangeSet &singleKey, const FieldRange
Set &multiKey ) | |
| :_singleKey( singleKey ), _multiKey( multiKey ) {} | | :_singleKey( singleKey ), _multiKey( multiKey ) {} | |
| void assertValidIndex( const NamespaceDetails *d, int idxNo ) const
; | | void assertValidIndex( const NamespaceDetails *d, int idxNo ) const
; | |
| void assertValidIndexOrNoIndex( const NamespaceDetails *d, int idxN
o ) const; | | void assertValidIndexOrNoIndex( const NamespaceDetails *d, int idxN
o ) const; | |
| /** matchPossibleForIndex() must be true. */ | | /** matchPossibleForIndex() must be true. */ | |
|
| BSONObj simplifiedQueryForIndex( NamespaceDetails *d, int idxNo, co
nst BSONObj &keyPattern ) const; | | | |
| FieldRangeSet _singleKey; | | FieldRangeSet _singleKey; | |
| FieldRangeSet _multiKey; | | FieldRangeSet _multiKey; | |
| friend class OrRangeGenerator; | | friend class OrRangeGenerator; | |
| friend struct QueryUtilIndexed; | | friend struct QueryUtilIndexed; | |
| }; | | }; | |
| | | | |
| class IndexSpec; | | class IndexSpec; | |
| | | | |
| /** | | /** | |
| * An ordered list of fields and their FieldRanges, corresponding to va
lid | | * An ordered list of fields and their FieldRanges, corresponding to va
lid | |
| | | | |
| skipping to change at line 894 | | skipping to change at line 933 | |
| /** @return FieldRangeSetPair for the current $or clause. */ | | /** @return FieldRangeSetPair for the current $or clause. */ | |
| FieldRangeSetPair *topFrsp() const; | | FieldRangeSetPair *topFrsp() const; | |
| /** | | /** | |
| * @return original FieldRangeSetPair for the current $or clause. W
hile the | | * @return original FieldRangeSetPair for the current $or clause. W
hile the | |
| * original bounds are looser, they are composed of fewer ranges an
d it | | * original bounds are looser, they are composed of fewer ranges an
d it | |
| * is faster to do operations with them; when they can be used inst
ead of | | * is faster to do operations with them; when they can be used inst
ead of | |
| * more precise bounds, they should. | | * more precise bounds, they should. | |
| */ | | */ | |
| FieldRangeSetPair *topFrspOriginal() const; | | FieldRangeSetPair *topFrspOriginal() const; | |
| | | | |
|
| set<string> getSpecial() const { return _baseSet.getSpecial(); } | | SpecialIndices getSpecial() const { return _baseSet.getSpecial(); } | |
| private: | | private: | |
| void assertMayPopOrClause(); | | void assertMayPopOrClause(); | |
| void _popOrClause( const FieldRangeSet *toDiff, NamespaceDetails *d
, int idxNo, const BSONObj &keyPattern ); | | void _popOrClause( const FieldRangeSet *toDiff, NamespaceDetails *d
, int idxNo, const BSONObj &keyPattern ); | |
| FieldRangeSetPair _baseSet; | | FieldRangeSetPair _baseSet; | |
| list<FieldRangeSetPair> _orSets; | | list<FieldRangeSetPair> _orSets; | |
| list<FieldRangeSetPair> _originalOrSets; | | list<FieldRangeSetPair> _originalOrSets; | |
| // ensure memory is owned | | // ensure memory is owned | |
| list<FieldRangeSetPair> _oldOrSets; | | list<FieldRangeSetPair> _oldOrSets; | |
| bool _orFound; | | bool _orFound; | |
| friend struct QueryUtilIndexed; | | friend struct QueryUtilIndexed; | |
| | | | |
End of changes. 8 change blocks. |
| 16 lines changed or deleted | | 61 lines changed or added | |
|
| rs.h | | rs.h | |
| | | | |
| skipping to change at line 50 | | skipping to change at line 50 | |
| * startReplSets forks off a new thread for replica set activities. It cre
ates | | * startReplSets forks off a new thread for replica set activities. It cre
ates | |
| * the global theReplSet variable and calls go() on it. | | * the global theReplSet variable and calls go() on it. | |
| * | | * | |
| * theReplSet's constructor changes the replica set's state to RS_STARTUP, | | * theReplSet's constructor changes the replica set's state to RS_STARTUP, | |
| * starts the replica set manager, and loads the config (if the replica set | | * starts the replica set manager, and loads the config (if the replica set | |
| * has been initialized). | | * has been initialized). | |
| */ | | */ | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
|
| struct HowToFixUp; | | class Cloner; | |
| struct Target; | | | |
| class DBClientConnection; | | class DBClientConnection; | |
|
| class ReplSetImpl; | | struct HowToFixUp; | |
| class OplogReader; | | class OplogReader; | |
|
| | | class ReplSetImpl; | |
| | | struct Target; | |
| extern bool replSet; // true if using repl sets | | extern bool replSet; // true if using repl sets | |
| extern class ReplSet *theReplSet; // null until initialized | | extern class ReplSet *theReplSet; // null until initialized | |
| extern Tee *rsLog; | | extern Tee *rsLog; | |
| | | | |
| /* member of a replica set */ | | /* member of a replica set */ | |
| class Member : public List1<Member>::Base { | | class Member : public List1<Member>::Base { | |
| private: | | private: | |
| ~Member(); // intentionally unimplemented as should never be called
-- see List1<>::Base. | | ~Member(); // intentionally unimplemented as should never be called
-- see List1<>::Base. | |
| Member(const Member&); | | Member(const Member&); | |
| public: | | public: | |
| | | | |
| skipping to change at line 79 | | skipping to change at line 80 | |
| ReplSetConfig::MemberCfg& configw() { return _config; } | | ReplSetConfig::MemberCfg& configw() { return _config; } | |
| const HeartbeatInfo& hbinfo() const { return _hbinfo; } | | const HeartbeatInfo& hbinfo() const { return _hbinfo; } | |
| HeartbeatInfo& get_hbinfo() { return _hbinfo; } | | HeartbeatInfo& get_hbinfo() { return _hbinfo; } | |
| string lhb() const { return _hbinfo.lastHeartbeatMsg; } | | string lhb() const { return _hbinfo.lastHeartbeatMsg; } | |
| MemberState state() const { return _hbinfo.hbstate; } | | MemberState state() const { return _hbinfo.hbstate; } | |
| const HostAndPort& h() const { return _h; } | | const HostAndPort& h() const { return _h; } | |
| unsigned id() const { return _hbinfo.id(); } | | unsigned id() const { return _hbinfo.id(); } | |
| | | | |
| bool potentiallyHot() const { return _config.potentiallyHot(); } //
not arbiter, not priority 0 | | bool potentiallyHot() const { return _config.potentiallyHot(); } //
not arbiter, not priority 0 | |
| void summarizeMember(stringstream& s) const; | | void summarizeMember(stringstream& s) const; | |
|
| | | // If we could sync from this member. This doesn't tell us anythin | |
| | | g about the quality of | |
| | | // this member, just if they are a possible sync target. | |
| | | bool syncable() const; | |
| | | | |
| private: | | private: | |
| friend class ReplSetImpl; | | friend class ReplSetImpl; | |
| ReplSetConfig::MemberCfg _config; | | ReplSetConfig::MemberCfg _config; | |
| const HostAndPort _h; | | const HostAndPort _h; | |
| HeartbeatInfo _hbinfo; | | HeartbeatInfo _hbinfo; | |
| }; | | }; | |
| | | | |
| class Manager : public task::Server { | | class Manager : public task::Server { | |
| ReplSetImpl *rs; | | ReplSetImpl *rs; | |
| | | | |
| skipping to change at line 150 | | skipping to change at line 154 | |
| * Say we have an S1--->S2--->P situation and this node is S2. rid | | * Say we have an S1--->S2--->P situation and this node is S2. rid | |
| * would refer to S1. S2 would create a ghost slave of S1 and conn
ect | | * would refer to S1. S2 would create a ghost slave of S1 and conn
ect | |
| * it to P (_currentSyncTarget). Then it would use this connection
to | | * it to P (_currentSyncTarget). Then it would use this connection
to | |
| * pretend to be S1, replicating off of P. | | * pretend to be S1, replicating off of P. | |
| */ | | */ | |
| void percolate(const BSONObj& rid, const OpTime& last); | | void percolate(const BSONObj& rid, const OpTime& last); | |
| void associateSlave(const BSONObj& rid, const int memberId); | | void associateSlave(const BSONObj& rid, const int memberId); | |
| void updateSlave(const mongo::OID& id, const OpTime& last); | | void updateSlave(const mongo::OID& id, const OpTime& last); | |
| }; | | }; | |
| | | | |
|
| struct Target; | | | |
| | | | |
| class Consensus { | | class Consensus { | |
| ReplSetImpl &rs; | | ReplSetImpl &rs; | |
| struct LastYea { | | struct LastYea { | |
| LastYea() : when(0), who(0xffffffff) { } | | LastYea() : when(0), who(0xffffffff) { } | |
| time_t when; | | time_t when; | |
| unsigned who; | | unsigned who; | |
| }; | | }; | |
| static SimpleMutex lyMutex; | | static SimpleMutex lyMutex; | |
| Guarded<LastYea,lyMutex> ly; | | Guarded<LastYea,lyMutex> ly; | |
| unsigned yea(unsigned memberId); // throws VoteException | | unsigned yea(unsigned memberId); // throws VoteException | |
| | | | |
| skipping to change at line 337 | | skipping to change at line 339 | |
| static string stateAsHtml(MemberState state); | | static string stateAsHtml(MemberState state); | |
| | | | |
| /* todo thread */ | | /* todo thread */ | |
| void msgUpdateHBInfo(HeartbeatInfo); | | void msgUpdateHBInfo(HeartbeatInfo); | |
| | | | |
| StateBox box; | | StateBox box; | |
| | | | |
| OpTime lastOpTimeWritten; | | OpTime lastOpTimeWritten; | |
| long long lastH; // hash we use to make sure we are reading the rig
ht flow of ops and aren't on an out-of-date "fork" | | long long lastH; // hash we use to make sure we are reading the rig
ht flow of ops and aren't on an out-of-date "fork" | |
| bool forceSyncFrom(const string& host, string& errmsg, BSONObjBuild
er& result); | | bool forceSyncFrom(const string& host, string& errmsg, BSONObjBuild
er& result); | |
|
| | | // Check if the current sync target is suboptimal. This must be cal | |
| | | led while holding a mutex | |
| | | // that prevents the sync source from changing. | |
| | | bool shouldChangeSyncTarget(const OpTime& target) const; | |
| | | | |
| /** | | /** | |
| * Find the closest member (using ping time) with a higher latest o
ptime. | | * Find the closest member (using ping time) with a higher latest o
ptime. | |
| */ | | */ | |
| const Member* getMemberToSyncTo(); | | const Member* getMemberToSyncTo(); | |
| void veto(const string& host, unsigned secs=10); | | void veto(const string& host, unsigned secs=10); | |
| bool gotForceSync(); | | bool gotForceSync(); | |
| void goStale(const Member* m, const BSONObj& o); | | void goStale(const Member* m, const BSONObj& o); | |
| private: | | private: | |
| set<ReplSetHealthPollTask*> healthTasks; | | set<ReplSetHealthPollTask*> healthTasks; | |
| | | | |
| skipping to change at line 504 | | skipping to change at line 509 | |
| void getTargets(list<Target>&, int &configVersion); | | void getTargets(list<Target>&, int &configVersion); | |
| void startThreads(); | | void startThreads(); | |
| friend class FeedbackThread; | | friend class FeedbackThread; | |
| friend class CmdReplSetElect; | | friend class CmdReplSetElect; | |
| friend class Member; | | friend class Member; | |
| friend class Manager; | | friend class Manager; | |
| friend class GhostSync; | | friend class GhostSync; | |
| friend class Consensus; | | friend class Consensus; | |
| | | | |
| private: | | private: | |
|
| bool _syncDoInitialSync_clone( const char *master, const list<strin | | bool _syncDoInitialSync_clone(Cloner &cloner, const char *master, | |
| g>& dbs , bool dataPass ); | | const list<string>& dbs, bool dataPas | |
| | | s); | |
| bool _syncDoInitialSync_applyToHead( replset::SyncTail& syncer, Opl
ogReader* r , | | bool _syncDoInitialSync_applyToHead( replset::SyncTail& syncer, Opl
ogReader* r , | |
| const Member* source, const BS
ONObj& lastOp, | | const Member* source, const BS
ONObj& lastOp, | |
| BSONObj& minValidOut); | | BSONObj& minValidOut); | |
| void _syncDoInitialSync(); | | void _syncDoInitialSync(); | |
| void syncDoInitialSync(); | | void syncDoInitialSync(); | |
| void _syncThread(); | | void _syncThread(); | |
| void syncTail(); | | void syncTail(); | |
| unsigned _syncRollback(OplogReader& r); | | unsigned _syncRollback(OplogReader& r); | |
| void syncFixUp(HowToFixUp& h, OplogReader& r); | | void syncFixUp(HowToFixUp& h, OplogReader& r); | |
| | | | |
| | | | |
| skipping to change at line 545 | | skipping to change at line 551 | |
| static const int replWriterThreadCount; | | static const int replWriterThreadCount; | |
| static const int replPrefetcherThreadCount; | | static const int replPrefetcherThreadCount; | |
| threadpool::ThreadPool& getPrefetchPool() { return _prefetcherPool;
} | | threadpool::ThreadPool& getPrefetchPool() { return _prefetcherPool;
} | |
| threadpool::ThreadPool& getWriterPool() { return _writerPool; } | | threadpool::ThreadPool& getWriterPool() { return _writerPool; } | |
| | | | |
| const ReplSetConfig::MemberCfg& myConfig() const { return _config;
} | | const ReplSetConfig::MemberCfg& myConfig() const { return _config;
} | |
| bool tryToGoLiveAsASecondary(OpTime&); // readlocks | | bool tryToGoLiveAsASecondary(OpTime&); // readlocks | |
| void syncRollback(OplogReader& r); | | void syncRollback(OplogReader& r); | |
| void syncThread(); | | void syncThread(); | |
| const OpTime lastOtherOpTime() const; | | const OpTime lastOtherOpTime() const; | |
|
| | | | |
| | | /** | |
| | | * When a member reaches its minValid optime it is in a consistent | |
| | | state. Thus, minValid is | |
| | | * set as the last step in initial sync (if no minValid is set, thi | |
| | | s indicates that initial | |
| | | * sync is necessary). It is also used during "normal" sync: the la | |
| | | st op in each batch is | |
| | | * used to set minValid, to indicate that we are in a consistent st | |
| | | ate when the batch has | |
| | | * been fully applied. | |
| | | */ | |
| static void setMinValid(BSONObj obj); | | static void setMinValid(BSONObj obj); | |
|
| | | static OpTime getMinValid(); | |
| | | | |
| int oplogVersion; | | int oplogVersion; | |
| private: | | private: | |
| IndexPrefetchConfig _indexPrefetchConfig; | | IndexPrefetchConfig _indexPrefetchConfig; | |
| }; | | }; | |
| | | | |
| class ReplSet : public ReplSetImpl { | | class ReplSet : public ReplSetImpl { | |
| public: | | public: | |
| static ReplSet* make(ReplSetCmdline& replSetCmdline); | | static ReplSet* make(ReplSetCmdline& replSetCmdline); | |
| virtual ~ReplSet() {} | | virtual ~ReplSet() {} | |
| | | | |
| skipping to change at line 628 | | skipping to change at line 643 | |
| */ | | */ | |
| class ReplSetCommand : public Command { | | class ReplSetCommand : public Command { | |
| protected: | | protected: | |
| ReplSetCommand(const char * s, bool show=false) : Command(s, show)
{ } | | ReplSetCommand(const char * s, bool show=false) : Command(s, show)
{ } | |
| virtual bool slaveOk() const { return true; } | | virtual bool slaveOk() const { return true; } | |
| virtual bool adminOnly() const { return true; } | | virtual bool adminOnly() const { return true; } | |
| virtual bool logTheOp() { return false; } | | virtual bool logTheOp() { return false; } | |
| virtual LockType locktype() const { return NONE; } | | virtual LockType locktype() const { return NONE; } | |
| virtual void help( stringstream &help ) const { help << "internal";
} | | virtual void help( stringstream &help ) const { help << "internal";
} | |
| | | | |
|
| /** | | | |
| * Some replica set commands call this and then call check(). This | | | |
| is | | | |
| * intentional, as they might do things before theReplSet is initia | | | |
| lized | | | |
| * that still need to be checked for auth. | | | |
| */ | | | |
| bool checkAuth(string& errmsg, BSONObjBuilder& result) { | | | |
| if( !noauth ) { | | | |
| AuthenticationInfo *ai = cc().getAuthenticationInfo(); | | | |
| if (!ai->isAuthorizedForLock("admin", locktype())) { | | | |
| errmsg = "replSet command unauthorized"; | | | |
| return false; | | | |
| } | | | |
| } | | | |
| return true; | | | |
| } | | | |
| | | | |
| bool check(string& errmsg, BSONObjBuilder& result) { | | bool check(string& errmsg, BSONObjBuilder& result) { | |
| if( !replSet ) { | | if( !replSet ) { | |
| errmsg = "not running with --replSet"; | | errmsg = "not running with --replSet"; | |
| if( cmdLine.configsvr ) { | | if( cmdLine.configsvr ) { | |
| result.append("info", "configsvr"); // for shell prompt | | result.append("info", "configsvr"); // for shell prompt | |
| } | | } | |
| return false; | | return false; | |
| } | | } | |
| | | | |
| if( theReplSet == 0 ) { | | if( theReplSet == 0 ) { | |
| result.append("startupStatus", ReplSet::startupStatus); | | result.append("startupStatus", ReplSet::startupStatus); | |
| string s; | | string s; | |
| errmsg = ReplSet::startupStatusMsg.empty() ? "replset unkno
wn error 2" : ReplSet::startupStatusMsg.get(); | | errmsg = ReplSet::startupStatusMsg.empty() ? "replset unkno
wn error 2" : ReplSet::startupStatusMsg.get(); | |
| if( ReplSet::startupStatus == 3 ) | | if( ReplSet::startupStatus == 3 ) | |
| result.append("info", "run rs.initiate(...) if not yet
done for the set"); | | result.append("info", "run rs.initiate(...) if not yet
done for the set"); | |
| return false; | | return false; | |
| } | | } | |
| | | | |
|
| return checkAuth(errmsg, result); | | return true; | |
| } | | } | |
| }; | | }; | |
| | | | |
| /** | | /** | |
| * does local authentication | | * does local authentication | |
| * directly authorizes against AuthenticationInfo | | * directly authorizes against AuthenticationInfo | |
| */ | | */ | |
| void replLocalAuth(); | | void replLocalAuth(); | |
| | | | |
| /** inlines ----------------- */ | | /** inlines ----------------- */ | |
| | | | |
End of changes. 11 change blocks. |
| 26 lines changed or deleted | | 29 lines changed or added | |
|
| s2common.h | | s2common.h | |
| | | | |
| skipping to change at line 17 | | skipping to change at line 17 | |
| * | | * | |
| * This program is distributed in the hope that it will be useful, | | * This program is distributed in the hope that it will be useful, | |
| * 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/>. | |
| */ | | */ | |
| | | | |
|
| #include "mongo/db/geo/geojsonparser.h" | | #include "mongo/db/geo/geoparser.h" | |
| #include "third_party/s2/s2.h" | | #include "third_party/s2/s2.h" | |
| #include "third_party/s2/s2regioncoverer.h" | | #include "third_party/s2/s2regioncoverer.h" | |
| #include "third_party/s2/s2cell.h" | | #include "third_party/s2/s2cell.h" | |
| #include "third_party/s2/s2polyline.h" | | #include "third_party/s2/s2polyline.h" | |
| #include "third_party/s2/s2polygon.h" | | #include "third_party/s2/s2polygon.h" | |
| #include "third_party/s2/s2regioncoverer.h" | | #include "third_party/s2/s2regioncoverer.h" | |
| | | | |
| #pragma once | | #pragma once | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| // This is used by both s2cursor and s2nearcursor. | | // This is used by both s2cursor and s2nearcursor. | |
| class S2SearchUtil { | | class S2SearchUtil { | |
| public: | | public: | |
| // Given a coverer, region, and field name, generate a BSONObj that
we can pass to a | | // Given a coverer, region, and field name, generate a BSONObj that
we can pass to a | |
| // FieldRangeSet so that we only examine the keys that the provided
region may intersect. | | // FieldRangeSet so that we only examine the keys that the provided
region may intersect. | |
|
| static BSONObj coverAsBSON(S2RegionCoverer *coverer, const S2Region | | static BSONObj coverAsBSON(const vector<S2CellId> &cover, const str | |
| ®ion, | | ing& field, | |
| const string& field); | | const int coarsestIndexedLevel); | |
| }; | | }; | |
| | | | |
| // Used for passing geo data from the newCursor entry point to the S2Cu
rsor class. | | // Used for passing geo data from the newCursor entry point to the S2Cu
rsor class. | |
|
| struct GeoQueryField { | | struct QueryGeometry { | |
| GeoQueryField(const string& f) : field(f), cell(NULL), line(NULL), | | QueryGeometry(const string& f) : field(f), predicate(INTERSECT) {} | |
| polygon(NULL) { } | | enum Predicate { | |
| | | WITHIN, | |
| | | INTERSECT, | |
| | | }; | |
| | | | |
| // Name of the field in the query. | | // Name of the field in the query. | |
| string field; | | string field; | |
| // Only one of these should be non-NULL. S2Region is a superclass
but it only supports | | // Only one of these should be non-NULL. S2Region is a superclass
but it only supports | |
| // testing against S2Cells. We need the most specific class we can
get. | | // testing against S2Cells. We need the most specific class we can
get. | |
| // Owned by S2Cursor. | | // Owned by S2Cursor. | |
|
| S2Cell *cell; | | shared_ptr<S2Cell> cell; | |
| S2Polyline *line; | | shared_ptr<S2Polyline> line; | |
| S2Polygon *polygon; | | shared_ptr<S2Polygon> polygon; | |
| | | Predicate predicate; | |
| | | | |
|
| // Does this GeoQueryField intersect the provided data? Sadly ther | | string toString() const; | |
| e is no common good way | | | |
| | | bool satisfiesPredicate(const BSONObj &obj); | |
| | | | |
| | | // Does this QueryGeometry intersect the provided data? Sadly ther | |
| | | e is no common good way | |
| // to check this, so we do different things for all query/data pair
s. | | // to check this, so we do different things for all query/data pair
s. | |
|
| bool intersectsPoint(const S2Cell& otherPoint); | | bool intersects(const S2Cell& otherPoint); | |
| bool intersectsLine(const S2Polyline& otherLine); | | bool intersects(const S2Polyline& otherLine); | |
| bool intersectsPolygon(const S2Polygon& otherPolygon); | | bool intersects(const S2Polygon& otherPolygon); | |
| | | // And, within. | |
| | | bool isWithin(const S2Cell& otherPoint); | |
| | | bool isWithin(const S2Polyline& otherLine); | |
| | | bool isWithin(const S2Polygon& otherPolygon); | |
| | | | |
| // One region is not NULL and this returns it. | | // One region is not NULL and this returns it. | |
| const S2Region& getRegion() const; | | const S2Region& getRegion() const; | |
|
| // Delete the not NULL region. | | | |
| void free(); | | | |
| // Get the centroid, boring if we're a point, interesting if we're
not. | | // Get the centroid, boring if we're a point, interesting if we're
not. | |
| S2Point getCentroid() const; | | S2Point getCentroid() const; | |
| // Try to parse the provided object into the right place. | | // Try to parse the provided object into the right place. | |
|
| bool parseFrom(BSONObj& obj); | | bool parseFrom(const BSONObj &obj); | |
| }; | | }; | |
| | | | |
| struct S2IndexingParams { | | struct S2IndexingParams { | |
| // Since we take the cartesian product when we generate keys for an
insert, | | // Since we take the cartesian product when we generate keys for an
insert, | |
| // we need a cap. | | // we need a cap. | |
| size_t maxKeysPerInsert; | | size_t maxKeysPerInsert; | |
| // This is really an advisory parameter that we pass to the cover g
enerator. The | | // This is really an advisory parameter that we pass to the cover g
enerator. The | |
| // finest/coarsest index level determine the required # of cells. | | // finest/coarsest index level determine the required # of cells. | |
| int maxCellsInCovering; | | int maxCellsInCovering; | |
| // What's the finest grained level that we'll index? When we query
for a point | | // What's the finest grained level that we'll index? When we query
for a point | |
| // we start at that -- we index nothing finer than this. | | // we start at that -- we index nothing finer than this. | |
| int finestIndexedLevel; | | int finestIndexedLevel; | |
| // And, what's the coarsest? When we search in larger coverings we
know we | | // And, what's the coarsest? When we search in larger coverings we
know we | |
| // can stop here -- we index nothing coarser than this. | | // can stop here -- we index nothing coarser than this. | |
| int coarsestIndexedLevel; | | int coarsestIndexedLevel; | |
|
| // What is the radius of the sphere/earth we're using? Not everybo | | | |
| dy likes giving | | | |
| // radians or degrees all the time. In meters. | | | |
| double radius; | | double radius; | |
| | | | |
| string toString() const { | | string toString() const { | |
| stringstream ss; | | stringstream ss; | |
| ss << "maxKeysPerInsert: " << maxKeysPerInsert << endl; | | ss << "maxKeysPerInsert: " << maxKeysPerInsert << endl; | |
| ss << "maxCellsInCovering: " << maxCellsInCovering << endl; | | ss << "maxCellsInCovering: " << maxCellsInCovering << endl; | |
| ss << "finestIndexedLevel: " << finestIndexedLevel << endl; | | ss << "finestIndexedLevel: " << finestIndexedLevel << endl; | |
| ss << "coarsestIndexedLevel: " << coarsestIndexedLevel << endl; | | ss << "coarsestIndexedLevel: " << coarsestIndexedLevel << endl; | |
|
| ss << "radius: " << radius << endl; | | | |
| return ss.str(); | | return ss.str(); | |
| } | | } | |
| | | | |
| void configureCoverer(S2RegionCoverer *coverer) const { | | void configureCoverer(S2RegionCoverer *coverer) const { | |
| coverer->set_min_level(coarsestIndexedLevel); | | coverer->set_min_level(coarsestIndexedLevel); | |
| coverer->set_max_level(finestIndexedLevel); | | coverer->set_max_level(finestIndexedLevel); | |
| // This is advisory; the two above are strict. | | // This is advisory; the two above are strict. | |
| coverer->set_max_cells(maxCellsInCovering); | | coverer->set_max_cells(maxCellsInCovering); | |
| } | | } | |
| }; | | }; | |
| | | | |
End of changes. 10 change blocks. |
| 22 lines changed or deleted | | 30 lines changed or added | |
|
| s2nearcursor.h | | s2nearcursor.h | |
| | | | |
| skipping to change at line 31 | | skipping to change at line 31 | |
| #include "mongo/db/cursor.h" | | #include "mongo/db/cursor.h" | |
| #include "mongo/db/diskloc.h" | | #include "mongo/db/diskloc.h" | |
| #include "mongo/db/matcher.h" | | #include "mongo/db/matcher.h" | |
| #include "mongo/db/queryutil.h" | | #include "mongo/db/queryutil.h" | |
| #include "mongo/db/geo/s2common.h" | | #include "mongo/db/geo/s2common.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| class S2NearCursor : public Cursor { | | class S2NearCursor : public Cursor { | |
| public: | | public: | |
| S2NearCursor(const BSONObj &keyPattern, const IndexDetails* details
, const BSONObj &query, | | S2NearCursor(const BSONObj &keyPattern, const IndexDetails* details
, const BSONObj &query, | |
|
| const vector<GeoQueryField> ®ions, const S2Indexing
Params ¶ms, | | const vector<QueryGeometry> ®ions, const S2Indexing
Params ¶ms, | |
| int numWanted, double maxDistance); | | int numWanted, double maxDistance); | |
| virtual ~S2NearCursor(); | | virtual ~S2NearCursor(); | |
| virtual CoveredIndexMatcher *matcher() const; | | virtual CoveredIndexMatcher *matcher() const; | |
| | | | |
| virtual bool supportYields() { return true; } | | virtual bool supportYields() { return true; } | |
| virtual bool supportGetMore() { return true; } | | virtual bool supportGetMore() { return true; } | |
| virtual bool isMultiKey() const { return true; } | | virtual bool isMultiKey() const { return true; } | |
| virtual bool autoDedup() const { return false; } | | virtual bool autoDedup() const { return false; } | |
| virtual bool modifiedKeys() const { return true; } | | virtual bool modifiedKeys() const { return true; } | |
| virtual bool getsetdup(DiskLoc loc) { return false; } | | virtual bool getsetdup(DiskLoc loc) { return false; } | |
| | | | |
| skipping to change at line 55 | | skipping to change at line 55 | |
| virtual Record* _current(); | | virtual Record* _current(); | |
| virtual BSONObj current(); | | virtual BSONObj current(); | |
| virtual DiskLoc currLoc(); | | virtual DiskLoc currLoc(); | |
| virtual bool advance(); | | virtual bool advance(); | |
| virtual BSONObj currKey() const; | | virtual BSONObj currKey() const; | |
| virtual DiskLoc refLoc(); | | virtual DiskLoc refLoc(); | |
| virtual void noteLocation(); | | virtual void noteLocation(); | |
| virtual void checkLocation(); | | virtual void checkLocation(); | |
| virtual long long nscanned(); | | virtual long long nscanned(); | |
| virtual void explainDetails(BSONObjBuilder& b); | | virtual void explainDetails(BSONObjBuilder& b); | |
|
| | | | |
| | | double currentDistance() const; | |
| private: | | private: | |
| // We use this to cache results of the search. Results are sorted
to have decreasing | | // We use this to cache results of the search. Results are sorted
to have decreasing | |
| // distance, and callers are interested in loc and key. | | // distance, and callers are interested in loc and key. | |
| struct Result { | | struct Result { | |
| Result(const DiskLoc &dl, const BSONObj &ck, double dist) : loc
(dl), key(ck), | | Result(const DiskLoc &dl, const BSONObj &ck, double dist) : loc
(dl), key(ck), | |
| dis
tance(dist) { } | | dis
tance(dist) { } | |
| bool operator<(const Result& other) const { | | bool operator<(const Result& other) const { | |
| // We want increasing distance, not decreasing, so we rever
se the <. | | // We want increasing distance, not decreasing, so we rever
se the <. | |
| return distance > other.distance; | | return distance > other.distance; | |
| } | | } | |
| | | | |
| skipping to change at line 79 | | skipping to change at line 81 | |
| | | | |
| // Make the object that describes all keys that are within our curr
ent search annulus. | | // Make the object that describes all keys that are within our curr
ent search annulus. | |
| BSONObj makeFRSObject(); | | BSONObj makeFRSObject(); | |
| // Fill _results with all of the results in the annulus defined by
_innerRadius and | | // Fill _results with all of the results in the annulus defined by
_innerRadius and | |
| // _outerRadius. If no results are found, grow the annulus and rep
eat until success (or | | // _outerRadius. If no results are found, grow the annulus and rep
eat until success (or | |
| // until the edge of the world). | | // until the edge of the world). | |
| void fillResults(); | | void fillResults(); | |
| // Grow _innerRadius and _outerRadius by _radiusIncrement, capping
_outerRadius at halfway | | // Grow _innerRadius and _outerRadius by _radiusIncrement, capping
_outerRadius at halfway | |
| // around the world (pi * _params.radius). | | // around the world (pi * _params.radius). | |
| void nextAnnulus(); | | void nextAnnulus(); | |
|
| | | double distanceBetween(const QueryGeometry &field, const BSONObj &o
bj); | |
| | | | |
| // Need this to make a FieldRangeSet. | | // Need this to make a FieldRangeSet. | |
| const IndexDetails *_details; | | const IndexDetails *_details; | |
|
| // The query with the geo stuff taken out. We use this with a matc | | | |
| her. | | // How we need/use the query: | |
| | | // Matcher: Can have geo fields in it, but only with $within. | |
| | | // This only really happens (right now) from geoNear comma | |
| | | nd. | |
| | | // We assume the caller takes care of this in the right wa | |
| | | y. | |
| | | // FRS: No geo fields allowed! | |
| | | // So, on that note: the query with the geo stuff taken out, used b | |
| | | y makeFRSObject(). | |
| BSONObj _filteredQuery; | | BSONObj _filteredQuery; | |
| // What geo regions are we looking for? | | // What geo regions are we looking for? | |
|
| vector<GeoQueryField> _fields; | | vector<QueryGeometry> _fields; | |
| // We use this for matching non-GEO stuff. | | // We use this for matching non-GEO stuff. | |
| shared_ptr<CoveredIndexMatcher> _matcher; | | shared_ptr<CoveredIndexMatcher> _matcher; | |
| // How were the keys created? We need this to search for the right
stuff. | | // How were the keys created? We need this to search for the right
stuff. | |
| S2IndexingParams _params; | | S2IndexingParams _params; | |
| // How many things did we scan/look at? Not sure exactly how this
is defined. | | // How many things did we scan/look at? Not sure exactly how this
is defined. | |
| long long _nscanned; | | long long _nscanned; | |
| // We have to pass this to the FieldRangeVector ctor (in modified f
orm). | | // We have to pass this to the FieldRangeVector ctor (in modified f
orm). | |
| BSONObj _keyPattern; | | BSONObj _keyPattern; | |
| // We also pass this to the FieldRangeVector ctor. | | // We also pass this to the FieldRangeVector ctor. | |
| IndexSpec _specForFRV; | | IndexSpec _specForFRV; | |
| | | | |
End of changes. 5 change blocks. |
| 4 lines changed or deleted | | 15 lines changed or added | |
|
| server_status.h | | server_status.h | |
| | | | |
| skipping to change at line 22 | | skipping to change at line 22 | |
| * 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 <string> | | #include <string> | |
|
| | | #include "mongo/db/commands.h" | |
| #include "mongo/db/jsobj.h" | | #include "mongo/db/jsobj.h" | |
| #include "mongo/db/stats/counters.h" | | #include "mongo/db/stats/counters.h" | |
| #include "mongo/platform/atomic_word.h" | | #include "mongo/platform/atomic_word.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| class ServerStatusSection { | | class ServerStatusSection { | |
| public: | | public: | |
| ServerStatusSection( const string& sectionName ); | | ServerStatusSection( const string& sectionName ); | |
| virtual ~ServerStatusSection(){} | | virtual ~ServerStatusSection(){} | |
| | | | |
| skipping to change at line 54 | | skipping to change at line 55 | |
| * foo : 1 = included | | * foo : 1 = included | |
| * foo missing = included | | * foo missing = included | |
| * includeByDefault returning false | | * includeByDefault returning false | |
| * foo : 0 = not included | | * foo : 0 = not included | |
| * foo : 1 = included | | * foo : 1 = included | |
| * foo missing = false | | * foo missing = false | |
| */ | | */ | |
| virtual bool includeByDefault() const = 0; | | virtual bool includeByDefault() const = 0; | |
| | | | |
| /** | | /** | |
|
| * if only admins can view this section | | * Adds the privileges that are required to view this section | |
| * API will change to better auth version | | * TODO: Remove this empty default implementation and implement for | |
| | | every section. | |
| */ | | */ | |
|
| virtual bool adminOnly() const = 0; | | virtual void addRequiredPrivileges(std::vector<Privilege>* out) {}; | |
| | | | |
| /** | | /** | |
| * actually generate the result | | * actually generate the result | |
| * @param configElement the element from the actual command related
to this section | | * @param configElement the element from the actual command related
to this section | |
| * so if the section is 'foo', this is cmdObj[
'foo'] | | * so if the section is 'foo', this is cmdObj[
'foo'] | |
| */ | | */ | |
|
| virtual BSONObj generateSection( const BSONElement& configElement,
bool userIsAdmin ) const = 0; | | virtual BSONObj generateSection(const BSONElement& configElement) c
onst = 0; | |
| | | | |
| private: | | private: | |
| const string _sectionName; | | const string _sectionName; | |
| }; | | }; | |
| | | | |
| class OpCounterServerStatusSection : public ServerStatusSection { | | class OpCounterServerStatusSection : public ServerStatusSection { | |
| public: | | public: | |
| OpCounterServerStatusSection( const string& sectionName, OpCounters
* counters ); | | OpCounterServerStatusSection( const string& sectionName, OpCounters
* counters ); | |
| virtual bool includeByDefault() const { return true; } | | virtual bool includeByDefault() const { return true; } | |
|
| virtual bool adminOnly() const { return false; } | | | |
| | | | |
|
| virtual BSONObj generateSection( const BSONElement& configElement,
bool userIsAdmin ) const; | | virtual BSONObj generateSection(const BSONElement& configElement) c
onst; | |
| | | | |
| private: | | private: | |
| const OpCounters* _counters; | | const OpCounters* _counters; | |
| }; | | }; | |
| | | | |
| class ServerStatusMetric { | | class ServerStatusMetric { | |
| public: | | public: | |
| /** | | /** | |
| * @param name is a dotted path of a counter name | | * @param name is a dotted path of a counter name | |
| * if name starts with . its treated as a path from the
serverStatus root | | * if name starts with . its treated as a path from the
serverStatus root | |
| * otherwise it will live under the "counters" namespac
e | | * otherwise it will live under the "counters" namespac
e | |
| * so foo.bar would be serverStatus().counters.foo.bar | | * so foo.bar would be serverStatus().counters.foo.bar | |
| */ | | */ | |
|
| ServerStatusMetric( const string& name, bool adminOnly ); | | ServerStatusMetric(const string& name); | |
| virtual ~ServerStatusMetric(){} | | virtual ~ServerStatusMetric(){} | |
| | | | |
| string getMetricName() const { return _name; } | | string getMetricName() const { return _name; } | |
| | | | |
|
| virtual bool adminOnly() const { return _adminOnly; } | | | |
| | | | |
| virtual void appendAtLeaf( BSONObjBuilder& b ) const = 0; | | virtual void appendAtLeaf( BSONObjBuilder& b ) const = 0; | |
| | | | |
| protected: | | protected: | |
| static string _parseLeafName( const string& name ); | | static string _parseLeafName( const string& name ); | |
| | | | |
| const string _name; | | const string _name; | |
|
| const bool _adminOnly; | | | |
| const string _leafName; | | const string _leafName; | |
| }; | | }; | |
| | | | |
| /** | | /** | |
| * usage | | * usage | |
| * | | * | |
| * declared once | | * declared once | |
| * Counter counter; | | * Counter counter; | |
|
| * ServerStatusMetricField myAwesomeCounterDisplay( "path.to.counter
", false, &counter ); | | * ServerStatusMetricField myAwesomeCounterDisplay( "path.to.counter
", &counter ); | |
| * | | * | |
| * call | | * call | |
| * counter.hit(); | | * counter.hit(); | |
| * | | * | |
| * will show up in db.serverStatus().metrics.path.to.counter | | * will show up in db.serverStatus().metrics.path.to.counter | |
| */ | | */ | |
| template< typename T > | | template< typename T > | |
| class ServerStatusMetricField : public ServerStatusMetric { | | class ServerStatusMetricField : public ServerStatusMetric { | |
| public: | | public: | |
|
| ServerStatusMetricField( const string& name, bool adminOnly, const | | ServerStatusMetricField( const string& name, const T* t ) | |
| T* t ) | | : ServerStatusMetric(name), _t(t) { | |
| : ServerStatusMetric( name, adminOnly ), _t(t) { | | | |
| } | | } | |
| | | | |
| const T* get() { return _t; } | | const T* get() { return _t; } | |
| | | | |
| virtual void appendAtLeaf( BSONObjBuilder& b ) const { | | virtual void appendAtLeaf( BSONObjBuilder& b ) const { | |
| b.append( _leafName, *_t ); | | b.append( _leafName, *_t ); | |
| } | | } | |
| | | | |
| private: | | private: | |
| const T* _t; | | const T* _t; | |
| | | | |
End of changes. 11 change blocks. |
| 14 lines changed or deleted | | 11 lines changed or added | |
|
| sock.h | | sock.h | |
| | | | |
| skipping to change at line 36 | | skipping to change at line 36 | |
| #include <sys/socket.h> | | #include <sys/socket.h> | |
| #include <sys/types.h> | | #include <sys/types.h> | |
| #include <sys/socket.h> | | #include <sys/socket.h> | |
| #include <sys/un.h> | | #include <sys/un.h> | |
| #include <errno.h> | | #include <errno.h> | |
| | | | |
| #ifdef __openbsd__ | | #ifdef __openbsd__ | |
| # include <sys/uio.h> | | # include <sys/uio.h> | |
| #endif | | #endif | |
| | | | |
|
| #endif // _WIN32 | | #endif // not _WIN32 | |
| | | | |
| #ifdef MONGO_SSL | | #ifdef MONGO_SSL | |
| #include <openssl/ssl.h> | | #include <openssl/ssl.h> | |
| #include "mongo/util/net/ssl_manager.h" | | #include "mongo/util/net/ssl_manager.h" | |
| #endif | | #endif | |
| | | | |
|
| | | #include "mongo/platform/compiler.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| const int SOCK_FAMILY_UNKNOWN_ERROR=13078; | | const int SOCK_FAMILY_UNKNOWN_ERROR=13078; | |
| | | | |
| void disableNagle(int sock); | | void disableNagle(int sock); | |
| | | | |
| #if defined(_WIN32) | | #if defined(_WIN32) | |
| | | | |
| typedef short sa_family_t; | | typedef short sa_family_t; | |
| typedef int socklen_t; | | typedef int socklen_t; | |
| | | | |
| skipping to change at line 186 | | skipping to change at line 188 | |
| Socket(int sock, const SockAddr& farEnd); | | Socket(int sock, const SockAddr& farEnd); | |
| | | | |
| /** In some cases the timeout will actually be 2x this value - eg w
e do a partial send, | | /** In some cases the timeout will actually be 2x this value - eg w
e do a partial send, | |
| then the timeout fires, then we try to send again, then the tim
eout fires again with | | then the timeout fires, then we try to send again, then the tim
eout fires again with | |
| no data sent, then we detect that the other side is down. | | no data sent, then we detect that the other side is down. | |
| | | | |
| Generally you don't want a timeout, you should be very prepared
for errors if you set one. | | Generally you don't want a timeout, you should be very prepared
for errors if you set one. | |
| */ | | */ | |
| Socket(double so_timeout = 0, int logLevel = 0 ); | | Socket(double so_timeout = 0, int logLevel = 0 ); | |
| | | | |
|
| ~Socket() { | | ~Socket(); | |
| close(); | | | |
| } | | | |
| | | | |
| bool connect(SockAddr& farEnd); | | bool connect(SockAddr& farEnd); | |
| void close(); | | void close(); | |
| | | | |
| void send( const char * data , int len, const char *context ); | | void send( const char * data , int len, const char *context ); | |
| void send( const vector< pair< char *, int > > &data, const char *c
ontext ); | | void send( const vector< pair< char *, int > > &data, const char *c
ontext ); | |
| | | | |
| // recv len or throw SocketException | | // recv len or throw SocketException | |
| void recv( char * data , int len ); | | void recv( char * data , int len ); | |
| int unsafe_recv( char *buf, int max ); | | int unsafe_recv( char *buf, int max ); | |
| | | | |
| skipping to change at line 221 | | skipping to change at line 221 | |
| void setTimeout( double secs ); | | void setTimeout( double secs ); | |
| | | | |
| #ifdef MONGO_SSL | | #ifdef MONGO_SSL | |
| /** secures inline */ | | /** secures inline */ | |
| void secure( SSLManager * ssl ); | | void secure( SSLManager * ssl ); | |
| | | | |
| void secureAccepted( SSLManager * ssl ); | | void secureAccepted( SSLManager * ssl ); | |
| #endif | | #endif | |
| | | | |
| /** | | /** | |
|
| * call this after a fork for server sockets | | * This function calls SSL_accept() if SSL-encrypted sockets | |
| | | * are desired. SSL_accept() waits until the remote host calls | |
| | | * SSL_connect(). | |
| | | * This function may throw SocketException. | |
| */ | | */ | |
|
| void postFork(); | | void doSSLHandshake(); | |
| | | | |
| /** | | /** | |
| * @return the time when the socket was opened. | | * @return the time when the socket was opened. | |
| */ | | */ | |
| uint64_t getSockCreationMicroSec() const { | | uint64_t getSockCreationMicroSec() const { | |
| return _fdCreationMicroSec; | | return _fdCreationMicroSec; | |
| } | | } | |
| | | | |
| private: | | private: | |
| void _init(); | | void _init(); | |
| | | | |
|
| /** raw send, same semantics as ::send */ | | | |
| public: | | | |
| int _send( const char * data , int len ); | | | |
| private: | | | |
| | | | |
| /** sends dumbly, just each buffer at a time */ | | /** sends dumbly, just each buffer at a time */ | |
| void _send( const vector< pair< char *, int > > &data, const char *
context ); | | void _send( const vector< pair< char *, int > > &data, const char *
context ); | |
| | | | |
|
| | | /** raw send, same semantics as ::send */ | |
| | | int _send( const char * data , int len ); | |
| | | | |
| /** raw recv, same semantics as ::recv */ | | /** raw recv, same semantics as ::recv */ | |
| int _recv( char * buf , int max ); | | int _recv( char * buf , int max ); | |
| | | | |
|
| | | void _handleRecvError(int ret, int len, int* retries); | |
| | | MONGO_COMPILER_NORETURN void _handleSendError(int ret, const char* | |
| | | context); | |
| | | | |
| int _fd; | | int _fd; | |
| uint64_t _fdCreationMicroSec; | | uint64_t _fdCreationMicroSec; | |
| SockAddr _remote; | | SockAddr _remote; | |
| double _timeout; | | double _timeout; | |
| | | | |
| long long _bytesIn; | | long long _bytesIn; | |
| long long _bytesOut; | | long long _bytesOut; | |
| | | | |
| #ifdef MONGO_SSL | | #ifdef MONGO_SSL | |
| SSL* _ssl; | | SSL* _ssl; | |
| | | | |
End of changes. 8 change blocks. |
| 11 lines changed or deleted | | 16 lines changed or added | |
|
| string_data.h | | string_data.h | |
|
| | | // string_data.h | |
| | | | |
| /* Copyright 2010 10gen Inc. | | /* Copyright 2010 10gen Inc. | |
| * | | * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | | * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | | * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | | * You may obtain a copy of the License at | |
| * | | * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | | * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | | * | |
| * 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 <algorithm> // for min | | #include <algorithm> // for min | |
| #include <cstring> | | #include <cstring> | |
|
| | | #include <iosfwd> | |
| | | #include <limits> | |
| #include <string> | | #include <string> | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| using std::string; | | using std::string; | |
| | | | |
| /** | | /** | |
| * A StringData object wraps a 'const string&' or a 'const char*' witho
ut copying its | | * A StringData object wraps a 'const string&' or a 'const char*' witho
ut copying its | |
| * contents. The most common usage is as a function argument that takes
any of the two | | * contents. The most common usage is as a function argument that takes
any of the two | |
| * forms of strings above. Fundamentally, this class tries go around th
e fact that string | | * forms of strings above. Fundamentally, this class tries go around th
e fact that string | |
| * literals in C++ are char[N]'s. | | * literals in C++ are char[N]'s. | |
| * | | * | |
| * Notes: | | * Notes: | |
| * | | * | |
| * + The object StringData wraps around must be alive while the String
Data is. | | * + The object StringData wraps around must be alive while the String
Data is. | |
| * | | * | |
|
| * + Because strings accept null characters, we allow them in StringDa | | * + Because string data can be used to pass a substring around, one s | |
| ta. But this use is | | hould never assume a | |
| * *strongly* discouraged. One problem this case may encounter is wh | | * rawData() terminates with a null. | |
| en asking for data() | | | |
| * out of a StringData that was feed with, say "a\0b". If interprete | | | |
| d as a c-string, | | | |
| * the null character would cut the original string short. | | | |
| */ | | */ | |
| class StringData { | | class StringData { | |
| public: | | public: | |
| | | | |
|
| | | /** Constructs an empty string data */ | |
| | | StringData() | |
| | | : _data(NULL), _size(0) {} | |
| | | | |
| /** | | /** | |
| * Constructs a StringData, for the case where the length of string
is not known. 'c' | | * Constructs a StringData, for the case where the length of string
is not known. 'c' | |
| * must be a pointer to a null-terminated string. | | * must be a pointer to a null-terminated string. | |
| */ | | */ | |
| StringData( const char* c ) | | StringData( const char* c ) | |
|
| : _data(c), _size(string::npos){} | | : _data(c), _size((c == NULL) ? 0 : string::npos) {} | |
| | | | |
| /** | | /** | |
| * Constructs a StringData explicitly, for the case where the lengt
h of the string is | | * Constructs a StringData explicitly, for the case where the lengt
h of the string is | |
| * already known. 'c' must be a pointer to a null-terminated string
, and strlenOfc must | | * already known. 'c' must be a pointer to a null-terminated string
, and strlenOfc must | |
| * be the length that strlen(c) would return, a.k.a the index of th
e terminator in c. | | * be the length that strlen(c) would return, a.k.a the index of th
e terminator in c. | |
| */ | | */ | |
| StringData( const char* c, size_t len ) | | StringData( const char* c, size_t len ) | |
| : _data(c), _size(len) {} | | : _data(c), _size(len) {} | |
| | | | |
| /** Constructs a StringData, for the case of a string. */ | | /** Constructs a StringData, for the case of a string. */ | |
| | | | |
| skipping to change at line 76 | | skipping to change at line 82 | |
| */ | | */ | |
| struct LiteralTag {}; | | struct LiteralTag {}; | |
| template<size_t N> | | template<size_t N> | |
| StringData( const char (&val)[N], LiteralTag ) | | StringData( const char (&val)[N], LiteralTag ) | |
| : _data(&val[0]), _size(N-1) {} | | : _data(&val[0]), _size(N-1) {} | |
| | | | |
| /** | | /** | |
| * Returns -1, 0, or 1 if 'this' is less, equal, or greater than 'o
ther' in | | * Returns -1, 0, or 1 if 'this' is less, equal, or greater than 'o
ther' in | |
| * lexicographical order. | | * lexicographical order. | |
| */ | | */ | |
|
| int compare(const StringData& other) const { | | int compare(const StringData& other) const; | |
| // Sizes might not have been computed yet. | | | |
| size(); | | /** | |
| other.size(); | | * note: this uses tolower, and therefore does not handle | |
| | | * come languages correctly. | |
| int res = memcmp(_data, other._data, std::min(_size, other._siz | | * should be use sparingly | |
| e)); | | */ | |
| if (res != 0) { | | bool equalCaseInsensitive( const StringData& other ) const; | |
| return res > 0 ? 1 : -1; | | | |
| } | | void copyTo( char* dest, bool includeEndingNull ) const; | |
| else if (_size == other._size) { | | | |
| return 0; | | StringData substr( size_t pos, size_t n = std::numeric_limits<size_ | |
| } | | t>::max() ) const; | |
| else { | | | |
| return _size > other._size ? 1 : -1; | | // | |
| } | | // finders | |
| } | | // | |
| | | | |
| | | size_t find( char c ) const; | |
| | | size_t find( const StringData& needle ) const; | |
| | | | |
| | | /** | |
| | | * Returns true if 'prefix' is a substring of this instance, anchor | |
| | | ed at position 0. | |
| | | */ | |
| | | bool startsWith( const StringData& prefix ) const; | |
| | | | |
| | | /** | |
| | | * Returns true if 'suffix' is a substring of this instance, anchor | |
| | | ed at the end. | |
| | | */ | |
| | | bool endsWith( const StringData& suffix ) const; | |
| | | | |
| // | | // | |
| // accessors | | // accessors | |
| // | | // | |
| | | | |
|
| const char* data() const { return _data; } | | /** | |
| | | * this is not guaranteed to be null-terminated, | |
| | | * if you use this without all using size(), you are likely doing s | |
| | | omething wrong | |
| | | */ | |
| | | const char* rawData() const { return _data; } | |
| | | | |
| size_t size() const { fillSize(); return _size; } | | size_t size() const { fillSize(); return _size; } | |
| bool empty() const { return size() == 0; } | | bool empty() const { return size() == 0; } | |
|
| string toString() const { return string(data(), size()); } | | string toString() const { return string(_data, size()); } | |
| | | char operator[] ( unsigned pos ) const { return _data[pos]; } | |
| | | | |
| private: | | private: | |
|
| const char* const _data; // is always null terminated, but see "no
tes" above | | const char* _data; // is not guaranted to be null terminated
(see "notes" above) | |
| mutable size_t _size; // 'size' does not include the null termi
nator | | mutable size_t _size; // 'size' does not include the null termi
nator | |
| | | | |
| void fillSize() const { | | void fillSize() const { | |
| if (_size == string::npos) { | | if (_size == string::npos) { | |
| _size = strlen(_data); | | _size = strlen(_data); | |
| } | | } | |
| } | | } | |
| }; | | }; | |
| | | | |
| inline bool operator==(const StringData& lhs, const StringData& rhs) { | | inline bool operator==(const StringData& lhs, const StringData& rhs) { | |
| | | | |
| skipping to change at line 137 | | skipping to change at line 162 | |
| } | | } | |
| | | | |
| inline bool operator>(const StringData& lhs, const StringData& rhs) { | | inline bool operator>(const StringData& lhs, const StringData& rhs) { | |
| return lhs.compare(rhs) > 0; | | return lhs.compare(rhs) > 0; | |
| } | | } | |
| | | | |
| inline bool operator>=(const StringData& lhs, const StringData& rhs) { | | inline bool operator>=(const StringData& lhs, const StringData& rhs) { | |
| return lhs.compare(rhs) >= 0; | | return lhs.compare(rhs) >= 0; | |
| } | | } | |
| | | | |
|
| | | std::ostream& operator<<(std::ostream& stream, const StringData& value) | |
| | | ; | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
|
| | | | |
| | | #include "string_data-inl.h" | |
| | | | |
End of changes. 11 change blocks. |
| 28 lines changed or deleted | | 57 lines changed or added | |
|
| type_chunk.h | | type_chunk.h | |
| | | | |
| skipping to change at line 24 | | skipping to change at line 24 | |
| * 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 <string> | | #include <string> | |
| | | | |
| #include "mongo/base/disallow_copying.h" | | #include "mongo/base/disallow_copying.h" | |
| #include "mongo/base/string_data.h" | | #include "mongo/base/string_data.h" | |
| #include "mongo/db/jsobj.h" | | #include "mongo/db/jsobj.h" | |
|
| #include "mongo/s/util.h" // for ShardChunkVersion | | #include "mongo/s/chunk_version.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| /** | | /** | |
| * This class represents the layout and contents of documents contained
in the | | * This class represents the layout and contents of documents contained
in the | |
| * config.chunks collection. All manipulation of documents coming from
that | | * config.chunks collection. All manipulation of documents coming from
that | |
| * collection should be done with this class. | | * collection should be done with this class. | |
| * | | * | |
| * Usage Example: | | * Usage Example: | |
| * | | * | |
| | | | |
| skipping to change at line 64 | | skipping to change at line 64 | |
| public: | | public: | |
| | | | |
| // | | // | |
| // schema declarations | | // schema declarations | |
| // | | // | |
| | | | |
| // Name of the chunk collection in the config server. | | // Name of the chunk collection in the config server. | |
| static const std::string ConfigNS; | | static const std::string ConfigNS; | |
| | | | |
| // Field names and types in the chunk collection type. | | // Field names and types in the chunk collection type. | |
|
| static BSONField<std::string> name; | | static BSONField<std::string> name; // chunk's id | |
| static BSONField<std::string> ns; | | static BSONField<std::string> ns; // namespace this chunk is | |
| static BSONField<BSONObj> min; | | in | |
| static BSONField<BSONObj> max; | | static BSONField<BSONObj> min; // first key of the chunk, | |
| static BSONField<BSONArray> version; | | including | |
| static BSONField<std::string> shard; | | static BSONField<BSONObj> max; // last key of the chunk, n | |
| static BSONField<bool> jumbo; | | on-including | |
| | | static BSONField<BSONArray> version; // [Date_t, OID] | |
| | | static BSONField<std::string> shard; // home of this chunk | |
| | | static BSONField<bool> jumbo; // too big to move? | |
| | | | |
| // Transition to new format, 2.2 -> 2.4 | | // Transition to new format, 2.2 -> 2.4 | |
| // 2.2 can read both lastmod + lastmodEpoch format and 2.4 [ lastmo
d, OID ] formats. | | // 2.2 can read both lastmod + lastmodEpoch format and 2.4 [ lastmo
d, OID ] formats. | |
| static BSONField<Date_t> DEPRECATED_lastmod; // major | minor vers
ions | | static BSONField<Date_t> DEPRECATED_lastmod; // major | minor vers
ions | |
|
| static BSONField<OID> DEPRECATED_epoch; // disambiguates coll
ection incarnations | | static BSONField<OID> DEPRECATED_epoch; // OID, to disambigua
te collection incarnations | |
| | | | |
| // | | // | |
| // chunk type methods | | // chunk type methods | |
| // | | // | |
| | | | |
| ChunkType(); | | ChunkType(); | |
| ~ChunkType(); | | ~ChunkType(); | |
| | | | |
| /** | | /** | |
| * Returns true if all the mandatory fields are present and have va
lid | | * Returns true if all the mandatory fields are present and have va
lid | |
| | | | |
| skipping to change at line 97 | | skipping to change at line 97 | |
| */ | | */ | |
| bool isValid(std::string* errMsg) const; | | bool isValid(std::string* errMsg) const; | |
| | | | |
| /** | | /** | |
| * Returns the BSON representation of the entry. | | * Returns the BSON representation of the entry. | |
| */ | | */ | |
| BSONObj toBSON() const; | | BSONObj toBSON() const; | |
| | | | |
| /** | | /** | |
| * Clears and populates the internal state using the 'source' BSON
object if the | | * Clears and populates the internal state using the 'source' BSON
object if the | |
|
| * latter contains valid values. Otherwise clear the internal state
. | | * latter contains valid values. Otherwise sets errMsg and returns
false. | |
| */ | | */ | |
|
| void parseBSON(BSONObj source); | | bool parseBSON(BSONObj source, std::string* errMsg); | |
| | | | |
| /** | | /** | |
| * Clears the internal state. | | * Clears the internal state. | |
| */ | | */ | |
| void clear(); | | void clear(); | |
| | | | |
| /** | | /** | |
| * Copies all the fields present in 'this' to 'other'. | | * Copies all the fields present in 'this' to 'other'. | |
| */ | | */ | |
|
| void cloneTo(ChunkType* other); | | void cloneTo(ChunkType* other) const; | |
| | | | |
| /** | | /** | |
| * Returns a string representation of the current internal state. | | * Returns a string representation of the current internal state. | |
| */ | | */ | |
| std::string toString() const; | | std::string toString() const; | |
| | | | |
| // | | // | |
| // individual field accessors | | // individual field accessors | |
| // | | // | |
| | | | |
|
| void setName(const StringData& name) { _name = std::string(name.dat | | void setName(const StringData& name) { | |
| a(), name.size()); } | | _name = name.toString(); | |
| const std::string& getName() const { return _name; } | | } | |
| | | | |
| void setNS(const StringData& ns) { _ns = std::string(ns.data(), ns. | | const std::string& getName() const { | |
| size()); } | | return _name; | |
| const std::string& getNS() const { return _ns; } | | } | |
| | | | |
| void setMin(const BSONObj& min) { _min = min.getOwned(); } | | void setNS(const StringData& ns) { | |
| BSONObj getMin() const { return _min; } | | _ns = ns.toString(); | |
| | | } | |
| void setMax(const BSONObj& max) { _max = max.getOwned(); } | | | |
| BSONObj getMax() const { return _max; } | | const std::string& getNS() const { | |
| | | return _ns; | |
| void setVersion(const ShardChunkVersion& version) { _version = vers | | } | |
| ion; } | | | |
| const ShardChunkVersion& getVersion() const { return _version; } | | void setMin(const BSONObj& min) { | |
| | | _min = min.getOwned(); | |
| void setShard(const StringData& shard) { _shard=std::string(shard. | | } | |
| data(), shard.size()); } | | | |
| const std::string& getShard() const { return _shard; } | | BSONObj getMin() const { | |
| | | return _min; | |
| void setJumbo(bool jumbo) { _jumbo = jumbo; } | | } | |
| bool getJumbo() const { return _jumbo; } | | | |
| | | void setMax(const BSONObj& max) { | |
| | | _max = max.getOwned(); | |
| | | } | |
| | | | |
| | | BSONObj getMax() const { | |
| | | return _max; | |
| | | } | |
| | | | |
| | | void setVersion(const ChunkVersion& version) { | |
| | | _version = version; | |
| | | } | |
| | | | |
| | | const ChunkVersion& getVersion() const { | |
| | | return _version; | |
| | | } | |
| | | | |
| | | void setShard(const StringData& shard) { | |
| | | _shard = shard.toString(); | |
| | | } | |
| | | | |
| | | const std::string& getShard() const { | |
| | | return _shard; | |
| | | } | |
| | | | |
| | | void setJumbo(bool jumbo) { | |
| | | _jumbo = jumbo; | |
| | | } | |
| | | | |
| | | bool getJumbo() const { | |
| | | return _jumbo; | |
| | | } | |
| | | | |
| private: | | private: | |
| // Convention: (M)andatory, (O)ptional, (S)pecial rule. | | // Convention: (M)andatory, (O)ptional, (S)pecial rule. | |
|
| string _name; // (M) chunk's id | | string _name; // (M) chunk's id | |
| string _ns; // (M) collection this chunk is in | | string _ns; // (M) collection this chunk is in | |
| BSONObj _min; // (M) first key of the range, inclusi | | BSONObj _min; // (M) first key of the range, inclusive | |
| ve | | BSONObj _max; // (M) last key of the range, non-inclusive | |
| BSONObj _max; // (M) last key of the range, non-incl | | ChunkVersion _version; // (M) version of this chunk | |
| usive | | string _shard; // (M) shard this chunk lives in | |
| ShardChunkVersion _version; // (M) version of this chunk | | bool _jumbo; // (O) too big to move? | |
| string _shard; // (M) shard this chunk lives in | | | |
| bool _jumbo; // (O) too big to move? | | | |
| }; | | }; | |
| | | | |
|
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 9 change blocks. |
| 45 lines changed or deleted | | 77 lines changed or added | |
|
| type_collection.h | | type_collection.h | |
| | | | |
| skipping to change at line 46 | | skipping to change at line 46 | |
| * BSONObj query = QUERY(CollectionType::ns("db.coll") << | | * BSONObj query = QUERY(CollectionType::ns("db.coll") << | |
| * CollectionType::unique(true)); | | * CollectionType::unique(true)); | |
| * collDoc = conn->findOne(CollectionType::ConfigNS, query); | | * collDoc = conn->findOne(CollectionType::ConfigNS, query); | |
| * | | * | |
| * // Process the response. | | * // Process the response. | |
| * CollectionType coll; | | * CollectionType coll; | |
| * coll.fromBSON(collDoc); | | * coll.fromBSON(collDoc); | |
| * if (! coll.isValid()) { | | * if (! coll.isValid()) { | |
| * // Can't use 'coll'. Take action. | | * // Can't use 'coll'. Take action. | |
| * } | | * } | |
|
| | | * if (coll.isDropped()) { | |
| | | * // Coll doesn't exist, Take action. | |
| | | * } | |
| | | * | |
| * // use 'coll' | | * // use 'coll' | |
| * | | * | |
| */ | | */ | |
| class CollectionType { | | class CollectionType { | |
| MONGO_DISALLOW_COPYING(CollectionType); | | MONGO_DISALLOW_COPYING(CollectionType); | |
| public: | | public: | |
| | | | |
| // | | // | |
| // schema declarations | | // schema declarations | |
| // | | // | |
| | | | |
| // Name of the collection in the config server. | | // Name of the collection in the config server. | |
| static const std::string ConfigNS; | | static const std::string ConfigNS; | |
| | | | |
| // Field names and types in the collection type. | | // Field names and types in the collection type. | |
| static BSONField<std::string> ns; // collection's namespace | | static BSONField<std::string> ns; // collection's namespace | |
| static BSONField<std::string> primary; // primary db when not shard
ed | | static BSONField<std::string> primary; // primary db when not shard
ed | |
| static BSONField<BSONObj> keyPattern; // sharding key, if sharded | | static BSONField<BSONObj> keyPattern; // sharding key, if sharded | |
| static BSONField<bool> unique; // sharding key unique? | | static BSONField<bool> unique; // sharding key unique? | |
|
| static BSONField<Date_t> createdAt; // when collection was creat
ed | | static BSONField<Date_t> updatedAt; // when collection was creat
ed | |
| static BSONField<bool> noBalance; // true if balancing is disa
bled | | static BSONField<bool> noBalance; // true if balancing is disa
bled | |
| static BSONField<OID> epoch; // disambiguate ns (drop/rec
reate) | | static BSONField<OID> epoch; // disambiguate ns (drop/rec
reate) | |
|
| | | // To-be-deprecated, not yet | |
| | | static BSONField<bool> dropped; // true if we should ignore | |
| | | this collection entry | |
| | | | |
| // Deprecated fields should only be used in parseBSON calls. Expose
d here for testing only. | | // Deprecated fields should only be used in parseBSON calls. Expose
d here for testing only. | |
| static BSONField<OID> DEPRECATED_lastmodEpoch; | | static BSONField<OID> DEPRECATED_lastmodEpoch; | |
| static BSONField<Date_t> DEPRECATED_lastmod; | | static BSONField<Date_t> DEPRECATED_lastmod; | |
|
| static BSONField<bool> DEPRECATED_dropped; | | | |
| | | | |
| // | | // | |
| // collection type methods | | // collection type methods | |
| // | | // | |
| | | | |
| CollectionType(); | | CollectionType(); | |
| ~CollectionType(); | | ~CollectionType(); | |
| | | | |
| /** | | /** | |
| * Returns true if all the mandatory fields are present and have va
lid | | * Returns true if all the mandatory fields are present and have va
lid | |
| | | | |
| skipping to change at line 94 | | skipping to change at line 99 | |
| */ | | */ | |
| bool isValid(std::string* errMsg) const; | | bool isValid(std::string* errMsg) const; | |
| | | | |
| /** | | /** | |
| * Returns the BSON representation of the entry. | | * Returns the BSON representation of the entry. | |
| */ | | */ | |
| BSONObj toBSON() const; | | BSONObj toBSON() const; | |
| | | | |
| /** | | /** | |
| * Clears and populates the internal state using the 'source' BSON
object if the | | * Clears and populates the internal state using the 'source' BSON
object if the | |
|
| * latter contains valid values. Otherwise clear the internal state
. | | * latter contains valid values. Otherwise sets errMsg and returns
false. | |
| */ | | */ | |
|
| void parseBSON(BSONObj source); | | bool parseBSON(BSONObj source, std::string* errMsg); | |
| | | | |
| /** | | /** | |
| * Clears the internal state. | | * Clears the internal state. | |
| */ | | */ | |
| void clear(); | | void clear(); | |
| | | | |
| /** | | /** | |
| * Copies all the fields present in 'this' to 'other'. | | * Copies all the fields present in 'this' to 'other'. | |
| */ | | */ | |
|
| void cloneTo(CollectionType* other); | | void cloneTo(CollectionType* other) const; | |
| | | | |
| /** | | /** | |
| * Returns a string representation of the current internal state. | | * Returns a string representation of the current internal state. | |
| */ | | */ | |
| std::string toString() const; | | std::string toString() const; | |
| | | | |
| // | | // | |
| // individual field accessors | | // individual field accessors | |
| // | | // | |
| | | | |
|
| void setNS(const StringData& ns) { _ns = std::string(ns.data(), ns.
size()); } | | void setNS(const StringData& ns) { _ns = ns.toString(); } | |
| const std::string& getNS() const { return _ns; } | | const std::string& getNS() const { return _ns; } | |
| | | | |
|
| void setPrimary(const StringData& name) { _primary=std::string(name
.data(), name.size()); } | | void setPrimary(const StringData& name) { _primary = name.toString(
); } | |
| const std::string& getPrimary() const { return _primary; } | | const std::string& getPrimary() const { return _primary; } | |
| | | | |
| void setKeyPattern(const BSONObj keyPattern) { _keyPattern = keyPat
tern.getOwned(); } | | void setKeyPattern(const BSONObj keyPattern) { _keyPattern = keyPat
tern.getOwned(); } | |
| BSONObj getKeyPattern() const { return _keyPattern; } | | BSONObj getKeyPattern() const { return _keyPattern; } | |
| | | | |
| void setUnique(bool unique) { _unique = unique; } | | void setUnique(bool unique) { _unique = unique; } | |
|
| bool getUnique() const { return _unique; } | | bool isUnique() const { return _unique; } | |
| | | | |
|
| void setCreatedAt(const Date_t& time) { _createdAt = time; } | | void setUpdatedAt(const Date_t& time) { _updatedAt = time; } | |
| Date_t getCreatedAt() const { return _createdAt; } | | Date_t getUpdatedAt() const { return _updatedAt; } | |
| | | | |
| void setNoBalance(bool noBalance) { _noBalance = noBalance; } | | void setNoBalance(bool noBalance) { _noBalance = noBalance; } | |
| bool getNoBalance() const { return _noBalance; } | | bool getNoBalance() const { return _noBalance; } | |
| | | | |
| void setEpoch(OID oid) { _epoch = oid; } | | void setEpoch(OID oid) { _epoch = oid; } | |
| OID getEpoch() const { return _epoch; } | | OID getEpoch() const { return _epoch; } | |
| | | | |
|
| | | void setDropped(bool dropped) { _dropped = dropped; } | |
| | | bool isDropped() const { return _dropped; } | |
| | | | |
| private: | | private: | |
| // Convention: (M)andatory, (O)ptional, (S)pecial rule. | | // Convention: (M)andatory, (O)ptional, (S)pecial rule. | |
| std::string _ns; // (M) namespace | | std::string _ns; // (M) namespace | |
| std::string _primary; // (S) either/or with _keyPattern | | std::string _primary; // (S) either/or with _keyPattern | |
| BSONObj _keyPattern; // (S) sharding pattern if sharded | | BSONObj _keyPattern; // (S) sharding pattern if sharded | |
| bool _unique; // (S) mandatory if sharded, index is unique | | bool _unique; // (S) mandatory if sharded, index is unique | |
|
| Date_t _createdAt; // (M) creation time | | Date_t _updatedAt; // (M) last updated time | |
| bool _noBalance; // (S) optional if sharded, disable balancin
g | | bool _noBalance; // (S) optional if sharded, disable balancin
g | |
| OID _epoch; // (M) disambiguates collection incarnations | | OID _epoch; // (M) disambiguates collection incarnations | |
|
| | | bool _dropped; // (O) if true, ignore this entry | |
| }; | | }; | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 14 change blocks. |
| 12 lines changed or deleted | | 21 lines changed or added | |
|
| type_database.h | | type_database.h | |
| | | | |
| skipping to change at line 41 | | skipping to change at line 41 | |
| * | | * | |
| * Usage Example: | | * Usage Example: | |
| * | | * | |
| * // Contact the config. 'conn' has been obtained before. | | * // Contact the config. 'conn' has been obtained before. | |
| * DBClientBase* conn; | | * DBClientBase* conn; | |
| * BSONObj query = QUERY(DatabaseType::name("mydb")); | | * BSONObj query = QUERY(DatabaseType::name("mydb")); | |
| * dbDoc = conn->findOne(DatbaseType::ConfigNS, query); | | * dbDoc = conn->findOne(DatbaseType::ConfigNS, query); | |
| * | | * | |
| * // Process the response. | | * // Process the response. | |
| * DatabaseType db; | | * DatabaseType db; | |
|
| * db.fromBSON(dbDoc); | | * string errMsg; | |
| * if (! db.isValid()) { | | * if (!db.parseBSON(dbDoc, &errMsg) || !db.isValid(&errMsg)) { | |
| * // Can't use 'db'. Take action. | | * // Can't use 'db'. Take action. | |
| * } | | * } | |
| * // use 'db' | | * // use 'db' | |
| * | | * | |
| */ | | */ | |
| class DatabaseType { | | class DatabaseType { | |
| MONGO_DISALLOW_COPYING(DatabaseType); | | MONGO_DISALLOW_COPYING(DatabaseType); | |
| public: | | public: | |
| | | | |
| // | | // | |
| // schema declarations | | // schema declarations | |
| // | | // | |
| | | | |
| // Name of the database collection in the config server. | | // Name of the database collection in the config server. | |
| static const std::string ConfigNS; | | static const std::string ConfigNS; | |
| | | | |
| // Field names and types in the database collection type. | | // Field names and types in the database collection type. | |
|
| static BSONField<std::string> name; | | static BSONField<std::string> name; // database's name | |
| static BSONField<std::string> primary; | | static BSONField<std::string> primary; // primary shard for the da | |
| static BSONField<bool> scattered; | | tabase | |
| static BSONField<bool> draining; | | static BSONField<bool> draining; // is the database being re | |
| | | moved? | |
| | | | |
| // This field was last used in 2.2 series (version 3). | | // This field was last used in 2.2 series (version 3). | |
| static BSONField<bool> DEPRECATED_partitioned; | | static BSONField<bool> DEPRECATED_partitioned; | |
| | | | |
| // These fields were last used in 1.4 series (version 2). | | // These fields were last used in 1.4 series (version 2). | |
| static BSONField<std::string> DEPRECATED_name; | | static BSONField<std::string> DEPRECATED_name; | |
| static BSONField<bool> DEPRECATED_sharded; | | static BSONField<bool> DEPRECATED_sharded; | |
| | | | |
| // | | // | |
| // database type methods | | // database type methods | |
| | | | |
| skipping to change at line 92 | | skipping to change at line 91 | |
| */ | | */ | |
| bool isValid(std::string* errMsg) const; | | bool isValid(std::string* errMsg) const; | |
| | | | |
| /** | | /** | |
| * Returns the BSON representation of the entry. | | * Returns the BSON representation of the entry. | |
| */ | | */ | |
| BSONObj toBSON() const; | | BSONObj toBSON() const; | |
| | | | |
| /** | | /** | |
| * Clears and populates the internal state using the 'source' BSON
object if the | | * Clears and populates the internal state using the 'source' BSON
object if the | |
|
| * latter contains valid values. Otherwise clear the internal state
. | | * latter contains valid values. Otherwise sets errMsg and returns
false. | |
| */ | | */ | |
|
| void parseBSON(BSONObj source); | | bool parseBSON(BSONObj source, std::string* errMsg); | |
| | | | |
| /** | | /** | |
| * Clears the internal state. | | * Clears the internal state. | |
| */ | | */ | |
| void clear(); | | void clear(); | |
| | | | |
| /** | | /** | |
| * Copies all the fields present in 'this' to 'other'. | | * Copies all the fields present in 'this' to 'other'. | |
| */ | | */ | |
|
| void cloneTo(DatabaseType* other); | | void cloneTo(DatabaseType* other) const; | |
| | | | |
| /** | | /** | |
| * Returns a string representation of the current internal state. | | * Returns a string representation of the current internal state. | |
| */ | | */ | |
| std::string toString() const; | | std::string toString() const; | |
| | | | |
| // | | // | |
| // individual field accessors | | // individual field accessors | |
| // | | // | |
| | | | |
|
| void setName(const StringData& name) { _name = std::string(name.dat
a(), name.size()); } | | void setName(const StringData& name) { _name = name.toString(); } | |
| const std::string& getName() const { return _name; } | | const std::string& getName() const { return _name; } | |
| | | | |
|
| void setPrimary(const StringData& shard) {_primary=std::string(shar
d.data(), shard.size());} | | void setPrimary(const StringData& shard) { _primary = shard.toStrin
g(); } | |
| const std::string& getPrimary() const { return _primary; } | | const std::string& getPrimary() const { return _primary; } | |
| | | | |
|
| void setScattered(bool scattered) { _scattered = scattered; } | | void setDraining(bool draining) { _draining = draining; } | |
| bool getScattered() { return _scattered; } | | | |
| | | | |
| void setDrainig(bool draining) { _draining = draining; } | | | |
| bool getDraining() const { return _draining; } | | bool getDraining() const { return _draining; } | |
| | | | |
| private: | | private: | |
| // Convention: (M)andatory, (O)ptional, (S)pecial rule. | | // Convention: (M)andatory, (O)ptional, (S)pecial rule. | |
| string _name; // (M) database name | | string _name; // (M) database name | |
| string _primary; // (M) primary shard for the database | | string _primary; // (M) primary shard for the database | |
|
| bool _scattered; // (O) can db collections live outside the primar
y? | | | |
| bool _draining; // (O) is this database about to be deleted? | | bool _draining; // (O) is this database about to be deleted? | |
| }; | | }; | |
| | | | |
| } // namespace mongo | | } // namespace mongo | |
| | | | |
End of changes. 9 change blocks. |
| 16 lines changed or deleted | | 13 lines changed or added | |
|
| unordered_fast_key_table.h | | unordered_fast_key_table.h | |
| | | | |
| skipping to change at line 26 | | skipping to change at line 26 | |
| */ | | */ | |
| | | | |
| #pragma once | | #pragma once | |
| | | | |
| #include <boost/smart_ptr/scoped_array.hpp> | | #include <boost/smart_ptr/scoped_array.hpp> | |
| | | | |
| #include "mongo/base/disallow_copying.h" | | #include "mongo/base/disallow_copying.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
|
| | | template<typename K_L, typename K_S> | |
| | | struct UnorderedFastKeyTable_LS_C { | |
| | | K_S operator()( const K_L& a ) const { | |
| | | return K_S(a); | |
| | | } | |
| | | }; | |
| | | | |
| template< typename K_L, // key lookup | | template< typename K_L, // key lookup | |
| typename K_S, // key storage | | typename K_S, // key storage | |
| typename V, // value | | typename V, // value | |
| typename H , // hash of K_L | | typename H , // hash of K_L | |
| typename E, // equal of K_L | | typename E, // equal of K_L | |
|
| typename C // convertor from K_S -> K_L | | typename C, // convertor from K_S -> K_L | |
| | | typename C_LS=UnorderedFastKeyTable_LS_C<K_L,K_S> // converto | |
| | | r from K_L -> K_S | |
| > | | > | |
| class UnorderedFastKeyTable { | | class UnorderedFastKeyTable { | |
|
| MONGO_DISALLOW_COPYING(UnorderedFastKeyTable); | | | |
| public: | | public: | |
| typedef std::pair<K_S, V> value_type; | | typedef std::pair<K_S, V> value_type; | |
|
| | | typedef K_L key_type; | |
| typedef V mapped_type; | | typedef V mapped_type; | |
| | | | |
| private: | | private: | |
| struct Entry { | | struct Entry { | |
| Entry() | | Entry() | |
| : used( false ), everUsed( false ) { | | : used( false ), everUsed( false ) { | |
| } | | } | |
| | | | |
| bool used; | | bool used; | |
| bool everUsed; | | bool everUsed; | |
| size_t curHash; | | size_t curHash; | |
| value_type data; | | value_type data; | |
| }; | | }; | |
| | | | |
| struct Area { | | struct Area { | |
| Area( unsigned capacity, double maxProbeRatio ); | | Area( unsigned capacity, double maxProbeRatio ); | |
|
| | | Area( const Area& other ); | |
| | | | |
| int find( const K_L& key, size_t hash, int* firstEmpty, const U
norderedFastKeyTable& sm ) const; | | int find( const K_L& key, size_t hash, int* firstEmpty, const U
norderedFastKeyTable& sm ) const; | |
| | | | |
| void transfer( Area* newArea, const UnorderedFastKeyTable& sm )
const; | | void transfer( Area* newArea, const UnorderedFastKeyTable& sm )
const; | |
| | | | |
| void swap( Area* other ) { | | void swap( Area* other ) { | |
|
| std::swap( _capacity, other->_capacity ); | | using std::swap; | |
| std::swap( _maxProbe, other->_maxProbe ); | | swap( _capacity, other->_capacity ); | |
| _entries.swap( other->_entries ); | | swap( _maxProbe, other->_maxProbe ); | |
| | | swap( _entries, other->_entries ); | |
| } | | } | |
| | | | |
| unsigned _capacity; | | unsigned _capacity; | |
| unsigned _maxProbe; | | unsigned _maxProbe; | |
| boost::scoped_array<Entry> _entries; | | boost::scoped_array<Entry> _entries; | |
| }; | | }; | |
| | | | |
| public: | | public: | |
| static const unsigned DEFAULT_STARTING_CAPACITY = 20; | | static const unsigned DEFAULT_STARTING_CAPACITY = 20; | |
| | | | |
| /** | | /** | |
| * @param startingCapacity how many buckets should exist on initial
creation | | * @param startingCapacity how many buckets should exist on initial
creation | |
| * DEFAULT_STARTING_CAPACITY | | * DEFAULT_STARTING_CAPACITY | |
| * @param maxProbeRatio the percentage of buckets we're willing to
probe | | * @param maxProbeRatio the percentage of buckets we're willing to
probe | |
| * no defined default as you can't have a stat
ic const double on windows | | * no defined default as you can't have a stat
ic const double on windows | |
| */ | | */ | |
| UnorderedFastKeyTable( unsigned startingCapacity = DEFAULT_STARTING
_CAPACITY, | | UnorderedFastKeyTable( unsigned startingCapacity = DEFAULT_STARTING
_CAPACITY, | |
| double maxProbeRatio = 0.05 ); | | double maxProbeRatio = 0.05 ); | |
| | | | |
|
| | | UnorderedFastKeyTable( const UnorderedFastKeyTable& other ); | |
| | | | |
| | | UnorderedFastKeyTable& operator=( const UnorderedFastKeyTable& othe | |
| | | r ) { | |
| | | other.copyTo( this ); | |
| | | return *this; | |
| | | } | |
| | | | |
| | | void copyTo( UnorderedFastKeyTable* out ) const; | |
| | | | |
| /** | | /** | |
| * @return number of elements in map | | * @return number of elements in map | |
| */ | | */ | |
| size_t size() const { return _size; } | | size_t size() const { return _size; } | |
| | | | |
| bool empty() const { return _size == 0; } | | bool empty() const { return _size == 0; } | |
| | | | |
| /* | | /* | |
| * @return storage space | | * @return storage space | |
| */ | | */ | |
| size_t capacity() const { return _area._capacity; } | | size_t capacity() const { return _area._capacity; } | |
| | | | |
| V& operator[]( const K_L& key ) { return get( key ); } | | V& operator[]( const K_L& key ) { return get( key ); } | |
| | | | |
| V& get( const K_L& key ); | | V& get( const K_L& key ); | |
| | | | |
|
| | | /** | |
| | | * @return number of elements removed | |
| | | */ | |
| | | size_t erase( const K_L& key ); | |
| | | | |
| class const_iterator { | | class const_iterator { | |
| public: | | public: | |
|
| const_iterator() { _theEntry = NULL; } | | const_iterator() { _position = -1; } | |
| const_iterator( const Entry* entry ) { _theEntry = entry; } | | const_iterator( const Area* area ) { | |
| | | _area = area; | |
| | | _position = 0; | |
| | | _max = _area->_capacity - 1; | |
| | | _skip(); | |
| | | } | |
| | | const_iterator( const Area* area, int pos ) { | |
| | | _area = area; | |
| | | _position = pos; | |
| | | _max = pos; | |
| | | } | |
| | | | |
|
| const value_type* operator->() const { return &_theEntry->data;
} | | const value_type* operator->() const { return &_area->_entries[
_position].data; } | |
| | | | |
|
| const_iterator operator++( int n ) { _theEntry = NULL; return * | | const_iterator operator++() { | |
| this; } | | if ( _position < 0 ) | |
| | | return *this; | |
| | | _position++; | |
| | | if ( _position > _max ) | |
| | | _position = -1; | |
| | | else | |
| | | _skip(); | |
| | | return *this; | |
| | | } | |
| | | | |
| bool operator==( const const_iterator& other ) const { | | bool operator==( const const_iterator& other ) const { | |
|
| return _theEntry == other._theEntry; | | return _position == other._position; | |
| } | | } | |
| bool operator!=( const const_iterator& other ) const { | | bool operator!=( const const_iterator& other ) const { | |
|
| return _theEntry != other._theEntry; | | return _position != other._position; | |
| } | | } | |
| | | | |
| private: | | private: | |
|
| const Entry* _theEntry; | | | |
| | | void _skip() { | |
| | | while ( true ) { | |
| | | if ( _area->_entries[_position].used ) | |
| | | break; | |
| | | if ( _position >= _max ) { | |
| | | _position = -1; | |
| | | break; | |
| | | } | |
| | | ++_position; | |
| | | } | |
| | | } | |
| | | | |
| | | const Area* _area; | |
| | | int _position; | |
| | | int _max; // inclusive | |
| }; | | }; | |
| | | | |
|
| | | /** | |
| | | * @return either a one-shot iterator with the key, or end() | |
| | | */ | |
| const_iterator find( const K_L& key ) const; | | const_iterator find( const K_L& key ) const; | |
| | | | |
|
| | | const_iterator begin() const; | |
| | | | |
| const_iterator end() const; | | const_iterator end() const; | |
| | | | |
| private: | | private: | |
| /* | | /* | |
| * @param firstEmpty, if we return -1, and firstEmpty != NULL, | | * @param firstEmpty, if we return -1, and firstEmpty != NULL, | |
| * this will be set to the first empty bucket we
found | | * this will be set to the first empty bucket we
found | |
| * @retrun offset into _entries or -1 if not there | | * @retrun offset into _entries or -1 if not there | |
| */ | | */ | |
| int _find( const K_L& key, int hash, int* firstEmpty ) const; | | int _find( const K_L& key, int hash, int* firstEmpty ) const; | |
| | | | |
| void _grow(); | | void _grow(); | |
| | | | |
| // ---- | | // ---- | |
| | | | |
| size_t _size; | | size_t _size; | |
|
| const double _maxProbeRatio; | | double _maxProbeRatio; | |
| Area _area; | | Area _area; | |
| | | | |
| H _hash; | | H _hash; | |
| E _equals; | | E _equals; | |
| C _convertor; | | C _convertor; | |
|
| | | C_LS _convertorOther; | |
| }; | | }; | |
| | | | |
| } | | } | |
| | | | |
| #include "mongo/util/unordered_fast_key_table_internal.h" | | #include "mongo/util/unordered_fast_key_table_internal.h" | |
| | | | |
End of changes. 18 change blocks. |
| 14 lines changed or deleted | | 79 lines changed or added | |
|
| unordered_fast_key_table_internal.h | | unordered_fast_key_table_internal.h | |
| | | | |
| skipping to change at line 18 | | skipping to change at line 18 | |
| * | | * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | | * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | | * | |
| * 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. | |
| */ | | */ | |
| | | | |
|
| | | #include "mongo/util/assert_util.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
|
| template< typename K_L, typename K_S, typename V, typename H, typename | | template< typename K_L, typename K_S, typename V, typename H, typename | |
| E, typename C > | | E, typename C, typename C_LS > | |
| inline UnorderedFastKeyTable<K_L, K_S, V, H, E, C>::Area::Area(unsigned | | inline UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::Area::Area(un | |
| capacity, | | signed capacity, | |
| double m
axProbeRatio) | | double m
axProbeRatio) | |
| : _capacity( capacity ), | | : _capacity( capacity ), | |
| _maxProbe( static_cast<unsigned>( capacity * maxProbeRatio ) ), | | _maxProbe( static_cast<unsigned>( capacity * maxProbeRatio ) ), | |
| _entries( new Entry[_capacity] ) { | | _entries( new Entry[_capacity] ) { | |
| } | | } | |
| | | | |
|
| template< typename K_L, typename K_S, typename V, typename H, typename | | template< typename K_L, typename K_S, typename V, typename H, typename | |
| E, typename C > | | E, typename C, typename C_LS > | |
| inline int UnorderedFastKeyTable<K_L, K_S, V, H, E, C>::Area::find( | | inline UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::Area::Area(co | |
| | | nst Area& other ) | |
| | | : _capacity( other._capacity ), | |
| | | _maxProbe( other._maxProbe ), | |
| | | _entries( new Entry[_capacity] ) { | |
| | | for ( unsigned i = 0; i < _capacity; i++ ) { | |
| | | _entries[i] = other._entries[i]; | |
| | | } | |
| | | } | |
| | | | |
| | | template< typename K_L, typename K_S, typename V, typename H, typename | |
| | | E, typename C, typename C_LS > | |
| | | inline int UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::Area::fin | |
| | | d( | |
| const K_L& key, | | const K_L& key, | |
| size_t hash, | | size_t hash, | |
| int* firstEmpty, | | int* firstEmpty, | |
| const UnorderedFastKeyTable& sm ) const { | | const UnorderedFastKeyTable& sm ) const { | |
| if ( firstEmpty ) | | if ( firstEmpty ) | |
| *firstEmpty = -1; | | *firstEmpty = -1; | |
| | | | |
| for ( unsigned probe = 0; probe < _maxProbe; probe++ ) { | | for ( unsigned probe = 0; probe < _maxProbe; probe++ ) { | |
| unsigned pos = (hash + probe) % _capacity; | | unsigned pos = (hash + probe) % _capacity; | |
| | | | |
| | | | |
| skipping to change at line 66 | | skipping to change at line 78 | |
| continue; | | continue; | |
| } | | } | |
| | | | |
| // hashes and strings are equal | | // hashes and strings are equal | |
| // yay! | | // yay! | |
| return pos; | | return pos; | |
| } | | } | |
| return -1; | | return -1; | |
| } | | } | |
| | | | |
|
| template< typename K_L, typename K_S, typename V, typename H, typename | | template< typename K_L, typename K_S, typename V, typename H, typename | |
| E, typename C > | | E, typename C, typename C_LS > | |
| inline void UnorderedFastKeyTable<K_L, K_S, V, H, E, C>::Area::transfer | | inline void UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::Area::tr | |
| ( | | ansfer( | |
| Area* newArea, | | Area* newArea, | |
| const UnorderedFastKeyTable& sm) const { | | const UnorderedFastKeyTable& sm) const { | |
| for ( unsigned i = 0; i < _capacity; i++ ) { | | for ( unsigned i = 0; i < _capacity; i++ ) { | |
| if ( ! _entries[i].used ) | | if ( ! _entries[i].used ) | |
| continue; | | continue; | |
| | | | |
| int firstEmpty = -1; | | int firstEmpty = -1; | |
| int loc = newArea->find( sm._convertor( _entries[i].data.first
), | | int loc = newArea->find( sm._convertor( _entries[i].data.first
), | |
| _entries[i].curHash, | | _entries[i].curHash, | |
| &firstEmpty, | | &firstEmpty, | |
| sm ); | | sm ); | |
| | | | |
| verify( loc == -1 ); | | verify( loc == -1 ); | |
| verify( firstEmpty >= 0 ); | | verify( firstEmpty >= 0 ); | |
| | | | |
| newArea->_entries[firstEmpty] = _entries[i]; | | newArea->_entries[firstEmpty] = _entries[i]; | |
| } | | } | |
| } | | } | |
| | | | |
|
| template< typename K_L, typename K_S, typename V, typename H, typename | | template< typename K_L, typename K_S, typename V, typename H, typename | |
| E, typename C > | | E, typename C, typename C_LS > | |
| inline UnorderedFastKeyTable<K_L, K_S, V, H, E, C>::UnorderedFastKeyTab | | inline UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::UnorderedFast | |
| le( | | KeyTable( | |
| unsigned startingCapacity, | | unsigned startingCapacity, | |
| double maxProbeRatio) | | double maxProbeRatio) | |
| : _maxProbeRatio( maxProbeRatio ), _area( startingCapacity, maxProb
eRatio ) { | | : _maxProbeRatio( maxProbeRatio ), _area( startingCapacity, maxProb
eRatio ) { | |
| _size = 0; | | _size = 0; | |
| } | | } | |
| | | | |
|
| template< typename K_L, typename K_S, typename V, typename H, typename | | template< typename K_L, typename K_S, typename V, typename H, typename | |
| E, typename C > | | E, typename C, typename C_LS > | |
| inline V& UnorderedFastKeyTable<K_L, K_S, V, H, E, C>::get( const K_L& | | inline UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::UnorderedFast | |
| key ) { | | KeyTable( | |
| | | const UnorderedFastKeyTable& other ) | |
| | | : _size( other._size ), | |
| | | _maxProbeRatio( other._maxProbeRatio ), | |
| | | _area( other._area ), | |
| | | _hash( other._hash ), | |
| | | _equals( other._equals ), | |
| | | _convertor( other._convertor ), | |
| | | _convertorOther( other._convertorOther ) { | |
| | | } | |
| | | | |
| | | template< typename K_L, typename K_S, typename V, typename H, typename | |
| | | E, typename C, typename C_LS > | |
| | | inline void UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::copyTo( | |
| | | UnorderedFastKeyTable* out ) const { | |
| | | out->_size = _size; | |
| | | out->_maxProbeRatio = _maxProbeRatio; | |
| | | Area x( _area ); | |
| | | out->_area.swap( &x ); | |
| | | } | |
| | | | |
| | | template< typename K_L, typename K_S, typename V, typename H, typename | |
| | | E, typename C, typename C_LS > | |
| | | inline V& UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::get( const | |
| | | K_L& key ) { | |
| | | | |
| const size_t hash = _hash( key ); | | const size_t hash = _hash( key ); | |
| | | | |
| for ( int numGrowTries = 0; numGrowTries < 10; numGrowTries++ ) { | | for ( int numGrowTries = 0; numGrowTries < 10; numGrowTries++ ) { | |
| int firstEmpty = -1; | | int firstEmpty = -1; | |
| int pos = _area.find( key, hash, &firstEmpty, *this ); | | int pos = _area.find( key, hash, &firstEmpty, *this ); | |
| if ( pos >= 0 ) | | if ( pos >= 0 ) | |
| return _area._entries[pos].data.second; | | return _area._entries[pos].data.second; | |
| | | | |
| // key not in map | | // key not in map | |
| // need to add | | // need to add | |
| if ( firstEmpty >= 0 ) { | | if ( firstEmpty >= 0 ) { | |
| _size++; | | _size++; | |
| _area._entries[firstEmpty].used = true; | | _area._entries[firstEmpty].used = true; | |
| _area._entries[firstEmpty].everUsed = true; | | _area._entries[firstEmpty].everUsed = true; | |
| _area._entries[firstEmpty].curHash = hash; | | _area._entries[firstEmpty].curHash = hash; | |
|
| _area._entries[firstEmpty].data.first = key; | | _area._entries[firstEmpty].data.first = _convertorOther(key
); | |
| return _area._entries[firstEmpty].data.second; | | return _area._entries[firstEmpty].data.second; | |
| } | | } | |
| | | | |
| // no space left in map | | // no space left in map | |
| _grow(); | | _grow(); | |
| } | | } | |
| msgasserted( 16471, "UnorderedFastKeyTable couldn't add entry after
growing many times" ); | | msgasserted( 16471, "UnorderedFastKeyTable couldn't add entry after
growing many times" ); | |
| } | | } | |
| | | | |
|
| template< typename K_L, typename K_S, typename V, typename H, typename | | template< typename K_L, typename K_S, typename V, typename H, typename | |
| E, typename C > | | E, typename C, typename C_LS > | |
| inline void UnorderedFastKeyTable<K_L, K_S, V, H, E, C>::_grow() { | | inline size_t UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::erase( | |
| | | const K_L& key ) { | |
| | | | |
| | | const size_t hash = _hash( key ); | |
| | | int pos = _area.find( key, hash, NULL, *this ); | |
| | | | |
| | | if ( pos < 0 ) | |
| | | return 0; | |
| | | | |
| | | _area._entries[pos].used = false; | |
| | | _area._entries[pos].data.second = V(); | |
| | | return 1; | |
| | | } | |
| | | | |
| | | template< typename K_L, typename K_S, typename V, typename H, typename | |
| | | E, typename C, typename C_LS > | |
| | | inline void UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::_grow() | |
| | | { | |
| Area newArea( _area._capacity * 2, _maxProbeRatio ); | | Area newArea( _area._capacity * 2, _maxProbeRatio ); | |
| _area.transfer( &newArea, *this ); | | _area.transfer( &newArea, *this ); | |
| _area.swap( &newArea ); | | _area.swap( &newArea ); | |
| } | | } | |
| | | | |
|
| | | template< typename K_L, typename K_S, typename V, typename H, typename | |
| | | E, typename C, typename C_LS > | |
| | | inline typename UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::cons | |
| | | t_iterator | |
| | | UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::find( const K_L& key | |
| | | ) const { | |
| | | if ( _size == 0 ) | |
| | | return const_iterator(); | |
| | | int pos = _area.find( key, _hash(key), 0, *this ); | |
| | | if ( pos < 0 ) | |
| | | return const_iterator(); | |
| | | return const_iterator( &_area, pos ); | |
| | | } | |
| | | | |
| | | template< typename K_L, typename K_S, typename V, typename H, typename | |
| | | E, typename C, typename C_LS > | |
| | | inline typename UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::cons | |
| | | t_iterator | |
| | | UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::end() const { | |
| | | return const_iterator(); | |
| | | } | |
| | | | |
| | | template< typename K_L, typename K_S, typename V, typename H, typename | |
| | | E, typename C, typename C_LS > | |
| | | inline typename UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::cons | |
| | | t_iterator | |
| | | UnorderedFastKeyTable<K_L, K_S, V, H, E, C, C_LS>::begin() const { | |
| | | return const_iterator( &_area ); | |
| | | } | |
| } | | } | |
| | | | |
End of changes. 9 change blocks. |
| 23 lines changed or deleted | | 108 lines changed or added | |
|
| update_internal.h | | update_internal.h | |
| | | | |
| skipping to change at line 33 | | skipping to change at line 33 | |
| #include "mongo/db/jsobjmanipulator.h" | | #include "mongo/db/jsobjmanipulator.h" | |
| #include "mongo/db/matcher.h" | | #include "mongo/db/matcher.h" | |
| #include "mongo/util/embedded_builder.h" | | #include "mongo/util/embedded_builder.h" | |
| #include "mongo/util/stringutils.h" | | #include "mongo/util/stringutils.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| | | | |
| class ModState; | | class ModState; | |
| class ModSetState; | | class ModSetState; | |
| | | | |
|
| | | /** | |
| | | * a.$ -> a | |
| | | * @return true if out is set and we made a change | |
| | | */ | |
| | | bool getCanonicalIndexField( const StringData& fullName, string* out ); | |
| | | | |
| /* Used for modifiers such as $inc, $set, $push, ... | | /* Used for modifiers such as $inc, $set, $push, ... | |
| * stores the info about a single operation | | * stores the info about a single operation | |
| * once created should never be modified | | * 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 11 12 13 | | 9 10 11 12 13 14 | |
| 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 , ADDTOSET, RENAME_FROM, RENAME_TO } op; | | TAND, BITOR , BIT , ADDTOSET, RENAME_FROM, RENAME_TO, SET_ON_INSERT } 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; | |
| | | | |
| // Determines if this mod must absoluetly be applied. In some repli
cation scenarios, a | | // Determines if this mod must absoluetly be applied. In some repli
cation scenarios, a | |
| // failed apply of a mod does not constitute an error. In those cas
es, setting strict | | // failed apply of a mod does not constitute an error. In those cas
es, setting strict | |
| // to off would not throw errors. | | // to off would not throw errors. | |
| | | | |
| skipping to change at line 146 | | skipping to change at line 152 | |
| static bool isIndexed( const string& fullName , const set<string>&
idxKeys ) { | | static bool isIndexed( const string& fullName , const set<string>&
idxKeys ) { | |
| const char * fieldName = fullName.c_str(); | | const char * fieldName = fullName.c_str(); | |
| // check if there is an index key that is a parent of mod | | // check if there is an index key that is a parent of mod | |
| for( const char* dot = strchr( fieldName, '.' ); dot; dot = str
chr( dot + 1, '.' ) ) | | for( const char* dot = strchr( fieldName, '.' ); dot; dot = str
chr( dot + 1, '.' ) ) | |
| if ( idxKeys.count( string( fieldName, dot - fieldName ) )
) | | if ( idxKeys.count( string( fieldName, dot - fieldName ) )
) | |
| return true; | | return true; | |
| | | | |
| // 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; | |
| } | | } | |
| | | | |
|
| | | /** | |
| | | * checks if mod is in the index by inspecting fieldName, and remov | |
| | | ing | |
| | | * .$ or .### substrings (#=digit) with any number of digits. | |
| | | * | |
| | | * @return true iff the mod is indexed | |
| | | */ | |
| bool isIndexed( const set<string>& idxKeys ) const { | | bool isIndexed( const set<string>& idxKeys ) const { | |
|
| string fullName = fieldName; | | | |
| | | | |
|
| if ( isIndexed( fullName , idxKeys ) ) | | // first, check if full name is in idxKeys | |
| | | if ( isIndexed( fieldName , idxKeys ) ) | |
| return true; | | return true; | |
| | | | |
|
| if ( strstr( fieldName , "." ) ) { | | string x; | |
| // check for a.0.1 | | if ( getCanonicalIndexField( fieldName, &x ) ) { | |
| StringBuilder buf; | | if ( isIndexed( x, idxKeys ) ) | |
| for ( size_t i=0; i<fullName.size(); i++ ) { | | | |
| char c = fullName[i]; | | | |
| | | | |
| if ( c == '$' && | | | |
| i > 0 && fullName[i-1] == '.' && | | | |
| i+1<fullName.size() && | | | |
| fullName[i+1] == '.' ) { | | | |
| i++; | | | |
| continue; | | | |
| } | | | |
| | | | |
| buf << c; | | | |
| | | | |
| if ( c != '.' ) | | | |
| continue; | | | |
| | | | |
| if ( ! isdigit( fullName[i+1] ) ) | | | |
| continue; | | | |
| | | | |
| bool possible = true; | | | |
| size_t j=i+2; | | | |
| for ( ; j<fullName.size(); j++ ) { | | | |
| char d = fullName[j]; | | | |
| if ( d == '.' ) | | | |
| break; | | | |
| if ( isdigit( d ) ) | | | |
| continue; | | | |
| possible = false; | | | |
| break; | | | |
| } | | | |
| | | | |
| if ( possible ) | | | |
| i = j; | | | |
| } | | | |
| string x = buf.str(); | | | |
| if ( isIndexed( x , idxKeys ) ) | | | |
| return true; | | return true; | |
| } | | } | |
| | | | |
| return false; | | return false; | |
| } | | } | |
| | | | |
| void apply( BSONBuilderBase& b , BSONElement in , ModState& ms ) co
nst; | | void apply( BSONBuilderBase& b , BSONElement in , ModState& ms ) co
nst; | |
| | | | |
| /** | | /** | |
| * @return true iff toMatch should be removed from the array | | * @return true iff toMatch should be removed from the array | |
| | | | |
| skipping to change at line 242 | | skipping to change at line 219 | |
| return elt.embeddedObjectUserCheck().firstElement().embeddedObj
ectUserCheck(); | | return elt.embeddedObjectUserCheck().firstElement().embeddedObj
ectUserCheck(); | |
| } | | } | |
| | | | |
| void parseEach( BSONElementSet& s ) const { | | void parseEach( BSONElementSet& s ) const { | |
| BSONObjIterator i(getEach()); | | BSONObjIterator i(getEach()); | |
| while ( i.more() ) { | | while ( i.more() ) { | |
| s.insert( i.next() ); | | s.insert( i.next() ); | |
| } | | } | |
| } | | } | |
| | | | |
|
| | | bool isSliceOnly() const { | |
| | | if ( elt.type() != Object ) | |
| | | return false; | |
| | | BSONObj obj = elt.embeddedObject(); | |
| | | if ( obj.nFields() != 2 ) | |
| | | return false; | |
| | | BSONObjIterator i( obj ); | |
| | | i.next(); | |
| | | BSONElement elemSlice = i.next(); | |
| | | return strcmp( elemSlice.fieldName(), "$slice" ) == 0; | |
| | | } | |
| | | | |
| | | long long getSlice() const { | |
| | | // The $slice may be the second or the third elemen in the fiel | |
| | | d object. | |
| | | // { <field name>: { $each: [<each array>], $slice: -N, $sort: | |
| | | <pattern> } } | |
| | | // 'elt' here is the BSONElement above. | |
| | | BSONObj obj = elt.embeddedObject(); | |
| | | BSONObjIterator i( obj ); | |
| | | i.next(); | |
| | | BSONElement elem = i.next(); | |
| | | if ( ! str::equals( elem.fieldName(), "$slice" ) ) { | |
| | | elem = i.next(); | |
| | | } | |
| | | dassert( elem.isNumber() ); | |
| | | | |
| | | // For now, we're only supporting slicing from the back of the | |
| | | array, i.e. | |
| | | // negative slice. But the code now is wired in the opposite wa | |
| | | y: trimming from the | |
| | | // back of the array is positive. | |
| | | // TODO: fix this. | |
| | | return -elem.numberLong(); | |
| | | } | |
| | | | |
| | | bool isSliceAndSort() const { | |
| | | if ( elt.type() != Object ) | |
| | | return false; | |
| | | BSONObj obj = elt.embeddedObject(); | |
| | | if ( obj.nFields() != 3 ) | |
| | | return false; | |
| | | BSONObjIterator i( obj ); | |
| | | i.next(); | |
| | | | |
| | | // Slice and sort may be switched. | |
| | | bool seenSlice = false; | |
| | | bool seenSort = false; | |
| | | while ( i.more() ) { | |
| | | BSONElement elem = i.next(); | |
| | | if ( str::equals( elem.fieldName(), "$slice" ) ) { | |
| | | if ( seenSlice ) return false; | |
| | | seenSlice = true; | |
| | | } | |
| | | else if ( str::equals( elem.fieldName(), "$sort" ) ) { | |
| | | if ( seenSort ) return false; | |
| | | seenSort = true; | |
| | | if ( elem.type() != Object ) return false; | |
| | | } | |
| | | else { | |
| | | return false; | |
| | | } | |
| | | } | |
| | | | |
| | | // If present, the $sort element would have been checked during | |
| | | ModSet construction. | |
| | | return seenSlice && seenSort; | |
| | | } | |
| | | | |
| | | BSONObj getSort() const { | |
| | | // The $sort may be the second or the third element in the fiel | |
| | | d object. | |
| | | // { <field name>: { $each: [<each array>], $slice: -N, $sort: | |
| | | <pattern> } } | |
| | | // 'elt' here is the BSONElement above. | |
| | | BSONObj obj = elt.embeddedObject(); | |
| | | BSONObjIterator i( obj ); | |
| | | i.next(); | |
| | | BSONElement elem = i.next(); | |
| | | if ( ! str::equals( elem.fieldName(), "$sort" ) ) { | |
| | | elem = i.next(); | |
| | | } | |
| | | return elem.embeddedObject(); | |
| | | } | |
| | | | |
| const char* renameFrom() const { | | const char* renameFrom() const { | |
| massert( 13492, "mod must be RENAME_TO type", op == Mod::RENAME
_TO ); | | massert( 13492, "mod must be RENAME_TO type", op == Mod::RENAME
_TO ); | |
| return elt.fieldName(); | | return elt.fieldName(); | |
| } | | } | |
| }; | | }; | |
| | | | |
| /** | | /** | |
| * stores a set of Mods | | * stores a set of Mods | |
| * once created, should never be changed | | * once created, should never be changed | |
| */ | | */ | |
| | | | |
| skipping to change at line 267 | | skipping to change at line 322 | |
| | | | |
| static Mod::Op opFromStr( const char* fn ) { | | static Mod::Op opFromStr( const char* fn ) { | |
| verify( fn[0] == '$' ); | | verify( fn[0] == '$' ); | |
| switch( fn[1] ) { | | switch( fn[1] ) { | |
| case 'i': { | | case 'i': { | |
| if ( fn[2] == 'n' && fn[3] == 'c' && fn[4] == 0 ) | | if ( fn[2] == 'n' && fn[3] == 'c' && fn[4] == 0 ) | |
| return Mod::INC; | | return Mod::INC; | |
| break; | | break; | |
| } | | } | |
| case 's': { | | case 's': { | |
|
| if ( fn[2] == 'e' && fn[3] == 't' && fn[4] == 0 ) | | if ( fn[2] == 'e' && fn[3] == 't' ) { | |
| return Mod::SET; | | if ( fn[4] == 0 ) { | |
| | | return Mod::SET; | |
| | | } | |
| | | else if ( fn[4] == 'O' && fn[5] == 'n' && fn[6] == 'I' | |
| | | && fn[7] == 'n' && | |
| | | fn[8] == 's' && fn[9] == 'e' && fn[10] == 'r' | |
| | | && fn[11] == 't' && | |
| | | fn[12] == 0 ) { | |
| | | return Mod::SET_ON_INSERT; | |
| | | } | |
| | | } | |
| break; | | break; | |
| } | | } | |
| case 'p': { | | case 'p': { | |
| if ( fn[2] == 'u' ) { | | if ( fn[2] == 'u' ) { | |
| if ( fn[3] == 's' && fn[4] == 'h' ) { | | if ( fn[3] == 's' && fn[4] == 'h' ) { | |
| if ( fn[5] == 0 ) | | if ( fn[5] == 0 ) | |
| return Mod::PUSH; | | return Mod::PUSH; | |
| if ( fn[5] == 'A' && fn[6] == 'l' && fn[7] == 'l' &
& fn[8] == 0 ) | | if ( fn[5] == 'A' && fn[6] == 'l' && fn[7] == 'l' &
& fn[8] == 0 ) | |
| return Mod::PUSH_ALL; | | return Mod::PUSH_ALL; | |
| } | | } | |
| | | | |
| skipping to change at line 396 | | skipping to change at line 459 | |
| case RIGHT_BEFORE: return false; | | case RIGHT_BEFORE: return false; | |
| case RIGHT_SUBFIELD: return true; | | case RIGHT_SUBFIELD: return true; | |
| } | | } | |
| } | | } | |
| return false; | | return false; | |
| } | | } | |
| | | | |
| }; | | }; | |
| | | | |
| /** | | /** | |
|
| | | * Comparator between two BSONObjects that takes in consideration only | |
| | | the keys and | |
| | | * direction described in the sort pattern. | |
| | | */ | |
| | | struct ProjectKeyCmp { | |
| | | BSONObj sortPattern; | |
| | | BSONObj projectionPattern; | |
| | | | |
| | | ProjectKeyCmp( BSONObj pattern ) : sortPattern( pattern ) { | |
| | | BSONObjBuilder projectBuilder; | |
| | | BSONObjIterator i( sortPattern ); | |
| | | while ( i.more() ) { | |
| | | BSONElement elem = i.next(); | |
| | | uassert( 16645, "sort pattern must be numeric", elem.isNumb | |
| | | er() ); | |
| | | | |
| | | double val = elem.Number(); | |
| | | uassert( 16646, "sort pattern must contain 1 or -1", val*va | |
| | | l == 1.0); | |
| | | | |
| | | // | |
| | | // If there are dots in the field name, check that they for | |
| | | m a proper | |
| | | // field path (e.g., no empty field parts). | |
| | | // | |
| | | | |
| | | StringData field( elem.fieldName() ); | |
| | | uassert( 16651, "sort pattern field name cannot be empty" , | |
| | | field.size() ); | |
| | | | |
| | | size_t pos = field.find('.'); | |
| | | while ( pos != string::npos ) { | |
| | | | |
| | | uassert( 16639, | |
| | | "empty field in dotted sort pattern", | |
| | | (pos > 0) && (pos != field.size() - 1) ); | |
| | | | |
| | | field = field.substr( pos+1 ); | |
| | | pos = field.find('.'); | |
| | | } | |
| | | | |
| | | projectBuilder.append( elem.fieldName(), 1 ); | |
| | | | |
| | | } | |
| | | projectionPattern = projectBuilder.obj(); | |
| | | } | |
| | | | |
| | | int operator()( const BSONObj& left, const BSONObj& right ) { | |
| | | BSONObj keyLeft = left.extractFields( projectionPattern, true ) | |
| | | ; | |
| | | BSONObj keyRight = right.extractFields( projectionPattern, true | |
| | | ); | |
| | | return keyLeft.woCompare( keyRight, sortPattern ) < 0; | |
| | | } | |
| | | }; | |
| | | | |
| | | /** | |
| * stores any information about a single Mod operating on a single Obje
ct | | * stores any information about a single Mod operating on a single Obje
ct | |
| */ | | */ | |
| class ModState : boost::noncopyable { | | class ModState : boost::noncopyable { | |
| public: | | public: | |
| const Mod* m; | | const Mod* m; | |
| BSONElement old; | | BSONElement old; | |
| BSONElement newVal; | | BSONElement newVal; | |
| BSONObj _objData; | | BSONObj _objData; | |
| | | | |
| const char* fixedOpName; | | const char* fixedOpName; | |
| | | | |
| skipping to change at line 535 | | skipping to change at line 648 | |
| | | | |
| //const Mod& m = *(ms.m); // HACK | | //const Mod& m = *(ms.m); // HACK | |
| Mod& m = *((Mod*)(ms.m)); // HACK | | Mod& m = *((Mod*)(ms.m)); // HACK | |
| | | | |
| switch ( m.op ) { | | switch ( m.op ) { | |
| | | | |
| case Mod::PUSH: { | | case Mod::PUSH: { | |
| ms.fixedOpName = "$set"; | | ms.fixedOpName = "$set"; | |
| if ( m.isEach() ) { | | if ( m.isEach() ) { | |
| BSONObj arr = m.getEach(); | | BSONObj arr = m.getEach(); | |
|
| b.appendArray( m.shortFieldName, arr ); | | if ( !m.isSliceOnly() && !m.isSliceAndSort() ) { | |
| ms.forceEmptyArray = true; | | b.appendArray( m.shortFieldName, arr ); | |
| ms.fixedArray = BSONArray(arr.getOwned()); | | | |
| } else { | | ms.forceEmptyArray = true; | |
| | | ms.fixedArray = BSONArray( arr.getOwned() ); | |
| | | } | |
| | | else if ( m.isSliceOnly() && ( m.getSlice() >= arr.nFie | |
| | | lds() ) ) { | |
| | | b.appendArray( m.shortFieldName, arr ); | |
| | | | |
| | | ms.forceEmptyArray = true; | |
| | | ms.fixedArray = BSONArray( arr.getOwned() ); | |
| | | } | |
| | | else if ( m.isSliceOnly() ) { | |
| | | BSONArrayBuilder arrBuilder( b.subarrayStart( m.sho | |
| | | rtFieldName ) ); | |
| | | long long skip = arr.nFields() - m.getSlice(); | |
| | | BSONObjIterator j( arr ); | |
| | | while ( j.more() ) { | |
| | | if ( skip-- > 0 ) { | |
| | | j.next(); | |
| | | continue; | |
| | | } | |
| | | arrBuilder.append( j.next() ); | |
| | | } | |
| | | | |
| | | ms.forceEmptyArray = true; | |
| | | ms.fixedArray = BSONArray( arrBuilder.done().getOwn | |
| | | ed() ); | |
| | | } | |
| | | else if ( m.isSliceAndSort() ) { | |
| | | long long slice = m.getSlice(); | |
| | | BSONObj sortPattern = m.getSort(); | |
| | | | |
| | | // Sort the $each array over sortPattern. | |
| | | vector<BSONObj> workArea; | |
| | | BSONObjIterator j( arr ); | |
| | | while ( j.more() ) { | |
| | | workArea.push_back( j.next().Obj() ); | |
| | | } | |
| | | sort( workArea.begin(), workArea.end(), ProjectKeyC | |
| | | mp( sortPattern) ); | |
| | | | |
| | | // Slice to the appropriate size. If slice is zero, | |
| | | that's equivalent | |
| | | // to resetting the array, ie, a no-op. | |
| | | BSONArrayBuilder arrBuilder( b.subarrayStart( m.sho | |
| | | rtFieldName ) ); | |
| | | if (slice > 0) { | |
| | | long long skip = std::max( 0LL, | |
| | | (long long)workArea. | |
| | | size() - slice ); | |
| | | for (vector<BSONObj>::iterator it = workArea.be | |
| | | gin(); | |
| | | it != workArea.end(); | |
| | | ++it ) { | |
| | | if ( skip-- > 0 ) { | |
| | | continue; | |
| | | } | |
| | | arrBuilder.append( *it ); | |
| | | } | |
| | | } | |
| | | | |
| | | // Log the full resulting array. | |
| | | ms.forceEmptyArray = true; | |
| | | ms.fixedArray = BSONArray( arrBuilder.done().getOwn | |
| | | ed() ); | |
| | | } | |
| | | } | |
| | | else { | |
| BSONObjBuilder arr( b.subarrayStart( m.shortFieldName )
); | | BSONObjBuilder arr( b.subarrayStart( m.shortFieldName )
); | |
| arr.appendAs( m.elt, "0" ); | | arr.appendAs( m.elt, "0" ); | |
|
| | | | |
| ms.forceEmptyArray = true; | | ms.forceEmptyArray = true; | |
| ms.fixedArray = BSONArray(arr.done().getOwned()); | | ms.fixedArray = BSONArray(arr.done().getOwned()); | |
| } | | } | |
| break; | | break; | |
| } | | } | |
| | | | |
| case Mod::ADDTOSET: { | | case Mod::ADDTOSET: { | |
| ms.fixedOpName = "$set"; | | ms.fixedOpName = "$set"; | |
| if ( m.isEach() ) { | | if ( m.isEach() ) { | |
| // Remove any duplicates in given array | | // Remove any duplicates in given array | |
| | | | |
| skipping to change at line 593 | | skipping to change at line 764 | |
| case Mod::POP: | | case Mod::POP: | |
| case Mod::PULL: | | case Mod::PULL: | |
| case Mod::PULL_ALL: | | case Mod::PULL_ALL: | |
| case Mod::UNSET: | | case Mod::UNSET: | |
| // No-op b/c unset/pull of nothing does nothing. Still, exp
licilty log that | | // No-op b/c unset/pull of nothing does nothing. Still, exp
licilty log that | |
| // the target array was reset. | | // the target array was reset. | |
| ms.fixedOpName = "$unset"; | | ms.fixedOpName = "$unset"; | |
| break; | | break; | |
| | | | |
| case Mod::INC: | | case Mod::INC: | |
|
| | | case Mod::SET_ON_INSERT: | |
| ms.fixedOpName = "$set"; | | ms.fixedOpName = "$set"; | |
| case Mod::SET: { | | case Mod::SET: { | |
| m._checkForAppending( m.elt ); | | m._checkForAppending( m.elt ); | |
| b.appendAs( m.elt, m.shortFieldName ); | | b.appendAs( m.elt, m.shortFieldName ); | |
| break; | | break; | |
| } | | } | |
| | | | |
| // shouldn't see RENAME_FROM here | | // shouldn't see RENAME_FROM here | |
| case Mod::RENAME_TO: | | case Mod::RENAME_TO: | |
| ms.handleRename( b, m.shortFieldName ); | | ms.handleRename( b, m.shortFieldName ); | |
| | | | |
End of changes. 13 change blocks. |
| 51 lines changed or deleted | | 249 lines changed or added | |
|
| v8_db.h | | v8_db.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 <boost/function.hpp> | | #include <boost/function.hpp> | |
|
| #include <cstdio> | | | |
| #include <cstdlib> | | | |
| #include <cstring> | | | |
| #include <v8.h> | | #include <v8.h> | |
| | | | |
| #include "mongo/scripting/engine_v8.h" | | #include "mongo/scripting/engine_v8.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
|
| class DBClientBase; | | | |
| // These functions may depend on the caller creating a handle scope and | | | |
| context scope. | | | |
| | | | |
| v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate( V8Scope * sc | | | |
| ope, bool local ); | | | |
| // void installDBTypes( V8Scope * scope, v8::Handle<v8::ObjectTemplate>& | | | |
| global ); | | | |
| void installDBTypes( V8Scope * scope, v8::Handle<v8::Object>& global ); | | | |
| | | | |
|
| // the actual globals | | class DBClientBase; | |
| | | | |
|
| mongo::DBClientBase * getConnection( const v8::Arguments& args ); | | /** | |
| | | * install the db related functions and objects in the given scope | |
| | | */ | |
| | | void installDBTypes(V8Scope* scope, v8::Handle<v8::Object>& global); | |
| | | | |
| | | /** | |
| | | * get the DBClientBase connection from JS args | |
| | | */ | |
| | | mongo::DBClientBase* getConnection(const v8::Arguments& args); | |
| | | | |
|
| // Mongo members | | // Mongo constructors | |
| v8::Handle<v8::Value> mongoConsLocal(V8Scope* scope, const v8::Argument
s& args); | | v8::Handle<v8::Value> mongoConsLocal(V8Scope* scope, const v8::Argument
s& args); | |
| v8::Handle<v8::Value> mongoConsExternal(V8Scope* scope, const v8::Argum
ents& args); | | v8::Handle<v8::Value> mongoConsExternal(V8Scope* scope, const v8::Argum
ents& args); | |
|
| | | v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate(V8Scope* scop
e, bool local); | |
| | | | |
|
| | | // Mongo member functions | |
| v8::Handle<v8::Value> mongoFind(V8Scope* scope, const v8::Arguments& ar
gs); | | v8::Handle<v8::Value> mongoFind(V8Scope* scope, const v8::Arguments& ar
gs); | |
| v8::Handle<v8::Value> mongoInsert(V8Scope* scope, const v8::Arguments&
args); | | v8::Handle<v8::Value> mongoInsert(V8Scope* scope, const v8::Arguments&
args); | |
| v8::Handle<v8::Value> mongoRemove(V8Scope* scope, const v8::Arguments&
args); | | v8::Handle<v8::Value> mongoRemove(V8Scope* scope, const v8::Arguments&
args); | |
| v8::Handle<v8::Value> mongoUpdate(V8Scope* scope, const v8::Arguments&
args); | | v8::Handle<v8::Value> mongoUpdate(V8Scope* scope, const v8::Arguments&
args); | |
| v8::Handle<v8::Value> mongoAuth(V8Scope* scope, const v8::Arguments& ar
gs); | | v8::Handle<v8::Value> mongoAuth(V8Scope* scope, const v8::Arguments& ar
gs); | |
| v8::Handle<v8::Value> mongoLogout(V8Scope* scope, const v8::Arguments&
args); | | v8::Handle<v8::Value> mongoLogout(V8Scope* scope, const v8::Arguments&
args); | |
| | | | |
|
| | | // Cursor object | |
| v8::Handle<v8::Value> internalCursorCons(V8Scope* scope, const v8::Argu
ments& args); | | v8::Handle<v8::Value> internalCursorCons(V8Scope* scope, const v8::Argu
ments& args); | |
| v8::Handle<v8::Value> internalCursorNext(V8Scope* scope, const v8::Argu
ments& args); | | v8::Handle<v8::Value> internalCursorNext(V8Scope* scope, const v8::Argu
ments& args); | |
| v8::Handle<v8::Value> internalCursorHasNext(V8Scope* scope, const v8::A
rguments& args); | | v8::Handle<v8::Value> internalCursorHasNext(V8Scope* scope, const v8::A
rguments& args); | |
| v8::Handle<v8::Value> internalCursorObjsLeftInBatch(V8Scope* scope, con
st v8::Arguments& args); | | v8::Handle<v8::Value> internalCursorObjsLeftInBatch(V8Scope* scope, con
st v8::Arguments& args); | |
| v8::Handle<v8::Value> internalCursorReadOnly(V8Scope* scope, const v8::
Arguments& args); | | v8::Handle<v8::Value> internalCursorReadOnly(V8Scope* scope, const v8::
Arguments& args); | |
| | | | |
|
| // DB members | | // BinData object | |
| | | v8::Handle<v8::Value> binDataInit(V8Scope* scope, const v8::Arguments& | |
| v8::Handle<v8::Value> dbInit(V8Scope* scope, const v8::Arguments& args) | | args); | |
| ; | | v8::Handle<v8::Value> binDataToString(V8Scope* scope, const v8::Argumen | |
| v8::Handle<v8::Value> collectionInit(V8Scope* scope, const v8::Argument | | ts& args); | |
| s& args ); | | v8::Handle<v8::Value> binDataToBase64(V8Scope* scope, const v8::Argumen | |
| v8::Handle<v8::Value> objectIdInit( V8Scope* scope, const v8::Arguments | | ts& args); | |
| & args ); | | v8::Handle<v8::Value> binDataToHex(V8Scope* scope, const v8::Arguments& | |
| | | args); | |
| | | | |
|
| v8::Handle<v8::Value> dbRefInit( V8Scope* scope, const v8::Arguments& a | | // NumberLong object | |
| rgs ); | | v8::Handle<v8::Value> numberLongInit(V8Scope* scope, const v8::Argument | |
| v8::Handle<v8::Value> dbPointerInit( V8Scope* scope, const v8::Argument | | s& args); | |
| s& args ); | | | |
| v8::Handle<v8::Value> dbTimestampInit( V8Scope* scope, const v8::Argume | | | |
| nts& args ); | | | |
| | | | |
| v8::Handle<v8::Value> binDataInit( V8Scope* scope, const v8::Arguments& | | | |
| args ); | | | |
| v8::Handle<v8::Value> binDataToString( V8Scope* scope, const v8::Argume | | | |
| nts& args ); | | | |
| v8::Handle<v8::Value> binDataToBase64( V8Scope* scope, const v8::Argume | | | |
| nts& args ); | | | |
| v8::Handle<v8::Value> binDataToHex( V8Scope* scope, const v8::Arguments | | | |
| & args ); | | | |
| | | | |
| v8::Handle<v8::Value> uuidInit( V8Scope* scope, const v8::Arguments& ar | | | |
| gs ); | | | |
| v8::Handle<v8::Value> md5Init( V8Scope* scope, const v8::Arguments& arg | | | |
| s ); | | | |
| v8::Handle<v8::Value> hexDataInit( V8Scope* scope, const v8::Arguments& | | | |
| args ); | | | |
| | | | |
| v8::Handle<v8::Value> numberLongInit( V8Scope* scope, const v8::Argumen | | | |
| ts& args ); | | | |
| v8::Handle<v8::Value> numberLongToNumber(V8Scope* scope, const v8::Argu
ments& args); | | v8::Handle<v8::Value> numberLongToNumber(V8Scope* scope, const v8::Argu
ments& args); | |
| v8::Handle<v8::Value> numberLongValueOf(V8Scope* scope, const v8::Argum
ents& args); | | v8::Handle<v8::Value> numberLongValueOf(V8Scope* scope, const v8::Argum
ents& args); | |
| v8::Handle<v8::Value> numberLongToString(V8Scope* scope, const v8::Argu
ments& args); | | v8::Handle<v8::Value> numberLongToString(V8Scope* scope, const v8::Argu
ments& args); | |
| | | | |
|
| v8::Handle<v8::Value> numberIntInit( V8Scope* scope, const v8::Argument | | // Number object | |
| s& args ); | | v8::Handle<v8::Value> numberIntInit(V8Scope* scope, const v8::Arguments | |
| | | & args); | |
| v8::Handle<v8::Value> numberIntToNumber(V8Scope* scope, const v8::Argum
ents& args); | | v8::Handle<v8::Value> numberIntToNumber(V8Scope* scope, const v8::Argum
ents& args); | |
| v8::Handle<v8::Value> numberIntValueOf(V8Scope* scope, const v8::Argume
nts& args); | | v8::Handle<v8::Value> numberIntValueOf(V8Scope* scope, const v8::Argume
nts& args); | |
| v8::Handle<v8::Value> numberIntToString(V8Scope* scope, const v8::Argum
ents& args); | | v8::Handle<v8::Value> numberIntToString(V8Scope* scope, const v8::Argum
ents& args); | |
| | | | |
|
| v8::Handle<v8::Value> dbQueryInit( V8Scope* scope, const v8::Arguments& | | // DBQuery object | |
| args ); | | v8::Handle<v8::Value> dbQueryInit(V8Scope* scope, const v8::Arguments& | |
| v8::Handle<v8::Value> dbQueryIndexAccess( ::uint32_t index , const v8:: | | args); | |
| AccessorInfo& info ); | | v8::Handle<v8::Value> dbQueryIndexAccess(::uint32_t index, const v8::Ac | |
| | | cessorInfo& info); | |
| | | | |
| | | // db constructor | |
| | | v8::Handle<v8::Value> dbInit(V8Scope* scope, const v8::Arguments& args) | |
| | | ; | |
| | | | |
| | | // collection constructor | |
| | | v8::Handle<v8::Value> collectionInit(V8Scope* scope, const v8::Argument | |
| | | s& args); | |
| | | | |
|
| v8::Handle<v8::Value> collectionGetter( v8::Local<v8::String> name, con | | // ObjectId constructor | |
| st v8::AccessorInfo &info); | | v8::Handle<v8::Value> objectIdInit(V8Scope* scope, const v8::Arguments& | |
| v8::Handle<v8::Value> collectionSetter( Local<v8::String> name, Local<V | | args); | |
| alue> value, const AccessorInfo& info ); | | | |
| | | | |
|
| v8::Handle<v8::Value> bsonsize( V8Scope* scope, const v8::Arguments& ar | | // DBRef constructor | |
| gs ); | | v8::Handle<v8::Value> dbRefInit(V8Scope* scope, const v8::Arguments& ar | |
| | | gs); | |
| | | | |
| | | // DBPointer constructor | |
| | | v8::Handle<v8::Value> dbPointerInit(V8Scope* scope, const v8::Arguments | |
| | | & args); | |
| | | | |
| | | // Timestamp constructor | |
| | | v8::Handle<v8::Value> dbTimestampInit(V8Scope* scope, const v8::Argumen | |
| | | ts& args); | |
| | | | |
| | | // UUID constructor | |
| | | v8::Handle<v8::Value> uuidInit(V8Scope* scope, const v8::Arguments& arg | |
| | | s); | |
| | | | |
| | | // MD5 constructor | |
| | | v8::Handle<v8::Value> md5Init(V8Scope* scope, const v8::Arguments& args | |
| | | ); | |
| | | | |
| | | // HexData constructor | |
| | | v8::Handle<v8::Value> hexDataInit(V8Scope* scope, const v8::Arguments& | |
| | | args); | |
| | | | |
| | | // Object.bsonsize() | |
| | | v8::Handle<v8::Value> bsonsize(V8Scope* scope, const v8::Arguments& arg | |
| | | s); | |
| | | | |
| | | // 'db.collection' property handlers | |
| | | v8::Handle<v8::Value> collectionGetter(v8::Local<v8::String> name, | |
| | | const v8::AccessorInfo& info); | |
| | | v8::Handle<v8::Value> collectionSetter(v8::Local<v8::String> name, v8:: | |
| | | Local<v8::Value> value, | |
| | | const v8::AccessorInfo& info); | |
| | | | |
| typedef boost::function<void (V8Scope*, const v8::Handle<v8::FunctionTe
mplate>&)> | | typedef boost::function<void (V8Scope*, const v8::Handle<v8::FunctionTe
mplate>&)> | |
|
| V8FunctionPrototypeManipulatorFn; | | V8FunctionPrototypeManipulatorFn; | |
| | | | |
| void v8RegisterMongoPrototypeManipulator(const V8FunctionPrototypeManip
ulatorFn& manipulator); | | void v8RegisterMongoPrototypeManipulator(const V8FunctionPrototypeManip
ulatorFn& manipulator); | |
| } | | } | |
| | | | |
End of changes. 15 change blocks. |
| 61 lines changed or deleted | | 81 lines changed or added | |
|
| value_internal.h | | value_internal.h | |
| | | | |
| skipping to change at line 20 | | skipping to change at line 20 | |
| * 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 License | | * You should have received a copy of the GNU Affero General Public License | |
| * 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 <algorithm> | | #include <algorithm> | |
|
| | | #include "bson/bsonobj.h" | |
| #include "bson/bsontypes.h" | | #include "bson/bsontypes.h" | |
|
| | | #include "bson/bsonmisc.h" | |
| #include "bson/oid.h" | | #include "bson/oid.h" | |
| #include "util/intrusive_counter.h" | | #include "util/intrusive_counter.h" | |
| #include "util/optime.h" | | #include "util/optime.h" | |
| | | | |
| namespace mongo { | | namespace mongo { | |
| class Document; | | class Document; | |
| class DocumentStorage; | | class DocumentStorage; | |
| class Value; | | class Value; | |
| | | | |
| //TODO: a MutableVector, similar to MutableDocument | | //TODO: a MutableVector, similar to MutableDocument | |
| /// A heap-allocated reference-counted std::vector | | /// A heap-allocated reference-counted std::vector | |
| class RCVector : public RefCountable { | | class RCVector : public RefCountable { | |
| public: | | public: | |
| RCVector() {} | | RCVector() {} | |
| RCVector(const vector<Value>& v) :vec(v) {} | | RCVector(const vector<Value>& v) :vec(v) {} | |
| vector<Value> vec; | | vector<Value> vec; | |
| }; | | }; | |
| | | | |
|
| | | class RCCodeWScope : public RefCountable { | |
| | | public: | |
| | | RCCodeWScope(const string& str, BSONObj obj) :code(str), scope(obj. | |
| | | getOwned()) {} | |
| | | const string code; | |
| | | const BSONObj scope; // Not worth converting to Document for now | |
| | | }; | |
| | | | |
| | | class RCDBRef : public RefCountable { | |
| | | public: | |
| | | RCDBRef(const string& str, const OID& o) :ns(str), oid(o) {} | |
| | | const string ns; | |
| | | const OID oid; | |
| | | }; | |
| | | | |
| #pragma pack(1) | | #pragma pack(1) | |
| class ValueStorage { | | class ValueStorage { | |
| public: | | public: | |
|
| | | // Note: it is important the memory is zeroed out (by calling zero( | |
| | | )) at the start of every | |
| | | // constructor. Much code relies on every byte being predictably in | |
| | | itialized to zero. | |
| | | | |
| // This is a "missing" Value | | // This is a "missing" Value | |
| ValueStorage() { zero(); type = EOO; } | | ValueStorage() { zero(); type = EOO; } | |
| | | | |
|
| explicit ValueStorage(BSONType t) { zero(); type = t;} | | explicit ValueStorage(BSONType t) { zero(); type = | |
| ValueStorage(BSONType t, int i) { zero(); type = t; int | | t; } | |
| Value = i; } | | ValueStorage(BSONType t, int i) { zero(); type = | |
| ValueStorage(BSONType t, long long l) { zero(); type = t; lon | | t; intValue = i; } | |
| gValue = l; } | | ValueStorage(BSONType t, long long l) { zero(); type = | |
| ValueStorage(BSONType t, double d) { zero(); type = t; dou | | t; longValue = l; } | |
| bleValue = d; } | | ValueStorage(BSONType t, double d) { zero(); type = | |
| ValueStorage(BSONType t, ReplTime r) { zero(); type = t; tim | | t; doubleValue = d; } | |
| estampValue = r; } | | ValueStorage(BSONType t, ReplTime r) { zero(); type = | |
| ValueStorage(BSONType t, bool b) { zero(); type = t; boo | | t; timestampValue = r; } | |
| lValue = b; } | | ValueStorage(BSONType t, bool b) { zero(); type = | |
| ValueStorage(BSONType t, const Document& d) { zero(); type = t; put | | t; boolValue = b; } | |
| Document(d); } | | ValueStorage(BSONType t, const Document& d) { zero(); type = | |
| ValueStorage(BSONType t, const RCVector* a) { zero(); type = t; put | | t; putDocument(d); } | |
| Vector(a); } | | ValueStorage(BSONType t, const RCVector* a) { zero(); type = | |
| ValueStorage(BSONType t, StringData s) { zero(); type = t; put | | t; putVector(a); } | |
| String(s); } | | ValueStorage(BSONType t, const StringData& s) { zero(); type = | |
| | | t; putString(s); } | |
| | | ValueStorage(BSONType t, const BSONBinData& bd) { zero(); type = | |
| | | t; putBinData(bd); } | |
| | | ValueStorage(BSONType t, const BSONRegEx& re) { zero(); type = | |
| | | t; putRegEx(re); } | |
| | | ValueStorage(BSONType t, const BSONCodeWScope& cs) { zero(); type = | |
| | | t; putCodeWScope(cs); } | |
| | | ValueStorage(BSONType t, const BSONDBRef& dbref) { zero(); type = | |
| | | t; putDBRef(dbref); } | |
| | | | |
|
| ValueStorage(BSONType t, OID& o) { | | ValueStorage(BSONType t, const OID& o) { | |
| zero(); | | zero(); | |
| type = t; | | type = t; | |
| memcpy(&oid, &o, sizeof(OID)); | | memcpy(&oid, &o, sizeof(OID)); | |
| BOOST_STATIC_ASSERT(sizeof(OID) == sizeof(oid)); | | BOOST_STATIC_ASSERT(sizeof(OID) == sizeof(oid)); | |
| } | | } | |
| | | | |
| ValueStorage(const ValueStorage& rhs) { | | ValueStorage(const ValueStorage& rhs) { | |
| memcpy(this, &rhs, sizeof(*this)); | | memcpy(this, &rhs, sizeof(*this)); | |
| memcpyed(); | | memcpyed(); | |
| } | | } | |
| | | | |
| skipping to change at line 93 | | skipping to change at line 116 | |
| memcpy(&rhs, temp, sizeof(*this)); | | memcpy(&rhs, temp, sizeof(*this)); | |
| } | | } | |
| | | | |
| /// Call this after memcpying to update ref counts if needed | | /// Call this after memcpying to update ref counts if needed | |
| void memcpyed() const { | | void memcpyed() const { | |
| if (refCounter) | | if (refCounter) | |
| intrusive_ptr_add_ref(genericRCPtr); | | intrusive_ptr_add_ref(genericRCPtr); | |
| } | | } | |
| | | | |
| /// These are only to be called during Value construction on an emp
ty Value | | /// These are only to be called during Value construction on an emp
ty Value | |
|
| void putString(StringData s); | | void putString(const StringData& s); | |
| void putVector(const RCVector* v); | | void putVector(const RCVector* v); | |
| void putDocument(const Document& d); | | void putDocument(const Document& d); | |
|
| | | void putRegEx(const BSONRegEx& re); | |
| | | void putBinData(const BSONBinData& bd) { | |
| | | putString(StringData(static_cast<const char*>(bd.data), bd.leng | |
| | | th)); | |
| | | binSubType = bd.type; | |
| | | } | |
| | | | |
| | | void putDBRef(const BSONDBRef& dbref) { | |
| | | putRefCountable(new RCDBRef(dbref.ns.toString(), dbref.oid)); | |
| | | } | |
| | | | |
| | | void putCodeWScope(const BSONCodeWScope& cws) { | |
| | | putRefCountable(new RCCodeWScope(cws.code.toString(), cws.scope | |
| | | )); | |
| | | } | |
| | | | |
| | | void putRefCountable(intrusive_ptr<const RefCountable> ptr) { | |
| | | genericRCPtr = ptr.get(); | |
| | | | |
| | | if (genericRCPtr) { | |
| | | intrusive_ptr_add_ref(genericRCPtr); | |
| | | refCounter = true; | |
| | | } | |
| | | } | |
| | | | |
| StringData getString() const { | | StringData getString() const { | |
| if (shortStr) { | | if (shortStr) { | |
| return StringData(shortStrStorage, shortStrSize); | | return StringData(shortStrStorage, shortStrSize); | |
| } | | } | |
| else { | | else { | |
| dassert(typeid(*genericRCPtr) == typeid(const RCString)); | | dassert(typeid(*genericRCPtr) == typeid(const RCString)); | |
| const RCString* stringPtr = static_cast<const RCString*>(ge
nericRCPtr); | | const RCString* stringPtr = static_cast<const RCString*>(ge
nericRCPtr); | |
| return StringData(stringPtr->c_str(), stringPtr->size()); | | return StringData(stringPtr->c_str(), stringPtr->size()); | |
| } | | } | |
| } | | } | |
| | | | |
| const vector<Value>& getArray() const { | | const vector<Value>& getArray() const { | |
| dassert(typeid(*genericRCPtr) == typeid(const RCVector)); | | dassert(typeid(*genericRCPtr) == typeid(const RCVector)); | |
| const RCVector* arrayPtr = static_cast<const RCVector*>(generic
RCPtr); | | const RCVector* arrayPtr = static_cast<const RCVector*>(generic
RCPtr); | |
| return arrayPtr->vec; | | return arrayPtr->vec; | |
| } | | } | |
| | | | |
|
| | | intrusive_ptr<const RCCodeWScope> getCodeWScope() const { | |
| | | dassert(typeid(*genericRCPtr) == typeid(const RCCodeWScope)); | |
| | | return static_cast<const RCCodeWScope*>(genericRCPtr); | |
| | | } | |
| | | | |
| | | intrusive_ptr<const RCDBRef> getDBRef() const { | |
| | | dassert(typeid(*genericRCPtr) == typeid(const RCDBRef)); | |
| | | return static_cast<const RCDBRef*>(genericRCPtr); | |
| | | } | |
| | | | |
| // Document is incomplete here so this can't be inline | | // Document is incomplete here so this can't be inline | |
| Document getDocument() const; | | Document getDocument() const; | |
| | | | |
| BSONType bsonType() const { | | BSONType bsonType() const { | |
|
| verify(type != EOO); | | | |
| return BSONType(type); | | return BSONType(type); | |
| } | | } | |
| | | | |
|
| | | BinDataType binDataType() const { | |
| | | dassert(type == BinData); | |
| | | return BinDataType(binSubType); | |
| | | } | |
| | | | |
| void zero() { | | void zero() { | |
|
| // This is important for identical() | | | |
| memset(this, 0, sizeof(*this)); | | memset(this, 0, sizeof(*this)); | |
| } | | } | |
| | | | |
| // Byte-for-byte identical | | // Byte-for-byte identical | |
| bool identical(const ValueStorage& other) const { | | bool identical(const ValueStorage& other) const { | |
| return (i64[0] == other.i64[0] | | return (i64[0] == other.i64[0] | |
| && i64[1] == other.i64[1]); | | && i64[1] == other.i64[1]); | |
| } | | } | |
| | | | |
| // This data is public because this should only be used by Value wh
ich would be a friend | | // This data is public because this should only be used by Value wh
ich would be a friend | |
| | | | |
| skipping to change at line 152 | | skipping to change at line 210 | |
| bool shortStr : 1; // true if we are using short string
s | | bool shortStr : 1; // true if we are using short string
s | |
| // reservedFlags: 6; | | // reservedFlags: 6; | |
| }; | | }; | |
| | | | |
| // bytes 3-16; | | // bytes 3-16; | |
| union { | | union { | |
| unsigned char oid[12]; | | unsigned char oid[12]; | |
| | | | |
| struct { | | struct { | |
| char shortStrSize; // TODO Consider moving into fla
gs union (4 bits) | | char shortStrSize; // TODO Consider moving into fla
gs union (4 bits) | |
|
| char shortStrStorage[16 - 3]; // ValueStorage is 16 | | char shortStrStorage[16/*total bytes*/ - 3/*offset* | |
| bytes, 3 byte offset | | / - 1/*NUL byte*/]; | |
| | | union { | |
| | | char nulTerminator; | |
| | | unsigned char binSubType; // type always goes h | |
| | | ere even if !shortStr | |
| | | }; | |
| }; | | }; | |
| | | | |
| struct { | | struct { | |
| union { | | union { | |
| char pad[6]; | | char pad[6]; | |
| char stringCache[6]; // TODO copy first few byt
es of strings in here | | char stringCache[6]; // TODO copy first few byt
es of strings in here | |
| }; | | }; | |
| union { // 8 bytes long and 8-byte aligned | | union { // 8 bytes long and 8-byte aligned | |
| // There should be no pointers to non-const dat
a | | // There should be no pointers to non-const dat
a | |
| const RefCountable* genericRCPtr; | | const RefCountable* genericRCPtr; | |
| | | | |
End of changes. 13 change blocks. |
| 23 lines changed or deleted | | 96 lines changed or added | |
|