accumulator.h   accumulator.h 
skipping to change at line 34 skipping to change at line 34
#include "bson/bsontypes.h" #include "bson/bsontypes.h"
namespace mongo { namespace mongo {
class ExpressionContext; class ExpressionContext;
class Accumulator : class Accumulator :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual void addOperand(const intrusive_ptr<Expression> &pExpressio n); virtual void addOperand(const intrusive_ptr<Expression> &pExpressio n);
virtual void addToBsonObj( virtual void addToBsonObj(BSONObjBuilder *pBuilder,
BSONObjBuilder *pBuilder, const std::string& fieldName, StringData fieldName,
bool requireExpression) const; bool requireExpression) const;
virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const; virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const;
/* /*
Get the accumulated value. Get the accumulated value.
@returns the accumulated value @returns the accumulated value
*/ */
virtual intrusive_ptr<const Value> getValue() const = 0; virtual Value getValue() const = 0;
protected: protected:
Accumulator(); Accumulator();
/* /*
Convenience method for doing this for accumulators. The pattern Convenience method for doing this for accumulators. The pattern
is always the same, so a common implementation works, but require s is always the same, so a common implementation works, but require s
knowing the operator name. knowing the operator name.
@param pBuilder the builder to add to @param pBuilder the builder to add to
@param fieldName the projected name @param fieldName the projected name
@param opName the operator name @param opName the operator name
*/ */
void opToBson( void opToBson(BSONObjBuilder *pBuilder, StringData opName,
BSONObjBuilder *pBuilder, const std::string& fieldName, const s StringData fieldName, bool requireExpression) const;
td::string& opName,
bool requireExpression) const;
}; };
class AccumulatorAddToSet : class AccumulatorAddToSet :
public Accumulator { public Accumulator {
public: public:
// virtuals from Expression // virtuals from Expression
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<Document> &pDocument) const; virtual Value getValue() const;
virtual intrusive_ptr<const Value> getValue() const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
/* /*
Create an appending accumulator. Create an appending accumulator.
@param pCtx the expression context @param pCtx the expression context
@returns the created accumulator @returns the created accumulator
*/ */
static intrusive_ptr<Accumulator> create( static intrusive_ptr<Accumulator> create(
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pCtx);
private: private:
AccumulatorAddToSet(const intrusive_ptr<ExpressionContext> &pTheCtx ); AccumulatorAddToSet(const intrusive_ptr<ExpressionContext> &pTheCtx );
typedef boost::unordered_set<intrusive_ptr<const Value>, Value::Has h > SetType; typedef boost::unordered_set<Value, Value::Hash > SetType;
mutable SetType set; mutable SetType set;
mutable SetType::iterator itr; mutable SetType::iterator itr;
intrusive_ptr<ExpressionContext> pCtx; intrusive_ptr<ExpressionContext> pCtx;
}; };
/* /*
This isn't a finished accumulator, but rather a convenient base class This isn't a finished accumulator, but rather a convenient base class
for others such as $first, $last, $max, $min, and similar. It just for others such as $first, $last, $max, $min, and similar. It just
provides a holder for a single Value, and the getter for that. The provides a holder for a single Value, and the getter for that. The
holder is protected so derived classes can manipulate it. holder is protected so derived classes can manipulate it.
*/ */
class AccumulatorSingleValue : class AccumulatorSingleValue :
public Accumulator { public Accumulator {
public: public:
// virtuals from Expression // virtuals from Expression
virtual intrusive_ptr<const Value> getValue() const; virtual Value getValue() const;
protected: protected:
AccumulatorSingleValue(); AccumulatorSingleValue();
mutable intrusive_ptr<const Value> pValue; /* current min/max */ mutable Value pValue; /* current min/max */
}; };
class AccumulatorFirst : class AccumulatorFirst :
public AccumulatorSingleValue { public AccumulatorSingleValue {
public: public:
// virtuals from Expression // virtuals from Expression
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<Document> &pDocument) const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
/* /*
Create the accumulator. Create the accumulator.
@returns the created accumulator @returns the created accumulator
*/ */
static intrusive_ptr<Accumulator> create( static intrusive_ptr<Accumulator> create(
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pCtx);
private: private:
AccumulatorFirst(); AccumulatorFirst();
}; };
class AccumulatorLast : class AccumulatorLast :
public AccumulatorSingleValue { public AccumulatorSingleValue {
public: public:
// virtuals from Expression // virtuals from Expression
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<Document> &pDocument) const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
/* /*
Create the accumulator. Create the accumulator.
@returns the created accumulator @returns the created accumulator
*/ */
static intrusive_ptr<Accumulator> create( static intrusive_ptr<Accumulator> create(
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pCtx);
private: private:
AccumulatorLast(); AccumulatorLast();
}; };
class AccumulatorSum : class AccumulatorSum :
public Accumulator { public Accumulator {
public: public:
// virtuals from Accumulator // virtuals from Accumulator
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<Document> &pDocument) const; virtual Value getValue() const;
virtual intrusive_ptr<const Value> getValue() const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
/* /*
Create a summing accumulator. Create a summing accumulator.
@param pCtx the expression context @param pCtx the expression context
@returns the created accumulator @returns the created accumulator
*/ */
static intrusive_ptr<Accumulator> create( static intrusive_ptr<Accumulator> create(
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pCtx);
skipping to change at line 179 skipping to change at line 174
mutable long long longTotal; mutable long long longTotal;
mutable double doubleTotal; mutable double doubleTotal;
// count is only used by AccumulatorAvg, but lives here to avoid co unting non-numeric values // count is only used by AccumulatorAvg, but lives here to avoid co unting non-numeric values
mutable long long count; mutable long long count;
}; };
class AccumulatorMinMax : class AccumulatorMinMax :
public AccumulatorSingleValue { public AccumulatorSingleValue {
public: public:
// virtuals from Expression // virtuals from Expression
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<Document> &pDocument) const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
/* /*
Create either the max or min accumulator. Create either the max or min accumulator.
@returns the created accumulator @returns the created accumulator
*/ */
static intrusive_ptr<Accumulator> createMin( static intrusive_ptr<Accumulator> createMin(
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pCtx);
static intrusive_ptr<Accumulator> createMax( static intrusive_ptr<Accumulator> createMax(
skipping to change at line 203 skipping to change at line 197
private: private:
AccumulatorMinMax(int theSense); AccumulatorMinMax(int theSense);
int sense; /* 1 for min, -1 for max; used to "scale" comparison */ int sense; /* 1 for min, -1 for max; used to "scale" comparison */
}; };
class AccumulatorPush : class AccumulatorPush :
public Accumulator { public Accumulator {
public: public:
// virtuals from Expression // virtuals from Expression
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<Document> &pDocument) const; virtual Value getValue() const;
virtual intrusive_ptr<const Value> getValue() const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
/* /*
Create an appending accumulator. Create an appending accumulator.
@param pCtx the expression context @param pCtx the expression context
@returns the created accumulator @returns the created accumulator
*/ */
static intrusive_ptr<Accumulator> create( static intrusive_ptr<Accumulator> create(
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pCtx);
private: private:
AccumulatorPush(const intrusive_ptr<ExpressionContext> &pTheCtx); AccumulatorPush(const intrusive_ptr<ExpressionContext> &pTheCtx);
mutable vector<intrusive_ptr<const Value> > vpValue; mutable vector<Value> vpValue;
intrusive_ptr<ExpressionContext> pCtx; intrusive_ptr<ExpressionContext> pCtx;
}; };
class AccumulatorAvg : class AccumulatorAvg :
public AccumulatorSum { public AccumulatorSum {
typedef AccumulatorSum Super; typedef AccumulatorSum Super;
public: public:
// virtuals from Accumulator // virtuals from Accumulator
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<Document> &pDocument) const; virtual Value getValue() const;
virtual intrusive_ptr<const Value> getValue() const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
/* /*
Create an averaging accumulator. Create an averaging accumulator.
@param pCtx the expression context @param pCtx the expression context
@returns the created accumulator @returns the created accumulator
*/ */
static intrusive_ptr<Accumulator> create( static intrusive_ptr<Accumulator> create(
const intrusive_ptr<ExpressionContext> &pCtx); const intrusive_ptr<ExpressionContext> &pCtx);
 End of changes. 14 change blocks. 
30 lines changed or deleted 21 lines changed or added


 action_set.h   action_set.h 
skipping to change at line 19 skipping to change at line 19
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <stdint.h> #include <bitset>
#include "mongo/base/status.h" #include "mongo/base/status.h"
#include "mongo/db/auth/action_type.h"
namespace mongo { namespace mongo {
/* /*
* An ActionSet is a bitmask of ActionTypes that represents a set of a ctions. * An ActionSet is a bitmask of ActionTypes that represents a set of a ctions.
* These are the actions that a Capability can grant a principal to pe rform on a resource. * These are the actions that a Privilege can grant a principal to per form on a resource.
*/ */
class ActionSet { class ActionSet {
public: public:
ActionSet() : _actions(0) {} ActionSet() : _actions(0) {}
// This describes the different types of actions that a principle c
an have the capability
// to perform on a resource
enum ActionType {
NONE = 0x0,
READ = 0x1, // Can query data, run read-only commands.
WRITE = 0x2, // Can read or write data, run any non-admin comma
nd, can create indexes.
USER_ADMIN = 0x4, // Can read and write system.users.
PRODUCTION_ADMIN = 0x8, // Can run single-db admin commands.
SUPER_ADMIN = 0x10, // Can run cluster-wide admin commands.
};
void addAction(const ActionType& action); void addAction(const ActionType& action);
void addAllActionsFromSet(const ActionSet& actionSet);
void addAllActions();
bool contains(const ActionType& action) const; bool contains(const ActionType& action) const;
// Returns true only if this ActionSet contains all the actions pre sent in the 'other' // Returns true only if this ActionSet contains all the actions pre sent in the 'other'
// ActionSet. // ActionSet.
bool isSupersetOf(const ActionSet& other) const; // TODO: test bool isSupersetOf(const ActionSet& other) const;
// Takes the string representation of a single action type and retu // Returns the string representation of this ActionSet
rns the corresponding std::string toString() const;
// ActionType enum.
static Status parseActionFromString(const std::string& actionString
,
ActionSet::ActionType* result);
// Takes a comma-separate string of action type string representati ons and returns // Takes a comma-separated string of action type string representat ions and returns
// an int bitmask of the actions. // an int bitmask of the actions.
static Status parseActionSetFromString(const std::string& actionsSt ring, ActionSet* result); static Status parseActionSetFromString(const std::string& actionsSt ring, ActionSet* result);
// Takes an ActionType and returns the string representation
static std::string actionToString(const ActionSet::ActionType& acti
on); // TODO
// Takes an ActionSet and returns the string representation
static std::string actionSetToString(const ActionSet& actionSet); /
/ TODO
private: private:
uint64_t _actions; // bitmask of actions this capability grants // bitmask of actions this privilege grants
std::bitset<ActionType::NUM_ACTION_TYPES> _actions;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 10 change blocks. 
32 lines changed or deleted 11 lines changed or added


 assert_util.h   assert_util.h 
skipping to change at line 179 skipping to change at line 179
} }
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() ); }
/** abends on condition failure */ /** aborts on condition failure */
inline void fassert( int msgid , bool testOK ) { if ( ! testOK ) fasser inline void fassert(int msgid, bool testOK) {if (MONGO_unlikely(!testOK
tFailed( msgid ); } )) 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) )
/* 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
 End of changes. 1 change blocks. 
3 lines changed or deleted 3 lines changed or added


 atomic_intrinsics_gcc.h   atomic_intrinsics_gcc.h 
skipping to change at line 68 skipping to change at line 68
return result; return result;
} }
static T load(volatile const T* value) { static T load(volatile const T* value) {
asm volatile ("mfence" ::: "memory"); asm volatile ("mfence" ::: "memory");
T result = *value; T result = *value;
asm volatile ("mfence" ::: "memory"); asm volatile ("mfence" ::: "memory");
return result; return result;
} }
static T loadRelaxed(volatile const T* value) {
return *value;
}
static void store(volatile T* dest, T newValue) { static void store(volatile T* dest, T newValue) {
asm volatile ("mfence" ::: "memory"); asm volatile ("mfence" ::: "memory");
*dest = newValue; *dest = newValue;
asm volatile ("mfence" ::: "memory"); asm volatile ("mfence" ::: "memory");
} }
static T fetchAndAdd(volatile T* dest, T increment) { static T fetchAndAdd(volatile T* dest, T increment) {
T result = increment; T result = increment;
asm volatile ("lock xadd %[src], %[dest]" asm volatile ("lock xadd %[src], %[dest]"
 End of changes. 1 change blocks. 
0 lines changed or deleted 4 lines changed or added


 atomic_intrinsics_win32.h   atomic_intrinsics_win32.h 
skipping to change at line 62 skipping to change at line 62
return InterlockedExchange(reinterpret_cast<volatile LONG*>(des t), LONG(newValue)); return InterlockedExchange(reinterpret_cast<volatile LONG*>(des t), LONG(newValue));
} }
static T load(volatile const T* value) { static T load(volatile const T* value) {
MemoryBarrier(); MemoryBarrier();
T result = *value; T result = *value;
MemoryBarrier(); MemoryBarrier();
return result; return result;
} }
static T loadRelaxed(volatile const T* value) {
return *value;
}
static void store(volatile T* dest, T newValue) { static void store(volatile T* dest, T newValue) {
MemoryBarrier(); MemoryBarrier();
*dest = newValue; *dest = newValue;
MemoryBarrier(); MemoryBarrier();
} }
static T fetchAndAdd(volatile T* dest, T increment) { static T fetchAndAdd(volatile T* dest, T increment) {
return InterlockedExchangeAdd(reinterpret_cast<volatile LONG*>( dest), LONG(increment)); return InterlockedExchangeAdd(reinterpret_cast<volatile LONG*>( dest), LONG(increment));
} }
 End of changes. 1 change blocks. 
0 lines changed or deleted 4 lines changed or added


 atomic_word.h   atomic_word.h 
skipping to change at line 65 skipping to change at line 65
explicit AtomicWord(WordType value=WordType(0)) : _value(value) {} explicit AtomicWord(WordType value=WordType(0)) : _value(value) {}
/** /**
* Gets the current value of this AtomicWord. * Gets the current value of this AtomicWord.
* *
* Has acquire and release semantics. * Has acquire and release semantics.
*/ */
WordType load() const { return AtomicIntrinsics<WordType>::load(&_v alue); } WordType load() const { return AtomicIntrinsics<WordType>::load(&_v alue); }
/** /**
* Gets the current value of this AtomicWord.
*
* Has relaxed semantics.
*/
WordType loadRelaxed() const { return AtomicIntrinsics<WordType>::l
oadRelaxed(&_value); }
/**
* Sets the value of this AtomicWord to "newValue". * Sets the value of this AtomicWord to "newValue".
* *
* Has acquire and release semantics. * Has acquire and release semantics.
*/ */
void store(WordType newValue) { AtomicIntrinsics<WordType>::store(& _value, newValue); } void store(WordType newValue) { AtomicIntrinsics<WordType>::store(& _value, newValue); }
/** /**
* Atomically swaps the current value of this with "newValue". * Atomically swaps the current value of this with "newValue".
* *
* Returns the old value. * Returns the old value.
 End of changes. 1 change blocks. 
0 lines changed or deleted 8 lines changed or added


 atomicops.h   atomicops.h 
/* Copyright (c) 2006, Google Inc. // Copyright 2010 the V8 project authors. All rights reserved.
* All rights reserved. // Redistribution and use in source and binary forms, with or without
* // modification, are permitted provided that the following conditions are
* Redistribution and use in source and binary forms, with or without // met:
* modification, are permitted provided that the following conditions are //
* met: // * Redistributions of source code must retain the above copyright
* // notice, this list of conditions and the following disclaimer.
* * Redistributions of source code must retain the above copyright // * Redistributions in binary form must reproduce the above
* notice, this list of conditions and the following disclaimer. // copyright notice, this list of conditions and the following
* * Redistributions in binary form must reproduce the above // disclaimer in the documentation and/or other materials provided
* copyright notice, this list of conditions and the following disclaimer // with the distribution.
* in the documentation and/or other materials provided with the // * Neither the name of Google Inc. nor the names of its
* distribution. // contributors may be used to endorse or promote products derived
* * Neither the name of Google Inc. nor the names of its // from this software without specific prior written permission.
* contributors may be used to endorse or promote products derived from //
* this software without specific prior written permission. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ---
* Author: Sanjay Ghemawat
*/
// For atomic operations on statistics counters, see atomic_stats_counter.h
.
// For atomic operations on sequence numbers, see atomic_sequence_num.h.
// For atomic operations on reference counts, see atomic_refcount.h.
// Some fast atomic operations -- typically with machine-dependent
// implementations. This file may need editing as Google code is
// ported to different architectures.
// The routines exported by this module are subtle. If you use them, even if // The routines exported by this module are subtle. If you use them, even if
// you get the code right, it will depend on careful reasoning about atomic ity // you get the code right, it will depend on careful reasoning about atomic ity
// and memory ordering; it will be less readable, and harder to maintain. If // and memory ordering; it will be less readable, and harder to maintain. If
// you plan to use these routines, you should have a good reason, such as s olid // you plan to use these routines, you should have a good reason, such as s olid
// evidence that performance would otherwise suffer, or there being no // evidence that performance would otherwise suffer, or there being no
// alternative. You should assume only properties explicitly guaranteed by the // alternative. You should assume only properties explicitly guaranteed by the
// specifications in this file. You are almost certainly _not_ writing cod e // specifications in this file. You are almost certainly _not_ writing cod e
// just for the x86; if you assume x86 semantics, x86 hardware bugs and // just for the x86; if you assume x86 semantics, x86 hardware bugs and
// implementations on other archtectures will cause your code to break. If you // implementations on other archtectures will cause your code to break. If you
// do not know what you are doing, avoid these routines, and use a Mutex. // do not know what you are doing, avoid these routines, and use a Mutex.
// //
// It is incorrect to make direct assignments to/from an atomic variable. // It is incorrect to make direct assignments to/from an atomic variable.
// You should use one of the Load or Store routines. The NoBarrier // You should use one of the Load or Store routines. The NoBarrier
// versions are provided when no barriers are needed: // versions are provided when no barriers are needed:
// NoBarrier_Store() // NoBarrier_Store()
// NoBarrier_Load() // NoBarrier_Load()
// Although there are currently no compiler enforcement, you are encouraged // Although there are currently no compiler enforcement, you are encouraged
// to use these. Moreover, if you choose to use base::subtle::Atomic64 typ // to use these.
e,
// you MUST use one of the Load or Store routines to get correct behavior
// on 32-bit platforms.
// //
// The intent is eventually to put all of these routines in namespace
// base::subtle
#ifndef THREAD_ATOMICOPS_H_ #ifndef V8_ATOMICOPS_H_
#define THREAD_ATOMICOPS_H_ #define V8_ATOMICOPS_H_
#include <config.h> #include "../include/v8.h"
#ifdef HAVE_STDINT_H #include "globals.h"
#include <stdint.h>
#endif
// ------------------------------------------------------------------------ namespace v8 {
// Include the platform specific implementations of the types namespace internal {
// and operations listed below. Implementations are to provide Atomic32
// and Atomic64 operations. If there is a mismatch between intptr_t and typedef int32_t Atomic32;
// the Atomic32 or Atomic64 types for a platform, the platform-specific hea #ifdef V8_HOST_ARCH_64_BIT
der // We need to be able to go between Atomic64 and AtomicWord implicitly. Th
// should define the macro, AtomicWordCastType in a clause similar to the is
// following: // means Atomic64 and AtomicWord should be the same type on 64-bit.
// #if ...pointers are 64 bits... #if defined(__APPLE__)
// # define AtomicWordCastType base::subtle::Atomic64 // MacOS is an exception to the implicit conversion rule above,
// #else // because it uses long for intptr_t.
// # define AtomicWordCastType Atomic32 typedef int64_t Atomic64;
// #endif
// TODO(csilvers): figure out ARCH_PIII/ARCH_K8 (perhaps via ./configure?)
// ------------------------------------------------------------------------
#include "base/arm_instruction_set_select.h"
// TODO(csilvers): match piii, not just __i386. Also, match k8
#if defined(__MACH__) && defined(__APPLE__)
#include "base/atomicops-internals-macosx.h"
#elif defined(__GNUC__) && defined(ARMV6)
#include "base/atomicops-internals-arm-v6plus.h"
#elif defined(ARMV3)
#include "base/atomicops-internals-arm-generic.h"
#elif defined(_WIN32)
#include "base/atomicops-internals-windows.h"
#elif defined(__GNUC__) && (defined(__i386) || defined(__x86_64__))
#include "base/atomicops-internals-x86.h"
#elif defined(__linux__) && defined(__PPC__)
#include "base/atomicops-internals-linuxppc.h"
#else #else
// Assume x86 for now. If you need to support a new architecture and typedef intptr_t Atomic64;
// don't know how to implement atomic ops, you can probably get away #endif
// with using pthreads, since atomicops is only used by spinlock.h/cc
//#error You need to implement atomic operations for this architecture
#include "base/atomicops-internals-x86.h"
#endif #endif
// Signed type that can hold a pointer and supports the atomic ops below, a // Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or
s // Atomic64 routines below, depending on your architecture.
// well as atomic loads and stores. Instances must be naturally-aligned.
typedef intptr_t AtomicWord; typedef intptr_t AtomicWord;
#ifdef AtomicWordCastType
// ------------------------------------------------------------------------
// This section is needed only when explicit type casting is required to
// cast AtomicWord to one of the basic atomic types (Atomic64 or Atomic32).
// It also serves to document the AtomicWord interface.
// ------------------------------------------------------------------------
namespace base {
namespace subtle {
// Atomically execute: // Atomically execute:
// result = *ptr; // result = *ptr;
// if (*ptr == old_value) // if (*ptr == old_value)
// *ptr = new_value; // *ptr = new_value;
// return result; // return result;
// //
// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value". // I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
// Always return the old value of "*ptr" // Always return the old value of "*ptr"
// //
// This routine implies no memory barriers. // This routine implies no memory barriers.
inline AtomicWord NoBarrier_CompareAndSwap(volatile AtomicWord* ptr, Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
AtomicWord old_value, Atomic32 old_value,
AtomicWord new_value) { Atomic32 new_value);
return NoBarrier_CompareAndSwap(
reinterpret_cast<volatile AtomicWordCastType*>(ptr),
old_value, new_value);
}
// Atomically store new_value into *ptr, returning the previous value held in // Atomically store new_value into *ptr, returning the previous value held in
// *ptr. This routine implies no memory barriers. // *ptr. This routine implies no memory barriers.
inline AtomicWord NoBarrier_AtomicExchange(volatile AtomicWord* ptr, Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_valu
AtomicWord new_value) { e);
return NoBarrier_AtomicExchange(
reinterpret_cast<volatile AtomicWordCastType*>(ptr), new_value);
}
// Atomically increment *ptr by "increment". Returns the new value of // Atomically increment *ptr by "increment". Returns the new value of
// *ptr with the increment applied. This routine implies no memory // *ptr with the increment applied. This routine implies no memory barrier
// barriers. s.
inline AtomicWord NoBarrier_AtomicIncrement(volatile AtomicWord* ptr, Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increme
AtomicWord increment) { nt);
return NoBarrier_AtomicIncrement(
reinterpret_cast<volatile AtomicWordCastType*>(ptr), increment); Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
} Atomic32 increment);
inline AtomicWord Barrier_AtomicIncrement(volatile AtomicWord* ptr,
AtomicWord increment) {
return Barrier_AtomicIncrement(
reinterpret_cast<volatile AtomicWordCastType*>(ptr), increment);
}
// ------------------------------------------------------------------------
// These following lower-level operations are typically useful only to peop le // These following lower-level operations are typically useful only to peop le
// implementing higher-level synchronization operations like spinlocks, // implementing higher-level synchronization operations like spinlocks,
// mutexes, and condition-variables. They combine CompareAndSwap(), a load , or // mutexes, and condition-variables. They combine CompareAndSwap(), a load , or
// a store with appropriate memory-ordering instructions. "Acquire" operat ions // a store with appropriate memory-ordering instructions. "Acquire" operat ions
// ensure that no later memory access can be reordered ahead of the operati on. // ensure that no later memory access can be reordered ahead of the operati on.
// "Release" operations ensure that no previous memory access can be reorde red // "Release" operations ensure that no previous memory access can be reorde red
// after the operation. "Barrier" operations have both "Acquire" and "Rele ase" // after the operation. "Barrier" operations have both "Acquire" and "Rele ase"
// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memo ry // semantics. A MemoryBarrier() has "Barrier" semantics, but does no memo ry
// access. // access.
// ------------------------------------------------------------------------
inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr,
AtomicWord old_value,
AtomicWord new_value) {
return base::subtle::Acquire_CompareAndSwap(
reinterpret_cast<volatile AtomicWordCastType*>(ptr),
old_value, new_value);
}
inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr,
AtomicWord old_value,
AtomicWord new_value) {
return base::subtle::Release_CompareAndSwap(
reinterpret_cast<volatile AtomicWordCastType*>(ptr),
old_value, new_value);
}
inline void NoBarrier_Store(volatile AtomicWord *ptr, AtomicWord value) {
NoBarrier_Store(
reinterpret_cast<volatile AtomicWordCastType*>(ptr), value);
}
inline void Acquire_Store(volatile AtomicWord* ptr, AtomicWord value) {
return base::subtle::Acquire_Store(
reinterpret_cast<volatile AtomicWordCastType*>(ptr), value);
}
inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) {
return base::subtle::Release_Store(
reinterpret_cast<volatile AtomicWordCastType*>(ptr), value);
}
inline AtomicWord NoBarrier_Load(volatile const AtomicWord *ptr) {
return NoBarrier_Load(
reinterpret_cast<volatile const AtomicWordCastType*>(ptr));
}
inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) {
return base::subtle::Acquire_Load(
reinterpret_cast<volatile const AtomicWordCastType*>(ptr));
}
inline AtomicWord Release_Load(volatile const AtomicWord* ptr) {
return base::subtle::Release_Load(
reinterpret_cast<volatile const AtomicWordCastType*>(ptr));
}
} // namespace base::subtle
} // namespace base
#endif // AtomicWordCastType
// ------------------------------------------------------------------------
// Commented out type definitions and method declarations for documentation
// of the interface provided by this module.
// ------------------------------------------------------------------------
#if 0
// Signed 32-bit type that supports the atomic ops below, as well as atomic
// loads and stores. Instances must be naturally aligned. This type diffe
rs
// from AtomicWord in 64-bit binaries where AtomicWord is 64-bits.
typedef int32_t Atomic32;
// Corresponding operations on Atomic32
namespace base {
namespace subtle {
// Signed 64-bit type that supports the atomic ops below, as well as atomic
// loads and stores. Instances must be naturally aligned. This type diffe
rs
// from AtomicWord in 32-bit binaries where AtomicWord is 32-bits.
typedef int64_t Atomic64;
Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value,
Atomic32 new_value);
Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_valu
e);
Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increme
nt);
Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
Atomic32 increment);
Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value, Atomic32 old_value,
Atomic32 new_value); Atomic32 new_value);
Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value, Atomic32 old_value,
Atomic32 new_value); Atomic32 new_value);
void MemoryBarrier();
void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value); void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value);
void Acquire_Store(volatile Atomic32* ptr, Atomic32 value); void Acquire_Store(volatile Atomic32* ptr, Atomic32 value);
void Release_Store(volatile Atomic32* ptr, Atomic32 value); void Release_Store(volatile Atomic32* ptr, Atomic32 value);
Atomic32 NoBarrier_Load(volatile const Atomic32* ptr); Atomic32 NoBarrier_Load(volatile const Atomic32* ptr);
Atomic32 Acquire_Load(volatile const Atomic32* ptr); Atomic32 Acquire_Load(volatile const Atomic32* ptr);
Atomic32 Release_Load(volatile const Atomic32* ptr); Atomic32 Release_Load(volatile const Atomic32* ptr);
// Corresponding operations on Atomic64 // 64-bit atomic operations (only available on 64-bit processors).
#ifdef V8_HOST_ARCH_64_BIT
Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
Atomic64 old_value, Atomic64 old_value,
Atomic64 new_value); Atomic64 new_value);
Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_valu e); Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_valu e);
Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increme nt); Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increme nt);
Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment ); Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment );
Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
Atomic64 old_value, Atomic64 old_value,
Atomic64 new_value); Atomic64 new_value);
Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr, Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
Atomic64 old_value, Atomic64 old_value,
Atomic64 new_value); Atomic64 new_value);
void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value); void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value);
void Acquire_Store(volatile Atomic64* ptr, Atomic64 value); void Acquire_Store(volatile Atomic64* ptr, Atomic64 value);
void Release_Store(volatile Atomic64* ptr, Atomic64 value); void Release_Store(volatile Atomic64* ptr, Atomic64 value);
Atomic64 NoBarrier_Load(volatile const Atomic64* ptr); Atomic64 NoBarrier_Load(volatile const Atomic64* ptr);
Atomic64 Acquire_Load(volatile const Atomic64* ptr); Atomic64 Acquire_Load(volatile const Atomic64* ptr);
Atomic64 Release_Load(volatile const Atomic64* ptr); Atomic64 Release_Load(volatile const Atomic64* ptr);
} // namespace base::subtle #endif // V8_HOST_ARCH_64_BIT
} // namespace base
void MemoryBarrier(); } } // namespace v8::internal
#endif // 0 // Include our platform specific implementation.
#if defined(_MSC_VER) && \
// ------------------------------------------------------------------------ (defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64))
// The following are to be deprecated when all uses have been changed to #include "atomicops_internals_x86_msvc.h"
// use the base::subtle namespace. #elif defined(__APPLE__) && \
// ------------------------------------------------------------------------ (defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64))
#include "atomicops_internals_x86_macosx.h"
#ifdef AtomicWordCastType #elif defined(__GNUC__) && \
// AtomicWord versions to be deprecated (defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64))
inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr, #include "atomicops_internals_x86_gcc.h"
AtomicWord old_value, #elif defined(__GNUC__) && defined(V8_HOST_ARCH_ARM)
AtomicWord new_value) { #include "atomicops_internals_arm_gcc.h"
return base::subtle::Acquire_CompareAndSwap(ptr, old_value, new_value); #elif defined(__GNUC__) && defined(V8_HOST_ARCH_MIPS)
} #include "atomicops_internals_mips_gcc.h"
#else
inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr, #error "Atomic operations are not supported on your platform"
AtomicWord old_value, #endif
AtomicWord new_value) {
return base::subtle::Release_CompareAndSwap(ptr, old_value, new_value);
}
inline void Acquire_Store(volatile AtomicWord* ptr, AtomicWord value) {
return base::subtle::Acquire_Store(ptr, value);
}
inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) {
return base::subtle::Release_Store(ptr, value);
}
inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) {
return base::subtle::Acquire_Load(ptr);
}
inline AtomicWord Release_Load(volatile const AtomicWord* ptr) {
return base::subtle::Release_Load(ptr);
}
#endif // AtomicWordCastType
// 32-bit Acquire/Release operations to be deprecated.
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value,
Atomic32 new_value) {
return base::subtle::Acquire_CompareAndSwap(ptr, old_value, new_value);
}
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value,
Atomic32 new_value) {
return base::subtle::Release_CompareAndSwap(ptr, old_value, new_value);
}
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
base::subtle::Acquire_Store(ptr, value);
}
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
return base::subtle::Release_Store(ptr, value);
}
inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
return base::subtle::Acquire_Load(ptr);
}
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
return base::subtle::Release_Load(ptr);
}
#ifdef BASE_HAS_ATOMIC64
// 64-bit Acquire/Release operations to be deprecated.
inline base::subtle::Atomic64 Acquire_CompareAndSwap(
volatile base::subtle::Atomic64* ptr,
base::subtle::Atomic64 old_value, base::subtle::Atomic64 new_value) {
return base::subtle::Acquire_CompareAndSwap(ptr, old_value, new_value);
}
inline base::subtle::Atomic64 Release_CompareAndSwap(
volatile base::subtle::Atomic64* ptr,
base::subtle::Atomic64 old_value, base::subtle::Atomic64 new_value) {
return base::subtle::Release_CompareAndSwap(ptr, old_value, new_value);
}
inline void Acquire_Store(
volatile base::subtle::Atomic64* ptr, base::subtle::Atomic64 value) {
base::subtle::Acquire_Store(ptr, value);
}
inline void Release_Store(
volatile base::subtle::Atomic64* ptr, base::subtle::Atomic64 value) {
return base::subtle::Release_Store(ptr, value);
}
inline base::subtle::Atomic64 Acquire_Load(
volatile const base::subtle::Atomic64* ptr) {
return base::subtle::Acquire_Load(ptr);
}
inline base::subtle::Atomic64 Release_Load(
volatile const base::subtle::Atomic64* ptr) {
return base::subtle::Release_Load(ptr);
}
#endif // BASE_HAS_ATOMIC64
#endif // THREAD_ATOMICOPS_H_ #endif // V8_ATOMICOPS_H_
 End of changes. 21 change blocks. 
310 lines changed or deleted 83 lines changed or added


 authentication_table.h   authentication_table.h 
skipping to change at line 62 skipping to change at line 62
BSONObj toBSON() const; BSONObj toBSON() const;
BSONObj copyCommandObjAddingAuth( const BSONObj& cmdObj ) const; BSONObj copyCommandObjAddingAuth( const BSONObj& cmdObj ) const;
static const AuthenticationTable& getInternalSecurityAuthentication Table(); static const AuthenticationTable& getInternalSecurityAuthentication Table();
// Only used once at startup to setup the authentication table. // Only used once at startup to setup the authentication table.
static AuthenticationTable& getMutableInternalSecurityAuthenticatio nTable(); static AuthenticationTable& getMutableInternalSecurityAuthenticatio nTable();
static const string fieldName; static const string fieldName;
private: private:
bool _shouldSendInternalSecurityTable() const;
typedef map<std::string,Auth> DBAuthMap; typedef map<std::string,Auth> DBAuthMap;
DBAuthMap _dbs; // dbname -> auth DBAuthMap _dbs; // dbname -> auth
}; };
} }
 End of changes. 1 change blocks. 
0 lines changed or deleted 3 lines changed or added


 balance.h   balance.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 "mongo/pch.h" #include "mongo/pch.h"
#include "../util/background.h"
#include "balancer_policy.h" #include "mongo/client/dbclientinterface.h"
#include "mongo/s/balancer_policy.h"
#include "mongo/util/background.h"
namespace mongo { namespace mongo {
/** /**
* The balancer is a background task that tries to keep the number of c hunks across all servers of the cluster even. Although * The balancer is a background task that tries to keep the number of c hunks across all servers of the cluster even. Although
* every mongos will have one balancer running, only one of them will b e active at the any given point in time. The balancer * every mongos will have one balancer running, only one of them will b e active at the any given point in time. The balancer
* uses a 'DistributedLock' for that coordination. * uses a 'DistributedLock' for that coordination.
* *
* The balancer does act continuously but in "rounds". At a given round , it would decide if there is an imbalance by * The balancer does act continuously but in "rounds". At a given round , it would decide if there is an imbalance by
* checking the difference in chunks between the most and least loaded shards. It would issue a request for a chunk * checking the difference in chunks between the most and least loaded shards. It would issue a request for a chunk
 End of changes. 1 change blocks. 
2 lines changed or deleted 4 lines changed or added


 balancer_policy.h   balancer_policy.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/>.
*/ */
#ifndef S_BALANCER_POLICY_HEADER #ifndef S_BALANCER_POLICY_HEADER
#define S_BALANCER_POLICY_HEADER #define S_BALANCER_POLICY_HEADER
#include "mongo/db/jsobj.h" #include "mongo/db/jsobj.h"
#include "mongo/s/cluster_constants.h"
namespace mongo { namespace mongo {
struct ChunkInfo { struct ChunkInfo {
const BSONObj min; const BSONObj min;
const BSONObj max; const BSONObj max;
ChunkInfo( const BSONObj& a_min, const BSONObj& a_max ) ChunkInfo( const BSONObj& a_min, const BSONObj& a_max )
: min( a_min.getOwned() ), max( a_max.getOwned() ){} : min( a_min.getOwned() ), max( a_max.getOwned() ){}
ChunkInfo( const BSONObj& chunk ) ChunkInfo( const BSONObj& chunk )
: min( chunk["min"].Obj().getOwned() ), max( chunk["max"].Obj() : min(chunk[ChunkFields::min()].Obj().getOwned()),
.getOwned() ) { max(chunk[ChunkFields::max()].Obj().getOwned()) {
} }
string toString() const; string toString() const;
}; };
struct TagRange { struct TagRange {
BSONObj min; BSONObj min;
BSONObj max; BSONObj max;
string tag; string tag;
skipping to change at line 82 skipping to change at line 84
* @return true if 'shardLimist' contains a field "draining". Expec ts the optional field * @return true if 'shardLimist' contains a field "draining". Expec ts the optional field
* "isDraining" on 'shrdLimits'. * "isDraining" on 'shrdLimits'.
*/ */
bool isDraining() const { return _draining; } bool isDraining() const { return _draining; }
/** /**
* @return true if a shard currently has operations in any of its w riteback queues * @return true if a shard currently has operations in any of its w riteback queues
*/ */
bool hasOpsQueued() const { return _hasOpsQueued; } bool hasOpsQueued() const { return _hasOpsQueued; }
long long getMaxSize() const { return _maxSize; }
long long getCurrSize() const { return _currSize; }
string toString() const; string toString() const;
private: private:
long long _maxSize; long long _maxSize;
long long _currSize; long long _currSize;
bool _draining; bool _draining;
bool _hasOpsQueued; bool _hasOpsQueued;
set<string> _tags; set<string> _tags;
}; };
 End of changes. 3 change blocks. 
2 lines changed or deleted 7 lines changed or added


 basictypes.h   basictypes.h 
// Copyright (c) 2005, Google Inc.
// All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Copyright 2001 - 2003 Google, Inc.
// modification, are permitted provided that the following conditions are
// met:
// //
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef _BASICTYPES_H_ #ifndef _BASICTYPES_H_
#define _BASICTYPES_H_ #define _BASICTYPES_H_
#include <config.h> #include "base/integral_types.h"
#include <string.h> // for memcpy() #include "base/casts.h"
#ifdef HAVE_INTTYPES_H #include "base/port.h"
#include <inttypes.h> // gets us PRId64, etc
#endif //
// Google-specific types
// To use this in an autoconf setting, make sure you run the following //
// autoconf macros:
// AC_HEADER_STDC /* for stdint_h and inttypes_h */ // id for odp categories
// AC_CHECK_TYPES([__int64]) /* defined in some windows platforms */ typedef uint32 CatId;
const CatId kIllegalCatId = static_cast<CatId>(0);
#ifdef HAVE_INTTYPES_H
#include <inttypes.h> // uint16_t might be here; PRId64 too. typedef uint32 TermId;
#endif const TermId kIllegalTermId = static_cast<TermId>(0);
#ifdef HAVE_STDINT_H
#include <stdint.h> // to get uint16_t (ISO naming madness) typedef uint32 HostId;
#endif const HostId kIllegalHostId = static_cast<HostId>(0);
#include <sys/types.h> // our last best hope for uint16_t
typedef uint32 DomainId;
// Standard typedefs const DomainId kIllegalDomainId = static_cast<DomainId>(0);
// All Google code is compiled with -funsigned-char to make "char"
// unsigned. Google code therefore doesn't need a "uchar" type. // Pagerank related types.
// TODO(csilvers): how do we make sure unsigned-char works on non-gcc syste // TODO(user) - we'd like to move this into google3/pagerank/
ms? // prtype.h, but this datatype is used all over and that would be
typedef signed char schar; // a major change.
typedef int8_t int8; // To get a complete picture of all the datatypes used for PageRank
typedef int16_t int16; // and the functions to convert between them, please see google3/
typedef int32_t int32; // pagerank/prtype.h
typedef int64_t int64; typedef uint16 DocumentPageRank; // value in [0, kNumPageRankValues)
const int kNumPageRankValues = 1 << (sizeof(DocumentPageRank) * 8);
// NOTE: unsigned types are DANGEROUS in loops and other arithmetical const DocumentPageRank kIllegalPagerank = 0;
// places. Use the signed types unless your variable represents a bit
// pattern (eg a hash value) or you really need the extra bit. Do NOT // Used for fielded search
// use 'unsigned' to express "this value should always be positive"; typedef int32 FieldValue;
// use assertions for this. const FieldValue kIllegalFieldValue = static_cast<FieldValue>(INT_MAX);
typedef uint8_t uint8; // It is expected that we *never* have a collision of Fingerprints for
typedef uint16_t uint16; // 2 distinct objects. No object has kIllegalFprint as its Fingerprint.
typedef uint32_t uint32; typedef uint64 Fprint;
typedef uint64_t uint64; const Fprint kIllegalFprint = static_cast<Fprint>(0);
const Fprint kMaxFprint = static_cast<Fprint>(kuint64max);
const uint16 kuint16max = ( (uint16) 0xFFFF);
const uint32 kuint32max = ( (uint32) 0xFFFFFFFF); // 64 bit checksum (see common/checksummer.{h,cc})
const uint64 kuint64max = ( (((uint64) kuint32max) << 32) | kuint32max ); typedef uint64 Checksum64;
const int8 kint8max = ( ( int8) 0x7F); const Checksum64 kIllegalChecksum = static_cast<Checksum64>(0);
const int16 kint16max = ( ( int16) 0x7FFF);
const int32 kint32max = ( ( int32) 0x7FFFFFFF); // In contrast to Fingerprints, we *do* expect Hash<i> values to collide
const int64 kint64max = ( ((( int64) kint32max) << 32) | kuint32max ); // from time to time (although we obviously prefer them not to). Also
// note that there is an illegal hash value for each size hash.
const int8 kint8min = ( ( int8) 0x80); typedef uint32 Hash32;
const int16 kint16min = ( ( int16) 0x8000); typedef uint16 Hash16;
const int32 kint32min = ( ( int32) 0x80000000); typedef unsigned char Hash8;
const int64 kint64min = ( ((( int64) kint32min) << 32) | 0 );
const Hash32 kIllegalHash32 = static_cast<Hash32>(4294967295UL); // 2^32
// Define the "portable" printf and scanf macros, if they're not -1
// already there (via the inttypes.h we #included above, hopefully). const Hash16 kIllegalHash16 = static_cast<Hash16>(65535U); // 2^16
// Mostly it's old systems that don't support inttypes.h, so we assume -1
// they're 32 bit. const Hash8 kIllegalHash8 = static_cast<Hash8>(255); // 2^8-
#ifndef PRIx64 1
#define PRIx64 "llx"
#endif // MetatagId refers to metatag-id that we assign to
#ifndef SCNx64 // each metatag <name, value> pair..
#define SCNx64 "llx" typedef uint32 MetatagId;
#endif
#ifndef PRId64 // Argument type used in interfaces that can optionally take ownership
#define PRId64 "lld" // of a passed in argument. If TAKE_OWNERSHIP is passed, the called
#endif // object takes ownership of the argument. Otherwise it does not.
#ifndef SCNd64 enum Ownership {
#define SCNd64 "lld" DO_NOT_TAKE_OWNERSHIP,
#endif TAKE_OWNERSHIP
#ifndef PRIu64
#define PRIu64 "llu"
#endif
#ifndef PRIxPTR
#define PRIxPTR "lx"
#endif
// Also allow for printing of a pthread_t.
#define GPRIuPTHREAD "lu"
#define GPRIxPTHREAD "lx"
#if defined(__CYGWIN__) || defined(__CYGWIN32__) || defined(__APPLE__) || d
efined(__FreeBSD__)
#define PRINTABLE_PTHREAD(pthreadt) reinterpret_cast<uintptr_t>(pthreadt)
#else
#define PRINTABLE_PTHREAD(pthreadt) pthreadt
#endif
// A macro to disallow the evil copy constructor and operator= functions
// This should be used in the private: declarations for a class
#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
// An alternate name that leaves out the moral judgment... :-)
#define DISALLOW_COPY_AND_ASSIGN(TypeName) DISALLOW_EVIL_CONSTRUCTORS(TypeN
ame)
// The COMPILE_ASSERT macro can be used to verify that a compile time
// expression is true. For example, you could use it to verify the
// size of a static array:
//
// COMPILE_ASSERT(sizeof(num_content_type_names) == sizeof(int),
// content_type_names_incorrect_size);
//
// or to make sure a struct is smaller than a certain size:
//
// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
//
// The second argument to the macro is the name of the variable. If
// the expression is false, most compilers will issue a warning/error
// containing the name of the variable.
//
// Implementation details of COMPILE_ASSERT:
//
// - COMPILE_ASSERT works by defining an array type that has -1
// elements (and thus is invalid) when the expression is false.
//
// - The simpler definition
//
// #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1]
//
// does not work, as gcc supports variable-length arrays whose sizes
// are determined at run-time (this is gcc's extension and not part
// of the C++ standard). As a result, gcc fails to reject the
// following code with the simple definition:
//
// int foo;
// COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is
// // not a compile-time constant.
//
// - By using the type CompileAssert<(bool(expr))>, we ensures that
// expr is a compile-time constant. (Template arguments must be
// determined at compile-time.)
//
// - The outter parentheses in CompileAssert<(bool(expr))> are necessary
// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written
//
// CompileAssert<bool(expr)>
//
// instead, these compilers will refuse to compile
//
// COMPILE_ASSERT(5 > 0, some_message);
//
// (They seem to think the ">" in "5 > 0" marks the end of the
// template argument list.)
//
// - The array size is (bool(expr) ? 1 : -1), instead of simply
//
// ((expr) ? 1 : -1).
//
// This is to avoid running into a bug in MS VC 7.1, which
// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
template <bool>
struct CompileAssert {
};
#define COMPILE_ASSERT(expr, msg) \
typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
#define arraysize(a) (sizeof(a) / sizeof(*(a)))
#define OFFSETOF_MEMBER(strct, field) \
(reinterpret_cast<char*>(&reinterpret_cast<strct*>(16)->field) - \
reinterpret_cast<char*>(16))
// bit_cast<Dest,Source> implements the equivalent of
// "*reinterpret_cast<Dest*>(&source)".
//
// The reinterpret_cast method would produce undefined behavior
// according to ISO C++ specification section 3.10 -15 -.
// bit_cast<> calls memcpy() which is blessed by the standard,
// especially by the example in section 3.9.
//
// Fortunately memcpy() is very fast. In optimized mode, with a
// constant size, gcc 2.95.3, gcc 4.0.1, and msvc 7.1 produce inline
// code with the minimal amount of data movement. On a 32-bit system,
// memcpy(d,s,4) compiles to one load and one store, and memcpy(d,s,8)
// compiles to two loads and two stores.
template <class Dest, class Source>
inline Dest bit_cast(const Source& source) {
COMPILE_ASSERT(sizeof(Dest) == sizeof(Source), bitcasting_unequal_sizes);
Dest dest;
memcpy(&dest, &source, sizeof(dest));
return dest;
}
#ifdef HAVE___ATTRIBUTE__
# define ATTRIBUTE_WEAK __attribute__((weak))
# define ATTRIBUTE_NOINLINE __attribute__((noinline))
#else
# define ATTRIBUTE_WEAK
# define ATTRIBUTE_NOINLINE
#endif
// Section attributes are supported for both ELF and Mach-O, but in
// very different ways. Here's the API we provide:
// 1) ATTRIBUTE_SECTION: put this with the declaration of all functions
// you want to be in the same linker section
// 2) DEFINE_ATTRIBUTE_SECTION_VARS: must be called once per unique
// name. You want to make sure this is executed before any
// DECLARE_ATTRIBUTE_SECTION_VARS; the easiest way is to put them
// in the same .cc file. Put this call at the global level.
// 3) INIT_ATTRIBUTE_SECTION_VARS: you can scatter calls to this in
// multiple places to help ensure execution before any
// DECLARE_ATTRIBUTE_SECTION_VARS. You must have at least one
// DEFINE, but you can have many INITs. Put each in its own scope.
// 4) DECLARE_ATTRIBUTE_SECTION_VARS: must be called before using
// ATTRIBUTE_SECTION_START or ATTRIBUTE_SECTION_STOP on a name.
// Put this call at the global level.
// 5) ATTRIBUTE_SECTION_START/ATTRIBUTE_SECTION_STOP: call this to say
// where in memory a given section is. All functions declared with
// ATTRIBUTE_SECTION are guaranteed to be between START and STOP.
#if defined(HAVE___ATTRIBUTE__) && defined(__ELF__)
# define ATTRIBUTE_SECTION(name) __attribute__ ((section (#name)))
// Weak section declaration to be used as a global declaration
// for ATTRIBUTE_SECTION_START|STOP(name) to compile and link
// even without functions with ATTRIBUTE_SECTION(name).
# define DECLARE_ATTRIBUTE_SECTION_VARS(name) \
extern char __start_##name[] ATTRIBUTE_WEAK; \
extern char __stop_##name[] ATTRIBUTE_WEAK
# define INIT_ATTRIBUTE_SECTION_VARS(name) // no-op for ELF
# define DEFINE_ATTRIBUTE_SECTION_VARS(name) // no-op for ELF
// Return void* pointers to start/end of a section of code with functions
// having ATTRIBUTE_SECTION(name), or 0 if no such function exists.
// One must DECLARE_ATTRIBUTE_SECTION(name) for this to compile and link.
# define ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void*>(__start_##n
ame))
# define ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void*>(__stop_##nam
e))
# define HAVE_ATTRIBUTE_SECTION_START 1
#elif defined(HAVE___ATTRIBUTE__) && defined(__MACH__)
# define ATTRIBUTE_SECTION(name) __attribute__ ((section ("__TEXT, " #name)
))
#include <mach-o/getsect.h>
#include <mach-o/dyld.h>
class AssignAttributeStartEnd {
public:
AssignAttributeStartEnd(const char* name, char** pstart, char** pend) {
// Find out what dynamic library name is defined in
if (_dyld_present()) {
for (int i = _dyld_image_count() - 1; i >= 0; --i) {
const mach_header* hdr = _dyld_get_image_header(i);
#ifdef MH_MAGIC_64
if (hdr->magic == MH_MAGIC_64) {
uint64_t len;
*pstart = getsectdatafromheader_64((mach_header_64*)hdr,
"__TEXT", name, &len);
if (*pstart) { // NULL if not defined in this dynamic library
*pstart += _dyld_get_image_vmaddr_slide(i); // correct for re
loc
*pend = *pstart + len;
return;
}
}
#endif
if (hdr->magic == MH_MAGIC) {
uint32_t len;
*pstart = getsectdatafromheader(hdr, "__TEXT", name, &len);
if (*pstart) { // NULL if not defined in this dynamic library
*pstart += _dyld_get_image_vmaddr_slide(i); // correct for re
loc
*pend = *pstart + len;
return;
}
}
}
}
// If we get here, not defined in a dll at all. See if defined statica
lly.
unsigned long len; // don't ask me why this type isn't uint32_t too.
..
*pstart = getsectdata("__TEXT", name, &len);
*pend = *pstart + len;
}
}; };
#define DECLARE_ATTRIBUTE_SECTION_VARS(name) \ // Use these as the mlock_bytes parameter to MLock and MLockGeneral
extern char* __start_##name; \ enum { MLOCK_ALL = -1, MLOCK_NONE = 0 };
extern char* __stop_##name
#define INIT_ATTRIBUTE_SECTION_VARS(name) \
DECLARE_ATTRIBUTE_SECTION_VARS(name); \
static const AssignAttributeStartEnd __assign_##name( \
#name, &__start_##name, &__stop_##name)
#define DEFINE_ATTRIBUTE_SECTION_VARS(name) \
char* __start_##name, *__stop_##name; \
INIT_ATTRIBUTE_SECTION_VARS(name)
# define ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void*>(__start_##n
ame))
# define ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void*>(__stop_##nam
e))
# define HAVE_ATTRIBUTE_SECTION_START 1
#else // not HAVE___ATTRIBUTE__ && __ELF__, nor HAVE___ATTRIBUTE__ && __MA
CH__
# define ATTRIBUTE_SECTION(name)
# define DECLARE_ATTRIBUTE_SECTION_VARS(name)
# define INIT_ATTRIBUTE_SECTION_VARS(name)
# define DEFINE_ATTRIBUTE_SECTION_VARS(name)
# define ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void*>(0))
# define ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void*>(0))
#endif // HAVE___ATTRIBUTE__ and __ELF__ or __MACH__
#if defined(HAVE___ATTRIBUTE__) && (defined(__i386__) || defined(__x86_64__
))
# define CACHELINE_ALIGNED __attribute__((aligned(64)))
#else
# define CACHELINE_ALIGNED
#endif // defined(HAVE___ATTRIBUTE__) && (__i386__ || __x86_64__)
// The following enum should be used only as a constructor argument to indi cate // The following enum should be used only as a constructor argument to indi cate
// that the variable has static storage class, and that the constructor sho uld // that the variable has static storage class, and that the constructor sho uld
// do nothing to its state. It indicates to the reader that it is legal to // do nothing to its state. It indicates to the reader that it is legal to
// declare a static nistance of the class, provided the constructor is give n // declare a static nistance of the class, provided the constructor is give n
// the base::LINKER_INITIALIZED argument. Normally, it is unsafe to declar e a // the base::LINKER_INITIALIZED argument. Normally, it is unsafe to declar e a
// static variable that has a constructor or a destructor because invocatio n // static variable that has a constructor or a destructor because invocatio n
// order is undefined. However, IF the type can be initialized by filling with // order is undefined. However, IF the type can be initialized by filling with
// zeroes (which the loader does for static variables), AND the destructor // zeroes (which the loader does for static variables), AND the type's
also // destructor does nothing to the storage, then a constructor for static in
// does nothing to the storage, then a constructor declared as itialization
// can be declared as
// explicit MyClass(base::LinkerInitialized x) {} // explicit MyClass(base::LinkerInitialized x) {}
// and invoked as // and invoked as
// static MyClass my_variable_name(base::LINKER_INITIALIZED); // static MyClass my_variable_name(base::LINKER_INITIALIZED);
namespace base { namespace base {
enum LinkerInitialized { LINKER_INITIALIZED }; enum LinkerInitialized { LINKER_INITIALIZED };
} }
#endif // _BASICTYPES_H_ #endif // _BASICTYPES_H_
 End of changes. 6 change blocks. 
347 lines changed or deleted 78 lines changed or added


 bgsync.h   bgsync.h 
skipping to change at line 45 skipping to change at line 45
// Gets the head of the buffer, but does not remove it. // Gets the head of the buffer, but does not remove it.
// Returns true if an element was present at the head; // Returns true if an element was present at the head;
// false if the queue was empty. // false if the queue was empty.
virtual bool peek(BSONObj* op) = 0; virtual bool peek(BSONObj* op) = 0;
// Deletes objects in the queue; // Deletes objects in the queue;
// called by sync thread after it has applied an op // called by sync thread after it has applied an op
virtual void consume() = 0; virtual void consume() = 0;
// Returns the member we're currently syncing from (or NULL) // Returns the member we're currently syncing from (or NULL)
virtual Member* getSyncTarget() = 0; virtual const Member* getSyncTarget() = 0;
// wait up to 1 second for more ops to appear // wait up to 1 second for more ops to appear
virtual void waitForMore() = 0; virtual void waitForMore() = 0;
}; };
/** /**
* notifierThread() uses lastOpTimeWritten to inform the sync target wh ere this member is * notifierThread() uses lastOpTimeWritten to inform the sync target wh ere this member is
* currently synced to. * currently synced to.
* *
* Lock order: * Lock order:
skipping to change at line 76 skipping to change at line 76
boost::mutex _mutex; boost::mutex _mutex;
// Production thread // Production thread
BlockingQueue<BSONObj> _buffer; BlockingQueue<BSONObj> _buffer;
OpTime _lastOpTimeFetched; OpTime _lastOpTimeFetched;
long long _lastH; long long _lastH;
// if produce thread should be running // if produce thread should be running
bool _pause; bool _pause;
Member* _currentSyncTarget; const Member* _currentSyncTarget;
// Notifier thread // Notifier thread
// used to wait until another op has been replicated // used to wait until another op has been replicated
boost::condition_variable _lastOpCond; boost::condition_variable _lastOpCond;
boost::mutex _lastOpMutex; boost::mutex _lastOpMutex;
Member* _oplogMarkerTarget; const Member* _oplogMarkerTarget;
OplogReader _oplogMarker; // not locked, only used by notifier thre ad OplogReader _oplogMarker; // not locked, only used by notifier thre ad
OpTime _consumedOpTime; // not locked, only used by notifier thread OpTime _consumedOpTime; // not locked, only used by notifier thread
struct QueueCounter { struct QueueCounter {
QueueCounter(); QueueCounter();
unsigned long long waitTime; unsigned long long waitTime;
unsigned int numElems; unsigned int numElems;
} _queueCounter; } _queueCounter;
BackgroundSync(); BackgroundSync();
skipping to change at line 132 skipping to change at line 132
// starts the producer thread // starts the producer thread
void producerThread(); void producerThread();
// starts the sync target notifying thread // starts the sync target notifying thread
void notifierThread(); void notifierThread();
// Interface implementation // Interface implementation
virtual bool peek(BSONObj* op); virtual bool peek(BSONObj* op);
virtual void consume(); virtual void consume();
virtual Member* getSyncTarget(); virtual const Member* getSyncTarget();
virtual void waitForMore(); virtual void waitForMore();
// For monitoring // For monitoring
BSONObj getCounters(); BSONObj getCounters();
}; };
} // namespace replset } // namespace replset
} // namespace mongo } // namespace mongo
 End of changes. 4 change blocks. 
4 lines changed or deleted 4 lines changed or added


 bson-inl.h   bson-inl.h 
skipping to change at line 244 skipping to change at line 244
return copy(); return copy();
} }
// wrap this element up as a singleton object. // wrap this element up as a singleton object.
inline BSONObj BSONElement::wrap() const { inline BSONObj BSONElement::wrap() const {
BSONObjBuilder b(size()+6); BSONObjBuilder b(size()+6);
b.append(*this); b.append(*this);
return b.obj(); return b.obj();
} }
inline BSONObj BSONElement::wrap( const char * newName ) const { inline BSONObj BSONElement::wrap( const StringData& newName ) const {
BSONObjBuilder b(size()+6+(int)strlen(newName)); BSONObjBuilder b(size() + 6 + newName.size());
b.appendAs(*this,newName); b.appendAs(*this,newName);
return b.obj(); return b.obj();
} }
inline void BSONObj::getFields(unsigned n, const char **fieldNames, BSO NElement *fields) const { inline void BSONObj::getFields(unsigned n, const char **fieldNames, BSO NElement *fields) const {
BSONObjIterator i(*this); BSONObjIterator i(*this);
while ( i.more() ) { while ( i.more() ) {
BSONElement e = i.next(); BSONElement e = i.next();
const char *p = e.fieldName(); const char *p = e.fieldName();
for( unsigned i = 0; i < n; i++ ) { for( unsigned i = 0; i < n; i++ ) {
 End of changes. 1 change blocks. 
2 lines changed or deleted 2 lines changed or added


 bson_field.h   bson_field.h 
skipping to change at line 20 skipping to change at line 20
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli ed.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#pragma once #pragma once
#include <string> #include <string>
#include "mongo/bson/bsonobj.h"
namespace mongo { namespace mongo {
/** /**
* A BSONField holds the name and the type intended for a given BSON el ement. The * A BSONField holds the name and the type intended for a given BSON el ement. The
* class helps documenting and enforcing that field's type. * class helps documenting and enforcing that field's type.
* *
* Example usages: * Example usages:
* *
* In a header file: * In a header file:
* // Determines the types for the fields used in a collection. * // Determines the types for the fields used in a collection.
skipping to change at line 90 skipping to change at line 92
} }
BSONFieldValue<T> operator()(const T& t) const { BSONFieldValue<T> operator()(const T& t) const {
return BSONFieldValue<T>(_name, t); return BSONFieldValue<T>(_name, t);
} }
const std::string& name() const { const std::string& name() const {
return _name; return _name;
} }
string operator()() const { std::string operator()() const {
return _name; return _name;
} }
BSONFieldValue<BSONObj> query(const char * q, const T& t) const; BSONFieldValue<BSONObj> query(const char * q, const T& t) const;
BSONFieldValue<BSONObj> gt(const T& t) const { BSONFieldValue<BSONObj> gt(const T& t) const {
return query("$gt", t); return query("$gt", t);
} }
BSONFieldValue<BSONObj> lt(const T& t) const { BSONFieldValue<BSONObj> lt(const T& t) const {
return query("$lt", t); return query("$lt", t);
} }
BSONFieldValue<BSONObj> ne(const T& t) const {
return query("$ne", t);
}
private: private:
std::string _name; std::string _name;
std::string _longName; std::string _longName;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 3 change blocks. 
1 lines changed or deleted 7 lines changed or added


 bsonelement.h   bsonelement.h 
skipping to change at line 137 skipping to change at line 137
/** Size of the element. /** Size of the element.
@param maxLen If maxLen is specified, don't scan more than maxL en bytes to calculate size. @param maxLen If maxLen is specified, don't scan more than maxL en bytes to calculate size.
*/ */
int size( int maxLen ) const; int size( int maxLen ) const;
int size() const; int size() const;
/** Wrap this element up as a singleton object. */ /** Wrap this element up as a singleton object. */
BSONObj wrap() const; BSONObj wrap() const;
/** Wrap this element up as a singleton object with a new name. */ /** Wrap this element up as a singleton object with a new name. */
BSONObj wrap( const char* newName) const; BSONObj wrap( const StringData& newName) const;
/** field name of the element. e.g., for /** field name of the element. e.g., for
name : "Joe" name : "Joe"
"name" is the fieldname "name" is the fieldname
*/ */
const char * fieldName() const { const char * fieldName() const {
if ( eoo() ) return ""; // no fieldname for it. if ( eoo() ) return ""; // no fieldname for it.
return data + 1; return data + 1;
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 bsonobj.h   bsonobj.h 
skipping to change at line 423 skipping to change at line 423
opALL = 0x0B, opALL = 0x0B,
NIN = 0x0C, NIN = 0x0C,
opEXISTS = 0x0D, opEXISTS = 0x0D,
opMOD = 0x0E, opMOD = 0x0E,
opTYPE = 0x0F, opTYPE = 0x0F,
opREGEX = 0x10, opREGEX = 0x10,
opOPTIONS = 0x11, opOPTIONS = 0x11,
opELEM_MATCH = 0x12, opELEM_MATCH = 0x12,
opNEAR = 0x13, opNEAR = 0x13,
opWITHIN = 0x14, opWITHIN = 0x14,
opMAX_DISTANCE=0x15 opMAX_DISTANCE = 0x15,
opINTERSECT = 0x16,
}; };
/** add all elements of the object to the specified vector */ /** add all elements of the object to the specified vector */
void elems(std::vector<BSONElement> &) const; void elems(std::vector<BSONElement> &) const;
/** add all elements of the object to the specified list */ /** add all elements of the object to the specified list */
void elems(std::list<BSONElement> &) const; void elems(std::list<BSONElement> &) const;
/** add all values of the object to the specified vector. If type mismatches, exception. /** add all values of the object to the specified vector. If type mismatches, exception.
this is most useful when the BSONObj is an array, but can be us ed with non-arrays too in theory. this is most useful when the BSONObj is an array, but can be us ed with non-arrays too in theory.
 End of changes. 1 change blocks. 
1 lines changed or deleted 2 lines changed or added


 bsonobjbuilder.h   bsonobjbuilder.h 
skipping to change at line 365 skipping to change at line 365
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 */
BSONObjBuilder& append(const StringData& fieldName, const StringDat
a& str) {
return append(fieldName, str.data(), (int) str.size()+1);
}
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;
} }
/** Implements builder interface but no-op in ObjBuilder */ /** Implements builder interface but no-op in ObjBuilder */
skipping to change at line 407 skipping to change at line 411
} }
// 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
s a Date, as follows:
*
* builder.appendTimestamp("field", optime.asDate());
*
* 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;
} }
/** /**
Timestamps are a special BSON datatype that is used internally for replication. Timestamps are a special BSON datatype that is used internally for replication.
Append a timestamp element to the object being ebuilt. Append a timestamp element to the object being ebuilt.
skipping to change at line 770 skipping to change at line 781
fill( name ); fill( name );
append( e ); append( e );
return *this; return *this;
} }
BSONArrayBuilder& appendTimestamp(unsigned int sec, unsigned int in c) { BSONArrayBuilder& appendTimestamp(unsigned int sec, unsigned int in c) {
_b.appendTimestamp(num(), sec, inc); _b.appendTimestamp(num(), sec, inc);
return *this; return *this;
} }
BSONArrayBuilder& append(const StringData& s) {
_b.append(num(), s);
return *this;
}
bool isArray() const { bool isArray() const {
return true; return true;
} }
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
 End of changes. 3 change blocks. 
0 lines changed or deleted 18 lines changed or added


 btree.h   btree.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 "mongo/pch.h" #include "mongo/pch.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/diskloc.h" #include "mongo/db/diskloc.h"
#include "mongo/db/pdfile.h" #include "mongo/db/dur.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/key.h" #include "mongo/db/key.h"
namespace mongo { namespace mongo {
/** /**
* Our btree implementation generally follows the standard btree algori thm, * Our btree implementation generally follows the standard btree algori thm,
* which is described in many places. The nodes of our btree are refer red to * which is described in many places. The nodes of our btree are refer red to
* as buckets below. These buckets are of size BucketSize and their bo dy is * as buckets below. These buckets are of size BucketSize and their bo dy is
* an ordered array of <bson key, disk loc> pairs, where disk loc is th e disk * an ordered array of <bson key, disk loc> pairs, where disk loc is th e disk
* location of a document and bson key is a projection of this document into * location of a document and bson key is a projection of this document into
skipping to change at line 253 skipping to change at line 254
verify( la <= 0xffffff ); // must fit in 3 bytes verify( la <= 0xffffff ); // must fit in 3 bytes
if( la < 0 ) { if( la < 0 ) {
if ( la != -1 ) { if ( la != -1 ) {
log() << "btree diskloc isn't negative 1: " << la << en dl; log() << "btree diskloc isn't negative 1: " << la << en dl;
verify ( la == -1 ); verify ( la == -1 );
} }
la = 0; la = 0;
ofs = OurNullOfs; ofs = OurNullOfs;
} }
memcpy(_a, &la, 3); // endian memcpy(_a, &la, 3); // endian
dassert( ofs != 0 );
} }
DiskLoc56Bit& writing() const { DiskLoc56Bit& writing() const {
return *((DiskLoc56Bit*) getDur().writingPtr((void*)this, 7)); return *((DiskLoc56Bit*) getDur().writingPtr((void*)this, 7));
} }
}; };
class BtreeData_V1 { class BtreeData_V1 {
public: public:
typedef DiskLoc56Bit Loc; typedef DiskLoc56Bit Loc;
//typedef DiskLoc Loc; //typedef DiskLoc Loc;
skipping to change at line 380 skipping to change at line 380
const BucketBasics *d = 0; const BucketBasics *d = 0;
return (char*)&(d->data) - (char*)&(d->parent); return (char*)&(d->data) - (char*)&(d->parent);
} }
static int bodySize() { return Version::BucketSize - headerSize(); } static int bodySize() { return Version::BucketSize - headerSize(); }
static int lowWaterMark() { return bodySize() / 2 - Version::KeyMax - sizeof( _KeyNode ) + 1; } // see comment in btree.cpp static int lowWaterMark() { return bodySize() / 2 - Version::KeyMax - sizeof( _KeyNode ) + 1; } // see comment in btree.cpp
// for testing // for testing
int nKeys() const { return this->n; } int nKeys() const { return this->n; }
const DiskLoc getNextChild() const { return this->nextChild; } const DiskLoc getNextChild() const { return this->nextChild; }
// for tree inspection and statistical analysis
// NOTE: topSize and emptySize have different types in BtreeData_V0
and BtreeData_V1
/** Size used for bson storage, including storage of old keys. */
unsigned int getTopSize() const { return static_cast<unsigned int>(
this->topSize); }
/** Size of the empty region. */
unsigned int getEmptySize() const { return static_cast<unsigned int
>(this->emptySize); }
protected: protected:
char * dataAt(short ofs) { return this->data + ofs; } char * dataAt(short ofs) { return this->data + ofs; }
/** Initialize the header for a new node. */ /** Initialize the header for a new node. */
void init(); void init();
/** /**
* Preconditions: * Preconditions:
* - 0 <= keypos <= n * - 0 <= keypos <= n
* - If key is inserted at position keypos, the bucket's keys will still be * - If key is inserted at position keypos, the bucket's keys will still be
skipping to change at line 582 skipping to change at line 590
* - The bson 'key' must fit in the bucket without packing. * - The bson 'key' must fit in the bucket without packing.
* - If 'key' and 'prevChildBucket' are set at index i, the btree * - If 'key' and 'prevChildBucket' are set at index i, the btree
* ordering properties will be maintained. * ordering properties will be maintained.
* Postconditions: * Postconditions:
* - The specified key is set at index i, replacing the existing * - The specified key is set at index i, replacing the existing
* _KeyNode data and without shifting any other _KeyNode objects . * _KeyNode data and without shifting any other _KeyNode objects .
*/ */
void setKey( int i, const DiskLoc recordLoc, const Key& key, const DiskLoc prevChildBucket ); void setKey( int i, const DiskLoc recordLoc, const Key& key, const DiskLoc prevChildBucket );
}; };
class IndexDetails;
class IndexInsertionContinuation; class IndexInsertionContinuation;
template< class V> template< class V>
struct IndexInsertionContinuationImpl; struct IndexInsertionContinuationImpl;
/** /**
* This class adds functionality for manipulating buckets that are asse mbled * This class adds functionality for manipulating buckets that are asse mbled
* in a tree. The requirements for const and non const functions and * in a tree. The requirements for const and non const functions and
* arguments are generally the same as in BtreeBucket. Because this cl ass * arguments are generally the same as in BtreeBucket. Because this cl ass
* deals with tree structure, some functions that are marked const may * deals with tree structure, some functions that are marked const may
* trigger modification of another node in the btree or potentially of the * trigger modification of another node in the btree or potentially of the
* current node. In such cases, the function's implementation explicit ly * current node. In such cases, the function's implementation explicit ly
skipping to change at line 1001 skipping to change at line 1009
* - If the key cannot be replaced, it will be marked as unused. This * - If the key cannot be replaced, it will be marked as unused. This
* is only expected in legacy btrees. * is only expected in legacy btrees.
*/ */
void deleteInternalKey( const DiskLoc thisLoc, int keypos, IndexDet ails &id, const Ordering &order ); void deleteInternalKey( const DiskLoc thisLoc, int keypos, IndexDet ails &id, const Ordering &order );
public: public:
/** simply builds and returns a dup key error message string */ /** simply builds and returns a dup key error message string */
static string dupKeyError( const IndexDetails& idx , const Key& key ); static string dupKeyError( const IndexDetails& idx , const Key& key );
}; };
#pragma pack() #pragma pack()
class FieldRangeVector;
class FieldRangeVectorIterator;
/**
* A Cursor class for Btree iteration.
*
* A BtreeCursor can record its current btree position (noteLoc()) and
then relocate this
* position after a write (checkLoc()). A recorded btree position cons
ists of a btree bucket,
* bucket key offset, and unique btree key. To relocate a unique btree
key, a BtreeCursor first
* checks the btree key at its recorded btree bucket and bucket key off
set. If the key at that
* location does not match the recorded btree key, and an adjacent key
also fails to match,
* the recorded key (or the next existing key following it) is located
in the btree using binary
* search. If the recorded btree bucket is invalidated, the initial re
corded bucket check is
* not attempted (see SERVER-4575).
*/
class BtreeCursor : public Cursor {
protected:
BtreeCursor( NamespaceDetails* nsd , int theIndexNo, const IndexDet
ails& idxDetails );
/*
BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails&,
const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int
direction );
BtreeCursor( NamespaceDetails *_d, int _idxNo, const IndexDetails&
_id,
const shared_ptr< FieldRangeVector > &_bounds, int sing
leIntervalLimit,
int _direction );
*/
virtual void init( const BSONObj &startKey, const BSONObj &endKey,
bool endKeyInclusive, int direction );
virtual void init( const shared_ptr< FieldRangeVector > &_bounds, i
nt singleIntervalLimit, int _direction );
private:
void _finishConstructorInit();
static BtreeCursor* make( NamespaceDetails * nsd , int idxNo , cons
t IndexDetails& indexDetails );
public:
virtual ~BtreeCursor();
/** makes an appropriate subclass depending on the index version */
static BtreeCursor* make( NamespaceDetails *_d, const IndexDetails&
, const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int
direction );
static BtreeCursor* make( NamespaceDetails *_d, const IndexDetails&
_id, const shared_ptr< FieldRangeVector > &_bounds, int _direction );
static BtreeCursor* make( NamespaceDetails *_d, int _idxNo, const I
ndexDetails&, const BSONObj &startKey, const BSONObj &endKey, bool endKeyIn
clusive, int direction );
static BtreeCursor* make( NamespaceDetails *_d, int _idxNo, const I
ndexDetails& _id,
const shared_ptr< FieldRangeVector > &_bou
nds,
int singleIntervalLimit, int _direction );
virtual bool ok() { return !bucket.isNull(); }
virtual bool advance();
virtual void noteLocation(); // updates keyAtKeyOfs...
virtual void checkLocation() = 0;
virtual bool supportGetMore() { return true; }
virtual bool supportYields() { return true; }
/**
* used for multikey index traversal to avoid sending back dups. se
e Matcher::matches().
* if a multikey index traversal:
* if loc has already been sent, returns true.
* otherwise, marks loc as sent.
* @return false if the loc has not been seen
*/
virtual bool getsetdup(DiskLoc loc) {
if( _multikey ) {
pair<set<DiskLoc>::iterator, bool> p = _dups.insert(loc);
return !p.second;
}
return false;
}
virtual bool modifiedKeys() const { return _multikey; }
virtual bool isMultiKey() const { return _multikey; }
/*const _KeyNode& _currKeyNode() const {
verify( !bucket.isNull() );
const _KeyNode& kn = keyNode(keyOfs);
verify( kn.isUsed() );
return kn;
}*/
/** returns BSONObj() if ofs is out of range */
virtual BSONObj keyAt(int ofs) const = 0;
virtual BSONObj currKey() const = 0;
virtual BSONObj indexKeyPattern() { return _order; }
virtual void aboutToDeleteBucket(const DiskLoc& b) {
if ( bucket == b )
keyOfs = -1;
}
virtual DiskLoc currLoc() = 0; // { return !bucket.isNull() ? _cur
rKeyNode().recordLoc : DiskLoc(); }
virtual DiskLoc refLoc() { return currLoc(); }
virtual Record* _current() { return currLoc().rec(); }
virtual BSONObj current() { return BSONObj::make(_current()); }
virtual string toString();
BSONObj prettyKey( const BSONObj &key ) const {
return key.replaceFieldNames( indexDetails.keyPattern() ).clien
tReadable();
}
virtual BSONObj prettyIndexBounds() const;
virtual CoveredIndexMatcher *matcher() const { return _matcher.get(
); }
virtual void setMatcher( shared_ptr< CoveredIndexMatcher > matcher
) { _matcher = matcher; }
virtual const Projection::KeyOnly *keyFieldsOnly() const { return _
keyFieldsOnly.get(); }
virtual void setKeyFieldsOnly( const shared_ptr<Projection::KeyOnly
> &keyFieldsOnly ) {
_keyFieldsOnly = keyFieldsOnly;
}
virtual long long nscanned() { return _nscanned; }
/** for debugging only */
const DiskLoc getBucket() const { return bucket; }
int getKeyOfs() const { return keyOfs; }
// just for unit tests
virtual bool curKeyHasChild() = 0;
protected:
/**
* Our btrees may (rarely) have "unused" keys when items are delete
d.
* Skip past them.
*/
virtual bool skipUnusedKeys() = 0;
bool skipOutOfRangeKeysAndCheckEnd();
void skipAndCheck();
void checkEnd();
/** selective audits on construction */
void audit();
virtual void _audit() = 0;
virtual DiskLoc _locate(const BSONObj& key, const DiskLoc& loc) = 0
;
virtual DiskLoc _advance(const DiskLoc& thisLoc, int& keyOfs, int d
irection, const char *caller) = 0;
virtual void _advanceTo(DiskLoc &thisLoc, int &keyOfs, const BSONOb
j &keyBegin, int keyBeginLen, bool afterKey, const vector< const BSONElemen
t * > &keyEnd, const vector< bool > &keyEndInclusive, const Ordering &order
, int direction ) = 0;
/** set initial bucket */
void initWithoutIndependentFieldRanges();
/** if afterKey is true, we want the first key with values of the k
eyBegin fields greater than keyBegin */
void advanceTo( const BSONObj &keyBegin, int keyBeginLen, bool afte
rKey, const vector< const BSONElement * > &keyEnd, const vector< bool > &ke
yEndInclusive );
// these are set in the construtor
NamespaceDetails * const d;
const int idxNo;
const IndexDetails& indexDetails;
// these are all set in init()
set<DiskLoc> _dups;
BSONObj startKey;
BSONObj endKey;
bool _endKeyInclusive;
bool _multikey; // this must be updated every getmore batch in case
someone added a multikey
BSONObj _order; // this is the same as indexDetails.keyPattern()
Ordering _ordering;
DiskLoc bucket;
int keyOfs;
int _direction; // 1=fwd,-1=reverse
BSONObj keyAtKeyOfs; // so we can tell if things moved around on us
between the query and the getMore call
DiskLoc locAtKeyOfs;
shared_ptr< FieldRangeVector > _bounds;
auto_ptr< FieldRangeVectorIterator > _boundsIterator;
shared_ptr< CoveredIndexMatcher > _matcher;
shared_ptr<Projection::KeyOnly> _keyFieldsOnly;
bool _independentFieldRanges;
long long _nscanned;
};
/** /**
* give us a writable version of the btree bucket (declares write inten t). * give us a writable version of the btree bucket (declares write inten t).
* note it is likely more efficient to declare write intent on somethin g smaller when you can. * note it is likely more efficient to declare write intent on somethin g smaller when you can.
*/ */
template< class V > template< class V >
BtreeBucket<V> * DiskLoc::btreemod() const { BtreeBucket<V> * DiskLoc::btreemod() const {
verify( _a != -1 ); verify( _a != -1 );
BtreeBucket<V> *b = const_cast< BtreeBucket<V> * >( btree<V>() ); BtreeBucket<V> *b = const_cast< BtreeBucket<V> * >( btree<V>() );
return static_cast< BtreeBucket<V>* >( getDur().writingPtr( b, V::B ucketSize ) ); return static_cast< BtreeBucket<V>* >( getDur().writingPtr( b, V::B ucketSize ) );
} }
 End of changes. 7 change blocks. 
211 lines changed or deleted 15 lines changed or added


 btreebuilder.h   btreebuilder.h 
skipping to change at line 46 skipping to change at line 46
auto_ptr< typename V::KeyOwned > keyLast; auto_ptr< typename V::KeyOwned > keyLast;
BSONObj order; BSONObj order;
Ordering ordering; Ordering ordering;
/** true iff commit() completed successfully. */ /** true iff commit() completed successfully. */
bool committed; bool committed;
DiskLoc cur, first; DiskLoc cur, first;
BtreeBucket<V> *b; BtreeBucket<V> *b;
void newBucket(); void newBucket();
void buildNextLevel(DiskLoc); void buildNextLevel(DiskLoc loc, bool mayInterrupt);
void mayCommitProgressDurably(); void mayCommitProgressDurably();
public: public:
~BtreeBuilder();
BtreeBuilder(bool _dupsAllowed, IndexDetails& _idx); BtreeBuilder(bool _dupsAllowed, IndexDetails& _idx);
/** /**
* Preconditions: 'key' is > or >= last key passed to this function (depends on _dupsAllowed) * Preconditions: 'key' is > or >= last key passed to this function (depends on _dupsAllowed)
* Postconditions: 'key' is added to intermediate storage. * Postconditions: 'key' is added to intermediate storage.
*/ */
void addKey(BSONObj& key, DiskLoc loc); void addKey(BSONObj& key, DiskLoc loc);
/** /**
* commit work. if not called, destructor will clean up partially completed work * commit work. if not called, destructor will clean up partially completed work
* (in case exception has happened). * (in case exception has happened).
*/ */
void commit(); void commit(bool mayInterrupt);
unsigned long long getn() { return n; } unsigned long long getn() { return n; }
}; };
} }
 End of changes. 3 change blocks. 
4 lines changed or deleted 2 lines changed or added


 chunk.h   chunk.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 "../bson/util/atomic_int.h" #include "mongo/bson/util/atomic_int.h"
#include "../client/distlock.h" #include "mongo/client/distlock.h"
#include "mongo/s/cluster_constants.h"
#include "shardkey.h" #include "mongo/s/shard.h"
#include "shard.h" #include "mongo/s/shardkey.h"
#include "util.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 182 skipping to change at line 182
/** /**
* Attempt to refresh maximum chunk size from config. * Attempt to refresh maximum chunk size from config.
*/ */
static void refreshChunkSize(); static void refreshChunkSize();
// //
// public constants // public constants
// //
static string chunkMetadataNS;
static int MaxChunkSize; static int MaxChunkSize;
static int MaxObjectPerChunk; static int MaxObjectPerChunk;
static bool ShouldAutoSplit; static bool ShouldAutoSplit;
// //
// accessors and helpers // accessors and helpers
// //
string toString() const; string toString() const;
friend ostream& operator << (ostream& out, const Chunk& c) { return (out << c.toString()); } friend ostream& operator << (ostream& out, const Chunk& c) { return (out << c.toString()); }
// chunk equality is determined by comparing the min and max bounds of the chunk // chunk equality is determined by comparing the min and max bounds of the chunk
bool operator==(const Chunk& s) const; bool operator==(const Chunk& s) const;
bool operator!=(const Chunk& s) const { return ! ( *this == s ); } bool operator!=(const Chunk& s) const { return ! ( *this == s ); }
string getns() const; string getns() const;
const char * getNS() { return "config.chunks"; }
Shard getShard() const { return _shard; } Shard getShard() const { return _shard; }
const ChunkManager* getManager() const { return _manager; } const ChunkManager* getManager() const { return _manager; }
private: private:
// main shard info // main shard info
const ChunkManager * _manager; const ChunkManager * _manager;
BSONObj _min; BSONObj _min;
skipping to change at line 234 skipping to change at line 232
* is simply an ordered list of ascending/descending fiel d names. Examples: * is simply an ordered list of ascending/descending fiel d names. Examples:
* {a : 1, b : -1} is not special. {a : "hashed"} is. * {a : 1, b : -1} is not special. {a : "hashed"} is.
* *
* if sort 1, return lowest key * if sort 1, return lowest key
* if sort -1, return highest key * if sort -1, return highest key
* will return empty object if have none * will return empty object if have none
*/ */
BSONObj _getExtremeKey( int sort ) const; BSONObj _getExtremeKey( int sort ) const;
/** initializes _dataWritten with a random value so that a mongos r estart wouldn't cause delay in splitting */ /** initializes _dataWritten with a random value so that a mongos r estart wouldn't cause delay in splitting */
static long mkDataWritten(); static int mkDataWritten();
ShardKeyPattern skey() const; ShardKeyPattern skey() const;
}; };
class ChunkRange { class ChunkRange {
public: public:
const ChunkManager* getManager() const { return _manager; } const ChunkManager* getManager() const { return _manager; }
Shard getShard() const { return _shard; } Shard getShard() const { return _shard; }
const BSONObj& getMin() const { return _min; } const BSONObj& getMin() const { return _min; }
skipping to change at line 413 skipping to change at line 411
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; ShardChunkVersion getVersion( const Shard& shard ) const;
ShardChunkVersion getVersion() const; ShardChunkVersion getVersion() const;
void getInfo( BSONObjBuilder& b ) const { void getInfo( BSONObjBuilder& b ) const {
b.append( "key" , _key.key() ); b.append(CollectionFields::key(), _key.key());
b.appendBool( "unique" , _unique ); b.appendBool(CollectionFields::unique(), _unique);
_version.addEpochToBSON( b, "lastmod" ); _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;
 End of changes. 5 change blocks. 
12 lines changed or deleted 10 lines changed or added


 chunk_diff.hpp   chunk_diff.hpp 
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 "chunk_diff.h" #include "mongo/s/chunk_diff.h"
#include "mongo/s/cluster_constants.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 91 skipping to change at line 92
// 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(
ShardNS::chunk, diffQuery, 0, 0, 0, 0, ( DEBUG_BUILD ? 2 : 1000000 ) ); ConfigNS::chunk, diffQuery, 0, 0, 0, 0, ( DEBUG_BUILD ? 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 132 skipping to change at line 133
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( d iffChunkDoc, "lastmod" ); ShardChunkVersion chunkVersion = ShardChunkVersion::fromBSON(di ffChunkDoc, ChunkFields::lastmod());
if( diffChunkDoc[ "min" ].type() != Object || diffChunkDoc[ "ma if( diffChunkDoc[ChunkFields::min()].type() != Object ||
x" ].type() != Object || diffChunkDoc[ChunkFields::max()].type() != Object ||
diffChunkDoc[ "shard" ].type() != String ) diffChunkDoc[ChunkFields::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 "
skipping to change at line 158 skipping to change at line 160
// 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[ "shard" ].String() ); ShardType shard = shardFor( diffChunkDoc[ChunkFields::shard()]. String() );
typename map<ShardType, ShardChunkVersion>::iterator shardVersi onIt = _maxShardVersions->find( shard ); typename map<ShardType, ShardChunkVersion>::iterator shardVersi onIt = _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[ "min" ].Obj(), diffChunkDoc[ " removeOverlapping(diffChunkDoc[ChunkFields::min()].Obj(),
max" ].Obj() ); diffChunkDoc[ChunkFields::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[ "min" ].Obj().getOwned(); BSONObj min = chunkDoc[ChunkFields::min()].Obj().getOwned();
BSONObj max = chunkDoc[ "max" ].Obj().getOwned(); BSONObj max = chunkDoc[ChunkFields::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 ) );
} }
skipping to change at line 218 skipping to change at line 221
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
if( numStaleMinorClauses < maxMinorVersionClauses ){ queryB.append(ChunkFields::ns(), _ns);
BSONArrayBuilder queryOrB( queryB.subarrayStart( "$or" ) ); //
// If we have only a few minor versions to refresh, we can be more
selective in our query
//
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" ) );
{ {
BSONObjBuilder queryNewB( queryOrB.subobjStart() ); BSONObjBuilder queryNewB( queryOrB.subobjStart() );
queryNewB.append( "ns", _ns );
{ {
BSONObjBuilder ts( queryNewB.subobjStart( "lastmod" ) ) ; BSONObjBuilder ts(queryNewB.subobjStart(ChunkFields::la stmod()));
// 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, ShardChunkVersion>::const_iterator it = _maxShardVersions->begin(); it != _maxShardVersions->end(); it++ ){
BSONObjBuilder queryShardB( queryOrB.subobjStart() );
queryShardB.append( "ns", _ns ); BSONObjBuilder queryShardB( queryOrB.subobjStart() );
queryShardB.append( "shard", nameFrom( it->first ) ); queryShardB.append(ChunkFields::shard(), nameFrom( it->firs
t ) );
{ {
BSONObjBuilder ts( queryShardB.subobjStart( "lastmod" ) ); BSONObjBuilder ts(queryShardB.subobjStart(ChunkFields:: 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<ShardChunkVersion>::const_iterator it = extraMinorVers ions.begin(); it != extraMinorVersions.end(); it++ ){
BSONObjBuilder queryShardB( queryOrB.subobjStart() );
queryShardB.append( "ns", _ns ); BSONObjBuilder queryShardB( queryOrB.subobjStart() );
{ {
BSONObjBuilder ts( queryShardB.subobjStart( "lastmod" ) ); BSONObjBuilder ts(queryShardB.subobjStart(ChunkFields:: lastmod()));
ts.appendTimestamp( "$gt", it->toLong() ); ts.appendTimestamp( "$gt", it->toLong() );
ts.appendTimestamp( "$lt", ts.appendTimestamp( "$lt",
ShardChunkVersion( it->majorVersion () + 1, 0, OID() ).toLong() ); ShardChunkVersion( it->majorVersion () + 1, 0, OID() ).toLong() );
ts.done(); ts.done();
} }
queryShardB.done(); queryShardB.done();
} }
queryOrB.done(); queryOrB.done();
} }
else{
// BSONObj query = queryB.obj();
// We don't want to send a giant $or query to the server, so ju
st get all the chunks
//
queryB.append( "ns", _ns ); LOG(2) << "major version query from " << *_maxVersion << " and over
} "
<< _maxShardVersions->size() << " shards is " << query << en
dl;
BSONObj query = queryB.obj(); //
// NOTE: IT IS IMPORTANT FOR CONSISTENCY THAT WE SORT BY ASC VERSIO
N, TO HANDLE
// CURSOR YIELDING BETWEEN CHUNKS BEING MIGRATED.
//
// This ensures that changes to chunk version (which will always be
higher) will always
// come *after* our current position in the chunk cursor.
//
// log() << "major version query from " << *_maxVersion << " and ov Query queryObj(query);
er " << _maxShardVersions->size() << " shards is " << query << endl; queryObj.sort(BSON( "lastmod" << 1 ));
return Query( query ); return Query( query );
} }
} // namespace mongo } // namespace mongo
 End of changes. 23 change blocks. 
34 lines changed or deleted 42 lines changed or added


 client.h   client.h 
skipping to change at line 28 skipping to change at line 28
* 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/pch.h"
#include "security.h"
#include "namespace-inl.h" #include "mongo/db/client_common.h"
#include "lasterror.h" #include "mongo/db/d_concurrency.h"
#include "stats/top.h" #include "mongo/db/lasterror.h"
#include "../db/client_common.h"
#include "../util/concurrency/threadlocal.h"
#include "../util/net/message_port.h"
#include "../util/concurrency/rwlock.h"
#include "d_concurrency.h"
#include "mongo/db/lockstate.h" #include "mongo/db/lockstate.h"
#include "mongo/db/namespace-inl.h"
#include "mongo/db/security.h"
#include "mongo/db/stats/top.h"
#include "mongo/util/concurrency/rwlock.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;
class CurOp; class CurOp;
class Command; class Command;
class Client; class Client;
class AbstractMessagingPort; class AbstractMessagingPort;
class LockCollectionForReading; class LockCollectionForReading;
class PageFaultRetryableSection; class PageFaultRetryableSection;
TSP_DECLARE(Client, currentClient) TSP_DECLARE(Client, currentClient)
typedef long long ConnectionId; typedef long long ConnectionId;
/** the database's concept of an outside "client" */ /** the database's concept of an outside "client" */
class Client : public ClientBasic { class Client : public ClientBasic {
static Client *syncThread;
public: public:
// always be in clientsMutex when manipulating this. killop stuff u ses these. // always be in clientsMutex when manipulating this. killop stuff u ses these.
static set<Client*>& clients; static set<Client*>& clients;
static mongo::mutex& clientsMutex; static mongo::mutex& clientsMutex;
static int getActiveClientCount( int& writers , int& readers ); static int getActiveClientCount( int& writers , int& readers );
class Context; class Context;
~Client(); ~Client();
static int recommendedYieldMicros( int * writers = 0 , int * reader s = 0, static int recommendedYieldMicros( int * writers = 0 , int * reader s = 0,
bool needExact = false ); bool needExact = false );
/** each thread which does db operations has a Client object in TLS . /** each thread which does db operations has a Client object in TLS .
skipping to change at line 84 skipping to change at line 83
if( currentClient.get() ) if( currentClient.get() )
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();
/** set so isSyncThread() works */
void iAmSyncThread() {
wassert( syncThread == 0 );
syncThread = this;
}
/** @return true if this client is the replication secondary pull t
hread. not used much, is used in create index sync code. */
bool isSyncThread() const { return this == syncThread; }
string clientAddress(bool includePort=false) const; string clientAddress(bool includePort=false) const;
const AuthenticationInfo * getAuthenticationInfo() const { return & _ai; } const AuthenticationInfo * getAuthenticationInfo() const { return & _ai; }
AuthenticationInfo * getAuthenticationInfo() { return &_ai; } AuthenticationInfo * getAuthenticationInfo() { return &_ai; }
bool isAdmin() { return _ai.isAuthorized( "admin" ); } 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; }
skipping to change at line 113 skipping to change at line 104
/** caution -- use Context class instead */ /** caution -- use Context class instead */
void setContext(Context *c) { _context = c; } void setContext(Context *c) { _context = c; }
/* report what the last operation was. used by getlasterror */ /* report what the last operation was. used by getlasterror */
void appendLastOp( BSONObjBuilder& b ) const; void appendLastOp( BSONObjBuilder& b ) const;
bool isGod() const { return _god; } /* this is for map/reduce write s */ bool isGod() const { return _god; } /* this is for map/reduce write s */
string toString() const; string toString() const;
void gotHandshake( const BSONObj& o ); void gotHandshake( const BSONObj& o );
bool hasRemote() const { return _mp; }
HostAndPort getRemote() const { verify( _mp ); return _mp->remote()
; }
BSONObj getRemoteID() const { return _remoteId; } BSONObj getRemoteID() const { return _remoteId; }
BSONObj getHandshake() const { return _handshake; } BSONObj getHandshake() const { return _handshake; }
AbstractMessagingPort * port() const { return _mp; }
ConnectionId getConnectionId() const { return _connectionId; } ConnectionId getConnectionId() const { return _connectionId; }
bool inPageFaultRetryableSection() const { return _pageFaultRetryab leSection != 0; } bool inPageFaultRetryableSection() const { return _pageFaultRetryab leSection != 0; }
PageFaultRetryableSection* getPageFaultRetryableSection() const { r eturn _pageFaultRetryableSection; } PageFaultRetryableSection* getPageFaultRetryableSection() const { r eturn _pageFaultRetryableSection; }
bool hasWrittenThisPass() const { return _hasWrittenThisPass; } bool hasWrittenThisPass() const { return _hasWrittenThisPass; }
void writeHappened() { _hasWrittenThisPass = true; } void writeHappened() { _hasWrittenThisPass = true; }
void newTopLevelRequest() { _hasWrittenThisPass = false; } void newTopLevelRequest() { _hasWrittenThisPass = false; }
bool allowedToThrowPageFaultException() const; bool allowedToThrowPageFaultException() const;
skipping to change at line 145 skipping to change at line 133
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; AuthenticationInfo _ai;
OpTime _lastOp; OpTime _lastOp;
BSONObj _handshake; BSONObj _handshake;
BSONObj _remoteId; BSONObj _remoteId;
AbstractMessagingPort * const _mp;
bool _hasWrittenThisPass; bool _hasWrittenThisPass;
PageFaultRetryableSection *_pageFaultRetryableSection; PageFaultRetryableSection *_pageFaultRetryableSection;
LockState _ls; LockState _ls;
friend class PageFaultRetryableSection; // TEMP friend class PageFaultRetryableSection; // TEMP
friend class NoPageFaultsAllowed; // TEMP friend class NoPageFaultsAllowed; // TEMP
public: public:
 End of changes. 7 change blocks. 
24 lines changed or deleted 9 lines changed or added


 client_common.h   client_common.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 "../pch.h" #include <boost/scoped_ptr.hpp>
//#include "security.h"
#include "../util/net/hostandport.h" #include "mongo/db/auth/authentication_session.h"
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/util/net/hostandport.h"
#include "mongo/util/net/message_port.h"
namespace mongo { namespace mongo {
class AuthenticationInfo; class AuthenticationInfo;
/** /**
* this is the base class for Client and ClientInfo * this is the base class for Client and ClientInfo
* Client is for mongod * Client is for mongod
* ClientInfo is for mongos * ClientInfo is for mongos
* They should converge slowly * They should converge slowly
* The idea is this has the basic api so that not all code has to be du plicated * The idea is this has the basic api so that not all code has to be du plicated
*/ */
class ClientBasic : boost::noncopyable { class ClientBasic : boost::noncopyable {
public: public:
virtual ~ClientBasic(){} virtual ~ClientBasic(){}
virtual const AuthenticationInfo * getAuthenticationInfo() const = 0; virtual const AuthenticationInfo * getAuthenticationInfo() const = 0;
virtual AuthenticationInfo * getAuthenticationInfo() = 0; virtual AuthenticationInfo * getAuthenticationInfo() = 0;
AuthenticationSession* getAuthenticationSession() { return _authent
virtual bool hasRemote() const = 0; icationSession.get(); }
virtual HostAndPort getRemote() const = 0; void resetAuthenticationSession(AuthenticationSession* newSession)
{
_authenticationSession.reset(newSession);
}
void swapAuthenticationSession(boost::scoped_ptr<AuthenticationSess
ion>& other) {
_authenticationSession.swap(other);
}
AuthorizationManager* getAuthorizationManager() {
massert(16481,
"No AuthorizationManager has been set up for this conne
ction",
_authorizationManager != NULL);
return _authorizationManager.get();
}
// setAuthorizationManager must be called in the initialization of
any ClientBasic that
// corresponds to an incoming client connection.
void setAuthorizationManager(AuthorizationManager* authorizationMan
ager) {
massert(16477,
"An AuthorizationManager has already been set up for th
is connection",
_authorizationManager == NULL);
_authorizationManager.reset(authorizationManager);
}
bool getIsLocalHostConnection() { return getRemote().isLocalHost();
}
virtual bool hasRemote() const { return _messagingPort; }
virtual HostAndPort getRemote() const {
verify( _messagingPort );
return _messagingPort->remote();
}
AbstractMessagingPort * port() const { return _messagingPort; }
static ClientBasic* getCurrent(); static ClientBasic* getCurrent();
static bool hasCurrent();
protected:
ClientBasic(AbstractMessagingPort* messagingPort) : _messagingPort(
messagingPort) {}
private:
boost::scoped_ptr<AuthenticationSession> _authenticationSession;
boost::scoped_ptr<AuthorizationManager> _authorizationManager;
AbstractMessagingPort* const _messagingPort;
}; };
} }
 End of changes. 3 change blocks. 
6 lines changed or deleted 53 lines changed or added


 client_info.h   client_info.h 
skipping to change at line 30 skipping to change at line 30
#include "mongo/pch.h" #include "mongo/pch.h"
#include "mongo/db/client_common.h" #include "mongo/db/client_common.h"
#include "mongo/db/security.h" #include "mongo/db/security.h"
#include "mongo/s/chunk.h" #include "mongo/s/chunk.h"
#include "mongo/s/writeback_listener.h" #include "mongo/s/writeback_listener.h"
#include "mongo/util/net/hostandport.h" #include "mongo/util/net/hostandport.h"
namespace mongo { namespace mongo {
class AbstractMessagingPort;
/** /**
* holds information about a client connected to a mongos * holds information about a client connected to a mongos
* 1 per client socket * 1 per client socket
* currently implemented with a thread local * currently implemented with a thread local
*/ */
class ClientInfo : public ClientBasic { class ClientInfo : public ClientBasic {
public: public:
ClientInfo(); ClientInfo(AbstractMessagingPort* messagingPort);
~ClientInfo(); ~ClientInfo();
/** new request on behalf of a client, adjusts internal state */ /** new request on behalf of a client, adjusts internal state */
void newPeerRequest( const HostAndPort& peer ); void newPeerRequest( const HostAndPort& peer );
/** new request not associated (yet or ever) with a client */ /** new request not associated (yet or ever) with a client */
void newRequest(); void newRequest();
/** client disconnected */ /** client disconnected */
void disconnect(); void disconnect();
skipping to change at line 100 skipping to change at line 102
const BSONObj& options , const BSONObj& options ,
BSONObjBuilder& result , BSONObjBuilder& result ,
string& errmsg, string& errmsg,
bool fromWriteBackListener = false ); bool fromWriteBackListener = false );
/** @return if its ok to auto split from this client */ /** @return if its ok to auto split from this client */
bool autoSplitOk() const { return _autoSplitOk && Chunk::ShouldAuto Split; } bool autoSplitOk() const { return _autoSplitOk && Chunk::ShouldAuto Split; }
void noAutoSplit() { _autoSplitOk = false; } void noAutoSplit() { _autoSplitOk = false; }
static ClientInfo * get(); // Returns whether or not a ClientInfo for this thread has already
been created and stored
// in _tlInfo.
static bool exists();
// Gets the ClientInfo object for this thread from _tlInfo. If no C
lientInfo object exists
// yet for this thread, it creates one.
static ClientInfo * get(AbstractMessagingPort* messagingPort = NULL
);
// Creates a ClientInfo and stores it in _tlInfo
static ClientInfo* create(AbstractMessagingPort* messagingPort);
const AuthenticationInfo* getAuthenticationInfo() const { return (A uthenticationInfo*)&_ai; } const AuthenticationInfo* getAuthenticationInfo() const { return (A uthenticationInfo*)&_ai; }
AuthenticationInfo* getAuthenticationInfo() { return (Authenticatio nInfo*)&_ai; } AuthenticationInfo* getAuthenticationInfo() { return (Authenticatio nInfo*)&_ai; }
bool isAdmin() { return _ai.isAuthorized( "admin" ); } bool isAdmin() { return _ai.isAuthorized( "admin" ); }
private: private:
AuthenticationInfo _ai; AuthenticationInfo _ai;
struct WBInfo { struct WBInfo {
WBInfo( const WriteBackListener::ConnectionIdent& c , OID o ) : ident( c ) , id( o ) {} WBInfo( const WriteBackListener::ConnectionIdent& c , OID o ) : ident( c ) , id( o ) {}
WriteBackListener::ConnectionIdent ident; WriteBackListener::ConnectionIdent ident;
OID id; OID id;
}; };
// Used to set up this thread's AuthorizationManager. Should be ca
lled during the
// initialization of this ClientInfo.
void _setupAuth();
// for getLastError // for getLastError
void _addWriteBack( vector<WBInfo>& all , const BSONObj& o ); void _addWriteBack( vector<WBInfo>& all , const BSONObj& o );
vector<BSONObj> _handleWriteBacks( vector<WBInfo>& all , bool fromW riteBackListener ); vector<BSONObj> _handleWriteBacks( vector<WBInfo>& all , bool fromW riteBackListener );
int _id; // unique client id int _id; // unique client id
HostAndPort _remote; // server:port of remote socket end HostAndPort _remote; // server:port of remote socket end
// we use _a and _b to store shards we've talked to on the current request and the previous // we use _a and _b to store shards we've talked to on the current request and the previous
// we use 2 so we can flip for getLastError type operations // we use 2 so we can flip for getLastError type operations
 End of changes. 4 change blocks. 
2 lines changed or deleted 19 lines changed or added


 clientcursor.h   clientcursor.h 
skipping to change at line 34 skipping to change at line 34
#pragma once #pragma once
#include "mongo/pch.h" #include "mongo/pch.h"
#include <boost/thread/recursive_mutex.hpp> #include <boost/thread/recursive_mutex.hpp>
#include "cursor.h" #include "cursor.h"
#include "jsobj.h" #include "jsobj.h"
#include "../util/net/message.h" #include "../util/net/message.h"
#include "../util/net/listen.h"
#include "../util/background.h" #include "../util/background.h"
#include "cc_by_loc.h"
#include "diskloc.h" #include "diskloc.h"
#include "dbhelpers.h" #include "dbhelpers.h"
#include "matcher.h" #include "matcher.h"
#include "projection.h" #include "projection.h"
#include "s/d_chunk_manager.h" #include "s/d_chunk_manager.h"
#include "mongo/db/keypattern.h" #include "mongo/db/keypattern.h"
#include "mongo/util/elapsed_tracker.h"
namespace mongo { namespace mongo {
typedef boost::recursive_mutex::scoped_lock recursive_scoped_lock; typedef boost::recursive_mutex::scoped_lock recursive_scoped_lock;
typedef long long CursorId; /* passed to the client so it can send back
on getMore */
static const CursorId INVALID_CURSOR_ID = -1; // But see SERVER-5726.
class Cursor; /* internal server cursor base class */ class Cursor; /* internal server cursor base class */
class ClientCursor; class ClientCursor;
class ParsedQuery; class ParsedQuery;
struct ByLocKey {
ByLocKey( const DiskLoc & l , const CursorId& i ) : loc(l), id(i) {
}
static ByLocKey min( const DiskLoc& l ) { return ByLocKey( l , nume
ric_limits<long long>::min() ); }
static ByLocKey max( const DiskLoc& l ) { return ByLocKey( l , nume
ric_limits<long long>::max() ); }
bool operator<( const ByLocKey &other ) const {
int x = loc.compare( other.loc );
if ( x )
return x < 0;
return id < other.id;
}
DiskLoc loc;
CursorId id;
};
/* todo: make this map be per connection. this will prevent cursor hij acking security attacks perhaps. /* todo: make this map be per connection. this will prevent cursor hij acking security attacks perhaps.
* ERH: 9/2010 this may not work since some drivers send getMore over a different connection * ERH: 9/2010 this may not work since some drivers send getMore over a different connection
*/ */
typedef map<CursorId, ClientCursor*> CCById; typedef map<CursorId, ClientCursor*> CCById;
typedef map<ByLocKey, ClientCursor*> CCByLoc;
extern BSONObj id_obj; extern BSONObj id_obj;
class ClientCursor : private boost::noncopyable { class ClientCursor : private boost::noncopyable {
friend class CmdCursorInfo; friend class CmdCursorInfo;
public: public:
static void assertNoCursors(); static void assertNoCursors();
/* use this to assure we don't in the background time out cursor wh ile it is under use. /* use this to assure we don't in the background time out cursor wh ile it is under use.
if you are using noTimeout() already, there is no risk anyway. if you are using noTimeout() already, there is no risk anyway.
skipping to change at line 388 skipping to change at line 367
/** Just for testing. */ /** Just for testing. */
OpTime getSlaveReadTill() const { return _slaveReadTill; } OpTime getSlaveReadTill() const { return _slaveReadTill; }
public: // static methods public: // static methods
static void idleTimeReport(unsigned millis); static void idleTimeReport(unsigned millis);
static void appendStats( BSONObjBuilder& result ); static void appendStats( BSONObjBuilder& result );
static unsigned numCursors() { return clientCursorsById.size(); } static unsigned numCursors() { return clientCursorsById.size(); }
static void informAboutToDeleteBucket(const DiskLoc& b); static void informAboutToDeleteBucket(const DiskLoc& b);
static void aboutToDelete(const DiskLoc& dl); static void aboutToDelete(const NamespaceDetails* nsd, const DiskLo c& dl);
static void find( const string& ns , set<CursorId>& all ); static void find( const string& ns , set<CursorId>& all );
private: // methods private: // methods
// cursors normally timeout after an inactivity period to prevent e xcess memory use // cursors normally timeout after an inactivity period to prevent e xcess memory use
// setting this prevents timeout of the cursor in question. // setting this prevents timeout of the cursor in question.
void noTimeout() { _pinValue++; } void noTimeout() { _pinValue++; }
CCByLoc& byLoc() { return _db->ccByLoc; } CCByLoc& byLoc() { return _db->ccByLoc; }
 End of changes. 7 change blocks. 
28 lines changed or deleted 3 lines changed or added


 cmdline.h   cmdline.h 
skipping to change at line 75 skipping to change at line 75
std::string ourSetName() const { std::string ourSetName() const {
std::string setname; std::string setname;
size_t sl = _replSet.find('/'); size_t sl = _replSet.find('/');
if( sl == std::string::npos ) if( sl == std::string::npos )
return _replSet; return _replSet;
return _replSet.substr(0, sl); return _replSet.substr(0, sl);
} }
bool usingReplSets() const { return !_replSet.empty(); } bool usingReplSets() const { return !_replSet.empty(); }
std::string rsIndexPrefetch;// --indexPrefetch std::string rsIndexPrefetch;// --indexPrefetch
bool indexBuildRetry; // --noIndexBuildRetry
// for master/slave replication // for master/slave replication
std::string source; // --source std::string source; // --source
std::string only; // --only std::string only; // --only
bool quiet; // --quiet bool quiet; // --quiet
bool noTableScan; // --notablescan no table scans allowed bool noTableScan; // --notablescan no table scans allowed
bool prealloc; // --noprealloc no preallocation of data fil es bool prealloc; // --noprealloc no preallocation of data fil es
bool preallocj; // --nopreallocj no preallocation of journal files bool preallocj; // --nopreallocj no preallocation of journal files
bool smallfiles; // --smallfiles allocate smaller data files bool smallfiles; // --smallfiles allocate smaller data files
skipping to change at line 145 skipping to change at line 146
#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
SSLManager* sslServerManager; // currently leaks on close SSLManager* sslServerManager; // currently leaks on close
#endif #endif
/**
* Switches to enable experimental (unsupported) features.
*/
struct ExperimentalFeatures {
ExperimentalFeatures()
: indexStatsCmdEnabled(false)
, storageDetailsCmdEnabled(false)
{}
bool indexStatsCmdEnabled; // -- enableExperimentalIndexStatsCm
d
bool storageDetailsCmdEnabled; // -- enableExperimentalStorageD
etailsCmd
} experimental;
static void launchOk(); static void launchOk();
static void addGlobalOptions( boost::program_options::options_descr iption& general , static void addGlobalOptions( boost::program_options::options_descr iption& general ,
boost::program_options::options_descr iption& hidden , boost::program_options::options_descr iption& hidden ,
boost::program_options::options_descr iption& ssl_options ); boost::program_options::options_descr iption& ssl_options );
static void addWindowsOptions( boost::program_options::options_desc ription& windows , static void addWindowsOptions( boost::program_options::options_desc ription& windows ,
boost::program_options::options_desc ription& hidden ); boost::program_options::options_desc ription& hidden );
static void parseConfigFile( istream &f, std::stringstream &ss); static void parseConfigFile( istream &f, std::stringstream &ss);
skipping to change at line 178 skipping to change at line 191
static void censor(std::vector<std::string>* args); static void censor(std::vector<std::string>* args);
static BSONArray getArgvArray(); static BSONArray getArgvArray();
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), 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(false), oplogSize(0), defaultProfile(0),
slowMS(100), defaultLocalThresholdMillis(15), pretouch(0), movePara noia( true ), slowMS(100), defaultLocalThresholdMillis(15), pretouch(0), movePara noia( true ),
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
 End of changes. 3 change blocks. 
1 lines changed or deleted 16 lines changed or added


 commandlineflags.h   commandlineflags.h 
// Copyright (c) 2005, Google Inc. // Copyright 2010 Google
// All rights reserved. // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// //
// Redistribution and use in source and binary forms, with or without // http://www.apache.org/licenses/LICENSE-2.0
// modification, are permitted provided that the following conditions are
// met:
// //
// * Redistributions of source code must retain the above copyright // Unless required by applicable law or agreed to in writing, software
// notice, this list of conditions and the following disclaimer. // distributed under the License is distributed on an "AS IS" BASIS,
// * Redistributions in binary form must reproduce the above // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// copyright notice, this list of conditions and the following disclaimer // See the License for the specific language governing permissions and
// in the documentation and/or other materials provided with the // limitations under the License.
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ---
// This file is a compatibility layer that defines Google's version of
// command line flags that are used for configuration.
//
// We put flags into their own namespace. It is purposefully
// named in an opaque way that people should have trouble typing
// directly. The idea is that DEFINE puts the flag in the weird
// namespace, and DECLARE imports the flag from there into the
// current namespace. The net result is to force people to use
// DECLARE to get access to a flag, rather than saying
// extern bool FLAGS_logtostderr;
// or some such instead. We want this so we can put extra
// functionality (like sanity-checking) in DECLARE if we want,
// and make sure it is picked up everywhere.
//
// We also put the type of the variable in the namespace, so that
// people can't DECLARE_int32 something that they DEFINE_bool'd
// elsewhere.
#ifndef BASE_COMMANDLINEFLAGS_H_
#define BASE_COMMANDLINEFLAGS_H_
#include <config.h>
#include <string>
#include <string.h> // for memchr
#include <stdlib.h> // for getenv
#include "base/basictypes.h"
#define DECLARE_VARIABLE(type, name)
\
namespace FLAG__namespace_do_not_use_directly_use_DECLARE_##type##_instea
d { \
extern PERFTOOLS_DLL_DECL type FLAGS_##name;
\
}
\
using FLAG__namespace_do_not_use_directly_use_DECLARE_##type##_instead::F
LAGS_##name
#define DEFINE_VARIABLE(type, name, value, meaning) \
namespace FLAG__namespace_do_not_use_directly_use_DECLARE_##type##_instea
d { \
PERFTOOLS_DLL_DECL type FLAGS_##name(value);
\
char FLAGS_no##name;
\
}
\
using FLAG__namespace_do_not_use_directly_use_DECLARE_##type##_instead::F
LAGS_##name
// bool specialization
#define DECLARE_bool(name) \
DECLARE_VARIABLE(bool, name)
#define DEFINE_bool(name, value, meaning) \
DEFINE_VARIABLE(bool, name, value, meaning)
// int32 specialization
#define DECLARE_int32(name) \
DECLARE_VARIABLE(int32, name)
#define DEFINE_int32(name, value, meaning) \
DEFINE_VARIABLE(int32, name, value, meaning)
// int64 specialization
#define DECLARE_int64(name) \
DECLARE_VARIABLE(int64, name)
#define DEFINE_int64(name, value, meaning) \
DEFINE_VARIABLE(int64, name, value, meaning)
#define DECLARE_uint64(name) \
DECLARE_VARIABLE(uint64, name)
#define DEFINE_uint64(name, value, meaning) \
DEFINE_VARIABLE(uint64, name, value, meaning)
// double specialization
#define DECLARE_double(name) \
DECLARE_VARIABLE(double, name)
#define DEFINE_double(name, value, meaning) \
DEFINE_VARIABLE(double, name, value, meaning)
// Special case for string, because we have to specify the namespace
// std::string, which doesn't play nicely with our FLAG__namespace hackery.
#define DECLARE_string(name) \
namespace FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead
{ \
extern std::string FLAGS_##name;
\
}
\
using FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead::FLA
GS_##name
#define DEFINE_string(name, value, meaning) \
namespace FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead
{ \
std::string FLAGS_##name(value);
\
char FLAGS_no##name;
\
}
\
using FLAG__namespace_do_not_use_directly_use_DECLARE_string_instead::FLA
GS_##name
// These macros (could be functions, but I don't want to bother with a .cc
// file), make it easier to initialize flags from the environment.
#define EnvToString(envname, dflt) \
(!getenv(envname) ? (dflt) : getenv(envname))
#define EnvToBool(envname, dflt) \
(!getenv(envname) ? (dflt) : memchr("tTyY1\0", getenv(envname)[0], 6) !=
NULL)
#define EnvToInt(envname, dflt) \
(!getenv(envname) ? (dflt) : strtol(getenv(envname), NULL, 10))
#define EnvToInt64(envname, dflt) \ #ifndef BASE_COMMANDLINEFLAGS_H
(!getenv(envname) ? (dflt) : strtoll(getenv(envname), NULL, 10)) #define BASE_COMMANDLINEFLAGS_H
#define EnvToDouble(envname, dflt) \ #include "gflags/gflags.h"
(!getenv(envname) ? (dflt) : strtod(getenv(envname), NULL))
#endif // BASE_COMMANDLINEFLAGS_H_ #endif // BASE_COMMANDLINEFLAGS_H
 End of changes. 6 change blocks. 
145 lines changed or deleted 13 lines changed or added


 commands.h   commands.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 "jsobj.h" #include <vector>
#include "../util/mongoutils/str.h"
#include "mongo/db/auth/privilege.h"
#include "mongo/db/jsobj.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;
/** mongodb "commands" (sent via db.$cmd.findOne(...)) /** mongodb "commands" (sent via db.$cmd.findOne(...))
subclass to make a command. define a singleton object for it. subclass to make a command. define a singleton object for it.
skipping to change at line 109 skipping to change at line 112
*/ */
virtual bool logTheOp() { return false; } virtual bool logTheOp() { return false; }
virtual void help( stringstream& help ) const; virtual void help( stringstream& help ) const;
/* Return true if authentication and security applies to the comman ds. Some commands /* Return true if authentication and security applies to the comman ds. Some commands
(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
* the invocation described by "cmdObj".
*/
virtual void addRequiredPrivileges(const std::string& dbname,
const BSONObj& cmdObj,
std::vector<Privilege>* out);
/* 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 */ }
 End of changes. 2 change blocks. 
2 lines changed or deleted 14 lines changed or added


 compact.h   compact.h 
skipping to change at line 35 skipping to change at line 35
SortPhaseOne() { SortPhaseOne() {
n = 0; n = 0;
nkeys = 0; nkeys = 0;
multi = false; multi = false;
} }
shared_ptr<BSONObjExternalSorter> sorter; shared_ptr<BSONObjExternalSorter> sorter;
unsigned long long n; // # of records unsigned long long n; // # of records
unsigned long long nkeys; unsigned long long nkeys;
bool multi; // multikey index bool multi; // multikey index
void addKeys(const IndexSpec& spec, const BSONObj& o, DiskLoc loc) { void addKeys(const IndexSpec& spec, const BSONObj& o, DiskLoc loc, bool mayInterrupt) {
BSONObjSet keys; BSONObjSet keys;
spec.getKeys(o, keys); spec.getKeys(o, keys);
int k = 0; int k = 0;
for ( BSONObjSet::iterator i=keys.begin(); i != keys.end(); i++ ) { for ( BSONObjSet::iterator i=keys.begin(); i != keys.end(); i++ ) {
if( ++k == 2 ) { if( ++k == 2 ) {
multi = true; multi = true;
} }
sorter->add(*i, loc); sorter->add(*i, loc, mayInterrupt);
nkeys++; nkeys++;
} }
n++; n++;
} }
}; };
} }
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 config.h   config.h 
skipping to change at line 37 skipping to change at line 37
#include "../client/model.h" #include "../client/model.h"
#include "mongo/client/dbclient_rs.h" #include "mongo/client/dbclient_rs.h"
#include "chunk.h" #include "chunk.h"
#include "shard.h" #include "shard.h"
#include "shardkey.h" #include "shardkey.h"
namespace mongo { namespace mongo {
struct ShardNS { struct ShardNS {
static string shard;
static string database;
static string collection;
static string chunk;
static string tags;
static string mongos; static string mongos;
static string settings; static string settings;
}; };
/**
* Field names used in the 'shards' collection.
*/
struct ShardFields {
static BSONField<bool> draining; // is it draining chunks?
static BSONField<long long> maxSize; // max allowed disk space usa
ge
};
class ConfigServer; class ConfigServer;
class DBConfig; class DBConfig;
typedef boost::shared_ptr<DBConfig> DBConfigPtr; typedef boost::shared_ptr<DBConfig> DBConfigPtr;
typedef shared_ptr<Shard> ShardPtr;
extern DBConfigPtr configServerPtr; extern DBConfigPtr configServerPtr;
extern ConfigServer& configServer; extern ConfigServer& configServer;
/** /**
* top level configuration for a database * top level configuration for a database
*/ */
class DBConfig { class DBConfig {
struct CollectionInfo { struct CollectionInfo {
skipping to change at line 135 skipping to change at line 119
string getName() const { return _name; }; string getName() const { return _name; };
/** /**
* @return if anything in this db is partitioned or not * @return if anything in this db is partitioned or not
*/ */
bool isShardingEnabled() { bool isShardingEnabled() {
return _shardingEnabled; return _shardingEnabled;
} }
void enableSharding( bool save = true ); void enableSharding( bool save = true );
ChunkManagerPtr shardCollection( const string& ns , ShardKeyPattern
fieldsAndOrder , bool unique , vector<BSONObj>* initPoints=0, vector<Shard /* Makes all the configuration changes necessary to shard a new col
>* initShards=0 ); lection.
* Optionally, chunks will be created based on a set of specified i
nitial split points, and
* distributed in a round-robin fashion onto a set of initial shard
s. If no initial shards
* are specified, only the primary will be used.
*
* WARNING: It's not safe to place initial chunks onto non-primary
shards using this method.
* The initShards parameter allows legacy behavior expected by map-
reduce.
*/
ChunkManagerPtr shardCollection( const string& ns ,
ShardKeyPattern fieldsAndOrder ,
bool unique ,
vector<BSONObj>* initPoints = 0,
vector<Shard>* initShards = 0 );
/** /**
@return true if there was sharding info to remove @return true if there was sharding info to remove
*/ */
bool removeSharding( const string& ns ); bool removeSharding( const string& ns );
/** /**
* @return whether or not the 'ns' collection is partitioned * @return whether or not the 'ns' collection is partitioned
*/ */
bool isSharded( const string& ns ); bool isSharded( const string& ns );
 End of changes. 4 change blocks. 
20 lines changed or deleted 19 lines changed or added


 connpool.h   connpool.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 <stack> #include <stack>
#include "mongo/util/background.h" #include "mongo/util/background.h"
#include "mongo/client/dbclientinterface.h" #include "mongo/client/dbclientinterface.h"
#include "mongo/platform/cstdint.h"
namespace mongo { namespace mongo {
class Shard; class Shard;
class DBConnectionPool; class DBConnectionPool;
/** /**
* not thread safe * not thread safe
* thread safety is handled by DBConnectionPool * thread safety is handled by DBConnectionPool
*/ */
class PoolForHost { class PoolForHost {
public: public:
PoolForHost() PoolForHost()
: _created(0) {} : _created(0), _minValidCreationTimeMicroSec(0) {}
PoolForHost( const PoolForHost& other ) { PoolForHost( const PoolForHost& other ) {
verify(other._pool.size() == 0); verify(other._pool.size() == 0);
_created = other._created; _created = other._created;
_minValidCreationTimeMicroSec = other._minValidCreationTimeMicr oSec;
verify( _created == 0 ); verify( _created == 0 );
} }
~PoolForHost(); ~PoolForHost();
int numAvailable() const { return (int)_pool.size(); } int numAvailable() const { return (int)_pool.size(); }
void createdOne( DBClientBase * base ); void createdOne( DBClientBase * base );
long long numCreated() const { return _created; } long long numCreated() const { return _created; }
skipping to change at line 68 skipping to change at line 70
// Deletes all connections in the pool // Deletes all connections in the pool
void clear(); void clear();
void done( DBConnectionPool * pool , DBClientBase * c ); void done( DBConnectionPool * pool , DBClientBase * c );
void flush(); void flush();
void getStaleConnections( vector<DBClientBase*>& stale ); void getStaleConnections( vector<DBClientBase*>& stale );
/**
* Sets the lower bound for creation times that can be considered a
s
* good connections.
*/
void reportBadConnectionAt(uint64_t microSec);
/**
* @return true if the given creation time is considered to be not
* good for use.
*/
bool isBadSocketCreationTime(uint64_t microSec);
/**
* Sets the host name to a new one, only if it is currently empty.
*/
void initializeHostName(const std::string& hostName);
static void setMaxPerHost( unsigned max ) { _maxPerHost = max; } static void setMaxPerHost( unsigned max ) { _maxPerHost = max; }
static unsigned getMaxPerHost() { return _maxPerHost; } static unsigned getMaxPerHost() { return _maxPerHost; }
private: private:
struct StoredConnection { struct StoredConnection {
StoredConnection( DBClientBase * c ); StoredConnection( DBClientBase * c );
bool ok( time_t now ); bool ok( time_t now );
DBClientBase* conn; DBClientBase* conn;
time_t when; time_t when;
}; };
std::string _hostName;
std::stack<StoredConnection> _pool; std::stack<StoredConnection> _pool;
long long _created; int64_t _created;
uint64_t _minValidCreationTimeMicroSec;
ConnectionString::ConnectionType _type; ConnectionString::ConnectionType _type;
static unsigned _maxPerHost; static unsigned _maxPerHost;
}; };
class DBConnectionHook { class DBConnectionHook {
public: public:
virtual ~DBConnectionHook() {} virtual ~DBConnectionHook() {}
virtual void onCreate( DBClientBase * conn ) {} virtual void onCreate( DBClientBase * conn ) {}
virtual void onHandedOut( DBClientBase * conn ) {} virtual void onHandedOut( DBClientBase * conn ) {}
skipping to change at line 136 skipping to change at line 157
void flush(); void flush();
DBClientBase *get(const string& host, double socketTimeout = 0); DBClientBase *get(const string& host, double socketTimeout = 0);
DBClientBase *get(const ConnectionString& host, double socketTimeou t = 0); DBClientBase *get(const ConnectionString& host, double socketTimeou t = 0);
void release(const string& host, DBClientBase *c); void release(const string& host, DBClientBase *c);
void addHook( DBConnectionHook * hook ); // we take ownership void addHook( DBConnectionHook * hook ); // we take ownership
void appendInfo( BSONObjBuilder& b ); void appendInfo( BSONObjBuilder& b );
/**
* Clears all connections for all host.
*/
void clear();
/**
* Checks whether the connection for a given host is black listed o
r not.
*
* @param hostName the name of the host the connection connects to.
* @param conn the connection to check.
*
* @return true if the connection is not bad, meaning, it is good t
o keep it for
* future use.
*/
bool isConnectionGood(const string& host, DBClientBase* conn);
// Removes and deletes all connections from the pool for the host ( regardless of timeout) // Removes and deletes all connections from the pool for the host ( regardless of timeout)
void removeHost( const string& host ); void removeHost( const string& host );
/** compares server namees, but is smart about replica set names */ /** compares server namees, but is smart about replica set names */
struct serverNameCompare { struct serverNameCompare {
bool operator()( const string& a , const string& b ) const; bool operator()( const string& a , const string& b ) const;
}; };
virtual string taskName() const { return "DBConnectionPool-cleaner" ; } virtual string taskName() const { return "DBConnectionPool-cleaner" ; }
virtual void taskDoWork(); virtual void taskDoWork();
skipping to change at line 242 skipping to change at line 279
// Gets a ScopedDbConnection designed to be used for internal commu nication within a cluster // Gets a ScopedDbConnection designed to be used for internal commu nication within a cluster
// The mongod/mongos implementations of these set the Authenticatio nTable on the underlying // 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 // 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 // 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(). // 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. // 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(); static ScopedDbConnection* getInternalScopedDbConnection();
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;
} }
/** get the associated connection object */ /** get the associated connection object */
DBClientBase& conn() { DBClientBase& conn() {
 End of changes. 8 change blocks. 
2 lines changed or deleted 44 lines changed or added


 core.h   core.h 
// core.h // core.h
/** /**
* Copyright (C) 2008 10gen Inc. * Copyright (C) 2008-2012 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 "mongo/pch.h" #include "mongo/pch.h"
#include "../jsobj.h" #include "mongo/db/jsobj.h"
#include "mongo/util/mongoutils/str.h"
#include <cmath> #include <cmath>
#ifndef M_PI #ifndef M_PI
# define M_PI 3.14159265358979323846 # define M_PI 3.14159265358979323846
#endif #endif
namespace mongo { #if 0
# define CDEBUG -1
class GeoBitSets { #else
public: # define CDEBUG 10
GeoBitSets() { #endif
for ( int i=0; i<32; i++ ) {
masks32[i] = ( 1 << ( 31 - i ) );
}
for ( int i=0; i<64; i++ ) {
masks64[i] = ( 1LL << ( 63 - i ) );
}
for ( unsigned i=0; i<16; i++ ) {
unsigned fixed = 0;
for ( int j=0; j<4; j++ ) {
if ( i & ( 1 << j ) )
fixed |= ( 1 << ( j * 2 ) );
}
hashedToNormal[fixed] = i;
}
long long currAllX = 0, currAllY = 0;
for ( int i = 0; i < 64; i++ ){
if( i % 2 == 0 ){
allX[ i / 2 ] = currAllX;
currAllX = currAllX + ( 1LL << ( 63 - i ) );
}
else{
allY[ i / 2 ] = currAllY;
currAllY = currAllY + ( 1LL << ( 63 - i ) );
}
}
}
int masks32[32];
long long masks64[64];
long long allX[32];
long long allY[32];
unsigned hashedToNormal[256];
};
extern GeoBitSets geoBitSets;
class GeoHash {
public:
GeoHash()
: _hash(0),_bits(0) {
}
explicit GeoHash( const char * hash ) {
init( hash );
}
explicit GeoHash( const string& hash ) {
init( hash );
}
static GeoHash makeFromBinData(const char *bindata, unsigned bits)
{
GeoHash h;
h._bits = bits;
h._copy( (char*)&h._hash , bindata );
h._fix();
return h;
}
explicit GeoHash( const BSONElement& e , unsigned bits=32 ) {
_bits = bits;
if ( e.type() == BinData ) {
int len = 0;
_copy( (char*)&_hash , e.binData( len ) );
verify( len == 8 );
_bits = bits;
}
else {
cout << "GeoHash bad element: " << e << endl;
uassert(13047,"wrong type for geo index. if you're using a
pre-release version, need to rebuild index",0);
}
_fix();
}
GeoHash( unsigned x , unsigned y , unsigned bits=32) {
init( x , y , bits );
}
GeoHash( const GeoHash& old ) {
_hash = old._hash;
_bits = old._bits;
}
GeoHash( long long hash , unsigned bits )
: _hash( hash ) , _bits( bits ) {
_fix();
}
void init( unsigned x , unsigned y , unsigned bits ) {
verify( bits <= 32 );
_hash = 0;
_bits = bits;
for ( unsigned i=0; i<bits; i++ ) {
if ( isBitSet( x , i ) ) _hash |= geoBitSets.masks64[i*2];
if ( isBitSet( y , i ) ) _hash |= geoBitSets.masks64[(i*2)+
1];
}
}
void unhash_fast( unsigned& x , unsigned& y ) const {
x = 0;
y = 0;
char * c = (char*)(&_hash);
for ( int i=0; i<8; i++ ) {
unsigned t = (unsigned)(c[i]) & 0x55;
y |= ( geoBitSets.hashedToNormal[t] << (4*(i)) );
t = ( (unsigned)(c[i]) >> 1 ) & 0x55;
x |= ( geoBitSets.hashedToNormal[t] << (4*(i)) );
}
}
void unhash_slow( unsigned& x , unsigned& y ) const {
x = 0;
y = 0;
for ( unsigned i=0; i<_bits; i++ ) {
if ( getBitX(i) )
x |= geoBitSets.masks32[i];
if ( getBitY(i) )
y |= geoBitSets.masks32[i];
}
}
void unhash( unsigned& x , unsigned& y ) const {
unhash_fast( x , y );
}
/**
* @param 0 = high
*/
static bool isBitSet( unsigned val , unsigned bit ) {
return geoBitSets.masks32[bit] & val;
}
GeoHash up() const {
return GeoHash( _hash , _bits - 1 );
}
bool hasPrefix( const GeoHash& other ) const {
verify( other._bits <= _bits );
if ( other._bits == 0 )
return true;
long long x = other._hash ^ _hash;
x = x >> (64-(other._bits*2));
return x == 0;
}
string toString() const {
StringBuilder buf;
for ( unsigned x=0; x<_bits*2; x++ )
buf.append( _hash & geoBitSets.masks64[x] ? "1" : "0" );
return buf.str();
}
string toStringHex1() const {
stringstream ss;
ss << hex << _hash;
return ss.str();
}
void init( const string& s ) {
_hash = 0;
_bits = s.size() / 2;
for ( unsigned pos=0; pos<s.size(); pos++ )
if ( s[pos] == '1' )
setBit( pos , 1 );
}
void setBit( unsigned pos , bool one ) {
verify( pos < _bits * 2 );
if ( one )
_hash |= geoBitSets.masks64[pos];
else if ( _hash & geoBitSets.masks64[pos] )
_hash &= ~geoBitSets.masks64[pos];
}
bool getBit( unsigned pos ) const {
return _hash & geoBitSets.masks64[pos];
}
bool getBitX( unsigned pos ) const {
verify( pos < 32 );
return getBit( pos * 2 );
}
bool getBitY( unsigned pos ) const {
verify( pos < 32 );
return getBit( ( pos * 2 ) + 1 );
}
BSONObj wrap( const char* name = "" ) const {
BSONObjBuilder b(20);
append( b , name );
BSONObj o = b.obj();
if( ! strlen( name ) ) verify( o.objsize() == 20 );
return o;
}
bool constrains() const {
return _bits > 0;
}
bool canRefine() const {
return _bits < 32;
}
bool atMinX() const {
return ( _hash & geoBitSets.allX[ _bits ] ) == 0;
}
bool atMinY() const {
//log() << " MinY : " << hex << (unsigned long long) _hash << "
" << _bits << " " << hex << (unsigned long long) geoBitSets.allY[ _bits ]
<< endl;
return ( _hash & geoBitSets.allY[ _bits ] ) == 0;
}
bool atMaxX() const {
return ( _hash & geoBitSets.allX[ _bits ] ) == geoBitSets.allX[
_bits ];
}
bool atMaxY() const {
return ( _hash & geoBitSets.allY[ _bits ] ) == geoBitSets.allY[
_bits ];
}
void move( int x , int y ) {
verify( _bits );
_move( 0 , x );
_move( 1 , y );
}
void _move( unsigned offset , int d ) {
if ( d == 0 )
return;
verify( d <= 1 && d>= -1 ); // TEMP
bool from, to;
if ( d > 0 ) {
from = 0;
to = 1;
}
else {
from = 1;
to = 0;
}
unsigned pos = ( _bits * 2 ) - 1;
if ( offset == 0 )
pos--;
while ( true ) {
if ( getBit(pos) == from ) {
setBit( pos , to );
return;
}
if ( pos < 2 ) {
// overflow
for ( ; pos < ( _bits * 2 ) ; pos += 2 ) {
setBit( pos , from );
}
return;
}
setBit( pos , from );
pos -= 2;
}
verify(0);
}
GeoHash& operator=(const GeoHash& h) {
_hash = h._hash;
_bits = h._bits;
return *this;
}
bool operator==(const GeoHash& h ) const {
return _hash == h._hash && _bits == h._bits;
}
bool operator!=(const GeoHash& h ) const {
return !( *this == h );
}
bool operator<(const GeoHash& h ) const {
if( _hash != h._hash ) return _hash < h._hash;
return _bits < h._bits;
}
GeoHash& operator+=( const char * s ) {
unsigned pos = _bits * 2;
_bits += strlen(s) / 2;
verify( _bits <= 32 );
while ( s[0] ) {
if ( s[0] == '1' )
setBit( pos , 1 );
pos++;
s++;
}
return *this;
}
GeoHash operator+( const char * s ) const {
GeoHash n = *this;
n+=s;
return n;
}
GeoHash operator+( const std::string& s ) const {
return operator+( s.c_str() );
}
void _fix() {
static long long FULL = 0xFFFFFFFFFFFFFFFFLL;
long long mask = FULL << ( 64 - ( _bits * 2 ) );
_hash &= mask;
}
void append( BSONObjBuilder& b , const char * name ) const {
char buf[8];
_copy( buf , (char*)&_hash );
b.appendBinData( name , 8 , bdtCustom , buf );
}
long long getHash() const {
return _hash;
}
unsigned getBits() const {
return _bits;
}
GeoHash commonPrefix( const GeoHash& other ) const {
unsigned i=0;
for ( ; i<_bits && i<other._bits; i++ ) {
if ( getBitX( i ) == other.getBitX( i ) &&
getBitY( i ) == other.getBitY( i ) )
continue;
break;
}
return GeoHash(_hash,i);
}
private:
static void _copy( char * dst , const char * src ) {
for ( unsigned a=0; a<8; a++ ) {
dst[a] = src[7-a];
}
}
long long _hash;
unsigned _bits; // bits per field, so 1 to 32
};
inline ostream& operator<<( ostream &s, const GeoHash &h ) {
s << h.toString();
return s;
}
class GeoConvert {
public:
virtual ~GeoConvert() {}
virtual void unhash( const GeoHash& h , double& x , double& y ) con
st = 0;
virtual GeoHash hash( double x , double y ) const = 0;
};
class Point {
public:
Point( const GeoConvert * g , const GeoHash& hash ) {
g->unhash( hash , _x , _y );
}
explicit Point( const BSONElement& e ) {
BSONObjIterator i(e.Obj());
_x = i.next().number();
_y = i.next().number();
}
explicit Point( const BSONObj& o ) {
BSONObjIterator i(o);
_x = i.next().number();
_y = i.next().number();
}
Point( double x , double y )
: _x( x ) , _y( y ) {
}
Point() : _x(0),_y(0) {
}
GeoHash hash( const GeoConvert * g ) {
return g->hash( _x , _y );
}
double distance( const Point& p ) const {
double a = _x - p._x;
double b = _y - p._y;
// Avoid numerical error if possible...
if( a == 0 ) return abs( _y - p._y );
if( b == 0 ) return abs( _x - p._x );
return sqrt( ( a * a ) + ( b * b ) );
}
/**
* Distance method that compares x or y coords when other direction
is zero,
* avoids numerical error when distances are very close to radius b
ut axis-aligned.
*
* An example of the problem is:
* (52.0 - 51.9999) - 0.0001 = 3.31965e-15 and 52.0 - 51.9999 > 0.0
001 in double arithmetic
* but:
* 51.9999 + 0.0001 <= 52.0
*
* This avoids some (but not all!) suprising results in $center que
ries where points are
* ( radius + center.x, center.y ) or vice-versa.
*/
bool distanceWithin( const Point& p, double radius ) const {
double a = _x - p._x;
double b = _y - p._y;
if( a == 0 ) {
//
// Note: For some, unknown reason, when a 32-bit g++ optim
izes this call, the sum is
// calculated imprecisely. We need to force the compiler t
o always evaluate it correctly,
// hence the weirdness.
//
// On some 32-bit linux machines, removing the volatile key
word or calculating the sum inline
// will make certain geo tests fail. Of course this check
will force volatile for all 32-bit systems,
// not just affected systems.
if( sizeof(void*) <= 4 ){
volatile double sum = _y > p._y ? p._y + radius : _y +
radius;
return _y > p._y ? sum >= _y : sum >= p._y;
}
else {
// Original math, correct for most systems
return _y > p._y ? p._y + radius >= _y : _y + radius >=
p._y;
}
}
if( b == 0 ) {
if( sizeof(void*) <= 4 ){
volatile double sum = _x > p._x ? p._x + radius : _x +
radius;
return _x > p._x ? sum >= _x : sum >= p._x;
}
else {
return _x > p._x ? p._x + radius >= _x : _x + radius >=
p._x;
}
}
return sqrt( ( a * a ) + ( b * b ) ) <= radius;
}
string toString() const {
StringBuilder buf;
buf << "(" << _x << "," << _y << ")";
return buf.str();
}
double _x; #if 0
double _y; # define GEODEBUGGING
}; # define GEODEBUG(x) cout << x << endl;
# define GEODEBUGPRINT(x) PRINT(x)
extern const double EARTH_RADIUS_KM; inline void PREFIXDEBUG(GeoHash prefix, const GeoConvert* g) {
extern const double EARTH_RADIUS_MILES; if (!prefix.constrains()) {
cout << "\t empty prefix" << endl;
// Technically lat/long bounds, not really tied to earth radius. return ;
inline void checkEarthBounds( Point p ) { }
uassert( 14808, str::stream() << "point " << p.toString() << " must
be in earth-like bounds of long : [-180, 180], lat : [-90, 90] ", Point ll (g, prefix); // lower left
p._x >= -180 && p._x <= 180 && p._y >= -90 && p._y <= 90 ) prefix.move(1,1);
; Point tr (g, prefix); // top right
}
inline double deg2rad(double deg) { return deg * (M_PI/180); } Point center ((ll._x+tr._x)/2, (ll._y+tr._y)/2);
inline double rad2deg(double rad) { return rad * (180/M_PI); } double radius = fabs(ll._x - tr._x) / 2;
// WARNING: _x and _y MUST be longitude and latitude in that order cout << "\t ll: " << ll.toString() << " tr: " << tr.toString()
// note: multiply by earth radius for distance << " center: " << center.toString() << " radius: " << radius <
inline double spheredist_rad( const Point& p1, const Point& p2 ) { < endl;
// this uses the n-vector formula: http://en.wikipedia.org/wiki/N-v
ector
// If you try to match the code to the formula, note that I inline
the cross-product.
// TODO: optimize with SSE
double sin_x1(sin(p1._x)), cos_x1(cos(p1._x));
double sin_y1(sin(p1._y)), cos_y1(cos(p1._y));
double sin_x2(sin(p2._x)), cos_x2(cos(p2._x));
double sin_y2(sin(p2._y)), cos_y2(cos(p2._y));
double cross_prod =
(cos_y1*cos_x1 * cos_y2*cos_x2) +
(cos_y1*sin_x1 * cos_y2*sin_x2) +
(sin_y1 * sin_y2);
if (cross_prod >= 1 || cross_prod <= -1) {
// fun with floats
verify( fabs(cross_prod)-1 < 1e-6 );
return cross_prod > 0 ? 0 : M_PI;
}
return acos(cross_prod);
} }
#else
# define GEODEBUG(x)
# define GEODEBUGPRINT(x)
# define PREFIXDEBUG(x, y)
#endif
// note: return is still in radians as that can be multiplied by radius // Used by haystack.cpp. XXX: change to something else/only have one of th
to get arc length ese geo things/nuke em
inline double spheredist_deg( const Point& p1, const Point& p2 ) { // all?
return spheredist_rad( #define GEOQUADDEBUG(x)
Point( deg2rad(p1._x), deg2rad(p1._y) ), //#define GEOQUADDEBUG(x) cout << x << endl
Point( deg2rad(p2._x), deg2rad(p2._y) )
);
}
// XXX: move elsewhere?
namespace mongo {
inline double deg2rad(const double deg) { return deg * (M_PI / 180.0);
}
inline double rad2deg(const double rad) { return rad * (180.0 / M_PI);
}
} }
 End of changes. 10 change blocks. 
538 lines changed or deleted 42 lines changed or added


 counters.h   counters.h 
skipping to change at line 47 skipping to change at line 47
void incInsertInWriteLock(int n) { _insert.x += n; } void incInsertInWriteLock(int n) { _insert.x += n; }
void gotInsert() { _insert++; } void gotInsert() { _insert++; }
void gotQuery() { _query++; } void gotQuery() { _query++; }
void gotUpdate() { _update++; } void gotUpdate() { _update++; }
void gotDelete() { _delete++; } void gotDelete() { _delete++; }
void gotGetMore() { _getmore++; } void gotGetMore() { _getmore++; }
void gotCommand() { _command++; } void gotCommand() { _command++; }
void gotOp( int op , bool isCommand ); void gotOp( int op , bool isCommand );
BSONObj getObj(); BSONObj getObj() const;
// thse are used by snmp, and other things, do not remove // thse are used by snmp, and other things, do not remove
const AtomicUInt * getInsert() const { return &_insert; } const AtomicUInt * getInsert() const { return &_insert; }
const AtomicUInt * getQuery() const { return &_query; } const AtomicUInt * getQuery() const { return &_query; }
const AtomicUInt * getUpdate() const { return &_update; } const AtomicUInt * getUpdate() const { return &_update; }
const AtomicUInt * getDelete() const { return &_delete; } const AtomicUInt * getDelete() const { return &_delete; }
const AtomicUInt * getGetMore() const { return &_getmore; } const AtomicUInt * getGetMore() const { return &_getmore; }
const AtomicUInt * getCommand() const { return &_command; } const AtomicUInt * getCommand() const { return &_command; }
private: private:
void _checkWrap();
// todo: there will be a lot of cache line contention on these. ne ed to do something // todo: there will be a lot of cache line contention on these. ne ed to do something
// else eventually. // else eventually.
AtomicUInt _insert; AtomicUInt _insert;
AtomicUInt _query; AtomicUInt _query;
AtomicUInt _update; AtomicUInt _update;
AtomicUInt _delete; AtomicUInt _delete;
AtomicUInt _getmore; AtomicUInt _getmore;
AtomicUInt _command; AtomicUInt _command;
}; };
extern OpCounters globalOpCounters; extern OpCounters globalOpCounters;
extern OpCounters replOpCounters; extern OpCounters replOpCounters;
class IndexCounters {
public:
IndexCounters();
// used without a mutex intentionally (can race)
void btree( char * node ) {
if ( ! _memSupported )
return;
btree( Record::likelyInPhysicalMemory( node ) );
}
void btree( bool memHit ) {
if ( memHit )
_btreeMemHits++;
else
_btreeMemMisses++;
_btreeAccesses++;
}
void btreeHit() { _btreeMemHits++; _btreeAccesses++; }
void btreeMiss() { _btreeMemMisses++; _btreeAccesses++; }
void append( BSONObjBuilder& b );
private:
bool _memSupported;
int _resets;
long long _maxAllowed;
long long _btreeMemMisses;
long long _btreeMemHits;
long long _btreeAccesses;
};
extern IndexCounters globalIndexCounters;
class FlushCounters {
public:
FlushCounters();
void flushed(int ms);
void append( BSONObjBuilder& b );
private:
long long _total_time;
long long _flushes;
int _last_time;
Date_t _last;
};
extern FlushCounters globalFlushCounters;
class GenericCounter {
public:
GenericCounter() : _mutex("GenericCounter") { }
void hit( const string& name , int count=0 );
BSONObj getObj();
private:
map<string,long long> _counts; // TODO: replace with thread safe ma
p
mongo::mutex _mutex;
};
class NetworkCounter { class NetworkCounter {
public: public:
NetworkCounter() : _bytesIn(0), _bytesOut(0), _requests(0), _overfl ows(0) {} NetworkCounter() : _bytesIn(0), _bytesOut(0), _requests(0), _overfl ows(0) {}
void hit( long long bytesIn , long long bytesOut ); void hit( long long bytesIn , long long bytesOut );
void append( BSONObjBuilder& b ); void append( BSONObjBuilder& b );
private: private:
long long _bytesIn; long long _bytesIn;
long long _bytesOut; long long _bytesOut;
long long _requests; long long _requests;
 End of changes. 3 change blocks. 
65 lines changed or deleted 2 lines changed or added


 curop.h   curop.h 
skipping to change at line 226 skipping to change at line 226
void setQuery(const BSONObj& query) { _query.set( query ); } void setQuery(const BSONObj& query) { _query.set( query ); }
Client * getClient() const { return _client; } Client * getClient() const { return _client; }
BSONObj info(); BSONObj info();
BSONObj infoNoauth(); BSONObj infoNoauth();
string getRemoteString( bool includePort = true ) { return _remote. toString(includePort); } string getRemoteString( bool includePort = true ) { return _remote. toString(includePort); }
ProgressMeter& setMessage( const char * msg , unsigned long long pr ogressMeterTotal = 0 , int secondsBetween = 3 ); ProgressMeter& setMessage( const char * msg , unsigned long long pr ogressMeterTotal = 0 , int secondsBetween = 3 );
string getMessage() const { return _message.toString(); } string getMessage() const { return _message.toString(); }
ProgressMeter& getProgressMeter() { return _progressMeter; } ProgressMeter& getProgressMeter() { return _progressMeter; }
CurOp *parent() const { return _wrapped; } CurOp *parent() const { return _wrapped; }
void kill(bool* pNotifyFlag = NULL); void kill(bool* pNotifyFlag = NULL);
bool killPending() const { return _killPending.load(); } bool killPendingStrict() const { return _killPending.load(); }
bool killPending() const { return _killPending.loadRelaxed(); }
void yielded() { _numYields++; } void yielded() { _numYields++; }
int numYields() const { return _numYields; } int numYields() const { return _numYields; }
void suppressFromCurop() { _suppressFromCurop = true; } void suppressFromCurop() { _suppressFromCurop = true; }
long long getExpectedLatencyMs() const { return _expectedLatencyMs; } long long getExpectedLatencyMs() const { return _expectedLatencyMs; }
void setExpectedLatencyMs( long long latency ) { _expectedLatencyMs = latency; } void setExpectedLatencyMs( long long latency ) { _expectedLatencyMs = latency; }
void recordGlobalTime( long long micros ) const; void recordGlobalTime( long long micros ) const;
const LockStat& lockStat() const { return _lockStat; } const LockStat& lockStat() const { return _lockStat; }
 End of changes. 1 change blocks. 
1 lines changed or deleted 2 lines changed or added


 cursors.h   cursors.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/client/parallel.h"
#include "../db/dbmessage.h" #include "mongo/db/dbmessage.h"
#include "../client/parallel.h" #include "mongo/db/jsobj.h"
#include "mongo/platform/random.h"
#include "request.h" #include "mongo/s/request.h"
namespace mongo { namespace mongo {
class ShardedClientCursor : boost::noncopyable { class ShardedClientCursor : boost::noncopyable {
public: public:
ShardedClientCursor( QueryMessage& q , ClusteredCursor * cursor ); ShardedClientCursor( QueryMessage& q , ClusteredCursor * cursor );
virtual ~ShardedClientCursor(); virtual ~ShardedClientCursor();
long long getId(); long long getId();
skipping to change at line 118 skipping to change at line 118
void appendInfo( BSONObjBuilder& result ) const ; void appendInfo( BSONObjBuilder& result ) const ;
long long genId(); long long genId();
void doTimeouts(); void doTimeouts();
void startTimeoutThread(); void startTimeoutThread();
private: private:
mutable mongo::mutex _mutex; mutable mongo::mutex _mutex;
PseudoRandom _random;
MapSharded _cursors; MapSharded _cursors;
MapNormal _refs; MapNormal _refs;
long long _shardedTotal; long long _shardedTotal;
static const int _myLogLevel; static const int _myLogLevel;
}; };
extern CursorCache cursorCache; extern CursorCache cursorCache;
} }
 End of changes. 2 change blocks. 
5 lines changed or deleted 7 lines changed or added


 d_logic.h   d_logic.h 
skipping to change at line 142 skipping to change at line 142
* @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 ); ShardChunkVersion version );
bool inCriticalMigrateSection(); bool inCriticalMigrateSection();
/**
* @return true if we are NOT in the critical section
*/
bool waitTillNotInCriticalSection( int maxSecondsToWait );
private: private:
bool _enabled; bool _enabled;
string _configServer; string _configServer;
string _shardName; string _shardName;
string _shardHost; string _shardHost;
// protects state below // protects state below
mutable mongo::mutex _mutex; mutable mongo::mutex _mutex;
 End of changes. 1 change blocks. 
0 lines changed or deleted 5 lines changed or added


 d_writeback.h   d_writeback.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 "../util/queue.h" #include "mongo/db/jsobj.h"
#include "../util/background.h" #include "mongo/util/queue.h"
#include "mongo/util/background.h"
namespace mongo { namespace mongo {
/* /*
* The WriteBackManager keeps one queue of pending operations per mongo s. The operations get here * The WriteBackManager keeps one queue of pending operations per mongo s. The operations get here
* if they were directed to a chunk that is no longer in this mongod se rver. The operations are * if they were directed to a chunk that is no longer in this mongod se rver. The operations are
* "written back" to the mongos server per its request (command 'writeb acklisten'). * "written back" to the mongos server per its request (command 'writeb acklisten').
* *
* The class is thread safe. * The class is thread safe.
*/ */
skipping to change at line 60 skipping to change at line 61
public: public:
WriteBackManager(); WriteBackManager();
~WriteBackManager(); ~WriteBackManager();
/* /*
* @param remote server ID this operation came from * @param remote server ID this operation came from
* @param op the operation itself * @param op the operation itself
* *
* Enqueues operation 'op' in server 'remote's queue. The operation will be written back to * Enqueues operation 'op' in server 'remote's queue. The operation will be written back to
* remote at a later stage. * remote at a later stage.
*
* @return the writebackId generated
*/ */
void queueWriteBack( const string& remote , const BSONObj& op ); OID queueWriteBack( const string& remote , BSONObjBuilder& opBuilde r );
/* /*
* @param remote server ID * @param remote server ID
* @return the queue for operations that came from 'remote' * @return the queue for operations that came from 'remote'
* *
* Gets access to server 'remote's queue, which is synchronized. * Gets access to server 'remote's queue, which is synchronized.
*/ */
shared_ptr<QueueInfo> getWritebackQueue( const string& remote ); shared_ptr<QueueInfo> getWritebackQueue( const string& remote );
/* /*
 End of changes. 3 change blocks. 
3 lines changed or deleted 6 lines changed or added


 database.h   database.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/db/cc_by_loc.h"
#include "mongo/db/cmdline.h" #include "mongo/db/cmdline.h"
#include "mongo/db/namespace_details.h" #include "mongo/db/namespace_details.h"
#include "mongo/db/record.h" #include "mongo/db/record.h"
namespace mongo { namespace mongo {
class Extent; class Extent;
class MongoDataFile; class MongoDataFile;
class ClientCursor;
struct ByLocKey;
typedef map<ByLocKey, ClientCursor*> CCByLoc;
/** /**
* Database represents a database database * Database represents a database database
* Each database database has its own set of files -- dbname.ns, dbname .0, dbname.1, ... * Each database database has its own set of files -- dbname.ns, dbname .0, dbname.1, ...
* NOT memory mapped * NOT memory mapped
*/ */
class Database { class Database {
public: public:
static bool _openAllFiles; static bool _openAllFiles;
 End of changes. 2 change blocks. 
3 lines changed or deleted 1 lines changed or added


 dbclient_rs.h   dbclient_rs.h 
skipping to change at line 150 skipping to change at line 150
* @param preference the read mode to use * @param preference the read mode to use
* @param tags the tags used for filtering nodes * @param tags the tags used for filtering nodes
* @param localThresholdMillis the exclusive upper bound of ping ti me to be * @param localThresholdMillis the exclusive upper bound of ping ti me to be
* considered as a local node. Local nodes are favored over non -local * considered as a local node. Local nodes are favored over non -local
* nodes if multiple nodes matches the other criteria. * nodes if multiple nodes matches the other criteria.
* @param lastHost the host used in the last successful request. Th is is used for * @param lastHost the host used in the last successful request. Th is is used for
* selecting a different node as much as possible, by doing a s imple round * selecting a different node as much as possible, by doing a s imple round
* robin, starting from the node next to this lastHost. This wi ll be overwritten * robin, starting from the node next to this lastHost. This wi ll be overwritten
* with the newly chosen host if not empty, not primary and whe n preference * with the newly chosen host if not empty, not primary and whe n preference
* is not Nearest. * is not Nearest.
* @param isPrimarySelected out parameter that is set to true if th
e returned host
* is a primary. Cannot be NULL and valid only if returned host
is not empty.
* *
* @return the host object of the node selected. If none of the nod es are * @return the host object of the node selected. If none of the nod es are
* eligible, returns an empty host. * eligible, returns an empty host.
*/ */
static HostAndPort selectNode(const std::vector<Node>& nodes, static HostAndPort selectNode(const std::vector<Node>& nodes,
ReadPreference preference, ReadPreference preference,
TagSet* tags, TagSet* tags,
int localThresholdMillis, int localThresholdMillis,
HostAndPort* lastHost); HostAndPort* lastHost,
bool* isPrimarySelected);
/** /**
* Selects the right node given the nodes to pick from and the pref erence. This * Selects the right node given the nodes to pick from and the pref erence. This
* will also attempt to refresh the local view of the replica set c onfiguration * will also attempt to refresh the local view of the replica set c onfiguration
* if the primary node needs to be returned but is not currently av ailable (except * if the primary node needs to be returned but is not currently av ailable (except
* for ReadPrefrence_Nearest). * for ReadPrefrence_Nearest).
* *
* @param preference the read mode to use * @param preference the read mode to use.
* @param tags the tags used for filtering nodes * @param tags the tags used for filtering nodes.
* @param isPrimarySelected out parameter that is set to true if th
e returned host
* is a primary. Cannot be NULL and valid only if returned host
is not empty.
* *
* @return the host object of the node selected. If none of the nod es are * @return the host object of the node selected. If none of the nod es are
* eligible, returns an empty host. * eligible, returns an empty host.
*/ */
HostAndPort selectAndCheckNode(ReadPreference preference, HostAndPort selectAndCheckNode(ReadPreference preference,
TagSet* tags); TagSet* tags,
bool* isPrimarySelected);
/** /**
* Creates a new ReplicaSetMonitor, if it doesn't already exist. * Creates a new ReplicaSetMonitor, if it doesn't already exist.
*/ */
static void createIfNeeded( const string& name , const vector<HostA ndPort>& servers ); static void createIfNeeded( const string& name , const vector<HostA ndPort>& servers );
/** /**
* gets a cached Monitor per name. If the monitor is not found and createFromSeed is false, * gets a cached Monitor per name. If the monitor is not found and createFromSeed is false,
* it will return none. If createFromSeed is true, it will try to l ook up the last known * it will return none. If createFromSeed is true, it will try to l ook up the last known
* servers list for this set and will create a new monitor using th at as the seed list. * servers list for this set and will create a new monitor using th at as the seed list.
*/ */
static ReplicaSetMonitorPtr get( const string& name, const bool cre ateFromSeed = false ); static ReplicaSetMonitorPtr get( const string& name, const bool cre ateFromSeed = false );
/** /**
* Populates activeSets with all the currently tracked replica set
names.
*/
static void getAllTrackedSets(set<string>* activeSets);
/**
* checks all sets for current master and new secondaries * checks all sets for current master and new secondaries
* usually only called from a BackgroundJob * usually only called from a BackgroundJob
*/ */
static void checkAll( bool checkAllSecondaries ); static void checkAll( bool checkAllSecondaries );
/** /**
* Removes the ReplicaSetMonitor for the given set name from _sets, which will delete it. * Removes the ReplicaSetMonitor for the given set name from _sets, which will delete it.
* If clearSeedCache is true, then the cached seed string for this Replica Set will be removed * If clearSeedCache is true, then the cached seed string for this Replica Set will be removed
* from _setServers. * from _setServers.
*/ */
skipping to change at line 557 skipping to change at line 568
* operation. * operation.
*/ */
static const size_t MAX_RETRY; static const size_t MAX_RETRY;
// Throws a DBException if the monitor doesn't exist and there isn' t a cached seed to use. // Throws a DBException if the monitor doesn't exist and there isn' t a cached seed to use.
ReplicaSetMonitorPtr _getMonitor() const; ReplicaSetMonitorPtr _getMonitor() const;
string _setName; string _setName;
HostAndPort _masterHost; HostAndPort _masterHost;
scoped_ptr<DBClientConnection> _master; // Note: reason why this is a shared_ptr is because we want _lastSl
aveOkConn to
// keep a reference of the _master connection when it selected a pr
imary node.
// This is because the primary connection is special in mongos - it
is the only
// connection that is versioned.
// WARNING: do not assign this variable (which will increment the i
nternal ref
// counter) to any other variable other than _lastSlaveOkConn.
boost::shared_ptr<DBClientConnection> _master;
// Last used host in a slaveOk query (can be a primary) // Last used host in a slaveOk query (can be a primary)
HostAndPort _lastSlaveOkHost; HostAndPort _lastSlaveOkHost;
// Last used connection in a slaveOk query (can be a primary) // Last used connection in a slaveOk query (can be a primary)
scoped_ptr<DBClientConnection> _lastSlaveOkConn; boost::shared_ptr<DBClientConnection> _lastSlaveOkConn;
double _so_timeout; double _so_timeout;
/** /**
* for storing authentication info * for storing authentication info
* fields are exactly for DBClientConnection::auth * fields are exactly for DBClientConnection::auth
*/ */
struct AuthInfo { struct AuthInfo {
// Default constructor provided only to make it compatible with std::map::operator[] // Default constructor provided only to make it compatible with std::map::operator[]
AuthInfo(): digestPassword(false) { } AuthInfo(): digestPassword(false) { }
 End of changes. 7 change blocks. 
6 lines changed or deleted 32 lines changed or added


 dbclientinterface.h   dbclientinterface.h 
skipping to change at line 28 skipping to change at line 28
* 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/client/authentication_table.h"
#include "mongo/db/jsobj.h" #include "mongo/db/jsobj.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
the final object's position. you can resume using the cursor la ter, from where it was located, the final object's position. you can resume using the cursor la ter, from where it was located,
if more data were received. Set on dbQuery and dbGetMore. if more data were received. Set on dbQuery and dbGetMore.
skipping to change at line 167 skipping to change at line 168
* Read from a secondary if available, otherwise read from the prim ary. * Read from a secondary if available, otherwise read from the prim ary.
*/ */
ReadPreference_SecondaryPreferred, ReadPreference_SecondaryPreferred,
/** /**
* Read from any member. * Read from any member.
*/ */
ReadPreference_Nearest, ReadPreference_Nearest,
}; };
/**
* @return true if the query object contains a read preference specific
ation object.
*/
bool hasReadPreference(const BSONObj& queryObj);
class DBClientBase; class DBClientBase;
/** /**
* 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
* for some special things such as s
harding config servers.
* See syncclusterconnection.h for m
ore info.
* *
* tyipcal use * tyipcal use
* string errmsg, * string errmsg,
* ConnectionString cs = ConnectionString::parse( url , errmsg ); * ConnectionString cs = ConnectionString::parse( url , errmsg );
* if ( ! cs.isValid() ) throw "bad: " + errmsg; * if ( ! cs.isValid() ) throw "bad: " + errmsg;
* DBClientBase * conn = cs.connect( errmsg ); * DBClientBase * conn = cs.connect( errmsg );
*/ */
class ConnectionString { class ConnectionString {
public: public:
enum ConnectionType { INVALID , MASTER , PAIR , SET , SYNC, CUSTOM }; enum ConnectionType { INVALID , MASTER , PAIR , SET , SYNC, CUSTOM };
skipping to change at line 249 skipping to change at line 258
string toString() const { return _string; } string toString() const { return _string; }
DBClientBase* connect( string& errmsg, double socketTimeout = 0 ) c onst; DBClientBase* connect( string& errmsg, double socketTimeout = 0 ) c onst;
string getSetName() const { return _setName; } string getSetName() const { return _setName; }
vector<HostAndPort> getServers() const { return _servers; } vector<HostAndPort> getServers() const { return _servers; }
ConnectionType type() const { return _type; } ConnectionType type() const { return _type; }
/**
* This returns true if this and other point to the same logical en
tity.
* For single nodes, thats the same address.
* For replica sets, thats just the same replica set name.
* For pair (deprecated) or sync cluster connections, that's the sa
me hosts in any ordering.
*/
bool sameLogicalEndpoint( const ConnectionString& other ) const;
static ConnectionString parse( const string& url , string& errmsg ) ; static ConnectionString parse( const string& url , string& errmsg ) ;
static string typeToString( ConnectionType type ); static string typeToString( ConnectionType type );
// //
// Allow overriding the default connection behavior // Allow overriding the default connection behavior
// This is needed for some tests, which otherwise would fail becaus e they are unable to contact // This is needed for some tests, which otherwise would fail becaus e they are unable to contact
// the correct servers. // the correct servers.
// //
skipping to change at line 927 skipping to change at line 944
bool _haveCachedAvailableOptions; bool _haveCachedAvailableOptions;
AuthenticationTable _authTable; AuthenticationTable _authTable;
bool _hasAuthentication; 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;
long long _connectionId; // unique connection id for this connectio
n
WriteConcern _writeConcern; WriteConcern _writeConcern;
public: public:
static const uint64_t INVALID_SOCK_CREATION_TIME;
DBClientBase() { DBClientBase() {
_writeConcern = W_NORMAL; _writeConcern = W_NORMAL;
_connectionId = ConnectionIdSequence.fetchAndAdd(1);
} }
long long getConnectionId() const { return _connectionId; }
WriteConcern getWriteConcern() const { return _writeConcern; } WriteConcern getWriteConcern() const { return _writeConcern; }
void setWriteConcern( WriteConcern w ) { _writeConcern = w; } void setWriteConcern( WriteConcern w ) { _writeConcern = w; }
/** send a query to the database. /** send a query to the database.
@param ns namespace to query, format is <dbname>.<collectname>[.<c ollectname>]* @param ns namespace to query, format is <dbname>.<collectname>[.<c ollectname>]*
@param query query to perform on the collection. this is a BSONOb j (binary JSON) @param query query to perform on the collection. this is a BSONOb j (binary JSON)
You may format as You may format as
{ query: { ... }, orderby: { ... } } { query: { ... }, orderby: { ... } }
to specify a sort order. to specify a sort order.
@param nToReturn n to return (i.e., limit). 0 = unlimited @param nToReturn n to return (i.e., limit). 0 = unlimited
skipping to change at line 1020 skipping to change at line 1043
virtual void killCursor( long long cursorID ) = 0; virtual void killCursor( long long cursorID ) = 0;
virtual bool callRead( Message& toSend , Message& response ) = 0; virtual bool callRead( Message& toSend , Message& response ) = 0;
// virtual bool callWrite( Message& toSend , Message& response ) = 0; // TODO: add this if needed // virtual bool callWrite( Message& toSend , Message& response ) = 0; // TODO: add this if needed
virtual ConnectionString::ConnectionType type() const = 0; virtual ConnectionString::ConnectionType type() const = 0;
virtual double getSoTimeout() const = 0; virtual double getSoTimeout() const = 0;
virtual uint64_t getSockCreationMicroSec() const {
return INVALID_SOCK_CREATION_TIME;
}
}; // DBClientBase }; // DBClientBase
class DBClientReplicaSet; class DBClientReplicaSet;
class ConnectException : public UserException { class ConnectException : public UserException {
public: public:
ConnectException(string msg) : UserException(9000,msg) { } ConnectException(string msg) : UserException(9000,msg) { }
}; };
/** /**
skipping to change at line 1153 skipping to change at line 1180
virtual bool lazySupported() const { return true; } virtual bool lazySupported() const { return true; }
static int getNumConnections() { static int getNumConnections() {
return _numConnections; return _numConnections;
} }
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;
protected: protected:
friend class SyncClusterConnection; friend class SyncClusterConnection;
virtual void sayPiggyBack( Message &toSend ); virtual void sayPiggyBack( Message &toSend );
DBClientReplicaSet *clientSet; DBClientReplicaSet *clientSet;
boost::scoped_ptr<MessagingPort> p; boost::scoped_ptr<MessagingPort> p;
boost::scoped_ptr<SockAddr> server; boost::scoped_ptr<SockAddr> server;
bool _failed; bool _failed;
const bool autoReconnect; const bool autoReconnect;
time_t lastReconnectTry; time_t lastReconnectTry;
 End of changes. 11 change blocks. 
1 lines changed or deleted 37 lines changed or added


 dbmessage.h   dbmessage.h 
skipping to change at line 214 skipping to change at line 214
massert( 10307 , "Client Error: bad object in message", fal se); massert( 10307 , "Client Error: bad object in message", fal se);
} }
nextjsobj += js.objsize(); nextjsobj += js.objsize();
if ( nextjsobj >= theEnd ) if ( nextjsobj >= theEnd )
nextjsobj = 0; nextjsobj = 0;
return js; return js;
} }
const Message& msg() const { return m; } const Message& msg() const { return m; }
const char * markGet() {
return nextjsobj;
}
void markSet() { void markSet() {
mark = nextjsobj; mark = nextjsobj;
} }
void markReset() { void markReset( const char * toMark = 0) {
verify( mark ); if( toMark == 0 ) toMark = mark;
nextjsobj = mark; verify( toMark );
nextjsobj = toMark;
} }
private: private:
const Message& m; const Message& m;
int* reserved; int* reserved;
const char *data; const char *data;
const char *nextjsobj; const char *nextjsobj;
const char *theEnd; const char *theEnd;
const char * mark; const char * mark;
 End of changes. 2 change blocks. 
3 lines changed or deleted 8 lines changed or added


 diskloc.h   diskloc.h 
skipping to change at line 25 skipping to change at line 25
*/ */
/* @file diskloc.h /* @file diskloc.h
Storage subsystem management. Storage subsystem management.
Lays out our datafiles on disk, manages disk space. Lays out our datafiles on disk, manages disk space.
*/ */
#pragma once #pragma once
#include "jsobj.h" #include "mongo/db/jsobj.h"
#include "mongo/platform/cstdint.h"
namespace mongo { namespace mongo {
class Record; class Record;
class DeletedRecord; class DeletedRecord;
class Extent; class Extent;
class MongoDataFile; class MongoDataFile;
class DiskLoc; class DiskLoc;
template< class Version > class BtreeBucket; template< class Version > class BtreeBucket;
skipping to change at line 51 skipping to change at line 52
*/ */
class DiskLoc { class DiskLoc {
int _a; // this will be volume, file #, etc. but is a logical v alue could be anything depending on storage engine int _a; // this will be volume, file #, etc. but is a logical v alue could be anything depending on storage engine
int ofs; int ofs;
public: public:
enum SentinelValues { enum SentinelValues {
/* note NullOfs is different. todo clean up. see refs to NullO fs in code - use is valid but outside DiskLoc context so confusing as-is. * / /* note NullOfs is different. todo clean up. see refs to NullO fs in code - use is valid but outside DiskLoc context so confusing as-is. * /
NullOfs = -1, NullOfs = -1,
MaxFiles=16000 // thus a limit of about 32TB of data per db
// Caps the number of files that may be allocated in a database
, allowing about 32TB of
// data per db. Note that the DiskLoc and DiskLoc56Bit types s
upports more files than
// this value, as does the data storage format.
MaxFiles=16000
}; };
DiskLoc(int a, int Ofs) : _a(a), ofs(Ofs) { } DiskLoc(int a, int Ofs) : _a(a), ofs(Ofs) { }
DiskLoc() { Null(); } DiskLoc() { Null(); }
DiskLoc(const DiskLoc& l) { DiskLoc(const DiskLoc& l) {
_a=l._a; _a=l._a;
ofs=l.ofs; ofs=l.ofs;
} }
bool questionable() const { bool questionable() const {
skipping to change at line 83 skipping to change at line 88
void setInvalid() { void setInvalid() {
_a = -2; _a = -2;
ofs = 0; ofs = 0;
} }
bool isValid() const { return _a != -2; } bool isValid() const { return _a != -2; }
string toString() const { string toString() const {
if ( isNull() ) if ( isNull() )
return "null"; return "null";
stringstream ss; stringstream ss;
ss << hex << _a << ':' << ofs; ss << _a << ':' << hex << ofs;
return ss.str(); return ss.str();
} }
BSONObj toBSONObj() const { return BSON( "file" << _a << "offset" < < ofs ); } BSONObj toBSONObj() const { return BSON( "file" << _a << "offset" < < ofs ); }
int a() const { return _a; } int a() const { return _a; }
int& GETOFS() { return ofs; } int& GETOFS() { return ofs; }
int getOfs() const { return ofs; } int getOfs() const { return ofs; }
void set(int a, int b) { void set(int a, int b) {
skipping to change at line 129 skipping to change at line 134
int compare(const DiskLoc& b) const { int compare(const DiskLoc& b) const {
int x = _a - b._a; int x = _a - b._a;
if ( x ) if ( x )
return x; return x;
return ofs - b.ofs; return ofs - b.ofs;
} }
bool operator<(const DiskLoc& b) const { bool operator<(const DiskLoc& b) const {
return compare(b) < 0; return compare(b) < 0;
} }
uint64_t asUint64() const { return *reinterpret_cast<const uint64_t
*>( this ); }
/** /**
* Marks this disk loc for writing * Marks this disk loc for writing
* @returns a non const reference to this disk loc * @returns a non const reference to this disk loc
* This function explicitly signals we are writing and casts away c onst * This function explicitly signals we are writing and casts away c onst
*/ */
DiskLoc& writing() const; // see dur.h DiskLoc& writing() const; // see dur.h
/* Get the "thing" associated with this disk location. /* Get the "thing" associated with this disk location.
it is assumed the object is what you say it is -- you must assur e that it is assumed the object is what you say it is -- you must assur e that
(think of this as an unchecked type cast) (think of this as an unchecked type cast)
skipping to change at line 157 skipping to change at line 164
const BtreeBucket<V> * btree() const; const BtreeBucket<V> * btree() const;
// Explicitly signals we are writing and casts away const // Explicitly signals we are writing and casts away const
template< class V > template< class V >
BtreeBucket<V> * btreemod() const; BtreeBucket<V> * btreemod() const;
/*MongoDataFile& pdf() const;*/ /*MongoDataFile& pdf() const;*/
}; };
#pragma pack() #pragma pack()
const DiskLoc minDiskLoc(0, 1); inline std::ostream& operator<<( std::ostream &stream, const DiskLoc &l
const DiskLoc maxDiskLoc(0x7fffffff, 0x7fffffff); oc ) {
return stream << loc.toString();
}
// Minimum allowed DiskLoc. No Record may begin at this location becau
se file and extent
// headers must precede Records in a file.
const DiskLoc minDiskLoc(0, 0);
// Maximum allowed DiskLoc. Note that only three bytes are used to rep
resent the file number
// for consistency with the v1 index DiskLoc storage format, which uses
only 7 bytes total.
// No Record may begin at this location because the minimum size of a R
ecord is larger than one
// byte.
const DiskLoc maxDiskLoc(0x00ffffff, 0x7fffffff);
} // namespace mongo } // namespace mongo
 End of changes. 5 change blocks. 
5 lines changed or deleted 31 lines changed or added


 distlock.h   distlock.h 
skipping to change at line 165 skipping to change at line 165
*/ */
static const string lockPingNS; static const string lockPingNS;
/** /**
* Namespace for locks * Namespace for locks
*/ */
static const string locksNS; static const string locksNS;
const ConnectionString _conn; const ConnectionString _conn;
const string _name; const string _name;
const BSONObj _id;
const string _processId; const string _processId;
// Timeout for lock, usually LOCK_TIMEOUT // Timeout for lock, usually LOCK_TIMEOUT
const unsigned long long _lockTimeout; const unsigned long long _lockTimeout;
const unsigned long long _maxClockSkew; const unsigned long long _maxClockSkew;
const unsigned long long _maxNetSkew; const unsigned long long _maxNetSkew;
const unsigned long long _lockPing; const unsigned long long _lockPing;
private: private:
 End of changes. 1 change blocks. 
1 lines changed or deleted 0 lines changed or added


 document.h   document.h 
skipping to change at line 19 skipping to change at line 19
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public 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 "mongo/pch.h" #include "mongo/db/pipeline/document_internal.h"
#include "util/intrusive_counter.h" #include <boost/functional/hash.hpp>
#include "mongo/bson/util/builder.h"
namespace mongo { namespace mongo {
class BSONObj; class BSONObj;
class FieldIterator; class FieldIterator;
class FieldPath;
class Value; class Value;
class MutableDocument;
class Document : /** An internal class that represents the position of a field in a docu
public IntrusiveCounterUnsigned { ment.
*
* This is a low-level class that you usually don't need to worry abou
t.
*
* The main use of this class for clients is to allow refetching or
* setting a field without looking it up again. It has a default
* constructor that represents a field not being in a document. It als
o
* has a method 'bool found()' that tells you if a field was found.
*
* For more details see document_internal.h
*/
class Position;
/** A Document is similar to a BSONObj but with a different in-memory r
epresentation.
*
* A Document can be treated as a const map<string, const Value> that
is
* very cheap to copy and is Assignable. Therefore, it is acceptable
to
* pass and return by Value. Note that the data in a Document is
* immutable, but you can replace a Document instance with assignment.
*
* See Also: Value class in Value.h
*/
class Document {
public: public:
~Document();
/* /// Empty Document (does no allocation)
Create a new Document from the given BSONObj. Document() {}
Document field values may be pointed to in the BSONObj, so it /// Create a new Document deep-converted from the given BSONObj.
must live at least as long as the resulting Document. explicit Document(const BSONObj& bson);
@returns shared pointer to the newly created Document void swap(Document& rhs) { _storage.swap(rhs._storage); }
*/
static intrusive_ptr<Document> createFromBsonObj(BSONObj* pBsonObj)
;
/* /// Look up a field by key name. Returns Value() if no such field.
Create a new empty Document. O(1)
const Value operator[] (StringData key) const { return getField(key
@param sizeHint a hint at what the number of fields will be; if ); }
known, this can be used to increase memory allocation efficienc const Value getField(StringData key) const { return storage().getFi
y eld(key); }
@returns shared pointer to the newly created Document
*/ /// Look up a field by Position. See positionOf and getNestedField.
static intrusive_ptr<Document> create(size_t sizeHint = 0); const Value operator[] (Position pos) const { return getField(pos);
}
/* const Value getField(Position pos) const { return storage().getFiel
Clone a document. d(pos).val; }
/** Similar to BSONObj::getFieldDotted, but using FieldPath rather
than a dotted string.
* If you pass a non-NULL positions vector, you get back a path su
itable
* to pass to MutableDocument::setNestedField.
*
* TODO a version that doesn't use FieldPath
*/
const Value getNestedField(const FieldPath& fieldNames,
vector<Position>* positions=NULL) const;
The new document shares all the fields' values with the original. /// Number of fields in this document. O(n)
size_t size() const { return storage().size(); }
This is not a deep copy. Only the fields on the top-level docume /// True if this document has no fields.
nt bool empty() const { return !_storage || storage().iterator().atEnd
are cloned. (); }
@returns the shallow clone of the document /// Create a new FieldIterator that can be used to examine the Docu
*/ ment's fields in order.
intrusive_ptr<Document> clone(); FieldIterator fieldIterator() const;
/* /// Convenience type for dealing with fields. Used by FieldIterator
Add this document to the BSONObj under construction with the .
given BSONObjBuilder. typedef pair<StringData, Value> FieldPair;
*/
void toBson(BSONObjBuilder *pBsonObjBuilder) const;
/* /** Get the approximate storage size of the document and sub-values
Create a new FieldIterator that can be used to examine the in bytes.
Document's fields. * Note: Some memory may be shared with other Documents or between
*/ fields within
FieldIterator *createFieldIterator(); * a single Document so this can overestimate usage.
*/
size_t getApproximateSize() const;
/* /** Compare two documents.
Get the value of the specified field. *
* BSON document field order is significant, so this just goes thr
ough
* 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
* of one character at a time.
*
* @returns an integer less than zero, zero, or an integer greater
than
* zero, depending on whether lhs < rhs, lhs == rhs, or l
hs > rhs
* Warning: may return values other than -1, 0, or 1
*/
static int compare(const Document& lhs, const Document& rhs);
@param fieldName the name of the field string toString() const; // TODO support streams
@return point to the requested field
*/
intrusive_ptr<const Value> getValue(const string &fieldName);
/* /** Calculate a hash value.
Add the given field to the Document. *
* Meant to be used to create composite hashes suitable for
* hashed container classes such as unordered_map.
*/
void hash_combine(size_t &seed) const;
BSON documents' fields are ordered; the new Field will be /// Add this document to the BSONObj under construction with the gi
appended to the current list of fields. ven BSONObjBuilder.
void toBson(BSONObjBuilder *pBsonObjBuilder) const;
It is an error to add a field that has the same name as another /** Return the abstract Position of a field, suitable to pass to op
field. erator[] or getField().
*/ * This can potentially save time if you need to refer to a field
void addField(const string &fieldName, multiple times.
const intrusive_ptr<const Value> &pValue); */
Position positionOf(StringData fieldName) const { return storage().
findField(fieldName); }
/* /** Clone a document.
Set the given field to be at the specified position in the *
Document. This will replace any field that is currently in that * This should only be called by MutableDocument and tests
position. The index must be within the current range of field *
indices, otherwise behavior is undefined. * The new document shares all the fields' values with the origina
l.
* This is not a deep copy. Only the fields on the top-level docu
ment
* are cloned.
*/
Document clone() const { return Document(storage().clone().get());
}
pValue.get() may be NULL, in which case the field will be // TEMP for compatibility with legacy intrusive_ptr<Document>
removed. fieldName is ignored in this case. Document& operator*() { return *this; }
const Document& operator*() const { return *this; }
Document* operator->() { return this; }
const Document* operator->() const { return this; }
const void* getPtr() const { return _storage.get(); }
void reset() { return _storage.reset(); }
static Document createFromBsonObj(BSONObj* pBsonObj) { return Docum
ent(*pBsonObj); }
size_t getFieldCount() const { return size(); }
Value getValue(StringData fieldName) const { return getField(fieldN
ame); }
@param index the field index in the list of fields // TODO: replace with logical equality once all current usages are
@param fieldName the new field name fixed
@param pValue the new Value bool operator== (const Document& lhs) const { return _storage == lh
*/ s._storage; }
void setField(size_t index,
const string &fieldName,
const intrusive_ptr<const Value> &pValue);
/* explicit Document(const DocumentStorage* ptr) : _storage(ptr) {};
Convenience type for dealing with fields.
*/
typedef pair<string, intrusive_ptr<const Value> > FieldPair;
/* private:
Get the indicated field. friend class FieldIterator;
friend class ValueStorage;
friend class MutableDocument;
@param index the field index in the list of fields const DocumentStorage& storage() const {
@returns the field name and value of the field return (_storage ? *_storage : DocumentStorage::emptyDoc());
*/ }
FieldPair getField(size_t index) const; intrusive_ptr<const DocumentStorage> _storage;
};
/* /** This class is returned by MutableDocument to allow you to modify it
Get the number of fields in the Document. s values.
* You are not allowed to hold variables of this type (enforced by the
type system).
*/
class MutableValue {
public:
void operator= (const Value& v) { _val = v; }
@returns the number of fields in the Document /** These are designed to allow things like mutDoc["a"]["b"]["c"] =
Value(10);
* It is safe to use even on nonexistent fields.
*/ */
size_t getFieldCount() const; MutableValue operator[] (StringData key) { return getField(key); }
MutableValue operator[] (Position pos) { return getField(pos); }
/*
Get the index of the given field.
@param fieldName the name of the field MutableValue getField(StringData key);
@returns the index of the field, or if it does not exist, the num MutableValue getField(Position pos);
ber
of fields (getFieldCount())
*/
size_t getFieldIndex(const string &fieldName) const;
/* private:
Get a field by name. friend class MutableDocument;
@param fieldName the name of the field /// can only be constructed or copied by self and friends
@returns the value of the field MutableValue(const MutableValue& other): _val(other._val) {}
*/ explicit MutableValue(Value& val): _val(val) {}
intrusive_ptr<const Value> getField(const string &fieldName) const;
/* /// Used by MutableDocument(MutableValue)
Get the approximate storage size of the document, in bytes. const RefCountable*& getDocPtr() {
if (_val.getType() != Object)
*this = Value(Document());
Under the assumption that field name strings are shared, they are return _val._storage.genericRCPtr;
not included in the total. }
@returns the approximate storage MutableValue& operator= (const MutableValue&); // not assignable wi
*/ th another MutableValue
size_t getApproximateSize() const;
/* Value& _val;
Compare two documents. };
BSON document field order is significant, so this just goes throu
gh
the fields in order. The comparison is done in roughly the same
way
as strings are compared, but comparing one field at a time instea
d
of one character at a time.
*/
static int compare(const intrusive_ptr<Document> &rL,
const intrusive_ptr<Document> &rR);
static string idName; // shared "_id"
/* /** MutableDocument is a Document builder that supports both adding and
Calculate a hash value. updating fields.
*
* This class fills a similar role to BSONObjBuilder, but allows you t
o
* change existing fields and more easily write to sub-Documents.
*
* To preserve the immutability of Documents, MutableDocument will
* shallow-clone its storage on write (COW) if it is shared with any o
ther
* Documents.
*/
class MutableDocument : boost::noncopyable {
public:
Meant to be used to create composite hashes suitable for /** Create a new empty Document.
boost classes such as unordered_map<>. *
* @param expectedFields a hint at what the number of fields will
be, if known.
* this can be used to increase memory allocation efficienc
y. There is
* no impact on correctness if this field over or under est
imates.
*
* TODO: find some way to convey field-name sizes to make even mor
e efficient
*/
MutableDocument() :_storageHolder(NULL), _storage(_storageHolder) {
}
explicit MutableDocument(size_t expectedFields);
@param seed value to augment with this' hash /// No copy yet. Copy-on-write. See storage()
*/ explicit MutableDocument(const Document& d) : _storageHolder(NULL)
void hash_combine(size_t &seed) const; , _storage(_storageHold
er) {
reset(d);
}
~MutableDocument() {
if (_storageHolder)
intrusive_ptr_release(_storageHolder);
}
/** Replace the current base Document with the argument
*
* All Positions from the passed in Document are valid and refer t
o the
* same field in this MutableDocument.
*/
void reset(const Document& d=Document()) { reset(d._storage.get());
}
// For debugging purposes only! /** Add the given field to the Document.
string toString() const; *
* BSON documents' fields are ordered; the new Field will be
* appended to the current list of fields.
*
* Unlike getField/setField, addField does not look for a field wi
th the
* same name and therefore cannot be used to update fields.
*
* It is an error to add a field that has the same name as another
field.
*
* TODO: This is currently allowed but getField only gets first fi
eld.
* Decide what level of support is needed for duplicate fiel
ds.
* If duplicates are not allowed, consider removing this met
hod.
*/
void addField(StringData fieldName, const Value& val) {
storage().appendField(fieldName) = val;
}
/** Update field by key. If there is no field with that key, add on
e.
*
* If the new value is missing(), the field is logically removed.
*/
MutableValue operator[] (StringData key) { return getField(key); }
void setField(StringData key, const Value& val) { getField(key) = v
al; }
MutableValue getField(StringData key) {
return MutableValue(storage().getField(key));
}
/// Update field by Position. Must already be a valid Position.
MutableValue operator[] (Position pos) { return getField(pos); }
void setField(Position pos, const Value& val) { getField(pos) = val
; }
MutableValue getField(Position pos) {
return MutableValue(storage().getField(pos).val);
}
/// Logically remove a field. Note that memory usage does not decre
ase.
void remove(StringData key) { getField(key) = Value(); }
/// Takes positions vector from Document::getNestedField.
MutableValue getNestedField(const vector<Position>& positions);
void setNestedField(const vector<Position>& positions, const Value&
val) {
getNestedField(positions) = val;
}
/** Convert to a read-only document and release reference.
*
* Call this to indicate that you are done with this Document and
will
* not be making further changes from this MutableDocument.
*
* TODO: there are some optimizations that may make sense at freez
e time.
*/
Document freeze() {
Document ret(storagePtr());
reset(NULL);
return ret;
}
/** Borrow a readable reference to this Document.
*
* Note that unlike freeze(), this indicates intention to continue
* modifying this document. The returned Document will not observe
* future changes to this MutableDocument.
*/
Document peek() {
return Document(storagePtr());
}
private: private:
friend class FieldIterator; friend class MutableValue; // for access to next constructor
explicit MutableDocument(MutableValue mv)
Document(size_t sizeHint); : _storageHolder(NULL)
Document(BSONObj* pBsonObj); , _storage(mv.getDocPtr())
{}
/* these two vectors parallel each other */
vector<string> vFieldName; void reset(const DocumentStorage* ds) {
vector<intrusive_ptr<const Value> > vpValue; if (_storage) intrusive_ptr_release(_storage);
_storage = ds;
if (_storage) intrusive_ptr_add_ref(_storage);
}
// This is split into 3 functions to speed up the fast-path
DocumentStorage& storage() {
if (MONGO_unlikely( !_storage ))
return newStorage();
if (MONGO_unlikely( _storage->isShared() ))
return clonedStorage();
// This function exists to ensure this is safe
return const_cast<DocumentStorage&>(*storagePtr());
}
DocumentStorage& newStorage() {
reset(new DocumentStorage);
return const_cast<DocumentStorage&>(*storagePtr());
}
DocumentStorage& clonedStorage() {
reset(storagePtr()->clone().get());
return const_cast<DocumentStorage&>(*storagePtr());
}
MutableValue getNestedFieldHelper(MutableDocument& md,
const vector<Position>& positions
,
size_t level);
// this should only be called by storage methods and peek/freeze
const DocumentStorage* storagePtr() const {
dassert(!_storage || typeid(*_storage) == typeid(const Document
Storage));
return static_cast<const DocumentStorage*>(_storage);
}
// These are both const to prevent modifications bypassing storage(
) method.
// 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*& _storage; // references either above member or
genericRCPtr in a Value
}; };
class FieldIterator : /// This is the public iterator over a document
boost::noncopyable { class FieldIterator {
public: public:
/* explicit FieldIterator(const Document& doc)
Ask if there are more fields to return. : _doc(doc)
, _it(_doc.storage().iterator())
@return true if there are more fields, false otherwise {}
*/
bool more() const; /// Ask if there are more fields to return.
bool more() const { return !_it.atEnd(); }
/*
Move the iterator to point to the next field and return it. /// Get next item and advance iterator
Document::FieldPair next() {
@return the next field's <name, Value> verify(more());
*/
Document::FieldPair next(); Document::FieldPair fp (_it->nameSD(), _it->val);
_it.advance();
/* return fp;
Constructor. }
@param pDocument points to the document whose fields are being
iterated
*/
FieldIterator(const intrusive_ptr<Document> &pDocument);
private: private:
friend class Document; // We'll hang on to the original document to ensure we keep its sto
rage alive
/* Document _doc;
We'll hang on to the original document to ensure we keep the DocumentStorageIterator _it;
fieldPtr vector alive.
*/
intrusive_ptr<Document> pDocument;
size_t index; // current field in iteration
}; };
} }
namespace std {
template<>
inline void swap(mongo::Document& lhs, mongo::Document& rhs) { lhs.swap
(rhs); }
}
/* ======================= INLINED IMPLEMENTATIONS ======================== == */ /* ======================= INLINED IMPLEMENTATIONS ======================== == */
namespace mongo { namespace mongo {
inline FieldIterator Document::fieldIterator() const {
inline size_t Document::getFieldCount() const { return FieldIterator(*this);
return vFieldName.size();
} }
inline Document::FieldPair Document::getField(size_t index) const { inline MutableValue MutableValue::getField(Position pos) {
verify( index < vFieldName.size() ); return MutableDocument(*this).getField(pos);
return FieldPair(vFieldName[index], vpValue[index]); }
inline MutableValue MutableValue::getField(StringData key) {
return MutableDocument(*this).getField(key);
} }
} }
 End of changes. 48 change blocks. 
177 lines changed or deleted 396 lines changed or added


 document_source.h   document_source.h 
skipping to change at line 31 skipping to change at line 31
#include <boost/unordered_map.hpp> #include <boost/unordered_map.hpp>
#include "util/intrusive_counter.h" #include "util/intrusive_counter.h"
#include "db/clientcursor.h" #include "db/clientcursor.h"
#include "db/jsobj.h" #include "db/jsobj.h"
#include "db/pipeline/document.h" #include "db/pipeline/document.h"
#include "db/pipeline/expression.h" #include "db/pipeline/expression.h"
#include "mongo/db/pipeline/expression_context.h" #include "mongo/db/pipeline/expression_context.h"
#include "db/pipeline/value.h" #include "db/pipeline/value.h"
#include "util/string_writer.h" #include "util/string_writer.h"
#include "mongo/db/projection.h" #include "mongo/db/projection.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 Matcher; class Matcher;
class Shard;
class ShardChunkManager;
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 92 skipping to change at line 91
in their own implementations in order to check for interrupts. in their own implementations in order to check for interrupts.
@returns whether there is another document to fetch, i.e., whethe r or @returns whether there is another document to fetch, i.e., whethe r or
not getCurrent() will succeed. This default implementation alw ays not getCurrent() will succeed. This default implementation alw ays
returns false. returns false.
*/ */
virtual bool advance(); virtual bool advance();
/** @returns the current Document without advancing. /** @returns the current Document without advancing.
* *
* some implementations do the equivalent of verify(!eof()) so che * It is illegal to call this without first checking eof() == fals
ck eof() first e or advance() == true.
*
* While it is legal to call getCurrent() multiple times between c
alls to advance, and
* you will get the same Document returned, some DocumentSources d
o expensive work in
* getCurrent(). You are advised to cache the result if you plan t
o access it more than
* once.
*/ */
virtual intrusive_ptr<Document> getCurrent() = 0; virtual Document getCurrent() = 0;
/** /**
* Inform the source that it is no longer needed and may release it s resources. After * Inform the source that it is no longer needed and may release it s resources. After
* dispose() is called the source must still be able to handle iter ation requests, but may * dispose() is called the source must still be able to handle iter ation requests, but may
* become eof(). * become eof().
* NOTE: For proper mutex yielding, dispose() must be called on any DocumentSource that will * NOTE: For proper mutex yielding, dispose() must be called on any DocumentSource that will
* not be advanced until eof(), see SERVER-6123. * not be advanced until eof(), see SERVER-6123.
*/ */
virtual void dispose(); virtual void dispose();
skipping to change at line 261 skipping to change at line 265
SplittableDocumentSource(intrusive_ptr<ExpressionContext> ctx) :Doc umentSource(ctx) {} SplittableDocumentSource(intrusive_ptr<ExpressionContext> ctx) :Doc umentSource(ctx) {}
}; };
class DocumentSourceBsonArray : class DocumentSourceBsonArray :
public DocumentSource { public DocumentSource {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceBsonArray(); virtual ~DocumentSourceBsonArray();
virtual bool eof(); virtual bool eof();
virtual bool advance(); virtual bool advance();
virtual intrusive_ptr<Document> getCurrent(); virtual Document getCurrent();
virtual void setSource(DocumentSource *pSource); virtual void setSource(DocumentSource *pSource);
/** /**
Create a document source based on a BSON array. Create a document source based on a BSON array.
This is usually put at the beginning of a chain of document sourc es This is usually put at the beginning of a chain of document sourc es
in order to fetch data from the database. in order to fetch data from the database.
CAUTION: the BSON is not read until the source is used. Any CAUTION: the BSON is not read until the source is used. Any
elements that appear after these documents must not be read until elements that appear after these documents must not be read until
skipping to change at line 303 skipping to change at line 307
bool haveCurrent; bool haveCurrent;
}; };
class DocumentSourceCommandShards : class DocumentSourceCommandShards :
public DocumentSource { public DocumentSource {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceCommandShards(); virtual ~DocumentSourceCommandShards();
virtual bool eof(); virtual bool eof();
virtual bool advance(); virtual bool advance();
virtual intrusive_ptr<Document> getCurrent(); virtual Document getCurrent();
virtual void setSource(DocumentSource *pSource); virtual void setSource(DocumentSource *pSource);
/* convenient shorthand for a commonly used type */ /* convenient shorthand for a commonly used type */
typedef map<Shard, BSONObj> ShardOutput; typedef map<Shard, BSONObj> ShardOutput;
/** /**
Create a DocumentSource that wraps the output of many shards Create a DocumentSource that wraps the output of many shards
@param shardOutput output from the individual shards @param shardOutput output from the individual shards
@param pExpCtx the expression context for the pipeline @param pExpCtx the expression context for the pipeline
skipping to change at line 337 skipping to change at line 341
/** /**
Advance to the next document, setting pCurrent appropriately. Advance to the next document, setting pCurrent appropriately.
Adjusts pCurrent, pBsonSource, and iterator, as needed. On exit, Adjusts pCurrent, pBsonSource, and iterator, as needed. On exit,
pCurrent is the Document to return, or NULL. If NULL, this pCurrent is the Document to return, or NULL. If NULL, this
indicates there is nothing more to return. indicates there is nothing more to return.
*/ */
void getNextDocument(); void getNextDocument();
bool unstarted;
bool hasCurrent;
bool newSource; // set to true for the first item of a new source bool newSource; // set to true for the first item of a new source
intrusive_ptr<DocumentSourceBsonArray> pBsonSource; intrusive_ptr<DocumentSourceBsonArray> pBsonSource;
intrusive_ptr<Document> pCurrent; Document pCurrent;
ShardOutput::const_iterator iterator; ShardOutput::const_iterator iterator;
ShardOutput::const_iterator listEnd; ShardOutput::const_iterator listEnd;
}; };
/** /**
* Constructs and returns Documents from the BSONObj objects produced b y a supplied Cursor. * Constructs and returns Documents from the BSONObj objects produced b y a supplied Cursor.
* An object of this type may only be used by one thread, see SERVER-61 23. * An object of this type may only be used by one thread, see SERVER-61 23.
*/ */
class DocumentSourceCursor : class DocumentSourceCursor :
public DocumentSource { public DocumentSource {
skipping to change at line 370 skipping to change at line 376
// members may depend on the read lock it acquires. // members may depend on the read lock it acquires.
Client::ReadContext _readContext; Client::ReadContext _readContext;
shared_ptr<ShardChunkManager> _chunkMgr; shared_ptr<ShardChunkManager> _chunkMgr;
ClientCursor::Holder _cursor; ClientCursor::Holder _cursor;
}; };
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceCursor(); virtual ~DocumentSourceCursor();
virtual bool eof(); virtual bool eof();
virtual bool advance(); virtual bool advance();
virtual intrusive_ptr<Document> getCurrent(); virtual Document getCurrent();
virtual void setSource(DocumentSource *pSource); virtual void setSource(DocumentSource *pSource);
/** /**
* Release the Cursor and the read lock it requires, but without ch anging the other data. * Release the Cursor and the read lock it requires, but without ch anging the other data.
* Releasing the lock is required for proper concurrency, see SERVE R-6123. This * Releasing the lock is required for proper concurrency, see SERVE R-6123. This
* functionality is also used by the explain version of pipeline ex ecution. * functionality is also used by the explain version of pipeline ex ecution.
*/ */
virtual void dispose(); virtual void dispose();
/** /**
skipping to change at line 438 skipping to change at line 444
// 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();
intrusive_ptr<Document> pCurrent; bool unstarted;
bool hasCurrent;
Document pCurrent;
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;
skipping to change at line 482 skipping to change at line 490
factored out so we could create DocumentSources that use both Matcher factored out so we could create DocumentSources that use both Matcher
style predicates as well as full Expressions. style predicates as well as full Expressions.
*/ */
class DocumentSourceFilterBase : class DocumentSourceFilterBase :
public DocumentSource { public DocumentSource {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceFilterBase(); virtual ~DocumentSourceFilterBase();
virtual bool eof(); virtual bool eof();
virtual bool advance(); virtual bool advance();
virtual intrusive_ptr<Document> getCurrent(); virtual Document getCurrent();
/** /**
Create a BSONObj suitable for Matcher construction. Create a BSONObj suitable for Matcher construction.
This is used after filter analysis has moved as many filters to This is used after filter analysis has moved as many filters to
as early a point as possible in the document processing pipeline. as early a point as possible in the document processing pipeline.
See db/Matcher.h and the associated wiki documentation for the See db/Matcher.h and the associated wiki documentation for the
format. This conversion is used to move back to the low-level format. This conversion is used to move back to the low-level
find() Cursor mechanism. find() Cursor mechanism.
skipping to change at line 508 skipping to change at line 516
DocumentSourceFilterBase( DocumentSourceFilterBase(
const intrusive_ptr<ExpressionContext> &pExpCtx); const intrusive_ptr<ExpressionContext> &pExpCtx);
/** /**
Test the given document against the predicate and report if it Test the given document against the predicate and report if it
should be accepted or not. should be accepted or not.
@param pDocument the document to test @param pDocument the document to test
@returns true if the document matches the filter, false otherwise @returns true if the document matches the filter, false otherwise
*/ */
virtual bool accept(const intrusive_ptr<Document> &pDocument) const = 0; virtual bool accept(const Document& pDocument) const = 0;
private: private:
void findNext(); void findNext();
bool unstarted; bool unstarted;
bool hasNext; bool hasCurrent;
intrusive_ptr<Document> pCurrent; Document pCurrent;
}; };
class DocumentSourceFilter : class DocumentSourceFilter :
public DocumentSourceFilterBase { public DocumentSourceFilterBase {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceFilter(); virtual ~DocumentSourceFilter();
virtual bool coalesce(const intrusive_ptr<DocumentSource> &pNextSou rce); virtual bool coalesce(const intrusive_ptr<DocumentSource> &pNextSou rce);
virtual void optimize(); virtual void optimize();
virtual const char *getSourceName() const; virtual const char *getSourceName() const;
skipping to change at line 570 skipping to change at line 578
*/ */
void toMatcherBson(BSONObjBuilder *pBuilder) const; void toMatcherBson(BSONObjBuilder *pBuilder) const;
static const char filterName[]; static const char filterName[];
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;
// virtuals from DocumentSourceFilterBase // virtuals from DocumentSourceFilterBase
virtual bool accept(const intrusive_ptr<Document> &pDocument) const ; virtual bool accept(const Document& pDocument) const;
private: private:
DocumentSourceFilter(const intrusive_ptr<Expression> &pFilter, DocumentSourceFilter(const intrusive_ptr<Expression> &pFilter,
const intrusive_ptr<ExpressionContext> &pExpCt x); const intrusive_ptr<ExpressionContext> &pExpCt x);
intrusive_ptr<Expression> pFilter; intrusive_ptr<Expression> pFilter;
}; };
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 intrusive_ptr<Document> getCurrent(); virtual Document getCurrent();
virtual GetDepsReturn getDependencies(set<string>& deps) const; virtual GetDepsReturn getDependencies(set<string>& deps) const;
/** /**
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 666 skipping to change at line 674
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;
intrusive_ptr<Expression> pIdExpression; intrusive_ptr<Expression> pIdExpression;
typedef boost::unordered_map<intrusive_ptr<const Value>, typedef boost::unordered_map<Value,
vector<intrusive_ptr<Accumulator> >, Value::Hash> GroupsType; vector<intrusive_ptr<Accumulator> >, Value::Hash> GroupsType;
GroupsType groups; GroupsType groups;
/* /*
The field names for the result documents and the accumulator The field names for the result documents and the accumulator
factories for the result documents. The Expressions are the factories for the result documents. The Expressions are the
common expressions used by each instance of each accumulator common expressions used by each instance of each accumulator
in order to find the right-hand side of what gets added to the in order to find the right-hand side of what gets added to the
accumulator. Note that each of those is the same for each group, accumulator. Note that each of those is the same for each group,
so we can share them across all groups by adding them to the so we can share them across all groups by adding them to the
accumulators after we use the factories to make a new set of accumulators after we use the factories to make a new set of
accumulators for each new group. accumulators for each new group.
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;
intrusive_ptr<Document> makeDocument( Document makeDocument(const GroupsType::iterator &rIter);
const GroupsType::iterator &rIter);
GroupsType::iterator groupsIterator; GroupsType::iterator groupsIterator;
intrusive_ptr<Document> pCurrent; 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 731 skipping to change at line 738
*/ */
void toMatcherBson(BSONObjBuilder *pBuilder) const; void toMatcherBson(BSONObjBuilder *pBuilder) const;
static const char matchName[]; static const char matchName[];
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;
// virtuals from DocumentSourceFilterBase // virtuals from DocumentSourceFilterBase
virtual bool accept(const intrusive_ptr<Document> &pDocument) const ; virtual bool accept(const Document& pDocument) const;
private: private:
DocumentSourceMatch(const BSONObj &query, DocumentSourceMatch(const BSONObj &query,
const intrusive_ptr<ExpressionContext> &pExpCtx); const intrusive_ptr<ExpressionContext> &pExpCtx);
Matcher matcher; Matcher matcher;
}; };
class DocumentSourceOut : class DocumentSourceOut :
public DocumentSource { public DocumentSource {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceOut(); virtual ~DocumentSourceOut();
virtual bool eof(); virtual bool eof();
virtual bool advance(); virtual bool advance();
virtual const char *getSourceName() const; virtual const char *getSourceName() const;
virtual intrusive_ptr<Document> getCurrent(); virtual Document getCurrent();
/** /**
Create a document source for output and pass-through. Create a document source for output and pass-through.
This can be put anywhere in a pipeline and will store content as This can be put anywhere in a pipeline and will store content as
well as pass it on. well as pass it on.
@param pBsonElement the raw BSON specification for the source @param pBsonElement the raw BSON specification for the source
@param pExpCtx the expression context for the pipeline @param pExpCtx the expression context for the pipeline
@returns the newly created document source @returns the newly created document source
skipping to change at line 783 skipping to change at line 790
}; };
class DocumentSourceProject : class DocumentSourceProject :
public DocumentSource { public DocumentSource {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceProject(); virtual ~DocumentSourceProject();
virtual bool eof(); virtual bool eof();
virtual bool advance(); virtual bool advance();
virtual const char *getSourceName() const; virtual const char *getSourceName() const;
virtual intrusive_ptr<Document> getCurrent(); virtual Document getCurrent();
virtual void optimize(); virtual void optimize();
virtual GetDepsReturn getDependencies(set<string>& deps) const; virtual GetDepsReturn getDependencies(set<string>& deps) const;
/** /**
Create a new projection DocumentSource from BSON. Create a new projection DocumentSource from BSON.
This is a convenience for directly handling BSON, and relies on t he This is a convenience for directly handling BSON, and relies on t he
above methods. above methods.
skipping to change at line 832 skipping to change at line 839
}; };
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 intrusive_ptr<Document> getCurrent(); virtual Document getCurrent();
virtual GetDepsReturn getDependencies(set<string>& deps) const; virtual GetDepsReturn getDependencies(set<string>& deps) const;
/* /*
TODO TODO
Adjacent sorts should reduce to the last sort. 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);
*/ */
/** /**
skipping to change at line 924 skipping to change at line 931
vector<bool> vAscending; vector<bool> vAscending;
/* /*
Compare two documents according to the specified sort key. Compare two documents according to the specified sort key.
@param rL reference to the left document @param rL reference to the left document
@param rR reference to the right document @param rR reference to the right document
@returns a number less than, equal to, or greater than zero, @returns a number less than, equal to, or greater than zero,
indicating pL < pR, pL == pR, or pL > pR, respectively indicating pL < pR, pL == pR, or pL > pR, respectively
*/ */
int compare(const intrusive_ptr<Document> &pL, int compare(const Document& pL, const Document& pR);
const intrusive_ptr<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()( bool operator()(const Document& pL, const Document& pR) {
const intrusive_ptr<Document> &pL,
const intrusive_ptr<Document> &pR) {
return (pSort->compare(pL, pR) < 0); return (pSort->compare(pL, pR) < 0);
} }
inline Comparator(DocumentSourceSort *pS): inline Comparator(DocumentSourceSort *pS):
pSort(pS) { pSort(pS) {
} }
private: private:
DocumentSourceSort *pSort; DocumentSourceSort *pSort;
}; };
typedef vector<intrusive_ptr<Document> > VectorType; typedef vector<Document> VectorType;
VectorType documents; VectorType documents;
VectorType::iterator docIterator; VectorType::iterator docIterator;
intrusive_ptr<Document> pCurrent; Document pCurrent;
}; };
class DocumentSourceLimit : class DocumentSourceLimit :
public DocumentSource { 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 intrusive_ptr<Document> getCurrent(); virtual Document getCurrent();
virtual const char *getSourceName() const; virtual const char *getSourceName() const;
virtual bool coalesce(const intrusive_ptr<DocumentSource> &pNextSou rce); virtual bool coalesce(const intrusive_ptr<DocumentSource> &pNextSou rce);
virtual GetDepsReturn getDependencies(set<string>& deps) const { virtual GetDepsReturn getDependencies(set<string>& deps) const {
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);
// Virtuals for SplittableDocumentSource
// 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> getRouterSource() { return th
is; }
long long getLimit() const { return limit; }
void setLimit(long long newLimit) { limit = newLimit; }
/** /**
Create a limiting DocumentSource from BSON. Create a limiting DocumentSource from BSON.
This is a convenience method that uses the above, and operates on This is a convenience method that uses the above, and operates on
a BSONElement that has been deteremined to be an Object with an a BSONElement that has been deteremined to be an Object with an
element named $limit. element named $limit.
@param pBsonElement the BSONELement that defines the limit @param pBsonElement the BSONELement that defines the limit
@param pExpCtx the expression context @param pExpCtx the expression context
@returns the grouping DocumentSource @returns the grouping DocumentSource
skipping to change at line 1005 skipping to change at line 1017
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 count; long long count;
intrusive_ptr<Document> pCurrent;
}; };
class DocumentSourceSkip : class DocumentSourceSkip :
public DocumentSource { public SplittableDocumentSource {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceSkip(); virtual ~DocumentSourceSkip();
virtual bool eof(); virtual bool eof();
virtual bool advance(); virtual bool advance();
virtual intrusive_ptr<Document> getCurrent(); virtual Document getCurrent();
virtual const char *getSourceName() const; virtual const char *getSourceName() const;
virtual bool coalesce(const intrusive_ptr<DocumentSource> &pNextSou rce); virtual bool coalesce(const intrusive_ptr<DocumentSource> &pNextSou rce);
virtual GetDepsReturn getDependencies(set<string>& deps) const { virtual GetDepsReturn getDependencies(set<string>& deps) const {
return SEE_NEXT; // This doesn't affect needed fields return SEE_NEXT; // This doesn't affect needed fields
} }
/** /**
Create a new skipping DocumentSource. Create a new skipping DocumentSource.
@param pExpCtx the expression context @param pExpCtx the expression context
@returns the DocumentSource @returns the DocumentSource
*/ */
static intrusive_ptr<DocumentSourceSkip> create( static intrusive_ptr<DocumentSourceSkip> create(
const intrusive_ptr<ExpressionContext> &pExpCtx); const intrusive_ptr<ExpressionContext> &pExpCtx);
// Virtuals for SplittableDocumentSource
// Need to run on rounter. Can't run on shards.
virtual intrusive_ptr<DocumentSource> getShardSource() { return NUL
L; }
virtual intrusive_ptr<DocumentSource> getRouterSource() { return th
is; }
long long getSkip() const { return skip; }
void setSkip(long long newSkip) { skip = newSkip; }
/** /**
Create a skipping DocumentSource from BSON. Create a skipping DocumentSource from BSON.
This is a convenience method that uses the above, and operates on This is a convenience method that uses the above, and operates on
a BSONElement that has been deteremined to be an Object with an a BSONElement that has been deteremined to be an Object with an
element named $skip. element named $skip.
@param pBsonElement the BSONELement that defines the skip @param pBsonElement the BSONELement that defines the skip
@param pExpCtx the expression context @param pExpCtx the expression context
@returns the grouping DocumentSource @returns the grouping DocumentSource
skipping to change at line 1063 skipping to change at line 1082
private: private:
DocumentSourceSkip(const intrusive_ptr<ExpressionContext> &pExpCtx) ; DocumentSourceSkip(const intrusive_ptr<ExpressionContext> &pExpCtx) ;
/* /*
Skips initial documents. Skips initial documents.
*/ */
void skipper(); void skipper();
long long skip; long long skip;
long long count; long long count;
intrusive_ptr<Document> pCurrent; Document pCurrent;
}; };
class DocumentSourceUnwind : class DocumentSourceUnwind :
public DocumentSource { public DocumentSource {
public: public:
// virtuals from DocumentSource // virtuals from DocumentSource
virtual ~DocumentSourceUnwind(); virtual ~DocumentSourceUnwind();
virtual bool eof(); virtual bool eof();
virtual bool advance(); virtual bool advance();
virtual const char *getSourceName() const; virtual const char *getSourceName() const;
virtual intrusive_ptr<Document> getCurrent(); virtual Document getCurrent();
virtual GetDepsReturn getDependencies(set<string>& deps) const; virtual GetDepsReturn getDependencies(set<string>& deps) const;
/** /**
Create a new projection DocumentSource from BSON. Create a new projection DocumentSource from BSON.
This is a convenience for directly handling BSON, and relies on t he This is a convenience for directly handling BSON, and relies on t he
above methods. above methods.
@param pBsonElement the BSONElement with an object named $project @param pBsonElement the BSONElement with an object named $project
 End of changes. 35 change blocks. 
38 lines changed or deleted 65 lines changed or added


 engine_spidermonkey.h   engine_spidermonkey.h 
skipping to change at line 51 skipping to change at line 51
#ifdef JSVAL_IS_TRACEABLE #ifdef JSVAL_IS_TRACEABLE
#define SM18 #define SM18
#endif #endif
#ifdef XULRUNNER #ifdef XULRUNNER
#define SM181 #define SM181
#endif #endif
namespace mongo { namespace mongo {
namespace spidermonkey {
class SMScope; class SMScope;
class Convertor; class Convertor;
extern JSClass bson_class; extern JSClass bson_class;
extern JSClass bson_ro_class; extern JSClass bson_ro_class;
extern JSClass object_id_class; extern JSClass object_id_class;
extern JSClass dbpointer_class; extern JSClass dbpointer_class;
extern JSClass dbref_class; extern JSClass dbref_class;
extern JSClass bindata_class; extern JSClass bindata_class;
extern JSClass timestamp_class; extern JSClass timestamp_class;
extern JSClass numberlong_class; extern JSClass numberlong_class;
extern JSClass numberint_class; extern JSClass numberint_class;
extern JSClass minkey_class; extern JSClass minkey_class;
extern JSClass maxkey_class; extern JSClass maxkey_class;
// internal things // internal things
void dontDeleteScope( SMScope * s ) {} inline void dontDeleteScope( SMScope * s ) {}
void errorReporter( JSContext *cx, const char *message, JSErrorReport * report ); void errorReporter( JSContext *cx, const char *message, JSErrorReport * report );
extern boost::thread_specific_ptr<SMScope> currentScope; extern boost::thread_specific_ptr<SMScope> currentScope;
// bson // bson
JSBool resolveBSONField( JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp ); JSBool resolveBSONField( JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp );
// mongo // mongo
void initMongoJS( SMScope * scope , JSContext * cx , JSObject * global , bool local ); void initMongoJS( SMScope * scope , JSContext * cx , JSObject * global , bool local );
bool appendSpecialDBObject( Convertor * c , BSONObjBuilder& b , const s tring& name , jsval val , JSObject * o ); bool appendSpecialDBObject( Convertor * c , BSONObjBuilder& b , const s tring& name , jsval val , JSObject * o );
skipping to change at line 101 skipping to change at line 102
memcpy( c_, c, copyLen ); memcpy( c_, c, copyLen );
} }
} }
~BinDataHolder() { ~BinDataHolder() {
if ( iFree_ ) if ( iFree_ )
free( c_ ); free( c_ );
} }
char *c_; char *c_;
bool iFree_; bool iFree_;
}; };
}
} // namespace spidermonkey
} // namespace mongo
 End of changes. 3 change blocks. 
1 lines changed or deleted 2 lines changed or added


 engine_v8.h   engine_v8.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 <vector>
#include "engine.h"
#include <v8.h> #include <v8.h>
#include <vector>
#include "mongo/scripting/engine.h"
using namespace v8; using namespace v8;
namespace mongo { namespace mongo {
class V8ScriptEngine; class V8ScriptEngine;
class V8Scope; class V8Scope;
typedef Handle< Value > (*v8Function) ( V8Scope* scope, const v8::Argum ents& args ); typedef Handle< Value > (*v8Function) ( V8Scope* scope, const v8::Argum ents& args );
skipping to change at line 148 skipping to change at line 149
Handle<v8::FunctionTemplate> createV8Function( v8Function func ); Handle<v8::FunctionTemplate> createV8Function( v8Function func );
void gc(); void gc();
Handle< Context > context() const { return _context; } Handle< Context > context() const { return _context; }
v8::Local<v8::Object> mongoToV8( const mongo::BSONObj & m , bool ar ray = 0 , bool readOnly = false ); v8::Local<v8::Object> mongoToV8( const mongo::BSONObj & m , bool ar ray = 0 , bool readOnly = false );
v8::Handle<v8::Object> mongoToLZV8( const mongo::BSONObj & m , bool array = 0 , bool readOnly = false ); v8::Handle<v8::Object> mongoToLZV8( const mongo::BSONObj & m , bool array = 0 , bool readOnly = false );
mongo::BSONObj v8ToMongo( v8::Handle<v8::Object> o , int depth = 0 ); mongo::BSONObj v8ToMongo( v8::Handle<v8::Object> o , int depth = 0 );
void v8ToMongoElement( BSONObjBuilder & b , const string sname , v8 // v8 to mongo/BSON conversion functions
::Handle<v8::Value> value , int depth = 0, BSONObj* originalParent=0 ); void v8ToMongoElement(BSONObjBuilder& b,
const string& sname,
v8::Handle<v8::Value> value,
int depth = 0,
BSONObj* originalParent = 0);
void v8ToMongoObject(BSONObjBuilder& b,
const string& sname,
v8::Handle<v8::Value> value,
int depth,
BSONObj* originalParent);
void v8ToMongoNumber(BSONObjBuilder& b,
const string& elementName,
v8::Handle<v8::Value> value,
BSONObj* originalParent);
void v8ToMongoNumberLong(BSONObjBuilder& b,
const string& elementName,
v8::Handle<v8::Object> obj);
void v8ToMongoInternal(BSONObjBuilder& b,
const string& elementName,
v8::Handle<v8::Object> obj);
void v8ToMongoRegex(BSONObjBuilder& b,
const string& elementName,
string& regex);
void v8ToMongoDBRef(BSONObjBuilder& b,
const string& elementName,
v8::Handle<v8::Object> obj);
void v8ToMongoBinData(BSONObjBuilder& b,
const string& elementName,
v8::Handle<v8::Object> obj);
void v8ToMongoObjectID(BSONObjBuilder& b,
const string& elementName,
v8::Handle<v8::Object> obj);
v8::Handle<v8::Value> mongoToV8Element( const BSONElement &f, bool readOnly = false ); v8::Handle<v8::Value> mongoToV8Element( const BSONElement &f, bool readOnly = false );
virtual void append( BSONObjBuilder & builder , const char * fieldN ame , const char * scopeName ); virtual void append( BSONObjBuilder & builder , const char * fieldN ame , const char * scopeName );
v8::Function * getNamedCons( const char * name ); v8::Function * getNamedCons( const char * name );
v8::Function * getObjectIdCons(); v8::Function * getObjectIdCons();
Local< v8::Value > newId( const OID &id ); Local< v8::Value > newId( const OID &id );
Persistent<v8::Object> wrapBSONObject(Local<v8::Object> obj, BSONHo lder* data); Persistent<v8::Object> wrapBSONObject(Local<v8::Object> obj, BSONHo lder* data);
Persistent<v8::Object> wrapArrayObject(Local<v8::Object> obj, char* data); Persistent<v8::Object> wrapArrayObject(Local<v8::Object> obj, char* data);
 End of changes. 3 change blocks. 
4 lines changed or deleted 37 lines changed or added


 error_codes.h   error_codes.h 
/* Copyright 2012 10gen Inc. // AUTO-GENERATED FILE DO NOT EDIT
* // See src/mongo/base/generate_error_codes.py
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or impli
ed.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once #pragma once
#include <string> #include "mongo/base/string_data.h"
namespace mongo { namespace mongo {
/** /**
* This is a generated class containg a table of error codes and their * This is a generated class containing a table of error codes and thei
corresponding r corresponding error
* error strings. The class is derived from the definitions in the erro * strings. The class is derived from the definitions in src/mongo/base
r_codes.err /error_codes.err file.
* file.
*
* TODO: Do not update this file directly. Update error_codes.err inste
ad.
*
* # Error table
* [OK, "ok"]
* [InternalError, 1]
* [BadValue, 2]
* ...
* [HostUnreachable, <nnnn>]
* [HostNotFound, <nnnn>]
*
* # Error classes
* [NetworkError, [HostUnreachable, HostNotFound]]
* *
* Do not update this file directly. Update src/mongo/base/error_codes. err instead.
*/ */
class ErrorCodes { class ErrorCodes {
public: public:
enum Error { enum Error {
OK = 0, OK = 0,
InternalError = 1, InternalError = 1,
BadValue = 2, BadValue = 2,
DuplicateKey = 3, DuplicateKey = 3,
NoSuchKey = 4, NoSuchKey = 4,
GraphContainsCycle = 5, GraphContainsCycle = 5,
HostUnreachable = 6, HostUnreachable = 6,
HostNotFound = 7, HostNotFound = 7,
UnknownError = 8, UnknownError = 8,
FailedToParse = 9, FailedToParse = 9,
CannotMutateObject = 10, CannotMutateObject = 10,
UserNotFound = 11, UserNotFound = 11,
UnsupportedFormat = 12, UnsupportedFormat = 12,
Unauthorized = 13, Unauthorized = 13,
TypeMismatch = 14,
Overflow = 15,
InvalidLength = 16,
ProtocolError = 17,
AuthenticationFailed = 18,
CannotReuseObject = 19,
IllegalOperation = 20,
EmptyArrayOperation = 21,
MaxError MaxError
}; };
static const char* errorString(Error err) { static const char* errorString(Error err);
switch (err) {
case OK: /**
return "OK"; * Parse an Error from its "name". Returns UnknownError if "name"
case InternalError: is unrecognized.
return "InternalError"; *
case BadValue: * NOTE: Also returns UnknownError for the string "UnknownError".
return "BadValue"; */
case NoSuchKey: static Error fromString(const StringData& name);
return "NoSuchKey";
case HostUnreachable: /**
return "HostUnreachable"; * Parse an Error from its "code". Returns UnknownError if "code"
case HostNotFound: is unrecognized.
return "HostNotFound"; *
case DuplicateKey: * NOTE: Also returns UnknownError for the integer code for Unknown
return "DuplicateKey"; Error.
case GraphContainsCycle: */
return "GraphContainsCycle"; static Error fromInt(int code);
case UnknownError:
return "UnknownError";
case FailedToParse:
return "FailedToParse";
case CannotMutateObject:
return "CannotMutateObject";
default:
return "Unknown error code";
}
}
static bool isNetworkError(Error err) {
switch (err) {
case HostUnreachable:
case HostNotFound:
return true;
default:
return false;
}
}
static bool isNetworkError(Error err);
}; };
} // namespace mongo } // namespace mongo
 End of changes. 9 change blocks. 
73 lines changed or deleted 36 lines changed or added


 expression.h   expression.h 
skipping to change at line 32 skipping to change at line 32
#include "db/pipeline/value.h" #include "db/pipeline/value.h"
#include "util/intrusive_counter.h" #include "util/intrusive_counter.h"
namespace mongo { namespace mongo {
class BSONArrayBuilder; class BSONArrayBuilder;
class BSONElement; class BSONElement;
class BSONObjBuilder; class BSONObjBuilder;
class Builder; class Builder;
class Document; class Document;
class MutableDocument;
class DocumentSource; class DocumentSource;
class ExpressionContext; class ExpressionContext;
class Value; class Value;
class Expression : class Expression :
public IntrusiveCounterUnsigned { public IntrusiveCounterUnsigned {
public: public:
virtual ~Expression() {}; virtual ~Expression() {};
/* /*
skipping to change at line 78 skipping to change at line 79
virtual void addDependencies(set<string>& deps, vector<string>* pat h=NULL) const = 0; virtual void addDependencies(set<string>& deps, vector<string>* pat h=NULL) const = 0;
/** simple expressions are just inclusion exclusion as supported by ExpressionObject */ /** simple expressions are just inclusion exclusion as supported by ExpressionObject */
virtual bool isSimple() { return false; } virtual bool isSimple() { return false; }
/* /*
Evaluate the Expression using the given document as input. Evaluate the Expression using the given document as input.
@returns the computed value @returns the computed value
*/ */
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const = 0;
const intrusive_ptr<Document> &pDocument) const = 0;
/* /*
Add the Expression (and any descendant Expressions) into a BSON Add the Expression (and any descendant Expressions) into a BSON
object that is under construction. object that is under construction.
Unevaluated Expressions always materialize as objects. Evaluatio n Unevaluated Expressions always materialize as objects. Evaluatio n
may produce a scalar or another object, either of which will be may produce a scalar or another object, either of which will be
substituted inline. substituted inline.
@param pBuilder the builder to add the expression to @param pBuilder the builder to add the expression to
@param fieldName the name the object should be given @param fieldName the name the object should be given
@param requireExpression specify true if the value must appear @param requireExpression specify true if the value must appear
as an expression; this is used by DocumentSources like as an expression; this is used by DocumentSources like
$project which distinguish between field inclusion and virtual $project which distinguish between field inclusion and virtual
field specification; See ExpressionConstant. field specification; See ExpressionConstant.
*/ */
virtual void addToBsonObj( virtual void addToBsonObj(BSONObjBuilder *pBuilder,
BSONObjBuilder *pBuilder, const std::string& fieldName, StringData fieldName,
bool requireExpression) const = 0; bool requireExpression) const = 0;
/* /*
Add the Expression (and any descendant Expressions) into a BSON Add the Expression (and any descendant Expressions) into a BSON
array that is under construction. array that is under construction.
Unevaluated Expressions always materialize as objects. Evaluatio n Unevaluated Expressions always materialize as objects. Evaluatio n
may produce a scalar or another object, either of which will be may produce a scalar or another object, either of which will be
substituted inline. substituted inline.
@param pBuilder the builder to add the expression to @param pBuilder the builder to add the expression to
skipping to change at line 223 skipping to change at line 223
protected: protected:
typedef vector<intrusive_ptr<Expression> > ExpressionVector; typedef vector<intrusive_ptr<Expression> > ExpressionVector;
}; };
class ExpressionNary : class ExpressionNary :
public Expression { public Expression {
public: public:
// virtuals from Expression // virtuals from Expression
virtual intrusive_ptr<Expression> optimize(); virtual intrusive_ptr<Expression> optimize();
virtual void addToBsonObj( virtual void addToBsonObj(BSONObjBuilder *pBuilder,
BSONObjBuilder *pBuilder, const std::string& fieldName, StringData fieldName,
bool requireExpression) const; bool requireExpression) const;
virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const; virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const;
virtual void addDependencies(set<string>& deps, vector<string>* pat h=NULL) const; virtual void addDependencies(set<string>& deps, vector<string>* pat h=NULL) const;
/* /*
Add an operand to the n-ary expression. Add an operand to the n-ary expression.
@param pExpression the expression to add @param pExpression the expression to add
*/ */
virtual void addOperand(const intrusive_ptr<Expression> &pExpressio n); virtual void addOperand(const intrusive_ptr<Expression> &pExpressio n);
skipping to change at line 312 skipping to change at line 312
@param reqArgs the number of arguments this operator requires @param reqArgs the number of arguments this operator requires
*/ */
void checkArgCount(unsigned reqArgs) const; void checkArgCount(unsigned reqArgs) const;
}; };
class ExpressionAdd : class ExpressionAdd :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from Expression // virtuals from Expression
virtual ~ExpressionAdd(); virtual ~ExpressionAdd();
virtual intrusive_ptr<const Value> evaluate(const intrusive_ptr<Doc ument> &pDocument) const; virtual Value evaluate(const Document& pDocument) const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual intrusive_ptr<ExpressionNary> (*getFactory() const)(); virtual intrusive_ptr<ExpressionNary> (*getFactory() const)();
/* /*
Create an expression that finds the sum of n operands. Create an expression that finds the sum of n operands.
@returns addition expression @returns addition expression
*/ */
static intrusive_ptr<ExpressionNary> create(); static intrusive_ptr<ExpressionNary> create();
}; };
class ExpressionAnd : class ExpressionAnd :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from Expression // virtuals from Expression
virtual ~ExpressionAnd(); virtual ~ExpressionAnd();
virtual intrusive_ptr<Expression> optimize(); virtual intrusive_ptr<Expression> optimize();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<Document> &pDocument) const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
virtual void toMatcherBson(BSONObjBuilder *pBuilder) const; virtual void toMatcherBson(BSONObjBuilder *pBuilder) const;
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual intrusive_ptr<ExpressionNary> (*getFactory() const)(); virtual intrusive_ptr<ExpressionNary> (*getFactory() const)();
/* /*
Create an expression that finds the conjunction of n operands. Create an expression that finds the conjunction of n operands.
The conjunction uses short-circuit logic; the expressions are The conjunction uses short-circuit logic; the expressions are
evaluated in the order they were added to the conjunction, and evaluated in the order they were added to the conjunction, and
skipping to change at line 362 skipping to change at line 361
ExpressionAnd(); ExpressionAnd();
}; };
class ExpressionCoerceToBool : class ExpressionCoerceToBool :
public Expression { public Expression {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionCoerceToBool(); virtual ~ExpressionCoerceToBool();
virtual intrusive_ptr<Expression> optimize(); virtual intrusive_ptr<Expression> optimize();
virtual void addDependencies(set<string>& deps, vector<string>* pat h=NULL) const; virtual void addDependencies(set<string>& deps, vector<string>* pat h=NULL) const;
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<Document> &pDocument) const; virtual void addToBsonObj(BSONObjBuilder *pBuilder,
virtual void addToBsonObj( StringData fieldName,
BSONObjBuilder *pBuilder, const std::string& fieldName, bool requireExpression) const;
bool requireExpression) const;
virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const; virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const;
static intrusive_ptr<ExpressionCoerceToBool> create( static intrusive_ptr<ExpressionCoerceToBool> create(
const intrusive_ptr<Expression> &pExpression); const intrusive_ptr<Expression> &pExpression);
private: private:
ExpressionCoerceToBool(const intrusive_ptr<Expression> &pExpression ); ExpressionCoerceToBool(const intrusive_ptr<Expression> &pExpression );
intrusive_ptr<Expression> pExpression; intrusive_ptr<Expression> pExpression;
}; };
class ExpressionCompare : class ExpressionCompare :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionCompare(); virtual ~ExpressionCompare();
virtual intrusive_ptr<Expression> optimize(); virtual intrusive_ptr<Expression> optimize();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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);
/* /*
Shorthands for creating various comparisons expressions. Shorthands for creating various comparisons expressions.
Provide for conformance with the uniform function pointer signatu re Provide for conformance with the uniform function pointer signatu re
required for parsing. required for parsing.
These create a particular comparison operand, without any These create a particular comparison operand, without any
operands. Those must be added via ExpressionNary::addOperand(). operands. Those must be added via ExpressionNary::addOperand().
skipping to change at line 417 skipping to change at line 414
ExpressionCompare(CmpOp cmpOp); ExpressionCompare(CmpOp cmpOp);
CmpOp cmpOp; CmpOp cmpOp;
}; };
class ExpressionCond : class ExpressionCond :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionCond(); virtual ~ExpressionCond();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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:
ExpressionCond(); ExpressionCond();
}; };
class ExpressionConstant : class ExpressionConstant :
public Expression { public Expression {
public: public:
// virtuals from Expression // virtuals from Expression
virtual ~ExpressionConstant(); virtual ~ExpressionConstant();
virtual intrusive_ptr<Expression> optimize(); virtual intrusive_ptr<Expression> optimize();
virtual void addDependencies(set<string>& deps, vector<string>* pat h=NULL) const; virtual void addDependencies(set<string>& deps, vector<string>* pat h=NULL) const;
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<Document> &pDocument) const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
virtual void addToBsonObj( virtual void addToBsonObj(BSONObjBuilder *pBuilder,
BSONObjBuilder *pBuilder, const std::string& fieldName, StringData fieldName,
bool requireExpression) const; bool requireExpression) const;
virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const; virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const;
static intrusive_ptr<ExpressionConstant> createFromBsonElement( static intrusive_ptr<ExpressionConstant> createFromBsonElement(
BSONElement *pBsonElement); BSONElement *pBsonElement);
static intrusive_ptr<ExpressionConstant> create( static intrusive_ptr<ExpressionConstant> create(const Value& pValue
const intrusive_ptr<const Value> &pValue); );
/* /*
Get the constant value represented by this Expression. Get the constant value represented by this Expression.
@returns the value @returns the value
*/ */
intrusive_ptr<const Value> getValue() const; Value getValue() const;
private: private:
ExpressionConstant(BSONElement *pBsonElement); ExpressionConstant(BSONElement *pBsonElement);
ExpressionConstant(const intrusive_ptr<const Value> &pValue); ExpressionConstant(const Value& pValue);
intrusive_ptr<const Value> pValue; Value pValue;
}; };
class ExpressionDayOfMonth : class ExpressionDayOfMonth :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionDayOfMonth(); virtual ~ExpressionDayOfMonth();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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:
ExpressionDayOfMonth(); ExpressionDayOfMonth();
}; };
class ExpressionDayOfWeek : class ExpressionDayOfWeek :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionDayOfWeek(); virtual ~ExpressionDayOfWeek();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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:
ExpressionDayOfWeek(); ExpressionDayOfWeek();
}; };
class ExpressionDayOfYear : class ExpressionDayOfYear :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionDayOfYear(); virtual ~ExpressionDayOfYear();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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:
ExpressionDayOfYear(); ExpressionDayOfYear();
}; };
class ExpressionDivide : class ExpressionDivide :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionDivide(); virtual ~ExpressionDivide();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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:
ExpressionDivide(); ExpressionDivide();
}; };
class ExpressionFieldPath : class ExpressionFieldPath :
public Expression { public Expression {
public: public:
// virtuals from Expression // virtuals from Expression
virtual ~ExpressionFieldPath(); virtual ~ExpressionFieldPath();
virtual intrusive_ptr<Expression> optimize(); virtual intrusive_ptr<Expression> optimize();
virtual void addDependencies(set<string>& deps, vector<string>* pat h=NULL) const; virtual void addDependencies(set<string>& deps, vector<string>* pat h=NULL) const;
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<Document> &pDocument) const; virtual void addToBsonObj(BSONObjBuilder *pBuilder,
virtual void addToBsonObj( StringData fieldName,
BSONObjBuilder *pBuilder, const std::string& fieldName, bool requireExpression) const;
bool requireExpression) const;
virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const; virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const;
/* /*
Create a field path expression. Create a field path expression.
Evaluation will extract the value associated with the given field Evaluation will extract the value associated with the given field
path from the source document. path from the source document.
@param fieldPath the field path string, without any leading docum ent @param fieldPath the field path string, without any leading docum ent
indicator indicator
skipping to change at line 588 skipping to change at line 577
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 pathLength maximum number of fields on field path
@param pDocument 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
*/ */
intrusive_ptr<const Value> evaluatePath( Value evaluatePath(
size_t index, const size_t pathLength, size_t index, const size_t pathLength,
intrusive_ptr<Document> pDocument) const; Document pDocument) 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();
virtual void addDependencies(set<string>& deps, vector<string>* pat h=NULL) const; virtual void addDependencies(set<string>& deps, vector<string>* pat h=NULL) const;
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<Document> &pDocument) const; virtual void addToBsonObj(BSONObjBuilder *pBuilder,
virtual void addToBsonObj( StringData fieldName,
BSONObjBuilder *pBuilder, const std::string& fieldName, bool requireExpression) const;
bool requireExpression) const;
virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const; virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const;
virtual void toMatcherBson(BSONObjBuilder *pBuilder) const; virtual void toMatcherBson(BSONObjBuilder *pBuilder) const;
/* /*
Create a field range expression. Create a field range expression.
Field ranges are meant to match up with classic Matcher semantics , Field ranges are meant to match up with classic Matcher semantics ,
and therefore are conjunctions. For example, these appear in and therefore are conjunctions. For example, these appear in
mongo shell predicates in one of these forms: mongo shell predicates in one of these forms:
{ a : C } -> (a == C) // degenerate "point" range { a : C } -> (a == C) // degenerate "point" range
skipping to change at line 632 skipping to change at line 620
Note that NE and CMP are not supported. Note that NE and CMP are not supported.
@param pFieldPath the field path for extracting the field value @param pFieldPath the field path for extracting the field value
@param cmpOp the comparison operator @param cmpOp the comparison operator
@param pValue the value to compare against @param pValue the value to compare against
@returns the newly created field range expression @returns the newly created field range expression
*/ */
static intrusive_ptr<ExpressionFieldRange> create( static intrusive_ptr<ExpressionFieldRange> create(
const intrusive_ptr<ExpressionFieldPath> &pFieldPath, const intrusive_ptr<ExpressionFieldPath> &pFieldPath,
CmpOp cmpOp, const intrusive_ptr<const Value> &pValue); CmpOp cmpOp, const Value& pValue);
/* /*
Add an intersecting range. Add an intersecting range.
This can be done any number of times after creation. The This can be done any number of times after creation. The
range is internally optimized for each new addition. If the new range is internally optimized for each new addition. If the new
intersection extends or reduces the values within the range, the intersection extends or reduces the values within the range, the
internal representation is adjusted to reflect that. internal representation is adjusted to reflect that.
Note that NE and CMP are not supported. Note that NE and CMP are not supported.
@param cmpOp the comparison operator @param cmpOp the comparison operator
@param pValue the value to compare against @param pValue the value to compare against
*/ */
void intersect(CmpOp cmpOp, const intrusive_ptr<const Value> &pValu e); void intersect(CmpOp cmpOp, const Value& pValue);
private: private:
ExpressionFieldRange(const intrusive_ptr<ExpressionFieldPath> &pFie ldPath, ExpressionFieldRange(const intrusive_ptr<ExpressionFieldPath> &pFie ldPath,
CmpOp cmpOp, CmpOp cmpOp,
const intrusive_ptr<const Value> &pValue); const Value& pValue);
intrusive_ptr<ExpressionFieldPath> pFieldPath; intrusive_ptr<ExpressionFieldPath> pFieldPath;
class Range { class Range {
public: public:
Range(CmpOp cmpOp, const intrusive_ptr<const Value> &pValue); Range(CmpOp cmpOp, const Value& pValue);
Range(const Range &rRange); Range(const Range &rRange);
Range *intersect(const Range *pRange) const; Range *intersect(const Range *pRange) const;
bool contains(const intrusive_ptr<const Value> &pValue) const; bool contains(const Value& pValue) const;
Range(const intrusive_ptr<const Value> &pBottom, bool bottomOpe Range(const Value& pBottom, bool bottomOpen,
n, const Value& pTop, bool topOpen);
const intrusive_ptr<const Value> &pTop, bool topOpen);
bool bottomOpen; bool bottomOpen;
bool topOpen; bool topOpen;
intrusive_ptr<const Value> pBottom; Value pBottom;
intrusive_ptr<const Value> pTop; Value pTop;
}; };
scoped_ptr<Range> pRange; scoped_ptr<Range> pRange;
/* /*
Add to a generic Builder. Add to a generic Builder.
The methods to append items to an object and an array differ by The methods to append items to an object and an array differ by
their inclusion of a field name. For more complicated objects, their inclusion of a field name. For more complicated objects,
it makes sense to abstract that out and use a generic builder tha t it makes sense to abstract that out and use a generic builder tha t
skipping to change at line 692 skipping to change at line 680
addToBsonArray() by using the common method. addToBsonArray() by using the common method.
*/ */
void addToBson(Builder *pBuilder) const; void addToBson(Builder *pBuilder) const;
}; };
class ExpressionHour : class ExpressionHour :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionHour(); virtual ~ExpressionHour();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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:
ExpressionHour(); ExpressionHour();
}; };
class ExpressionIfNull : class ExpressionIfNull :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionIfNull(); virtual ~ExpressionIfNull();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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 ExpressionMinute : class ExpressionMinute :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionMinute(); virtual ~ExpressionMinute();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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:
ExpressionMinute(); ExpressionMinute();
}; };
class ExpressionMod : class ExpressionMod :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionMod(); virtual ~ExpressionMod();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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:
ExpressionMod(); ExpressionMod();
}; };
class ExpressionMultiply : class ExpressionMultiply :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from Expression // virtuals from Expression
virtual ~ExpressionMultiply(); virtual ~ExpressionMultiply();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<Document> &pDocument) const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual intrusive_ptr<ExpressionNary> (*getFactory() const)(); virtual intrusive_ptr<ExpressionNary> (*getFactory() const)();
/* /*
Create an expression that finds the product of n operands. Create an expression that finds the product of n operands.
@returns multiplication expression @returns multiplication expression
*/ */
skipping to change at line 779 skipping to change at line 762
private: private:
ExpressionMultiply(); ExpressionMultiply();
}; };
class ExpressionMonth : class ExpressionMonth :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionMonth(); virtual ~ExpressionMonth();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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:
ExpressionMonth(); ExpressionMonth();
}; };
class ExpressionNot : class ExpressionNot :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionNot(); virtual ~ExpressionNot();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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:
ExpressionNot(); ExpressionNot();
}; };
class ExpressionObject : class ExpressionObject :
public Expression { public Expression {
public: public:
// virtuals from Expression // virtuals from Expression
virtual ~ExpressionObject(); virtual ~ExpressionObject();
virtual intrusive_ptr<Expression> optimize(); virtual intrusive_ptr<Expression> optimize();
virtual bool isSimple(); virtual bool isSimple();
virtual void addDependencies(set<string>& deps, vector<string>* pat h=NULL) const; virtual void addDependencies(set<string>& deps, vector<string>* pat h=NULL) const;
/** Only evaluates non inclusion expressions. For inclusions, use addToDocument(). */ /** Only evaluates non inclusion expressions. For inclusions, use addToDocument(). */
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<Document> &pDocument) const; virtual void addToBsonObj(BSONObjBuilder *pBuilder,
virtual void addToBsonObj( StringData fieldName,
BSONObjBuilder *pBuilder, const std::string& fieldName, bool requireExpression) const;
bool requireExpression) const;
virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const; virtual void addToBsonArray(BSONArrayBuilder *pBuilder) const;
/* /*
evaluate(), but return a Document instead of a Value-wrapped evaluate(), but return a Document instead of a Value-wrapped
Document. Document.
@param pDocument the input Document @param pDocument the input Document
@returns the result document @returns the result document
*/ */
intrusive_ptr<Document> evaluateDocument( Document evaluateDocument(const Document& pDocument) const;
const intrusive_ptr<Document> &pDocument) const;
/* /*
evaluate(), but add the evaluated fields to a given document evaluate(), but add the evaluated fields to a given document
instead of creating a new one. instead of creating a new one.
@param pResult the Document to add the evaluated expressions to @param pResult the Document to add the evaluated expressions to
@param pDocument the input Document for this level @param pDocument the input Document for this level
@param rootDoc the root of the whole input document @param rootDoc the root of the whole input document
*/ */
void addToDocument(const intrusive_ptr<Document>& pResult, void addToDocument(MutableDocument& pResult,
const intrusive_ptr<Document>& pDocument, const Document& pDocument,
const intrusive_ptr<Document>& rootDoc const Document& rootDoc
) const; ) const;
// estimated number of fields that will be output // estimated number of fields that will be output
size_t getSizeHint() const; size_t getSizeHint() const;
/* /*
Create an empty expression. Until fields are added, this Create an empty expression. Until fields are added, this
will evaluate to an empty document (object). will evaluate to an empty document (object).
*/ */
static intrusive_ptr<ExpressionObject> create(); static intrusive_ptr<ExpressionObject> create();
skipping to change at line 970 skipping to change at line 949
vector<string> *pvPath; 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 intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<Document> &pDocument) const;
virtual const char *getOpName() const; virtual const char *getOpName() const;
virtual void toMatcherBson(BSONObjBuilder *pBuilder) const; virtual void toMatcherBson(BSONObjBuilder *pBuilder) const;
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual intrusive_ptr<ExpressionNary> (*getFactory() const)(); virtual intrusive_ptr<ExpressionNary> (*getFactory() const)();
/* /*
Create an expression that finds the conjunction of n operands. Create an expression that finds the conjunction of n operands.
The conjunction uses short-circuit logic; the expressions are The conjunction uses short-circuit logic; the expressions are
evaluated in the order they were added to the conjunction, and evaluated in the order they were added to the conjunction, and
skipping to change at line 998 skipping to change at line 976
private: private:
ExpressionOr(); ExpressionOr();
}; };
class ExpressionSecond : class ExpressionSecond :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionSecond(); virtual ~ExpressionSecond();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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:
ExpressionSecond(); ExpressionSecond();
}; };
class ExpressionStrcasecmp : class ExpressionStrcasecmp :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionStrcasecmp(); virtual ~ExpressionStrcasecmp();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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:
ExpressionStrcasecmp(); ExpressionStrcasecmp();
}; };
class ExpressionSubstr : class ExpressionSubstr :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionSubstr(); virtual ~ExpressionSubstr();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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:
ExpressionSubstr(); ExpressionSubstr();
}; };
class ExpressionSubtract : class ExpressionSubtract :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionSubtract(); virtual ~ExpressionSubtract();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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:
ExpressionSubtract(); ExpressionSubtract();
}; };
class ExpressionToLower : class ExpressionToLower :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionToLower(); virtual ~ExpressionToLower();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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:
ExpressionToLower(); ExpressionToLower();
}; };
class ExpressionToUpper : class ExpressionToUpper :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionToUpper(); virtual ~ExpressionToUpper();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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:
ExpressionToUpper(); ExpressionToUpper();
}; };
class ExpressionWeek : class ExpressionWeek :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionWeek(); virtual ~ExpressionWeek();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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:
ExpressionWeek(); ExpressionWeek();
}; };
class ExpressionYear : class ExpressionYear :
public ExpressionNary { public ExpressionNary {
public: public:
// virtuals from ExpressionNary // virtuals from ExpressionNary
virtual ~ExpressionYear(); virtual ~ExpressionYear();
virtual intrusive_ptr<const Value> evaluate( virtual Value evaluate(const Document& pDocument) const;
const intrusive_ptr<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:
ExpressionYear(); ExpressionYear();
}; };
} }
skipping to change at line 1134 skipping to change at line 1104
namespace mongo { namespace mongo {
inline int Expression::signum(int i) { inline int Expression::signum(int i) {
if (i < 0) if (i < 0)
return -1; return -1;
if (i > 0) if (i > 0)
return 1; return 1;
return 0; return 0;
} }
inline intrusive_ptr<const Value> ExpressionConstant::getValue() const { inline Value ExpressionConstant::getValue() const {
return pValue; return pValue;
} }
inline string ExpressionFieldPath::getFieldPath(bool fieldPrefix) const { inline string ExpressionFieldPath::getFieldPath(bool fieldPrefix) const {
return fieldPath.getPath(fieldPrefix); return fieldPath.getPath(fieldPrefix);
} }
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);
 End of changes. 50 change blocks. 
103 lines changed or deleted 73 lines changed or added


 extsort.h   extsort.h 
skipping to change at line 61 skipping to change at line 61
bool operator()( const Data &l, const Data &r ) const { bool operator()( const Data &l, const Data &r ) const {
return _compare(_i, l, r, _order) < 0; return _compare(_i, l, r, _order) < 0;
}; };
private: private:
IndexInterface& _i; IndexInterface& _i;
const Ordering _order; const Ordering _order;
}; };
static IndexInterface *extSortIdxInterface; static IndexInterface *extSortIdxInterface;
static Ordering extSortOrder; static Ordering extSortOrder;
static bool extSortMayInterrupt;
static int extSortComp( const void *lv, const void *rv ); static int extSortComp( const void *lv, const void *rv );
class FileIterator : boost::noncopyable { class FileIterator : boost::noncopyable {
public: public:
FileIterator( const std::string& file ); FileIterator( const std::string& file );
~FileIterator(); ~FileIterator();
bool more(); bool more();
Data next(); Data next();
private: private:
bool _read( char* buf, long long count ); bool _read( char* buf, long long count );
skipping to change at line 99 skipping to change at line 100
private: private:
MyCmp _cmp; MyCmp _cmp;
vector<FileIterator*> _files; vector<FileIterator*> _files;
vector< pair<Data,bool> > _stash; vector< pair<Data,bool> > _stash;
InMemory * _in; InMemory * _in;
InMemory::iterator _it; InMemory::iterator _it;
}; };
void add( const BSONObj& o , const DiskLoc & loc ); void add( const BSONObj& o, const DiskLoc& loc, bool mayInterrupt )
void add( const BSONObj& o , int a , int b ) { ;
add( o , DiskLoc( a , b ) );
}
/* call after adding values, and before fetching the iterator */ /* call after adding values, and before fetching the iterator */
void sort(); void sort( bool mayInterrupt );
auto_ptr<Iterator> iterator() { auto_ptr<Iterator> iterator() {
uassert( 10052 , "not sorted" , _sorted ); uassert( 10052 , "not sorted" , _sorted );
return auto_ptr<Iterator>( new Iterator( this ) ); return auto_ptr<Iterator>( new Iterator( this ) );
} }
int numFiles() { int numFiles() {
return _files.size(); return _files.size();
} }
long getCurSizeSoFar() { return _curSizeSoFar; } long getCurSizeSoFar() { return _curSizeSoFar; }
void hintNumObjects( long long numObjects ) { void hintNumObjects( long long numObjects ) {
if ( numObjects < _arraySize ) if ( numObjects < _arraySize )
_arraySize = (int)(numObjects + 100); _arraySize = (int)(numObjects + 100);
} }
private: private:
void _sortInMem(); void _sortInMem( bool mayInterrupt );
void sort( const std::string& file ); void sort( const std::string& file );
void finishMap(); void finishMap( bool mayInterrupt );
BSONObj _order; BSONObj _order;
long _maxFilesize; long _maxFilesize;
boost::filesystem::path _root; boost::filesystem::path _root;
int _arraySize; int _arraySize;
InMemory * _cur; InMemory * _cur;
long _curSizeSoFar; long _curSizeSoFar;
list<string> _files; list<string> _files;
 End of changes. 5 change blocks. 
7 lines changed or deleted 6 lines changed or added


 fail_point_service.h   fail_point_service.h 
skipping to change at line 33 skipping to change at line 33
#include "mongo/base/init.h" #include "mongo/base/init.h"
#include "mongo/util/fail_point_registry.h" #include "mongo/util/fail_point_registry.h"
namespace mongo { namespace mongo {
/** /**
* @return the global fail point registry. * @return the global fail point registry.
*/ */
FailPointRegistry* getGlobalFailPointRegistry(); FailPointRegistry* getGlobalFailPointRegistry();
/** /**
* Installs the injectFault command and freezes the fail point registry
.
*
* Note: not thread-safe
*/
void enableFailPointCmd();
/**
* Convenience macro for declaring a fail point. Must be used in global scope and * Convenience macro for declaring a fail point. Must be used in global scope and
* never in a block with limited scope (ie, inside functions, loops, et c.) * never in a block with limited scope (ie, inside functions, loops, et c.)
*/ */
#define MONGO_FP_DECLARE(fp) FailPoint fp; \ #define MONGO_FP_DECLARE(fp) FailPoint fp; \
MONGO_INITIALIZER_GENERAL(fp, ("FailPointRegistry"), ("AllFaillPoin tsRegistered")) \ MONGO_INITIALIZER_GENERAL(fp, ("FailPointRegistry"), ("AllFailPoint sRegistered")) \
(::mongo::InitializerContext* context) { \ (::mongo::InitializerContext* context) { \
return getGlobalFailPointRegistry()->addFailPoint(#fp, &fp); \ return getGlobalFailPointRegistry()->addFailPoint(#fp, &fp); \
} }
} }
 End of changes. 2 change blocks. 
9 lines changed or deleted 1 lines changed or added


 file.h   file.h 
skipping to change at line 67 skipping to change at line 67
#if defined(_WIN32) #if defined(_WIN32)
#include <io.h> #include <io.h>
class File : public FileInterface { class File : public FileInterface {
HANDLE fd; HANDLE fd;
bool _bad; bool _bad;
string _name; string _name;
void err(BOOL b=false) { /* false = error happened */ void err(BOOL b=false) { /* false = error happened */
if( !b && !_bad ) { if( !b && !_bad ) {
_bad = true; _bad = true;
log() << "File " << _name << "I/O error " << GetLastError() << '\n'; log() << "File " << _name << "I/O error " << GetLastError() << endl;
} }
} }
public: public:
File() { File() {
fd = INVALID_HANDLE_VALUE; fd = INVALID_HANDLE_VALUE;
_bad = true; _bad = true;
} }
~File() { ~File() {
if( is_open() ) CloseHandle(fd); if( is_open() ) CloseHandle(fd);
fd = INVALID_HANDLE_VALUE; fd = INVALID_HANDLE_VALUE;
skipping to change at line 157 skipping to change at line 157
#else #else
class File : public FileInterface { class File : public FileInterface {
public: public:
int fd; int fd;
private: private:
bool _bad; bool _bad;
void err(bool ok) { void err(bool ok) {
if( !ok && !_bad ) { if( !ok && !_bad ) {
_bad = true; _bad = true;
log() << "File I/O " << errnoWithDescription() << '\n'; log() << "File I/O " << errnoWithDescription() << endl;
} }
} }
public: public:
File() { File() {
fd = -1; fd = -1;
_bad = true; _bad = true;
} }
~File() { ~File() {
if( is_open() ) ::close(fd); if( is_open() ) ::close(fd);
fd = -1; fd = -1;
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 hashindex.h   hashindex.h 
skipping to change at line 19 skipping to change at line 19
* *
* 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/btree.h"
#include "mongo/db/hasher.h" #include "mongo/db/hasher.h"
#include "mongo/db/index.h" #include "mongo/db/index.h"
#include "mongo/db/keypattern.h" #include "mongo/db/keypattern.h"
#include "mongo/db/matcher.h" #include "mongo/db/matcher.h"
#include "mongo/db/namespace-inl.h" #include "mongo/db/namespace-inl.h"
#include "mongo/db/pdfile.h" #include "mongo/db/pdfile.h"
namespace mongo { namespace mongo {
/* This is an index where the keys are hashes of a given field. /* This is an index where the keys are hashes of a given field.
 End of changes. 1 change blocks. 
1 lines changed or deleted 0 lines changed or added


 heap-profiler.h   heap-profiler.h 
/* Copyright (c) 2005, Google Inc. // Copyright 2009-2010 the V8 project authors. All rights reserved.
* All rights reserved. // Redistribution and use in source and binary forms, with or without
* // modification, are permitted provided that the following conditions are
* Redistribution and use in source and binary forms, with or without // met:
* modification, are permitted provided that the following conditions are //
* met: // * Redistributions of source code must retain the above copyright
* // notice, this list of conditions and the following disclaimer.
* * Redistributions of source code must retain the above copyright // * Redistributions in binary form must reproduce the above
* notice, this list of conditions and the following disclaimer. // copyright notice, this list of conditions and the following
* * Redistributions in binary form must reproduce the above // disclaimer in the documentation and/or other materials provided
* copyright notice, this list of conditions and the following disclaimer // with the distribution.
* in the documentation and/or other materials provided with the // * Neither the name of Google Inc. nor the names of its
* distribution. // contributors may be used to endorse or promote products derived
* * Neither the name of Google Inc. nor the names of its // from this software without specific prior written permission.
* contributors may be used to endorse or promote products derived from //
* this software without specific prior written permission. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef V8_HEAP_PROFILER_H_
*/ #define V8_HEAP_PROFILER_H_
/* The code has moved to gperftools/. Use that include-directory for #include "isolate.h"
* new code.
*/ namespace v8 {
#include <gperftools/heap-profiler.h> namespace internal {
class HeapSnapshot;
class HeapSnapshotsCollection;
#define HEAP_PROFILE(heap, call)
\
do {
\
v8::internal::HeapProfiler* profiler = heap->isolate()->heap_profiler()
; \
if (profiler != NULL && profiler->is_profiling()) {
\
profiler->call;
\
}
\
} while (false)
class HeapProfiler {
public:
static void SetUp();
static void TearDown();
static size_t GetMemorySizeUsedByProfiler();
static HeapSnapshot* TakeSnapshot(const char* name,
int type,
v8::ActivityControl* control);
static HeapSnapshot* TakeSnapshot(String* name,
int type,
v8::ActivityControl* control);
static void StartHeapObjectsTracking();
static void StopHeapObjectsTracking();
static SnapshotObjectId PushHeapObjectsStats(OutputStream* stream);
static int GetSnapshotsCount();
static HeapSnapshot* GetSnapshot(int index);
static HeapSnapshot* FindSnapshot(unsigned uid);
static SnapshotObjectId GetSnapshotObjectId(Handle<Object> obj);
static void DeleteAllSnapshots();
void ObjectMoveEvent(Address from, Address to);
void DefineWrapperClass(
uint16_t class_id, v8::HeapProfiler::WrapperInfoCallback callback);
v8::RetainedObjectInfo* ExecuteWrapperClassCallback(uint16_t class_id,
Object** wrapper);
INLINE(bool is_profiling()) {
return snapshots_->is_tracking_objects();
}
private:
HeapProfiler();
~HeapProfiler();
HeapSnapshot* TakeSnapshotImpl(const char* name,
int type,
v8::ActivityControl* control);
HeapSnapshot* TakeSnapshotImpl(String* name,
int type,
v8::ActivityControl* control);
void ResetSnapshots();
void StartHeapObjectsTrackingImpl();
void StopHeapObjectsTrackingImpl();
SnapshotObjectId PushHeapObjectsStatsImpl(OutputStream* stream);
HeapSnapshotsCollection* snapshots_;
unsigned next_snapshot_uid_;
List<v8::HeapProfiler::WrapperInfoCallback> wrapper_callbacks_;
};
} } // namespace v8::internal
#endif // V8_HEAP_PROFILER_H_
 End of changes. 1 change blocks. 
lines changed or deleted lines changed or added


 index.h   index.h 
skipping to change at line 264 skipping to change at line 264
class NamespaceDetails; class NamespaceDetails;
// changedId should be initialized to false // changedId should be initialized to false
void getIndexChanges(vector<IndexChanges>& v, const char *ns, Namespace Details& d, void getIndexChanges(vector<IndexChanges>& v, const char *ns, Namespace Details& d,
BSONObj newObj, BSONObj oldObj, bool &cangedId); BSONObj newObj, BSONObj oldObj, bool &cangedId);
void dupCheck(vector<IndexChanges>& v, NamespaceDetails& d, DiskLoc cur ObjLoc); void dupCheck(vector<IndexChanges>& v, NamespaceDetails& d, DiskLoc cur ObjLoc);
void assureSysIndexesEmptied(const char *ns, IndexDetails *exceptForIdI ndex); void assureSysIndexesEmptied(const char *ns, IndexDetails *exceptForIdI ndex);
int removeFromSysIndexes(const char *ns, const char *idxName); int removeFromSysIndexes(const char *ns, const char *idxName);
/**
* Prepare to build an index. Does not actually build it (except for a
special _id case).
* - We validate that the params are good
* - That the index does not already exist
* - Creates the source collection if it DNE
*
* example of 'io':
* { ns : 'test.foo', name : 'z', key : { z : 1 } }
*
* @throws DBException
*
* @param mayInterrupt - When true, killop may interrupt the function c
all.
* @param sourceNS - source NS we are indexing
* @param sourceCollection - its details ptr
* @return true if ok to continue. when false we stop/fail silently (i
ndex already exists)
*/
bool prepareToBuildIndex(const BSONObj& io,
bool mayInterrupt,
bool god,
string& sourceNS,
NamespaceDetails*& sourceCollection,
BSONObj& fixedIndexObject);
} // namespace mongo } // namespace mongo
 End of changes. 1 change blocks. 
0 lines changed or deleted 26 lines changed or added


 index_update.h   index_update.h 
skipping to change at line 22 skipping to change at line 22
* *
* You should have received a copy of the GNU Affero General Public Licen se * You should have received a copy of the GNU Affero General Public Licen se
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include "mongo/db/diskloc.h" #include "mongo/db/diskloc.h"
#include "mongo/db/index.h" #include "mongo/db/index.h"
#include "mongo/db/jsobj.h" #include "mongo/db/jsobj.h"
#include "mongo/platform/cstdint.h"
namespace mongo { namespace mongo {
class NamespaceDetails; class NamespaceDetails;
class Record; class Record;
// unindex all keys in index for this record. // unindex all keys in index for this record.
void unindexRecord(NamespaceDetails *d, Record *todelete, const DiskLoc & dl, bool noWarn = false); void unindexRecord(NamespaceDetails *d, Record *todelete, const DiskLoc & dl, bool noWarn = false);
// Build an index in the foreground // Build an index in the foreground
// If background is false, uses fast index builder // If background is false, uses fast index builder
// If background is true, uses background index builder; blocks until d one. // If background is true, uses background index builder; blocks until d one.
void buildAnIndex(const std::string& ns, void buildAnIndex(const std::string& ns,
NamespaceDetails *d, NamespaceDetails *d,
IndexDetails& idx, IndexDetails& idx,
int idxNo, int32_t idxNo,
bool background); bool background,
bool mayInterrupt);
// add index keys for a newly inserted record // add index keys for a newly inserted record
// done in two steps/phases to allow potential deferal of write lock po rtion in the future // done in two steps/phases to allow potential deferal of write lock po rtion in the future
void indexRecordUsingTwoSteps(const char *ns, NamespaceDetails *d, BSON Obj obj, void indexRecordUsingTwoSteps(const char *ns, NamespaceDetails *d, BSON Obj obj,
DiskLoc loc, bool shouldBeUnlocked ); DiskLoc loc, bool shouldBeUnlocked );
// Given an object, populate "inserter" with information necessary to u pdate indexes. // Given an object, populate "inserter" with information necessary to u pdate indexes.
void fetchIndexInserters(BSONObjSet & /*out*/keys, void fetchIndexInserters(BSONObjSet & /*out*/keys,
IndexInterface::IndexInserter &inserter, IndexInterface::IndexInserter &inserter,
NamespaceDetails *d, NamespaceDetails *d,
int idxNo, int idxNo,
const BSONObj& obj, const BSONObj& obj,
DiskLoc recordLoc, DiskLoc recordLoc,
const bool allowDups = false); const bool allowDups = false);
bool dropIndexes( NamespaceDetails *d, const char *ns, const char *name , string &errmsg, BSONObjBuilder &anObjBuilder, bool maydeleteIdIndex ); bool dropIndexes( NamespaceDetails *d, const char *ns, const char *name , string &errmsg, BSONObjBuilder &anObjBuilder, bool maydeleteIdIndex );
} /**
* Add an _id index to namespace @param 'ns' if not already present.
* @param mayInterrupt When true, killop may interrupt the function cal
l.
*/
void ensureHaveIdIndex(const char* ns, bool mayInterrupt);
////// The remaining functions are only included in this header file fo
r unit testing.
class BSONObjExternalSorter;
class CurOp;
class ProgressMeter;
class ProgressMeterHolder;
struct SortPhaseOne;
class Timer;
/** Extract index keys from the @param 'ns' to the external sorter in @
param 'phaseOne'. */
void addKeysToPhaseOne( const char* ns,
const IndexDetails& idx,
const BSONObj& order,
SortPhaseOne* phaseOne,
int64_t nrecords,
ProgressMeter* progressMeter,
bool mayInterrupt );
/** Popuate the index @param 'idx' using the keys contained in @param '
sorter'. */
template< class V >
void buildBottomUpPhases2And3( bool dupsAllowed,
IndexDetails& idx,
BSONObjExternalSorter& sorter,
bool dropDups,
set<DiskLoc>& dupsToDrop,
CurOp* op,
SortPhaseOne* phase1,
ProgressMeterHolder& pm,
Timer& t,
bool mayInterrupt );
/** Drop duplicate documents from the set @param 'dupsToDrop'. */
void doDropDups( const char* ns,
NamespaceDetails* d,
const set<DiskLoc>& dupsToDrop,
bool mayInterrupt );
} // namespace mongo
 End of changes. 3 change blocks. 
2 lines changed or deleted 4 lines changed or added


 init.h   init.h 
skipping to change at line 54 skipping to change at line 54
* In summary, the following partial order is provided: * In summary, the following partial order is provided:
* All MONGO_CONFIG_VARIABLE_REGISTER()s are evaluated before * All MONGO_CONFIG_VARIABLE_REGISTER()s are evaluated before
* The MONGO_CONFIG_VARIABLE_SETTER is evaluated before * The MONGO_CONFIG_VARIABLE_SETTER is evaluated before
* All MONGO_CONFIG_VARIABLE_VALIDATORs are evaluated before * All MONGO_CONFIG_VARIABLE_VALIDATORs are evaluated before
* Things dependent on "default" are evaluated. * Things dependent on "default" are evaluated.
*/ */
#pragma once #pragma once
#include "mongo/base/configuration_variable_manager.h" #include "mongo/base/configuration_variable_manager.h"
#include "mongo/base/initializer.h"
#include "mongo/base/initializer_context.h" #include "mongo/base/initializer_context.h"
#include "mongo/base/initializer_function.h" #include "mongo/base/initializer_function.h"
#include "mongo/base/global_initializer.h"
#include "mongo/base/global_initializer_registerer.h" #include "mongo/base/global_initializer_registerer.h"
#include "mongo/base/make_string_vector.h" #include "mongo/base/make_string_vector.h"
#include "mongo/base/status.h" #include "mongo/base/status.h"
/** /**
* Convenience parameter representing an empty set of prerequisites for an initializer function. * Convenience parameter representing an empty set of prerequisites for an initializer function.
*/ */
#define MONGO_NO_PREREQUISITES () #define MONGO_NO_PREREQUISITES ()
/** /**
skipping to change at line 166 skipping to change at line 168
* assigned as the default, at registration time (once main has started). This * assigned as the default, at registration time (once main has started). This
* allows DEFAULT_VALUE to be constructed after main() begins, so some opti ons * allows DEFAULT_VALUE to be constructed after main() begins, so some opti ons
* that are not available to static initializers may be available here. * that are not available to static initializers may be available here.
*/ */
#define MONGO_CONFIG_VARIABLE_REGISTER(NAME, STORAGE, DEFAULT_VALUE) \ #define MONGO_CONFIG_VARIABLE_REGISTER(NAME, STORAGE, DEFAULT_VALUE) \
MONGO_INITIALIZER_GENERAL(cvr_##NAME, \ MONGO_INITIALIZER_GENERAL(cvr_##NAME, \
("globalVariableConfigurationStarted"), \ ("globalVariableConfigurationStarted"), \
("globalVariablesDeclared"))( \ ("globalVariablesDeclared"))( \
::mongo::InitializerContext* context) { \ ::mongo::InitializerContext* context) { \
*(STORAGE) = (DEFAULT_VALUE); \ *(STORAGE) = (DEFAULT_VALUE); \
return GlobalInitializer::get().configurationVariables().registerVa riable( \ return ::mongo::getGlobalInitializer().getConfigurationVariableMana ger().registerVariable( \
#NAME, (STORAGE)); \ #NAME, (STORAGE)); \
} }
/** /**
* Convenience macro for functions that validate already-set values of glob al * Convenience macro for functions that validate already-set values of glob al
* variables. Run after the MONGO_CONFIG_VARIABLE_SETTER completes. * variables. Run after the MONGO_CONFIG_VARIABLE_SETTER completes.
*/ */
#define MONGO_CONFIG_VARIABLE_VALIDATOR(NAME) \ #define MONGO_CONFIG_VARIABLE_VALIDATOR(NAME) \
MONGO_INITIALIZER_GENERAL(NAME, ("globalVariablesConfigured"), ("defaul t")) MONGO_INITIALIZER_GENERAL(NAME, ("globalVariablesConfigured"), ("defaul t"))
 End of changes. 3 change blocks. 
1 lines changed or deleted 3 lines changed or added


 introspect.h   introspect.h 
skipping to change at line 32 skipping to change at line 32
#include "mongo/pch.h" #include "mongo/pch.h"
#include "jsobj.h" #include "jsobj.h"
#include "pdfile.h" #include "pdfile.h"
namespace mongo { namespace mongo {
/* --- profiling -------------------------------------------- /* --- profiling --------------------------------------------
do when database->profile is set do when database->profile is set
*/ */
void profile( const Client& c , CurOp& currentOp ); void profile(const Client& c, int op, CurOp& currentOp);
/** /**
* Get (or create) the profile collection * Get (or create) the profile collection
* *
* @param db Database in which to create the profile collection * @param db Database in which to create the profile collection
* @param force Always create the collection if it does not exist * @param force Always create the collection if it does not exist
* @return NamespaceDetails for the newly created collection, or NULL on error * @return NamespaceDetails for the newly created collection, or NULL on error
**/ **/
NamespaceDetails* getOrCreateProfileCollection(Database *db, bool force = false); NamespaceDetails* getOrCreateProfileCollection(Database *db, bool force = false);
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 intrusive_counter.h   intrusive_counter.h 
skipping to change at line 21 skipping to change at line 21
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public 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 <boost/intrusive_ptr.hpp> #include <boost/intrusive_ptr.hpp>
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include "mongo/platform/atomic_word.h"
#include "mongo/base/string_data.h"
namespace mongo { namespace mongo {
/* /*
IntrusiveCounter is a sharable implementation of a reference counter that IntrusiveCounter is a sharable implementation of a reference counter that
objects can use to be compatible with boost::intrusive_ptr<>. objects can use to be compatible with boost::intrusive_ptr<>.
Some objects that use IntrusiveCounter are immutable, and only have Some objects that use IntrusiveCounter are immutable, and only have
const methods. This may require their pointers to be declared as const methods. This may require their pointers to be declared as
intrusive_ptr<const ClassName> . In order to be able to share pointers t o intrusive_ptr<const ClassName> . In order to be able to share pointers t o
skipping to change at line 44 skipping to change at line 46
IntrusiveCounter itself is abstract, allowing for multiple implementation s. IntrusiveCounter itself is abstract, allowing for multiple implementation s.
For example, IntrusiveCounterUnsigned uses ordinary unsigned integers for For example, IntrusiveCounterUnsigned uses ordinary unsigned integers for
the reference count, and is good for situations where thread safety is no t the reference count, and is good for situations where thread safety is no t
required. For others, other implementations using atomic integers should required. For others, other implementations using atomic integers should
be used. For static objects, the implementations of addRef() and release () be used. For static objects, the implementations of addRef() and release ()
can be overridden to do nothing. can be overridden to do nothing.
*/ */
class IntrusiveCounter : class IntrusiveCounter :
boost::noncopyable { boost::noncopyable {
public: public:
virtual ~IntrusiveCounter() {}; virtual ~IntrusiveCounter() {};
// these are here for the boost intrusive_ptr<> class // these are here for the boost intrusive_ptr<> class
friend inline void intrusive_ptr_add_ref(const IntrusiveCounter *pIC friend inline void intrusive_ptr_add_ref(const IntrusiveCounter *pI
) { C) {
pIC->addRef(); }; pIC->addRef(); };
friend inline void intrusive_ptr_release(const IntrusiveCounter *pIC friend inline void intrusive_ptr_release(const IntrusiveCounter *pI
) { C) {
pIC->release(); }; pIC->release(); };
virtual void addRef() const = 0; virtual void addRef() const = 0;
virtual void release() const = 0; virtual void release() const = 0;
}; };
class IntrusiveCounterUnsigned : class IntrusiveCounterUnsigned :
public IntrusiveCounter { public IntrusiveCounter {
public: public:
// virtuals from IntrusiveCounter // virtuals from IntrusiveCounter
virtual void addRef() const; virtual void addRef() const;
virtual void release() const; virtual void release() const;
IntrusiveCounterUnsigned(); IntrusiveCounterUnsigned();
private: private:
mutable unsigned counter; mutable unsigned counter;
};
/// This is an alternative base class to the above ones (will replace t
hem eventually)
class RefCountable : boost::noncopyable {
public:
/// If false you have exclusive access to this object. This is usef
ul for implementing COW.
bool isShared() const {
// TODO: switch to unfenced read method after SERVER-6973
return reinterpret_cast<unsigned&>(_count) > 1;
}
friend void intrusive_ptr_add_ref(const RefCountable* ptr) {
ptr->_count.addAndFetch(1);
};
friend void intrusive_ptr_release(const RefCountable* ptr) {
if (ptr->_count.subtractAndFetch(1) == 0) {
delete ptr; // uses subclass destructor and operator delete
}
};
protected:
RefCountable() {}
virtual ~RefCountable() {}
private:
mutable AtomicUInt32 _count; // default initialized to 0
};
/// This is an immutable reference-counted string
class RCString : public RefCountable {
public:
const char* c_str() const { return reinterpret_cast<const char*>(th
is) + sizeof(RCString); }
int size() const { return _size; }
StringData stringData() const { return StringData(c_str(), _size);
}
static intrusive_ptr<const RCString> create(StringData s);
void operator delete (void* ptr) { free(ptr); }
private:
// these can only be created by calling create()
RCString() {};
void* operator new (size_t objSize, size_t realSize) { return mallo
c(realSize); }
int _size; // does NOT include trailing NUL byte.
// char[_size+1] array allocated past end of class
}; };
}; };
/* ======================= INLINED IMPLEMENTATIONS ======================== == */ /* ======================= INLINED IMPLEMENTATIONS ======================== == */
namespace mongo { namespace mongo {
inline IntrusiveCounterUnsigned::IntrusiveCounterUnsigned(): inline IntrusiveCounterUnsigned::IntrusiveCounterUnsigned():
counter(0) { counter(0) {
} }
}; };
 End of changes. 8 change blocks. 
16 lines changed or deleted 69 lines changed or added


 jsregexp.h   jsregexp.h 
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- // Copyright 2012 the V8 project authors. All rights reserved.
* // Redistribution and use in source and binary forms, with or without
* ***** BEGIN LICENSE BLOCK ***** // modification, are permitted provided that the following conditions are
* Version: MPL 1.1/GPL 2.0/LGPL 2.1 // met:
* //
* The contents of this file are subject to the Mozilla Public License Vers // * Redistributions of source code must retain the above copyright
ion // notice, this list of conditions and the following disclaimer.
* 1.1 (the "License"); you may not use this file except in compliance with // * Redistributions in binary form must reproduce the above
* the License. You may obtain a copy of the License at // copyright notice, this list of conditions and the following
* http://www.mozilla.org/MPL/ // disclaimer in the documentation and/or other materials provided
* // with the distribution.
* Software distributed under the License is distributed on an "AS IS" basi // * Neither the name of Google Inc. nor the names of its
s, // contributors may be used to endorse or promote products derived
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License // from this software without specific prior written permission.
* for the specific language governing rights and limitations under the //
* License. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* The Original Code is Mozilla Communicator client code, released // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* March 31, 1998. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* The Initial Developer of the Original Code is // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* Netscape Communications Corporation. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* Portions created by the Initial Developer are Copyright (C) 1998 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* the Initial Developer. All Rights Reserved. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* Contributor(s): // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Alternatively, the contents of this file may be used under the terms of #ifndef V8_JSREGEXP_H_
* either of the GNU General Public License Version 2 or later (the "GPL"), #define V8_JSREGEXP_H_
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL
"), #include "allocation.h"
* in which case the provisions of the GPL or the LGPL are applicable inste #include "assembler.h"
ad #include "zone-inl.h"
* of those above. If you wish to allow use of your version of this file on
ly namespace v8 {
* under the terms of either the GPL or the LGPL, and not to allow others t namespace internal {
o
* use your version of this file under the terms of the MPL, indicate your class NodeVisitor;
* decision by deleting the provisions above and replace them with the noti class RegExpCompiler;
ce class RegExpMacroAssembler;
* and other provisions required by the GPL or the LGPL. If you do not dele class RegExpNode;
te class RegExpTree;
* the provisions above, a recipient may use your version of this file unde class BoyerMooreLookahead;
r
* the terms of any one of the MPL, the GPL or the LGPL. class RegExpImpl {
* public:
* ***** END LICENSE BLOCK ***** */ // Whether V8 is compiled with native regexp support or not.
static bool UsesNativeRegExp() {
#ifndef jsregexp_h___ #ifdef V8_INTERPRETED_REGEXP
#define jsregexp_h___ return false;
/* #else
* JS regular expression interface. return true;
*/
#include <stddef.h>
#include "jspubtd.h"
#include "jsstr.h"
#ifdef JS_THREADSAFE
#include "jsdhash.h"
#endif #endif
}
// Creates a regular expression literal in the old space.
// This function calls the garbage collector if necessary.
static Handle<Object> CreateRegExpLiteral(Handle<JSFunction> constructor,
Handle<String> pattern,
Handle<String> flags,
bool* has_pending_exception);
// Returns a string representation of a regular expression.
// Implements RegExp.prototype.toString, see ECMA-262 section 15.10.6.4.
// This function calls the garbage collector if necessary.
static Handle<String> ToString(Handle<Object> value);
// Parses the RegExp pattern and prepares the JSRegExp object with
// generic data and choice of implementation - as well as what
// the implementation wants to store in the data field.
// Returns false if compilation fails.
static Handle<Object> Compile(Handle<JSRegExp> re,
Handle<String> pattern,
Handle<String> flags,
Zone* zone);
// See ECMA-262 section 15.10.6.2.
// This function calls the garbage collector if necessary.
static Handle<Object> Exec(Handle<JSRegExp> regexp,
Handle<String> subject,
int index,
Handle<JSArray> lastMatchInfo);
// Prepares a JSRegExp object with Irregexp-specific data.
static void IrregexpInitialize(Handle<JSRegExp> re,
Handle<String> pattern,
JSRegExp::Flags flags,
int capture_register_count);
static void AtomCompile(Handle<JSRegExp> re,
Handle<String> pattern,
JSRegExp::Flags flags,
Handle<String> match_pattern);
static Handle<Object> AtomExec(Handle<JSRegExp> regexp,
Handle<String> subject,
int index,
Handle<JSArray> lastMatchInfo);
enum IrregexpResult { RE_FAILURE = 0, RE_SUCCESS = 1, RE_EXCEPTION = -1 }
;
// Prepare a RegExp for being executed one or more times (using
// IrregexpExecOnce) on the subject.
// This ensures that the regexp is compiled for the subject, and that
// the subject is flat.
// Returns the number of integer spaces required by IrregexpExecOnce
// as its "registers" argument. If the regexp cannot be compiled,
// an exception is set as pending, and this function returns negative.
static int IrregexpPrepare(Handle<JSRegExp> regexp,
Handle<String> subject);
// Calculate the size of offsets vector for the case of global regexp
// and the number of matches this vector is able to store.
static int GlobalOffsetsVectorSize(Handle<JSRegExp> regexp,
int registers_per_match,
int* max_matches);
// Execute a regular expression on the subject, starting from index.
// If matching succeeds, return the number of matches. This can be large
r
// than one in the case of global regular expressions.
// The captures and subcaptures are stored into the registers vector.
// If matching fails, returns RE_FAILURE.
// If execution fails, sets a pending exception and returns RE_EXCEPTION.
static int IrregexpExecRaw(Handle<JSRegExp> regexp,
Handle<String> subject,
int index,
Vector<int> registers);
// Execute an Irregexp bytecode pattern.
// On a successful match, the result is a JSArray containing
// captured positions. On a failure, the result is the null value.
// Returns an empty handle in case of an exception.
static Handle<Object> IrregexpExec(Handle<JSRegExp> regexp,
Handle<String> subject,
int index,
Handle<JSArray> lastMatchInfo);
// Array index in the lastMatchInfo array.
static const int kLastCaptureCount = 0;
static const int kLastSubject = 1;
static const int kLastInput = 2;
static const int kFirstCapture = 3;
static const int kLastMatchOverhead = 3;
// Direct offset into the lastMatchInfo array.
static const int kLastCaptureCountOffset =
FixedArray::kHeaderSize + kLastCaptureCount * kPointerSize;
static const int kLastSubjectOffset =
FixedArray::kHeaderSize + kLastSubject * kPointerSize;
static const int kLastInputOffset =
FixedArray::kHeaderSize + kLastInput * kPointerSize;
static const int kFirstCaptureOffset =
FixedArray::kHeaderSize + kFirstCapture * kPointerSize;
// Used to access the lastMatchInfo array.
static int GetCapture(FixedArray* array, int index) {
return Smi::cast(array->get(index + kFirstCapture))->value();
}
static void SetLastCaptureCount(FixedArray* array, int to) {
array->set(kLastCaptureCount, Smi::FromInt(to));
}
static void SetLastSubject(FixedArray* array, String* to) {
array->set(kLastSubject, to);
}
static void SetLastInput(FixedArray* array, String* to) {
array->set(kLastInput, to);
}
static void SetCapture(FixedArray* array, int index, int to) {
array->set(index + kFirstCapture, Smi::FromInt(to));
}
static int GetLastCaptureCount(FixedArray* array) {
return Smi::cast(array->get(kLastCaptureCount))->value();
}
// For acting on the JSRegExp data FixedArray.
static int IrregexpMaxRegisterCount(FixedArray* re);
static void SetIrregexpMaxRegisterCount(FixedArray* re, int value);
static int IrregexpNumberOfCaptures(FixedArray* re);
static int IrregexpNumberOfRegisters(FixedArray* re);
static ByteArray* IrregexpByteCode(FixedArray* re, bool is_ascii);
static Code* IrregexpNativeCode(FixedArray* re, bool is_ascii);
// Limit the space regexps take up on the heap. In order to limit this w
e
// would like to keep track of the amount of regexp code on the heap. Th
is
// is not tracked, however. As a conservative approximation we track the
// total regexp code compiled including code that has subsequently been f
reed
// and the total executable memory at any point.
static const int kRegExpExecutableMemoryLimit = 16 * MB;
static const int kRegWxpCompiledLimit = 1 * MB;
private:
static String* last_ascii_string_;
static String* two_byte_cached_string_;
static bool CompileIrregexp(
Handle<JSRegExp> re, Handle<String> sample_subject, bool is_ascii);
static inline bool EnsureCompiledIrregexp(
Handle<JSRegExp> re, Handle<String> sample_subject, bool is_ascii);
// Set the subject cache. The previous string buffer is not deleted, so
the
// caller should ensure that it doesn't leak.
static void SetSubjectCache(String* subject,
char* utf8_subject,
int uft8_length,
int character_position,
int utf8_position);
// A one element cache of the last utf8_subject string and its length. T
he
// subject JS String object is cached in the heap. We also cache a
// translation between position and utf8 position.
static char* utf8_subject_cache_;
static int utf8_length_cache_;
static int utf8_position_;
static int character_position_;
};
// Represents the location of one element relative to the intersection of
// two sets. Corresponds to the four areas of a Venn diagram.
enum ElementInSetsRelation {
kInsideNone = 0,
kInsideFirst = 1,
kInsideSecond = 2,
kInsideBoth = 3
};
// Represents code units in the range from from_ to to_, both ends are
// inclusive.
class CharacterRange {
public:
CharacterRange() : from_(0), to_(0) { }
// For compatibility with the CHECK_OK macro
CharacterRange(void* null) { ASSERT_EQ(NULL, null); } //NOLINT
CharacterRange(uc16 from, uc16 to) : from_(from), to_(to) { }
static void AddClassEscape(uc16 type, ZoneList<CharacterRange>* ranges,
Zone* zone);
static Vector<const int> GetWordBounds();
static inline CharacterRange Singleton(uc16 value) {
return CharacterRange(value, value);
}
static inline CharacterRange Range(uc16 from, uc16 to) {
ASSERT(from <= to);
return CharacterRange(from, to);
}
static inline CharacterRange Everything() {
return CharacterRange(0, 0xFFFF);
}
bool Contains(uc16 i) { return from_ <= i && i <= to_; }
uc16 from() const { return from_; }
void set_from(uc16 value) { from_ = value; }
uc16 to() const { return to_; }
void set_to(uc16 value) { to_ = value; }
bool is_valid() { return from_ <= to_; }
bool IsEverything(uc16 max) { return from_ == 0 && to_ >= max; }
bool IsSingleton() { return (from_ == to_); }
void AddCaseEquivalents(ZoneList<CharacterRange>* ranges, bool is_ascii,
Zone* zone);
static void Split(ZoneList<CharacterRange>* base,
Vector<const int> overlay,
ZoneList<CharacterRange>** included,
ZoneList<CharacterRange>** excluded,
Zone* zone);
// Whether a range list is in canonical form: Ranges ordered by from valu
e,
// and ranges non-overlapping and non-adjacent.
static bool IsCanonical(ZoneList<CharacterRange>* ranges);
// Convert range list to canonical form. The characters covered by the ra
nges
// will still be the same, but no character is in more than one range, an
d
// adjacent ranges are merged. The resulting list may be shorter than the
// original, but cannot be longer.
static void Canonicalize(ZoneList<CharacterRange>* ranges);
// Negate the contents of a character range in canonical form.
static void Negate(ZoneList<CharacterRange>* src,
ZoneList<CharacterRange>* dst,
Zone* zone);
static const int kStartMarker = (1 << 24);
static const int kPayloadMask = (1 << 24) - 1;
private:
uc16 from_;
uc16 to_;
};
// A set of unsigned integers that behaves especially well on small
// integers (< 32). May do zone-allocation.
class OutSet: public ZoneObject {
public:
OutSet() : first_(0), remaining_(NULL), successors_(NULL) { }
OutSet* Extend(unsigned value, Zone* zone);
bool Get(unsigned value);
static const unsigned kFirstLimit = 32;
private:
// Destructively set a value in this set. In most cases you want
// to use Extend instead to ensure that only one instance exists
// that contains the same values.
void Set(unsigned value, Zone* zone);
// The successors are a list of sets that contain the same values
// as this set and the one more value that is not present in this
// set.
ZoneList<OutSet*>* successors(Zone* zone) { return successors_; }
OutSet(uint32_t first, ZoneList<unsigned>* remaining)
: first_(first), remaining_(remaining), successors_(NULL) { }
uint32_t first_;
ZoneList<unsigned>* remaining_;
ZoneList<OutSet*>* successors_;
friend class Trace;
};
// A mapping from integers, specified as ranges, to a set of integers.
// Used for mapping character ranges to choices.
class DispatchTable : public ZoneObject {
public:
explicit DispatchTable(Zone* zone) : tree_(zone) { }
class Entry {
public:
Entry() : from_(0), to_(0), out_set_(NULL) { }
Entry(uc16 from, uc16 to, OutSet* out_set)
: from_(from), to_(to), out_set_(out_set) { }
uc16 from() { return from_; }
uc16 to() { return to_; }
void set_to(uc16 value) { to_ = value; }
void AddValue(int value, Zone* zone) {
out_set_ = out_set_->Extend(value, zone);
}
OutSet* out_set() { return out_set_; }
private:
uc16 from_;
uc16 to_;
OutSet* out_set_;
};
class Config {
public:
typedef uc16 Key;
typedef Entry Value;
static const uc16 kNoKey;
static const Entry NoValue() { return Value(); }
static inline int Compare(uc16 a, uc16 b) {
if (a == b)
return 0;
else if (a < b)
return -1;
else
return 1;
}
};
void AddRange(CharacterRange range, int value, Zone* zone);
OutSet* Get(uc16 value);
void Dump();
template <typename Callback>
void ForEach(Callback* callback) {
return tree()->ForEach(callback);
}
private:
// There can't be a static empty set since it allocates its
// successors in a zone and caches them.
OutSet* empty() { return &empty_; }
OutSet empty_;
ZoneSplayTree<Config>* tree() { return &tree_; }
ZoneSplayTree<Config> tree_;
};
#define FOR_EACH_NODE_TYPE(VISIT) \
VISIT(End) \
VISIT(Action) \
VISIT(Choice) \
VISIT(BackReference) \
VISIT(Assertion) \
VISIT(Text)
#define FOR_EACH_REG_EXP_TREE_TYPE(VISIT) \
VISIT(Disjunction) \
VISIT(Alternative) \
VISIT(Assertion) \
VISIT(CharacterClass) \
VISIT(Atom) \
VISIT(Quantifier) \
VISIT(Capture) \
VISIT(Lookahead) \
VISIT(BackReference) \
VISIT(Empty) \
VISIT(Text)
#define FORWARD_DECLARE(Name) class RegExp##Name;
FOR_EACH_REG_EXP_TREE_TYPE(FORWARD_DECLARE)
#undef FORWARD_DECLARE
class TextElement {
public:
enum Type {UNINITIALIZED, ATOM, CHAR_CLASS};
TextElement() : type(UNINITIALIZED) { }
explicit TextElement(Type t) : type(t), cp_offset(-1) { }
static TextElement Atom(RegExpAtom* atom);
static TextElement CharClass(RegExpCharacterClass* char_class);
int length();
Type type;
union {
RegExpAtom* u_atom;
RegExpCharacterClass* u_char_class;
} data;
int cp_offset;
};
class Trace;
struct NodeInfo {
NodeInfo()
: being_analyzed(false),
been_analyzed(false),
follows_word_interest(false),
follows_newline_interest(false),
follows_start_interest(false),
at_end(false),
visited(false),
replacement_calculated(false) { }
// Returns true if the interests and assumptions of this node
// matches the given one.
bool Matches(NodeInfo* that) {
return (at_end == that->at_end) &&
(follows_word_interest == that->follows_word_interest) &&
(follows_newline_interest == that->follows_newline_interest) &&
(follows_start_interest == that->follows_start_interest);
}
// Updates the interests of this node given the interests of the
// node preceding it.
void AddFromPreceding(NodeInfo* that) {
at_end |= that->at_end;
follows_word_interest |= that->follows_word_interest;
follows_newline_interest |= that->follows_newline_interest;
follows_start_interest |= that->follows_start_interest;
}
bool HasLookbehind() {
return follows_word_interest ||
follows_newline_interest ||
follows_start_interest;
}
// Sets the interests of this node to include the interests of the
// following node.
void AddFromFollowing(NodeInfo* that) {
follows_word_interest |= that->follows_word_interest;
follows_newline_interest |= that->follows_newline_interest;
follows_start_interest |= that->follows_start_interest;
}
void ResetCompilationState() {
being_analyzed = false;
been_analyzed = false;
}
bool being_analyzed: 1;
bool been_analyzed: 1;
// These bits are set of this node has to know what the preceding
// character was.
bool follows_word_interest: 1;
bool follows_newline_interest: 1;
bool follows_start_interest: 1;
bool at_end: 1;
bool visited: 1;
bool replacement_calculated: 1;
};
// Details of a quick mask-compare check that can look ahead in the
// input stream.
class QuickCheckDetails {
public:
QuickCheckDetails()
: characters_(0),
mask_(0),
value_(0),
cannot_match_(false) { }
explicit QuickCheckDetails(int characters)
: characters_(characters),
mask_(0),
value_(0),
cannot_match_(false) { }
bool Rationalize(bool ascii);
// Merge in the information from another branch of an alternation.
void Merge(QuickCheckDetails* other, int from_index);
// Advance the current position by some amount.
void Advance(int by, bool ascii);
void Clear();
bool cannot_match() { return cannot_match_; }
void set_cannot_match() { cannot_match_ = true; }
struct Position {
Position() : mask(0), value(0), determines_perfectly(false) { }
uc16 mask;
uc16 value;
bool determines_perfectly;
};
int characters() { return characters_; }
void set_characters(int characters) { characters_ = characters; }
Position* positions(int index) {
ASSERT(index >= 0);
ASSERT(index < characters_);
return positions_ + index;
}
uint32_t mask() { return mask_; }
uint32_t value() { return value_; }
private:
// How many characters do we have quick check information from. This is
// the same for all branches of a choice node.
int characters_;
Position positions_[4];
// These values are the condensate of the above array after Rationalize()
.
uint32_t mask_;
uint32_t value_;
// If set to true, there is no way this quick check can match at all.
// E.g., if it requires to be at the start of the input, and isn't.
bool cannot_match_;
};
extern int kUninitializedRegExpNodePlaceHolder;
struct JSRegExpStatics { class RegExpNode: public ZoneObject {
JSString *input; /* input string to match (perl $_, GC root) public:
*/ explicit RegExpNode(Zone* zone)
JSBool multiline; /* whether input contains newlines (perl $* : replacement_(NULL), trace_count_(0), zone_(zone) {
) */ bm_info_[0] = bm_info_[1] = NULL;
uint16 parenCount; /* number of valid elements in parens[] */ }
uint16 moreLength; /* number of allocated elements in morePare virtual ~RegExpNode();
ns */ virtual void Accept(NodeVisitor* visitor) = 0;
JSSubString parens[9]; /* last set of parens matched (perl $1, $2) // Generates a goto to this node or actually generates the code at this p
*/ oint.
JSSubString *moreParens; /* null or realloc'd vector for $10, etc. * virtual void Emit(RegExpCompiler* compiler, Trace* trace) = 0;
/ // How many characters must this node consume at a minimum in order to
JSSubString lastMatch; /* last string matched (perl $&) */ // succeed. If we have found at least 'still_to_find' characters that
JSSubString lastParen; /* last paren matched (perl $+) */ // must be consumed there is no need to ask any following nodes whether
JSSubString leftContext; /* input to left of last match (perl $`) */ // they are sure to eat any more characters. The not_at_start argument i
JSSubString rightContext; /* input to right of last match (perl $') * s
/ // used to indicate that we know we are not at the start of the input. I
}; n
// this case anchored branches will always fail and can be ignored when
/* // determining how many characters are consumed on success.
* This struct holds a bitmap representation of a class from a regexp. virtual int EatsAtLeast(int still_to_find,
* There's a list of these referenced by the classList field in the JSRegEx int recursion_depth,
p bool not_at_start) = 0;
* struct below. The initial state has startIndex set to the offset in the // Emits some quick code that checks whether the preloaded characters mat
* original regexp source of the beginning of the class contents. The first ch.
* use of the class converts the source representation into a bitmap. // Falls through on certain failure, jumps to the label on possible succe
* ss.
*/ // If the node cannot make a quick check it does nothing and returns fals
typedef struct RECharSet { e.
JSPackedBool converted; bool EmitQuickCheck(RegExpCompiler* compiler,
JSPackedBool sense; Trace* trace,
uint16 length; bool preload_has_checked_bounds,
union { Label* on_possible_success,
uint8 *bits; QuickCheckDetails* details_return,
struct { bool fall_through_on_failure);
size_t startIndex; // For a given number of characters this returns a mask and a value. The
size_t length; // next n characters are anded with the mask and compared with the value.
} src; // A comparison failure indicates the node cannot match the next n charac
} u; ters.
} RECharSet; // A comparison success indicates the node may match.
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
/* RegExpCompiler* compiler,
* This macro is safe because moreParens is guaranteed to be allocated and int characters_filled_in,
big bool not_at_start) = 0;
* enough to hold parenCount, or else be null when parenCount is 0. static const int kNodeIsTooComplexForGreedyLoops = -1;
*/ virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoo
#define REGEXP_PAREN_SUBSTRING(res, num) ps; }
\ // Only returns the successor for a text node of length 1 that matches an
(((jsuint)(num) < (jsuint)(res)->parenCount) y
\ // character and that has no guards on it.
? ((jsuint)(num) < 9) virtual RegExpNode* GetSuccessorOfOmnivorousTextNode(
\ RegExpCompiler* compiler) {
? &(res)->parens[num] return NULL;
\ }
: &(res)->moreParens[(num) - 9]
\ // Collects information on the possible code units (mod 128) that can mat
: &js_EmptySubString) ch if
// we look forward. This is used for a Boyer-Moore-like string searching
typedef struct RENode RENode; // implementation. TODO(erikcorry): This should share more code with
// EatsAtLeast, GetQuickCheckDetails. The budget argument is used to lim
struct JSRegExp { it
jsrefcount nrefs; /* reference count */ // the number of nodes we are willing to look at in order to create this
uint16 flags; /* flags, see jsapi.h's JSREG_* defines */ data.
uint16 cloneIndex; /* index in fp->vars or funobj->slots of static const int kFillInBMBudget = 200;
cloned regexp object */ virtual void FillInBMInfo(int offset,
size_t parenCount; /* number of parenthesized submatches */ int recursion_depth,
size_t classCount; /* count [...] bitmaps */ int budget,
RECharSet *classList; /* list of [...] bitmaps */ BoyerMooreLookahead* bm,
JSString *source; /* locked source string, sans // */ bool not_at_start) {
jsbytecode program[1]; /* regular expression bytecode */ UNREACHABLE();
}; }
extern JSRegExp * // If we know that the input is ASCII then there are some nodes that can
js_NewRegExp(JSContext *cx, JSTokenStream *ts, // never match. This method returns a node that can be substituted for
JSString *str, uintN flags, JSBool flat); // itself, or NULL if the node can never match.
virtual RegExpNode* FilterASCII(int depth) { return this; }
extern JSRegExp * // Helper for FilterASCII.
js_NewRegExpOpt(JSContext *cx, JSTokenStream *ts, RegExpNode* replacement() {
JSString *str, JSString *opt, JSBool flat); ASSERT(info()->replacement_calculated);
return replacement_;
#define HOLD_REGEXP(cx, re) JS_ATOMIC_INCREMENT(&(re)->nrefs) }
#define DROP_REGEXP(cx, re) js_DestroyRegExp(cx, re) RegExpNode* set_replacement(RegExpNode* replacement) {
info()->replacement_calculated = true;
extern void replacement_ = replacement;
js_DestroyRegExp(JSContext *cx, JSRegExp *re); return replacement; // For convenience.
}
/*
* Execute re on input str at *indexp, returning null in *rval on mismatch. // We want to avoid recalculating the lookahead info, so we store it on t
* On match, return true if test is true, otherwise return an array object. he
* Update *indexp and cx->regExpStatics always on match. // node. Only info that is for this node is stored. We can tell that th
*/ e
extern JSBool // info is for this node when offset == 0, so the information is calculat
js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp ed
, // relative to this node.
JSBool test, jsval *rval); void SaveBMInfo(BoyerMooreLookahead* bm, bool not_at_start, int offset) {
if (offset == 0) set_bm_info(not_at_start, bm);
/* }
* These two add and remove GC roots, respectively, so their calls must be
* well-ordered. Label* label() { return &label_; }
*/ // If non-generic code is generated for a node (i.e. the node is not at t
extern JSBool he
js_InitRegExpStatics(JSContext *cx, JSRegExpStatics *res); // start of the trace) then it cannot be reused. This variable sets a li
mit
extern void // on how often we allow that to happen before we insist on starting a ne
js_FreeRegExpStatics(JSContext *cx, JSRegExpStatics *res); w
// trace and generating generic code for a node that can be reused by flu
#define JSVAL_IS_REGEXP(cx, v) shing
\ // the deferred actions in the current trace and generating a goto.
(JSVAL_IS_OBJECT(v) && JSVAL_TO_OBJECT(v) && static const int kMaxCopiesCodeGenerated = 10;
\
OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_RegExpClass) NodeInfo* info() { return &info_; }
extern JSClass js_RegExpClass; BoyerMooreLookahead* bm_info(bool not_at_start) {
return bm_info_[not_at_start ? 1 : 0];
extern JSObject * }
js_InitRegExpClass(JSContext *cx, JSObject *obj);
Zone* zone() const { return zone_; }
/*
* Export js_regexp_toString to the decompiler. protected:
*/ enum LimitResult { DONE, CONTINUE };
extern JSBool RegExpNode* replacement_;
js_regexp_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval); LimitResult LimitVersions(RegExpCompiler* compiler, Trace* trace);
/* void set_bm_info(bool not_at_start, BoyerMooreLookahead* bm) {
* Create, serialize/deserialize, or clone a RegExp object. bm_info_[not_at_start ? 1 : 0] = bm;
*/ }
extern JSObject *
js_NewRegExpObject(JSContext *cx, JSTokenStream *ts, private:
jschar *chars, size_t length, uintN flags); static const int kFirstCharBudget = 10;
Label label_;
extern JSBool NodeInfo info_;
js_XDRRegExp(JSXDRState *xdr, JSObject **objp); // This variable keeps track of how many times code has been generated fo
r
extern JSObject * // this node (in different traces). We don't keep track of where the
js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *parent); // generated code is located unless the code is generated at the start of
// a trace, in which case it is generic and can be reused by flushing the
/* // deferred operations in the current trace and generating a goto.
* Get and set the per-object (clone or clone-parent) lastIndex slot. int trace_count_;
*/ BoyerMooreLookahead* bm_info_[2];
extern JSBool
js_GetLastIndex(JSContext *cx, JSObject *obj, jsdouble *lastIndex); Zone* zone_;
};
// A simple closed interval.
class Interval {
public:
Interval() : from_(kNone), to_(kNone) { }
Interval(int from, int to) : from_(from), to_(to) { }
Interval Union(Interval that) {
if (that.from_ == kNone)
return *this;
else if (from_ == kNone)
return that;
else
return Interval(Min(from_, that.from_), Max(to_, that.to_));
}
bool Contains(int value) {
return (from_ <= value) && (value <= to_);
}
bool is_empty() { return from_ == kNone; }
int from() const { return from_; }
int to() const { return to_; }
static Interval Empty() { return Interval(); }
static const int kNone = -1;
private:
int from_;
int to_;
};
class SeqRegExpNode: public RegExpNode {
public:
explicit SeqRegExpNode(RegExpNode* on_success)
: RegExpNode(on_success->zone()), on_success_(on_success) { }
RegExpNode* on_success() { return on_success_; }
void set_on_success(RegExpNode* node) { on_success_ = node; }
virtual RegExpNode* FilterASCII(int depth);
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start) {
on_success_->FillInBMInfo(
offset, recursion_depth + 1, budget - 1, bm, not_at_start);
if (offset == 0) set_bm_info(not_at_start, bm);
}
protected:
RegExpNode* FilterSuccessor(int depth);
private:
RegExpNode* on_success_;
};
class ActionNode: public SeqRegExpNode {
public:
enum Type {
SET_REGISTER,
INCREMENT_REGISTER,
STORE_POSITION,
BEGIN_SUBMATCH,
POSITIVE_SUBMATCH_SUCCESS,
EMPTY_MATCH_CHECK,
CLEAR_CAPTURES
};
static ActionNode* SetRegister(int reg, int val, RegExpNode* on_success);
static ActionNode* IncrementRegister(int reg, RegExpNode* on_success);
static ActionNode* StorePosition(int reg,
bool is_capture,
RegExpNode* on_success);
static ActionNode* ClearCaptures(Interval range, RegExpNode* on_success);
static ActionNode* BeginSubmatch(int stack_pointer_reg,
int position_reg,
RegExpNode* on_success);
static ActionNode* PositiveSubmatchSuccess(int stack_pointer_reg,
int restore_reg,
int clear_capture_count,
int clear_capture_from,
RegExpNode* on_success);
static ActionNode* EmptyMatchCheck(int start_register,
int repetition_register,
int repetition_limit,
RegExpNode* on_success);
virtual void Accept(NodeVisitor* visitor);
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int filled_in,
bool not_at_start) {
return on_success()->GetQuickCheckDetails(
details, compiler, filled_in, not_at_start);
}
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
Type type() { return type_; }
// TODO(erikcorry): We should allow some action nodes in greedy loops.
virtual int GreedyLoopTextLength() { return kNodeIsTooComplexForGreedyLoo
ps; }
private:
union {
struct {
int reg;
int value;
} u_store_register;
struct {
int reg;
} u_increment_register;
struct {
int reg;
bool is_capture;
} u_position_register;
struct {
int stack_pointer_register;
int current_position_register;
int clear_register_count;
int clear_register_from;
} u_submatch;
struct {
int start_register;
int repetition_register;
int repetition_limit;
} u_empty_match_check;
struct {
int range_from;
int range_to;
} u_clear_captures;
} data_;
ActionNode(Type type, RegExpNode* on_success)
: SeqRegExpNode(on_success),
type_(type) { }
Type type_;
friend class DotPrinter;
};
class TextNode: public SeqRegExpNode {
public:
TextNode(ZoneList<TextElement>* elms,
RegExpNode* on_success)
: SeqRegExpNode(on_success),
elms_(elms) { }
TextNode(RegExpCharacterClass* that,
RegExpNode* on_success)
: SeqRegExpNode(on_success),
elms_(new(zone()) ZoneList<TextElement>(1, zone())) {
elms_->Add(TextElement::CharClass(that), zone());
}
virtual void Accept(NodeVisitor* visitor);
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start);
ZoneList<TextElement>* elements() { return elms_; }
void MakeCaseIndependent(bool is_ascii);
virtual int GreedyLoopTextLength();
virtual RegExpNode* GetSuccessorOfOmnivorousTextNode(
RegExpCompiler* compiler);
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
void CalculateOffsets();
virtual RegExpNode* FilterASCII(int depth);
private:
enum TextEmitPassType {
NON_ASCII_MATCH, // Check for characters that can't match.
SIMPLE_CHARACTER_MATCH, // Case-dependent single character check.
NON_LETTER_CHARACTER_MATCH, // Check characters that have no case equi
vs.
CASE_CHARACTER_MATCH, // Case-independent single character check
.
CHARACTER_CLASS_MATCH // Character class.
};
static bool SkipPass(int pass, bool ignore_case);
static const int kFirstRealPass = SIMPLE_CHARACTER_MATCH;
static const int kLastPass = CHARACTER_CLASS_MATCH;
void TextEmitPass(RegExpCompiler* compiler,
TextEmitPassType pass,
bool preloaded,
Trace* trace,
bool first_element_checked,
int* checked_up_to);
int Length();
ZoneList<TextElement>* elms_;
};
class AssertionNode: public SeqRegExpNode {
public:
enum AssertionNodeType {
AT_END,
AT_START,
AT_BOUNDARY,
AT_NON_BOUNDARY,
AFTER_NEWLINE
};
static AssertionNode* AtEnd(RegExpNode* on_success) {
return new(on_success->zone()) AssertionNode(AT_END, on_success);
}
static AssertionNode* AtStart(RegExpNode* on_success) {
return new(on_success->zone()) AssertionNode(AT_START, on_success);
}
static AssertionNode* AtBoundary(RegExpNode* on_success) {
return new(on_success->zone()) AssertionNode(AT_BOUNDARY, on_success);
}
static AssertionNode* AtNonBoundary(RegExpNode* on_success) {
return new(on_success->zone()) AssertionNode(AT_NON_BOUNDARY, on_succes
s);
}
static AssertionNode* AfterNewline(RegExpNode* on_success) {
return new(on_success->zone()) AssertionNode(AFTER_NEWLINE, on_success)
;
}
virtual void Accept(NodeVisitor* visitor);
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int filled_in,
bool not_at_start);
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
AssertionNodeType type() { return type_; }
void set_type(AssertionNodeType type) { type_ = type; }
private:
void EmitBoundaryCheck(RegExpCompiler* compiler, Trace* trace);
enum IfPrevious { kIsNonWord, kIsWord };
void BacktrackIfPrevious(RegExpCompiler* compiler,
Trace* trace,
IfPrevious backtrack_if_previous);
AssertionNode(AssertionNodeType t, RegExpNode* on_success)
: SeqRegExpNode(on_success), type_(t) { }
AssertionNodeType type_;
};
class BackReferenceNode: public SeqRegExpNode {
public:
BackReferenceNode(int start_reg,
int end_reg,
RegExpNode* on_success)
: SeqRegExpNode(on_success),
start_reg_(start_reg),
end_reg_(end_reg) { }
virtual void Accept(NodeVisitor* visitor);
int start_register() { return start_reg_; }
int end_register() { return end_reg_; }
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start) {
return;
}
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
private:
int start_reg_;
int end_reg_;
};
class EndNode: public RegExpNode {
public:
enum Action { ACCEPT, BACKTRACK, NEGATIVE_SUBMATCH_SUCCESS };
explicit EndNode(Action action, Zone* zone)
: RegExpNode(zone), action_(action) { }
virtual void Accept(NodeVisitor* visitor);
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
bool not_at_start) { return 0; }
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start) {
// Returning 0 from EatsAtLeast should ensure we never get here.
UNREACHABLE();
}
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start) {
// Returning 0 from EatsAtLeast should ensure we never get here.
UNREACHABLE();
}
private:
Action action_;
};
class NegativeSubmatchSuccess: public EndNode {
public:
NegativeSubmatchSuccess(int stack_pointer_reg,
int position_reg,
int clear_capture_count,
int clear_capture_start,
Zone* zone)
: EndNode(NEGATIVE_SUBMATCH_SUCCESS, zone),
stack_pointer_register_(stack_pointer_reg),
current_position_register_(position_reg),
clear_capture_count_(clear_capture_count),
clear_capture_start_(clear_capture_start) { }
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
private:
int stack_pointer_register_;
int current_position_register_;
int clear_capture_count_;
int clear_capture_start_;
};
class Guard: public ZoneObject {
public:
enum Relation { LT, GEQ };
Guard(int reg, Relation op, int value)
: reg_(reg),
op_(op),
value_(value) { }
int reg() { return reg_; }
Relation op() { return op_; }
int value() { return value_; }
private:
int reg_;
Relation op_;
int value_;
};
class GuardedAlternative {
public:
explicit GuardedAlternative(RegExpNode* node) : node_(node), guards_(NULL
) { }
void AddGuard(Guard* guard, Zone* zone);
RegExpNode* node() { return node_; }
void set_node(RegExpNode* node) { node_ = node; }
ZoneList<Guard*>* guards() { return guards_; }
private:
RegExpNode* node_;
ZoneList<Guard*>* guards_;
};
class AlternativeGeneration;
class ChoiceNode: public RegExpNode {
public:
explicit ChoiceNode(int expected_size, Zone* zone)
: RegExpNode(zone),
alternatives_(new(zone)
ZoneList<GuardedAlternative>(expected_size, zone)),
table_(NULL),
not_at_start_(false),
being_calculated_(false) { }
virtual void Accept(NodeVisitor* visitor);
void AddAlternative(GuardedAlternative node) {
alternatives()->Add(node, zone());
}
ZoneList<GuardedAlternative>* alternatives() { return alternatives_; }
DispatchTable* GetTable(bool ignore_case);
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
bool not_at_start);
int EatsAtLeastHelper(int still_to_find,
int recursion_depth,
RegExpNode* ignore_this_node,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start);
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
bool being_calculated() { return being_calculated_; }
bool not_at_start() { return not_at_start_; }
void set_not_at_start() { not_at_start_ = true; }
void set_being_calculated(bool b) { being_calculated_ = b; }
virtual bool try_to_emit_quick_check_for_alternative(int i) { return true
; }
virtual RegExpNode* FilterASCII(int depth);
protected:
int GreedyLoopTextLengthForAlternative(GuardedAlternative* alternative);
ZoneList<GuardedAlternative>* alternatives_;
private:
friend class DispatchTableConstructor;
friend class Analysis;
void GenerateGuard(RegExpMacroAssembler* macro_assembler,
Guard* guard,
Trace* trace);
int CalculatePreloadCharacters(RegExpCompiler* compiler, int eats_at_leas
t);
void EmitOutOfLineContinuation(RegExpCompiler* compiler,
Trace* trace,
GuardedAlternative alternative,
AlternativeGeneration* alt_gen,
int preload_characters,
bool next_expects_preload);
DispatchTable* table_;
// If true, this node is never checked at the start of the input.
// Allows a new trace to start with at_start() set to false.
bool not_at_start_;
bool being_calculated_;
};
class NegativeLookaheadChoiceNode: public ChoiceNode {
public:
explicit NegativeLookaheadChoiceNode(GuardedAlternative this_must_fail,
GuardedAlternative then_do_this,
Zone* zone)
: ChoiceNode(2, zone) {
AddAlternative(this_must_fail);
AddAlternative(then_do_this);
}
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start);
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start) {
alternatives_->at(1).node()->FillInBMInfo(
offset, recursion_depth + 1, budget - 1, bm, not_at_start);
if (offset == 0) set_bm_info(not_at_start, bm);
}
// For a negative lookahead we don't emit the quick check for the
// alternative that is expected to fail. This is because quick check cod
e
// starts by loading enough characters for the alternative that takes few
est
// characters, but on a negative lookahead the negative branch did not ta
ke
// part in that calculation (EatsAtLeast) so the assumptions don't hold.
virtual bool try_to_emit_quick_check_for_alternative(int i) { return i !=
0; }
virtual RegExpNode* FilterASCII(int depth);
};
class LoopChoiceNode: public ChoiceNode {
public:
explicit LoopChoiceNode(bool body_can_be_zero_length, Zone* zone)
: ChoiceNode(2, zone),
loop_node_(NULL),
continue_node_(NULL),
body_can_be_zero_length_(body_can_be_zero_length) { }
void AddLoopAlternative(GuardedAlternative alt);
void AddContinueAlternative(GuardedAlternative alt);
virtual void Emit(RegExpCompiler* compiler, Trace* trace);
virtual int EatsAtLeast(int still_to_find,
int recursion_depth,
bool not_at_start);
virtual void GetQuickCheckDetails(QuickCheckDetails* details,
RegExpCompiler* compiler,
int characters_filled_in,
bool not_at_start);
virtual void FillInBMInfo(int offset,
int recursion_depth,
int budget,
BoyerMooreLookahead* bm,
bool not_at_start);
RegExpNode* loop_node() { return loop_node_; }
RegExpNode* continue_node() { return continue_node_; }
bool body_can_be_zero_length() { return body_can_be_zero_length_; }
virtual void Accept(NodeVisitor* visitor);
virtual RegExpNode* FilterASCII(int depth);
private:
// AddAlternative is made private for loop nodes because alternatives
// should not be added freely, we need to keep track of which node
// goes back to the node itself.
void AddAlternative(GuardedAlternative node) {
ChoiceNode::AddAlternative(node);
}
RegExpNode* loop_node_;
RegExpNode* continue_node_;
bool body_can_be_zero_length_;
};
// Improve the speed that we scan for an initial point where a non-anchored
// regexp can match by using a Boyer-Moore-like table. This is done by
// identifying non-greedy non-capturing loops in the nodes that eat any
// character one at a time. For example in the middle of the regexp
// /foo[\s\S]*?bar/ we find such a loop. There is also such a loop implici
tly
// inserted at the start of any non-anchored regexp.
//
// When we have found such a loop we look ahead in the nodes to find the se
t of
// characters that can come at given distances. For example for the regexp
// /.?foo/ we know that there are at least 3 characters ahead of us, and th
e
// sets of characters that can occur are [any, [f, o], [o]]. We find a rang
e in
// the lookahead info where the set of characters is reasonably constrained
. In
// our example this is from index 1 to 2 (0 is not constrained). We can now
// look 3 characters ahead and if we don't find one of [f, o] (the union of
// [f, o] and [o]) then we can skip forwards by the range size (in this cas
e 2).
//
// For Unicode input strings we do the same, but modulo 128.
//
// We also look at the first string fed to the regexp and use that to get a
hint
// of the character frequencies in the inputs. This affects the assessment
of
// whether the set of characters is 'reasonably constrained'.
//
// We also have another lookahead mechanism (called quick check in the code
),
// which uses a wide load of multiple characters followed by a mask and com
pare
// to determine whether a match is possible at this point.
enum ContainedInLattice {
kNotYet = 0,
kLatticeIn = 1,
kLatticeOut = 2,
kLatticeUnknown = 3 // Can also mean both in and out.
};
inline ContainedInLattice Combine(ContainedInLattice a, ContainedInLattice
b) {
return static_cast<ContainedInLattice>(a | b);
}
ContainedInLattice AddRange(ContainedInLattice a,
const int* ranges,
int ranges_size,
Interval new_range);
class BoyerMoorePositionInfo : public ZoneObject {
public:
explicit BoyerMoorePositionInfo(Zone* zone)
: map_(new(zone) ZoneList<bool>(kMapSize, zone)),
map_count_(0),
w_(kNotYet),
s_(kNotYet),
d_(kNotYet),
surrogate_(kNotYet) {
for (int i = 0; i < kMapSize; i++) {
map_->Add(false, zone);
}
}
bool& at(int i) { return map_->at(i); }
static const int kMapSize = 128;
static const int kMask = kMapSize - 1;
int map_count() const { return map_count_; }
void Set(int character);
void SetInterval(const Interval& interval);
void SetAll();
bool is_non_word() { return w_ == kLatticeOut; }
bool is_word() { return w_ == kLatticeIn; }
private:
ZoneList<bool>* map_;
int map_count_; // Number of set bits in the map.
ContainedInLattice w_; // The \w character class.
ContainedInLattice s_; // The \s character class.
ContainedInLattice d_; // The \d character class.
ContainedInLattice surrogate_; // Surrogate UTF-16 code units.
};
class BoyerMooreLookahead : public ZoneObject {
public:
BoyerMooreLookahead(int length, RegExpCompiler* compiler, Zone* zone);
int length() { return length_; }
int max_char() { return max_char_; }
RegExpCompiler* compiler() { return compiler_; }
int Count(int map_number) {
return bitmaps_->at(map_number)->map_count();
}
BoyerMoorePositionInfo* at(int i) { return bitmaps_->at(i); }
void Set(int map_number, int character) {
if (character > max_char_) return;
BoyerMoorePositionInfo* info = bitmaps_->at(map_number);
info->Set(character);
}
void SetInterval(int map_number, const Interval& interval) {
if (interval.from() > max_char_) return;
BoyerMoorePositionInfo* info = bitmaps_->at(map_number);
if (interval.to() > max_char_) {
info->SetInterval(Interval(interval.from(), max_char_));
} else {
info->SetInterval(interval);
}
}
void SetAll(int map_number) {
bitmaps_->at(map_number)->SetAll();
}
void SetRest(int from_map) {
for (int i = from_map; i < length_; i++) SetAll(i);
}
bool EmitSkipInstructions(RegExpMacroAssembler* masm);
private:
// This is the value obtained by EatsAtLeast. If we do not have at least
this
// many characters left in the sample string then the match is bound to f
ail.
// Therefore it is OK to read a character this far ahead of the current m
atch
// point.
int length_;
RegExpCompiler* compiler_;
// 0x7f for ASCII, 0xffff for UTF-16.
int max_char_;
ZoneList<BoyerMoorePositionInfo*>* bitmaps_;
int GetSkipTable(int min_lookahead,
int max_lookahead,
Handle<ByteArray> boolean_skip_table);
bool FindWorthwhileInterval(int* from, int* to);
int FindBestInterval(
int max_number_of_chars, int old_biggest_points, int* from, int* to);
};
// There are many ways to generate code for a node. This class encapsulate
s
// the current way we should be generating. In other words it encapsulates
// the current state of the code generator. The effect of this is that we
// generate code for paths that the matcher can take through the regular
// expression. A given node in the regexp can be code-generated several ti
mes
// as it can be part of several traces. For example for the regexp:
// /foo(bar|ip)baz/ the code to match baz will be generated twice, once as
part
// of the foo-bar-baz trace and once as part of the foo-ip-baz trace. The
code
// to match foo is generated only once (the traces have a common prefix).
The
// code to store the capture is deferred and generated (twice) after the pl
aces
// where baz has been matched.
class Trace {
public:
// A value for a property that is either known to be true, know to be fal
se,
// or not known.
enum TriBool {
UNKNOWN = -1, FALSE = 0, TRUE = 1
};
class DeferredAction {
public:
DeferredAction(ActionNode::Type type, int reg)
: type_(type), reg_(reg), next_(NULL) { }
DeferredAction* next() { return next_; }
bool Mentions(int reg);
int reg() { return reg_; }
ActionNode::Type type() { return type_; }
private:
ActionNode::Type type_;
int reg_;
DeferredAction* next_;
friend class Trace;
};
class DeferredCapture : public DeferredAction {
public:
DeferredCapture(int reg, bool is_capture, Trace* trace)
: DeferredAction(ActionNode::STORE_POSITION, reg),
cp_offset_(trace->cp_offset()),
is_capture_(is_capture) { }
int cp_offset() { return cp_offset_; }
bool is_capture() { return is_capture_; }
private:
int cp_offset_;
bool is_capture_;
void set_cp_offset(int cp_offset) { cp_offset_ = cp_offset; }
};
class DeferredSetRegister : public DeferredAction {
public:
DeferredSetRegister(int reg, int value)
: DeferredAction(ActionNode::SET_REGISTER, reg),
value_(value) { }
int value() { return value_; }
private:
int value_;
};
class DeferredClearCaptures : public DeferredAction {
public:
explicit DeferredClearCaptures(Interval range)
: DeferredAction(ActionNode::CLEAR_CAPTURES, -1),
range_(range) { }
Interval range() { return range_; }
private:
Interval range_;
};
class DeferredIncrementRegister : public DeferredAction {
public:
explicit DeferredIncrementRegister(int reg)
: DeferredAction(ActionNode::INCREMENT_REGISTER, reg) { }
};
Trace()
: cp_offset_(0),
actions_(NULL),
backtrack_(NULL),
stop_node_(NULL),
loop_label_(NULL),
characters_preloaded_(0),
bound_checked_up_to_(0),
flush_budget_(100),
at_start_(UNKNOWN) { }
// End the trace. This involves flushing the deferred actions in the tra
ce
// and pushing a backtrack location onto the backtrack stack. Once this
is
// done we can start a new trace or go to one that has already been
// generated.
void Flush(RegExpCompiler* compiler, RegExpNode* successor);
int cp_offset() { return cp_offset_; }
DeferredAction* actions() { return actions_; }
// A trivial trace is one that has no deferred actions or other state tha
t
// affects the assumptions used when generating code. There is no record
ed
// backtrack location in a trivial trace, so with a trivial trace we will
// generate code that, on a failure to match, gets the backtrack location
// from the backtrack stack rather than using a direct jump instruction.
We
// always start code generation with a trivial trace and non-trivial trac
es
// are created as we emit code for nodes or add to the list of deferred
// actions in the trace. The location of the code generated for a node u
sing
// a trivial trace is recorded in a label in the node so that gotos can b
e
// generated to that code.
bool is_trivial() {
return backtrack_ == NULL &&
actions_ == NULL &&
cp_offset_ == 0 &&
characters_preloaded_ == 0 &&
bound_checked_up_to_ == 0 &&
quick_check_performed_.characters() == 0 &&
at_start_ == UNKNOWN;
}
TriBool at_start() { return at_start_; }
void set_at_start(bool at_start) { at_start_ = at_start ? TRUE : FALSE; }
Label* backtrack() { return backtrack_; }
Label* loop_label() { return loop_label_; }
RegExpNode* stop_node() { return stop_node_; }
int characters_preloaded() { return characters_preloaded_; }
int bound_checked_up_to() { return bound_checked_up_to_; }
int flush_budget() { return flush_budget_; }
QuickCheckDetails* quick_check_performed() { return &quick_check_performe
d_; }
bool mentions_reg(int reg);
// Returns true if a deferred position store exists to the specified
// register and stores the offset in the out-parameter. Otherwise
// returns false.
bool GetStoredPosition(int reg, int* cp_offset);
// These set methods and AdvanceCurrentPositionInTrace should be used onl
y on
// new traces - the intention is that traces are immutable after creation
.
void add_action(DeferredAction* new_action) {
ASSERT(new_action->next_ == NULL);
new_action->next_ = actions_;
actions_ = new_action;
}
void set_backtrack(Label* backtrack) { backtrack_ = backtrack; }
void set_stop_node(RegExpNode* node) { stop_node_ = node; }
void set_loop_label(Label* label) { loop_label_ = label; }
void set_characters_preloaded(int count) { characters_preloaded_ = count;
}
void set_bound_checked_up_to(int to) { bound_checked_up_to_ = to; }
void set_flush_budget(int to) { flush_budget_ = to; }
void set_quick_check_performed(QuickCheckDetails* d) {
quick_check_performed_ = *d;
}
void InvalidateCurrentCharacter();
void AdvanceCurrentPositionInTrace(int by, RegExpCompiler* compiler);
private:
int FindAffectedRegisters(OutSet* affected_registers, Zone* zone);
void PerformDeferredActions(RegExpMacroAssembler* macro,
int max_register,
OutSet& affected_registers,
OutSet* registers_to_pop,
OutSet* registers_to_clear,
Zone* zone);
void RestoreAffectedRegisters(RegExpMacroAssembler* macro,
int max_register,
OutSet& registers_to_pop,
OutSet& registers_to_clear);
int cp_offset_;
DeferredAction* actions_;
Label* backtrack_;
RegExpNode* stop_node_;
Label* loop_label_;
int characters_preloaded_;
int bound_checked_up_to_;
QuickCheckDetails quick_check_performed_;
int flush_budget_;
TriBool at_start_;
};
class NodeVisitor {
public:
virtual ~NodeVisitor() { }
#define DECLARE_VISIT(Type) \
virtual void Visit##Type(Type##Node* that) = 0;
FOR_EACH_NODE_TYPE(DECLARE_VISIT)
#undef DECLARE_VISIT
virtual void VisitLoopChoice(LoopChoiceNode* that) { VisitChoice(that); }
};
// Node visitor used to add the start set of the alternatives to the
// dispatch table of a choice node.
class DispatchTableConstructor: public NodeVisitor {
public:
DispatchTableConstructor(DispatchTable* table, bool ignore_case,
Zone* zone)
: table_(table),
choice_index_(-1),
ignore_case_(ignore_case),
zone_(zone) { }
void BuildTable(ChoiceNode* node);
void AddRange(CharacterRange range) {
table()->AddRange(range, choice_index_, zone_);
}
void AddInverse(ZoneList<CharacterRange>* ranges);
#define DECLARE_VISIT(Type) \
virtual void Visit##Type(Type##Node* that);
FOR_EACH_NODE_TYPE(DECLARE_VISIT)
#undef DECLARE_VISIT
DispatchTable* table() { return table_; }
void set_choice_index(int value) { choice_index_ = value; }
protected:
DispatchTable* table_;
int choice_index_;
bool ignore_case_;
Zone* zone_;
};
// Assertion propagation moves information about assertions such as
// \b to the affected nodes. For instance, in /.\b./ information must
// be propagated to the first '.' that whatever follows needs to know
// if it matched a word or a non-word, and to the second '.' that it
// has to check if it succeeds a word or non-word. In this case the
// result will be something like:
//
// +-------+ +------------+
// | . | | . |
// +-------+ ---> +------------+
// | word? | | check word |
// +-------+ +------------+
class Analysis: public NodeVisitor {
public:
Analysis(bool ignore_case, bool is_ascii)
: ignore_case_(ignore_case),
is_ascii_(is_ascii),
error_message_(NULL) { }
void EnsureAnalyzed(RegExpNode* node);
#define DECLARE_VISIT(Type) \
virtual void Visit##Type(Type##Node* that);
FOR_EACH_NODE_TYPE(DECLARE_VISIT)
#undef DECLARE_VISIT
virtual void VisitLoopChoice(LoopChoiceNode* that);
bool has_failed() { return error_message_ != NULL; }
const char* error_message() {
ASSERT(error_message_ != NULL);
return error_message_;
}
void fail(const char* error_message) {
error_message_ = error_message;
}
private:
bool ignore_case_;
bool is_ascii_;
const char* error_message_;
DISALLOW_IMPLICIT_CONSTRUCTORS(Analysis);
};
struct RegExpCompileData {
RegExpCompileData()
: tree(NULL),
node(NULL),
simple(true),
contains_anchor(false),
capture_count(0) { }
RegExpTree* tree;
RegExpNode* node;
bool simple;
bool contains_anchor;
Handle<String> error;
int capture_count;
};
class RegExpEngine: public AllStatic {
public:
struct CompilationResult {
explicit CompilationResult(const char* error_message)
: error_message(error_message),
code(HEAP->the_hole_value()),
num_registers(0) {}
CompilationResult(Object* code, int registers)
: error_message(NULL),
code(code),
num_registers(registers) {}
const char* error_message;
Object* code;
int num_registers;
};
static CompilationResult Compile(RegExpCompileData* input,
bool ignore_case,
bool global,
bool multiline,
Handle<String> pattern,
Handle<String> sample_subject,
bool is_ascii, Zone* zone);
static void DotPrint(const char* label, RegExpNode* node, bool ignore_cas
e);
};
class OffsetsVector {
public:
inline OffsetsVector(int num_registers, Isolate* isolate)
: offsets_vector_length_(num_registers) {
if (offsets_vector_length_ > Isolate::kJSRegexpStaticOffsetsVectorSize)
{
vector_ = NewArray<int>(offsets_vector_length_);
} else {
vector_ = isolate->jsregexp_static_offsets_vector();
}
}
inline ~OffsetsVector() {
if (offsets_vector_length_ > Isolate::kJSRegexpStaticOffsetsVectorSize)
{
DeleteArray(vector_);
vector_ = NULL;
}
}
inline int* vector() { return vector_; }
inline int length() { return offsets_vector_length_; }
static const int kStaticOffsetsVectorSize =
Isolate::kJSRegexpStaticOffsetsVectorSize;
private:
static Address static_offsets_vector_address(Isolate* isolate) {
return reinterpret_cast<Address>(isolate->jsregexp_static_offsets_vecto
r());
}
int* vector_;
int offsets_vector_length_;
friend class ExternalReference;
};
extern JSBool } } // namespace v8::internal
js_SetLastIndex(JSContext *cx, JSObject *obj, jsdouble lastIndex);
#endif /* jsregexp_h___ */ #endif // V8_JSREGEXP_H_
 End of changes. 5 change blocks. 
203 lines changed or deleted 1694 lines changed or added


 kill_current_op.h   kill_current_op.h 
skipping to change at line 67 skipping to change at line 67
void checkForInterrupt( bool heedMutex = true ); void checkForInterrupt( bool heedMutex = true );
/** @return "" if not interrupted. otherwise, you should stop. */ /** @return "" if not interrupted. otherwise, you should stop. */
const char *checkForInterruptNoAssert(); const char *checkForInterruptNoAssert();
/** set all flags for all the threads waiting for the current threa d's operation to /** set all flags for all the threads waiting for the current threa d's operation to
* end; part of internal synchronous kill mechanism * end; part of internal synchronous kill mechanism
**/ **/
void notifyAllWaiters(); void notifyAllWaiters();
/** Reset the object to its initial state. Only for testing. */
void reset();
private: private:
void interruptJs( AtomicUInt *op ); void interruptJs( AtomicUInt *op );
volatile bool _globalKill; volatile bool _globalKill;
boost::condition _condvar; boost::condition _condvar;
boost::mutex _mtx; boost::mutex _mtx;
/** /**
* @param i opid of operation to kill * @param i opid of operation to kill
* @param pNotifyFlag optional bool to be set to true when kill act ually happens * @param pNotifyFlag optional bool to be set to true when kill act ually happens
* @return if operation was found * @return if operation was found
 End of changes. 1 change blocks. 
0 lines changed or deleted 3 lines changed or added


 list.h   list.h 
skipping to change at line 90 skipping to change at line 90
scoped_lock lk(_m); scoped_lock lk(_m);
T *&prev = (T*&) _head; T *&prev = (T*&) _head;
T *n = prev; T *n = prev;
while( n != t ) { while( n != t ) {
uassert( 14050 , "List1: item to orphan not in list", n ); uassert( 14050 , "List1: item to orphan not in list", n );
prev = n->_next; prev = n->_next;
n = prev; n = prev;
} }
prev = t->_next; prev = t->_next;
if( ++_orphans > 500 ) if( ++_orphans > 500 )
log() << "warning List1 orphans=" << _orphans << '\n'; log() << "warning List1 orphans=" << _orphans << endl;
} }
private: private:
volatile T *_head; volatile T *_head;
mongo::mutex _m; mongo::mutex _m;
int _orphans; int _orphans;
}; };
}; };
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 listen.h   listen.h 
skipping to change at line 110 skipping to change at line 110
/** the "next" connection number. every connection to this process has a unique number */ /** the "next" connection number. every connection to this process has a unique number */
static AtomicInt64 globalConnectionNumber; static AtomicInt64 globalConnectionNumber;
/** keeps track of how many allowed connections there are and how m any are being used*/ /** keeps track of how many allowed connections there are and how m any are being used*/
static TicketHolder globalTicketHolder; static TicketHolder globalTicketHolder;
/** makes sure user input is sane */ /** makes sure user input is sane */
static void checkTicketNumbers(); static void checkTicketNumbers();
}; };
/**
* keep track of elapsed time
* after a set amount of time, tells you to do something
* only in this file because depends on Listener
*/
class ElapsedTracker {
public:
ElapsedTracker( int hitsBetweenMarks , int msBetweenMarks )
: _h( hitsBetweenMarks ) , _ms( msBetweenMarks ) , _pings(0) {
_last = Listener::getElapsedTimeMillis();
}
/**
* call this for every iteration
* returns true if one of the triggers has gone off
*/
bool intervalHasElapsed() {
if ( ( ++_pings % _h ) == 0 ) {
_last = Listener::getElapsedTimeMillis();
return true;
}
long long now = Listener::getElapsedTimeMillis();
if ( now - _last > _ms ) {
_last = now;
return true;
}
return false;
}
void resetLastTime() {
_last = Listener::getElapsedTimeMillis();
}
private:
const int _h;
const int _ms;
unsigned long long _pings;
long long _last;
};
class ListeningSockets { class ListeningSockets {
public: public:
ListeningSockets() ListeningSockets()
: _mutex("ListeningSockets") : _mutex("ListeningSockets")
, _sockets( new set<int>() ) , _sockets( new set<int>() )
, _socketPaths( new set<string>() ) , _socketPaths( new set<string>() )
{ } { }
void add( int sock ) { void add( int sock ) {
scoped_lock lk( _mutex ); scoped_lock lk( _mutex );
_sockets->insert( sock ); _sockets->insert( sock );
 End of changes. 1 change blocks. 
45 lines changed or deleted 0 lines changed or added


 log.h   log.h 
skipping to change at line 113 skipping to change at line 113
} }
const string& getLabel() const { return _label; } const string& getLabel() const { return _label; }
int getLevel() const { return _level; } int getLevel() const { return _level; }
private: private:
string _label; string _label;
int _level; int _level;
}; };
inline bool operator<( const LabeledLevel& ll, const int i ) { return l
l.getLevel() < i; }
inline bool operator<( const int i, const LabeledLevel& ll ) { return i
< ll.getLevel(); }
inline bool operator>( const LabeledLevel& ll, const int i ) { return l
l.getLevel() > i; }
inline bool operator>( const int i, const LabeledLevel& ll ) { return i
> ll.getLevel(); }
inline bool operator<=( const LabeledLevel& ll, const int i ) { return
ll.getLevel() <= i; }
inline bool operator<=( const int i, const LabeledLevel& ll ) { return
i <= ll.getLevel(); }
inline bool operator>=( const LabeledLevel& ll, const int i ) { return
ll.getLevel() >= i; }
inline bool operator>=( const int i, const LabeledLevel& ll ) { return
i >= ll.getLevel(); }
inline bool operator==( const LabeledLevel& ll, const int i ) { return
ll.getLevel() == i; }
inline bool operator==( const int i, const LabeledLevel& ll ) { return
i == ll.getLevel(); }
class LazyString { class LazyString {
public: public:
virtual ~LazyString() {} virtual ~LazyString() {}
virtual string val() const = 0; virtual string val() const = 0;
}; };
// Utility class for stringifying object only when val() called. // Utility class for stringifying object only when val() called.
template< class T > template< class T >
class LazyStringImpl : public LazyString { class LazyStringImpl : public LazyString {
public: public:
skipping to change at line 379 skipping to change at line 390
set tlogLevel to -1 to suppress tlog() output in a test program. */ set tlogLevel to -1 to suppress tlog() output in a test program. */
Nullstream& tlog( int level = 0 ); Nullstream& tlog( int level = 0 );
// log if debug build or if at a certain level // log if debug build or if at a certain level
inline Nullstream& dlog( int level ) { inline Nullstream& dlog( int level ) {
if ( level <= logLevel || DEBUG_BUILD ) if ( level <= logLevel || DEBUG_BUILD )
return Logstream::get().prolog(); return Logstream::get().prolog();
return nullstream; return nullstream;
} }
inline Nullstream& log( int level ) { #define MONGO_LOG(requiredLevel) \
if ( level > logLevel ) ( MONGO_likely( ::mongo::logLevel < (requiredLevel) ) ) \
return nullstream; ? ::mongo::log() : ::mongo::log()
return Logstream::get().prolog();
}
#define MONGO_LOG(level) if ( MONGO_likely(logLevel < (level)) ) { } else l
og( level )
#define LOG MONGO_LOG #define LOG MONGO_LOG
inline Nullstream& log( LogLevel l ) {
return Logstream::get().prolog().setLogLevel( l );
}
inline Nullstream& log( const LabeledLevel& ll ) {
Nullstream& stream = log( ll.getLevel() );
if( ll.getLabel() != "" )
stream << "[" << ll.getLabel() << "] ";
return stream;
}
inline Nullstream& log() { inline Nullstream& log() {
return Logstream::get().prolog(); return Logstream::get().prolog();
} }
inline Nullstream& error() { inline Nullstream& error() {
return log( LL_ERROR ); return MONGO_LOG( LL_ERROR );
} }
inline Nullstream& warning() { inline Nullstream& warning() {
return log( LL_WARNING ); return MONGO_LOG( LL_WARNING );
} }
/* default impl returns "" -- mongod overrides */ /* default impl returns "" -- mongod overrides */
extern const char * (*getcurns)(); extern const char * (*getcurns)();
inline Nullstream& problem( int level = 0 ) { inline Nullstream& problem( int level = 0 ) {
if ( level > logLevel ) if ( level > logLevel )
return nullstream; return nullstream;
Logstream& l = Logstream::get().prolog(); Logstream& l = Logstream::get().prolog();
l << ' ' << getcurns() << ' '; l << ' ' << getcurns() << ' ';
skipping to change at line 446 skipping to change at line 442
struct LogIndentLevel { struct LogIndentLevel {
LogIndentLevel(){ LogIndentLevel(){
Logstream::get().indentInc(); Logstream::get().indentInc();
} }
~LogIndentLevel(){ ~LogIndentLevel(){
Logstream::get().indentDec(); Logstream::get().indentDec();
} }
}; };
extern Tee* const warnings; // Things put here go in serverStatus extern Tee* const warnings; // Things put here go in serverStatus
extern Tee* startupWarningsLog; extern Tee* const startupWarningsLog; // Things put here get reported i n MMS
string errnoWithDescription(int errorcode = -1); string errnoWithDescription(int errorcode = -1);
void rawOut( const string &s ); void rawOut( const string &s );
/** /**
* Write the current context (backtrace), along with the optional "msg" . * Write the current context (backtrace), along with the optional "msg" .
*/ */
void logContext(const char *msg = NULL); void logContext(const char *msg = NULL);
} // namespace mongo } // namespace mongo
 End of changes. 6 change blocks. 
22 lines changed or deleted 27 lines changed or added


 logging.h   logging.h 
// Copyright (c) 2005, Google Inc. // Copyright 2010 Google
// All rights reserved. // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// //
// Redistribution and use in source and binary forms, with or without // http://www.apache.org/licenses/LICENSE-2.0
// modification, are permitted provided that the following conditions are
// met:
// //
// * Redistributions of source code must retain the above copyright // Unless required by applicable law or agreed to in writing, software
// notice, this list of conditions and the following disclaimer. // distributed under the License is distributed on an "AS IS" BASIS,
// * Redistributions in binary form must reproduce the above // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// copyright notice, this list of conditions and the following disclaimer // See the License for the specific language governing permissions and
// in the documentation and/or other materials provided with the // limitations under the License.
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ---
// This file contains #include information about logging-related stuff.
// Pretty much everybody needs to #include this file so that they can
// log various happenings.
//
#ifndef _LOGGING_H_
#define _LOGGING_H_
#include <config.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h> // for write()
#endif
#include <string.h> // for strlen(), strcmp()
#include <assert.h>
#include <errno.h> // for errno
#include "base/commandlineflags.h"
// On some systems (like freebsd), we can't call write() at all in a
// global constructor, perhaps because errno hasn't been set up.
// (In windows, we can't call it because it might call malloc.)
// Calling the write syscall is safer (it doesn't set errno), so we
// prefer that. Note we don't care about errno for logging: we just
// do logging on a best-effort basis.
#if defined(_MSC_VER)
#define WRITE_TO_STDERR(buf, len) WriteToStderr(buf, len); // in port.cc
#elif defined(HAVE_SYS_SYSCALL_H)
#include <sys/syscall.h>
#define WRITE_TO_STDERR(buf, len) syscall(SYS_write, STDERR_FILENO, buf, le
n)
#else
#define WRITE_TO_STDERR(buf, len) write(STDERR_FILENO, buf, len)
#endif
// MSVC and mingw define their own, safe version of vnsprintf (the #ifndef BASE_LOGGING_H
// windows one in broken) in port.cc. Everyone else can use the #define BASE_LOGGING_H
// version here. We had to give it a unique name for windows.
#ifndef _WIN32
# define perftools_vsnprintf vsnprintf
#endif
// We log all messages at this log-level and below. #include <stdlib.h>
// INFO == -1, WARNING == -2, ERROR == -3, FATAL == -4 #include <stdlib.h>
DECLARE_int32(verbose); #include <iostream>
using std::ostream;
// CHECK dies with a fatal error if condition is not true. It is *not* using std::cout;
// controlled by NDEBUG, so the check will be executed regardless of using std::endl;
// compilation mode. Therefore, it is safe to do things like:
// CHECK(fp->Write(x) == 4) #include "macros.h"
// Note we use write instead of printf/puts to avoid the risk we'll
// call malloc(). // Always-on checking
#define CHECK(condition) \ #define CHECK(x) if(x){}else LogMessageFatal(__FILE__, __LINE__).stre
do { \ am() << "Check failed: " #x
if (!(condition)) { \ #define CHECK_LT(x, y) CHECK((x) < (y))
WRITE_TO_STDERR("Check failed: " #condition "\n", \ #define CHECK_GT(x, y) CHECK((x) > (y))
sizeof("Check failed: " #condition "\n")-1); \ #define CHECK_LE(x, y) CHECK((x) <= (y))
abort(); \ #define CHECK_GE(x, y) CHECK((x) >= (y))
} \ #define CHECK_EQ(x, y) CHECK((x) == (y))
} while (0) #define CHECK_NE(x, y) CHECK((x) != (y))
#define CHECK_NOTNULL(x) CHECK((x) != NULL)
// This takes a message to print. The name is historical.
#define RAW_CHECK(condition, message) #ifndef NDEBUG
\ // Debug-only checking.
do { #define DCHECK(condition) CHECK(condition)
\ #define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2)
if (!(condition)) { #define DCHECK_NE(val1, val2) CHECK_NE(val1, val2)
\ #define DCHECK_LE(val1, val2) CHECK_LE(val1, val2)
WRITE_TO_STDERR("Check failed: " #condition ": " message "\n", #define DCHECK_LT(val1, val2) CHECK_LT(val1, val2)
\ #define DCHECK_GE(val1, val2) CHECK_GE(val1, val2)
sizeof("Check failed: " #condition ": " message "\n") #define DCHECK_GT(val1, val2) CHECK_GT(val1, val2)
-1);\
abort();
\
}
\
} while (0)
// This is like RAW_CHECK, but only in debug-mode
#ifdef NDEBUG
enum { DEBUG_MODE = 0 };
#define RAW_DCHECK(condition, message)
#else
enum { DEBUG_MODE = 1 };
#define RAW_DCHECK(condition, message) RAW_CHECK(condition, message)
#endif
// This prints errno as well. Note we use write instead of printf/puts to
// avoid the risk we'll call malloc().
#define PCHECK(condition) \
do { \
if (!(condition)) { \
const int err_no = errno; \
WRITE_TO_STDERR("Check failed: " #condition ": ", \
sizeof("Check failed: " #condition ": ")-1); \
WRITE_TO_STDERR(strerror(err_no), strlen(strerror(err_no))); \
WRITE_TO_STDERR("\n", sizeof("\n")-1); \
abort(); \
} \
} while (0)
// Helper macro for binary operators; prints the two values on error
// Don't use this macro directly in your code, use CHECK_EQ et al below
// WARNING: These don't compile correctly if one of the arguments is a poin
ter
// and the other is NULL. To work around this, simply static_cast NULL to t
he
// type of the desired pointer.
// TODO(jandrews): Also print the values in case of failure. Requires some
// sort of type-sensitive ToString() function.
#define CHECK_OP(op, val1, val2) \
do { \
if (!((val1) op (val2))) { \
fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \
abort(); \
} \
} while (0)
#define CHECK_EQ(val1, val2) CHECK_OP(==, val1, val2)
#define CHECK_NE(val1, val2) CHECK_OP(!=, val1, val2)
#define CHECK_LE(val1, val2) CHECK_OP(<=, val1, val2)
#define CHECK_LT(val1, val2) CHECK_OP(< , val1, val2)
#define CHECK_GE(val1, val2) CHECK_OP(>=, val1, val2)
#define CHECK_GT(val1, val2) CHECK_OP(> , val1, val2)
// Synonyms for CHECK_* that are used in some unittests.
#define EXPECT_EQ(val1, val2) CHECK_EQ(val1, val2)
#define EXPECT_NE(val1, val2) CHECK_NE(val1, val2)
#define EXPECT_LE(val1, val2) CHECK_LE(val1, val2)
#define EXPECT_LT(val1, val2) CHECK_LT(val1, val2)
#define EXPECT_GE(val1, val2) CHECK_GE(val1, val2)
#define EXPECT_GT(val1, val2) CHECK_GT(val1, val2)
#define ASSERT_EQ(val1, val2) EXPECT_EQ(val1, val2)
#define ASSERT_NE(val1, val2) EXPECT_NE(val1, val2)
#define ASSERT_LE(val1, val2) EXPECT_LE(val1, val2)
#define ASSERT_LT(val1, val2) EXPECT_LT(val1, val2)
#define ASSERT_GE(val1, val2) EXPECT_GE(val1, val2)
#define ASSERT_GT(val1, val2) EXPECT_GT(val1, val2)
// As are these variants.
#define EXPECT_TRUE(cond) CHECK(cond)
#define EXPECT_FALSE(cond) CHECK(!(cond))
#define EXPECT_STREQ(a, b) CHECK(strcmp(a, b) == 0)
#define ASSERT_TRUE(cond) EXPECT_TRUE(cond)
#define ASSERT_FALSE(cond) EXPECT_FALSE(cond)
#define ASSERT_STREQ(a, b) EXPECT_STREQ(a, b)
// Used for (libc) functions that return -1 and set errno
#define CHECK_ERR(invocation) PCHECK((invocation) != -1)
// A few more checks that only happen in debug mode
#ifdef NDEBUG
#define DCHECK_EQ(val1, val2)
#define DCHECK_NE(val1, val2)
#define DCHECK_LE(val1, val2)
#define DCHECK_LT(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK_GT(val1, val2)
#else #else
#define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2) #define DCHECK(condition) CHECK(false)
#define DCHECK_NE(val1, val2) CHECK_NE(val1, val2) #define DCHECK_EQ(val1, val2) CHECK(false)
#define DCHECK_LE(val1, val2) CHECK_LE(val1, val2) #define DCHECK_NE(val1, val2) CHECK(false)
#define DCHECK_LT(val1, val2) CHECK_LT(val1, val2) #define DCHECK_LE(val1, val2) CHECK(false)
#define DCHECK_GE(val1, val2) CHECK_GE(val1, val2) #define DCHECK_LT(val1, val2) CHECK(false)
#define DCHECK_GT(val1, val2) CHECK_GT(val1, val2) #define DCHECK_GE(val1, val2) CHECK(false)
#endif #define DCHECK_GT(val1, val2) CHECK(false)
#endif
#ifdef ERROR
#undef ERROR // may conflict with ERROR macro on windows #include "base/port.h"
#endif #define INFO std::cout
enum LogSeverity {INFO = -1, WARNING = -2, ERROR = -3, FATAL = -4}; #define FATAL std::cerr
#define DFATAL std::cerr
#define S2LOG(x) x
#define VLOG(x) if (x>0) {} else S2LOG(INFO)
namespace google_base {
class DateLogger {
public:
DateLogger();
char* const HumanDate();
private:
char buffer_[9];
};
} // namespace google_base
class LogMessage {
public:
LogMessage(const char* file, int line) {
std::cerr << "[" << pretty_date_.HumanDate() << "] "
<< file << ":" << line << ": ";
}
~LogMessage() { std::cerr << "\n"; }
std::ostream& stream() { return std::cerr; }
// NOTE: we add a newline to the end of the output if it's not there alread private:
y google_base::DateLogger pretty_date_;
inline void LogPrintf(int severity, const char* pat, va_list ap) { DISALLOW_COPY_AND_ASSIGN(LogMessage);
// We write directly to the stderr file descriptor and avoid FILE };
// buffering because that may invoke malloc()
char buf[600]; class LogMessageFatal : public LogMessage {
perftools_vsnprintf(buf, sizeof(buf)-1, pat, ap); public:
if (buf[0] != '\0' && buf[strlen(buf)-1] != '\n') { LogMessageFatal(const char* file, int line)
assert(strlen(buf)+1 < sizeof(buf)); : LogMessage(file, line) { }
strcat(buf, "\n"); ~LogMessageFatal() {
std::cerr << "\n";
::abort();
} }
WRITE_TO_STDERR(buf, strlen(buf)); private:
if ((severity) == FATAL) DISALLOW_COPY_AND_ASSIGN(LogMessageFatal);
abort(); // LOG(FATAL) indicates a big problem, so don't run atexit() c };
alls
}
// Note that since the order of global constructors is unspecified,
// global code that calls RAW_LOG may execute before FLAGS_verbose is set.
// Such code will run with verbosity == 0 no matter what.
#define VLOG_IS_ON(severity) (FLAGS_verbose >= severity)
// In a better world, we'd use __VA_ARGS__, but VC++ 7 doesn't support it.
#define LOG_PRINTF(severity, pat) do { \
if (VLOG_IS_ON(severity)) { \
va_list ap; \
va_start(ap, pat); \
LogPrintf(severity, pat, ap); \
va_end(ap); \
} \
} while (0)
// RAW_LOG is the main function; some synonyms are used in unittests.
inline void RAW_LOG(int lvl, const char* pat, ...) { LOG_PRINTF(lvl, pat);
}
inline void RAW_VLOG(int lvl, const char* pat, ...) { LOG_PRINTF(lvl, pat);
}
inline void LOG(int lvl, const char* pat, ...) { LOG_PRINTF(lvl, pat);
}
inline void VLOG(int lvl, const char* pat, ...) { LOG_PRINTF(lvl, pat);
}
inline void LOG_IF(int lvl, bool cond, const char* pat, ...) {
if (cond) LOG_PRINTF(lvl, pat);
}
// This isn't technically logging, but it's also IO and also is an
// attempt to be "raw" -- that is, to not use any higher-level libc
// routines that might allocate memory or (ideally) try to allocate
// locks. We use an opaque file handle (not necessarily an int)
// to allow even more low-level stuff in the future.
// Like other "raw" routines, these functions are best effort, and
// thus don't return error codes (except RawOpenForWriting()).
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__)
#ifndef NOMINMAX
#define NOMINMAX // @#!$& windows
#endif
#include <windows.h>
typedef HANDLE RawFD;
const RawFD kIllegalRawFD = INVALID_HANDLE_VALUE;
#else
typedef int RawFD;
const RawFD kIllegalRawFD = -1; // what open returns if it fails
#endif // defined(_WIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__)
RawFD RawOpenForWriting(const char* filename); // uses default permission
s
void RawWrite(RawFD fd, const char* buf, size_t len);
void RawClose(RawFD fd);
#endif // _LOGGING_H_ #endif // BASE_LOGGING_H
 End of changes. 9 change blocks. 
264 lines changed or deleted 91 lines changed or added


 memconcept.h   memconcept.h 
#pragma once
/** /**
* Copyright (C) 2012 10gen Inc. * Copyright (C) 2012 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/>.
*/ */
/* The idea here is to 'name' memory pointers so that we can do diagnostics . /* The idea here is to 'name' memory pointers so that we can do diagnostics .
these diagnostics might involve concurrency or other things. mainly wou ld these diagnostics might involve concurrency or other things. mainly wou ld
be for _DEBUG builds. Experimental we'll see how useful. be for _DEBUG builds. Experimental we'll see how useful.
*/ */
#pragma once
#include "mongo/base/string_data.h"
namespace mongo { namespace mongo {
namespace memconcept { namespace memconcept {
/** these are like fancy enums - you can use them as "types" of thi ngs /** these are like fancy enums - you can use them as "types" of thi ngs
and see if foo.concept == bar.concept. and see if foo.concept == bar.concept.
copyable. copyable.
*/ */
class concept { class concept {
public: public:
concept() { *this = err; } concept() { *this = err; }
skipping to change at line 56 skipping to change at line 58
private: private:
const char * c; const char * c;
concept(const char *); concept(const char *);
}; };
/** file was unmapped or something */ /** file was unmapped or something */
void invalidate(void *p, unsigned len=0); void invalidate(void *p, unsigned len=0);
/** note you can be more than one thing; a datafile header is also the starting pointer /** note you can be more than one thing; a datafile header is also the starting pointer
for a file */ for a file */
void is(void *p, concept c, const std::string desc = "", unsigned l en=0); void is(void *p, concept c, const StringData& desc = StringData( "" , 0 ), unsigned len=0);
#if 1 #if 1
//#if !defined(_DEBUG) //#if !defined(_DEBUG)
inline void invalidate(void *p, unsigned len) { } inline void invalidate(void *p, unsigned len) { }
inline void is(void *p, concept c, const std::string, unsigned) { } inline void is(void *p, concept c, const StringData& desc, unsigned ) { }
#endif #endif
} }
} }
 End of changes. 4 change blocks. 
4 lines changed or deleted 6 lines changed or added


 message_port.h   message_port.h 
skipping to change at line 114 skipping to change at line 114
bool connect(SockAddr& farEnd) { bool connect(SockAddr& farEnd) {
return psock->connect( farEnd ); return psock->connect( farEnd );
} }
#ifdef MONGO_SSL #ifdef MONGO_SSL
/** secures inline */ /** secures inline */
void secure( SSLManager * ssl ) { void secure( SSLManager * ssl ) {
psock->secure( ssl ); psock->secure( ssl );
} }
#endif #endif
uint64_t getSockCreationMicroSec() const {
return psock->getSockCreationMicroSec();
}
private: private:
PiggyBackData * piggyBackData; PiggyBackData * piggyBackData;
// this is the parsed version of remote // this is the parsed version of remote
// mutable because its initialized only on call to remote() // mutable because its initialized only on call to remote()
mutable HostAndPort _remoteParsed; mutable HostAndPort _remoteParsed;
public: public:
static void closeAllSockets(unsigned tagMask = 0xffffffff); static void closeAllSockets(unsigned tagMask = 0xffffffff);
 End of changes. 1 change blocks. 
0 lines changed or deleted 4 lines changed or added


 mock_dbclient_connection.h   mock_dbclient_connection.h 
skipping to change at line 60 skipping to change at line 60
const mongo::AuthenticationTable* auth = NULL); 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;
// //
// 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 98 skipping to change at line 100
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; const MockRemoteDBServer::InstanceID _remoteServerInstanceID;
MockRemoteDBServer* _remoteServer; MockRemoteDBServer* _remoteServer;
bool _isFailed; bool _isFailed;
uint64_t _sockCreationTime;
}; };
} }
 End of changes. 2 change blocks. 
0 lines changed or deleted 3 lines changed or added


 mock_remote_db_server.h   mock_remote_db_server.h 
skipping to change at line 39 skipping to change at line 39
* 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
r that can be used
* to allow clients using the ConnectionString::connect interface t
o create connections
* to this server. The requirements to make this hook fully functio
nal are:
*
* 1. hostName of this server should start with $.
* 2. No other instance has the same hostName as this.
*
* To register the hook, simply call setConnectionHook:
*
* MockRemoteDBServer mockServer;
* ConnectionString::setConnectionHook(mockServer.getConnectionHook
());
*
* @param hostName the host name for this server.
*/
MockRemoteDBServer(const std::string& hostName); MockRemoteDBServer(const std::string& hostName);
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 146 skipping to change at line 166
*/ */
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 r> > CmdToReplyObj; typedef std::map<std::string, boost::shared_ptr<CircularBSONIterato r> > CmdToReplyObj;
bool _isRunning; bool _isRunning;
skipping to change at line 173 skipping to change at line 216
// //
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. 4 change blocks. 
0 lines changed or deleted 53 lines changed or added


 namespace_details.h   namespace_details.h 
skipping to change at line 90 skipping to change at line 90
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. TODO: should this be 64 bit?
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; 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 indexBuildInProgress; // 1 if in prog
skipping to change at line 141 skipping to change at line 141
} }
}; };
Extra* extra() { Extra* extra() {
if( extraOffset == 0 ) return 0; if( extraOffset == 0 ) return 0;
return (Extra *) (((char *) this) + extraOffset); return (Extra *) (((char *) this) + extraOffset);
} }
/* add extra space for indexes when more than 10 */ /* add extra space for indexes when more than 10 */
Extra* allocExtra(const char *ns, int nindexessofar); Extra* allocExtra(const char *ns, int nindexessofar);
void copyingFrom(const char *thisns, NamespaceDetails *src); // mus t be called when renaming a NS to fix up extra void copyingFrom(const char *thisns, NamespaceDetails *src); // mus t be called when renaming a NS to fix up extra
/* called when loaded from disk */
void onLoad(const Namespace& k);
/* dump info on this namespace. for debugging. */ /* dump info on this namespace. for debugging. */
void dump(const Namespace& k); void dump(const Namespace& k);
/* dump info on all extents for this namespace. for debugging. */ /* dump info on all extents for this namespace. for debugging. */
void dumpExtents(); void dumpExtents();
private: private:
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);
skipping to change at line 228 skipping to change at line 225
/* 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);
/* add a new index. does not add to system.indexes etc. - just to /**
NamespaceDetails. * This fetches the IndexDetails for the next empty index slot. The
caller must populate returned object. caller must populate
* returned object. This handles allocating extra index space, if
necessary.
*/
IndexDetails& getNextIndexDetails(const char* thisns);
/**
* Add a new index. This does not add it to system.indexes etc. -
just to NamespaceDetails.
* This resets the transient namespace details.
*/ */
IndexDetails& addIndex(const char *thisns, bool resetTransient=true ); void addIndex(const char* thisns);
void aboutToDeleteAnIndex() { void aboutToDeleteAnIndex() {
clearSystemFlag( Flag_HaveIdIndex ); clearSystemFlag( Flag_HaveIdIndex );
} }
/* returns index of the first index in which the field is present. -1 if not present. */ /* returns index of the first index in which the field is present. -1 if not present. */
int fieldIsIndexed(const char *fieldName); int fieldIsIndexed(const char *fieldName);
/** /**
* @return the actual size to create * @return the actual size to create
skipping to change at line 356 skipping to change at line 360
} }
/* return which "deleted bucket" for this size object */ /* return which "deleted bucket" for this size object */
static int bucket(int n) { static int bucket(int n) {
for ( int i = 0; i < Buckets; i++ ) for ( int i = 0; i < Buckets; i++ )
if ( bucketSizes[i] > n ) if ( bucketSizes[i] > n )
return i; return i;
return Buckets-1; return Buckets-1;
} }
/* @return the size for an allocated record quantized to 1/16th of
the BucketSize
@param allocSize requested size to allocate
*/
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 a new record. lenToAlloc includes headers. */
DiskLoc alloc(const char *ns, int lenToAlloc, DiskLoc& extentLoc); 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 474 skipping to change at line 483
* @param query - Query used to select indexes and populate matcher s; not copied if unowned * @param query - Query used to select indexes and populate matcher s; not copied if unowned
* (see bsonobj.h). * (see bsonobj.h).
* *
* @param order - Required ordering spec for documents produced by this cursor, empty object * @param order - Required ordering spec for documents produced by this cursor, empty object
* default indicates no order requirement. If no index exists that satisfies the required * default indicates no order requirement. If no index exists that satisfies the required
* sort order, an empty shared_ptr is returned unless parsedQuery i s also provided. This is * sort order, an empty shared_ptr is returned unless parsedQuery i s also provided. This is
* not copied if unowned. * not copied if unowned.
* *
* @param planPolicy - A policy for selecting query plans - see que ryoptimizercursor.h * @param planPolicy - A policy for selecting query plans - see que ryoptimizercursor.h
* *
* @param simpleEqualityMatch - Set to true for certain simple quer
ies - see
* queryoptimizer.cpp.
*
* @param parsedQuery - Additional query parameters, as from a clie nt query request. * @param parsedQuery - Additional query parameters, as from a clie nt query request.
* *
* @param requireOrder - If false, the resulting cursor may return results in an order * @param requireOrder - If false, the resulting cursor may return results in an order
* inconsistent with the @param order spec. See queryoptimizercurs or.h for information on * inconsistent with the @param order spec. See queryoptimizercurs or.h for information on
* handling these results properly. * handling these results properly.
* *
* @param singlePlanSummary - Query plan summary information that m ay be provided when a * @param singlePlanSummary - Query plan summary information that m ay be provided when a
* cursor running a single plan is returned. * cursor running a single plan is returned.
* *
* 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, const BSONObj static shared_ptr<Cursor> getCursor( const char* ns,
&query, const BSONObj& query,
const BSONObj &order = BSONObj( const BSONObj& order = BSONObj
), (),
const QueryPlanSelectionPolicy const QueryPlanSelectionPolicy
&planPolicy = & planPolicy =
QueryPlanSelectionPolicy::any() QueryPlanSelectionPolicy::
, any(),
bool *simpleEqualityMatch = 0, const shared_ptr<const ParsedQ
const shared_ptr<const ParsedQu uery>& parsedQuery =
ery> &parsedQuery = shared_ptr<const ParsedQue
shared_ptr<const ParsedQuery>() ry>(),
, bool requireOrder = true,
bool requireOrder = true, QueryPlanSummary* singlePlanSu
QueryPlanSummary *singlePlanSum mmary = NULL );
mary = 0 );
/** /**
* @return a single cursor that may work well for the given query. A $or style query will * @return a single cursor that may work well for the given query. A $or style query will
* produce a single cursor, not a MultiCursor. * produce a single cursor, not a MultiCursor.
* It is possible no cursor is returned if the sort is not supporte d by an index. Clients are responsible * It is possible no cursor is returned if the sort is not supporte d by an index. Clients are responsible
* for checking this if they are not sure an index for a sort exist s, and defaulting to a non-sort if * for checking this if they are not sure an index for a sort exist s, and defaulting to a non-sort if
* no suitable indices exist. * no suitable indices exist.
*/ */
static shared_ptr<Cursor> bestGuessCursor( const char *ns, const BS ONObj &query, const BSONObj &sort ); static shared_ptr<Cursor> bestGuessCursor( const char *ns, const BS ONObj &query, const BSONObj &sort );
 End of changes. 8 change blocks. 
29 lines changed or deleted 36 lines changed or added


 ntservice.h   ntservice.h 
// ntservice.h
/* Copyright 2009 10gen Inc. /* Copyright 2009 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.
*/ */
/**
* The ntservice namespace provides minimal support for running mongo serve
rs as NT services.
*
* TODO: ntservice should only provide implementation for a more general se
rver process
* startup/shutdown/management interface.
*/
#pragma once #pragma once
#if defined(_WIN32) #ifdef _WIN32
#include <windows.h>
#include "boost/program_options.hpp" #include <boost/program_options.hpp>
#include <string>
#include <vector>
#include "mongo/platform/compiler.h"
namespace mongo { namespace mongo {
struct ntServiceDefaultStrings { namespace ntservice {
struct NtServiceDefaultStrings {
const wchar_t* serviceName; const wchar_t* serviceName;
const wchar_t* displayName; const wchar_t* displayName;
const wchar_t* serviceDescription; const wchar_t* serviceDescription;
}; };
typedef bool ( *ServiceCallback )( void ); typedef void (*ServiceCallback)(void);
bool serviceParamsCheck(
boost::program_options::variables_map& params, /**
const std::string& dbpath, * Configure the service.
const ntServiceDefaultStrings& defaultStrings, *
const vector<string>& disallowedOptions, * Also performs service installation and removal.
int argc, *
char* argv[] * This function calls _exit() with an error if bad parameters are pass
); ed in. If
* the parameters specify that the service should be installed, removed
class ServiceController { , etc, performs that
public: * operation and exits.
ServiceController(); *
virtual ~ServiceController() {} * If this function returns to the caller, the caller should either cal
l startService, or run
static bool installService( * the service as a regular process, depending on the return value of s
const std::wstring& serviceName, houldStartService().
const std::wstring& displayName, */
const std::wstring& serviceDesc, void configureService(
const std::wstring& serviceUser, ServiceCallback serviceCallback,
const std::wstring& servicePassword, const boost::program_options::variables_map& params,
const std::string& dbpath, const NtServiceDefaultStrings& defaultStrings,
int argc, const std::vector<std::string>& disallowedOptions,
char* argv[] const std::vector<std::string>& argv);
);
static bool removeService( const std::wstring& serviceName ); bool shouldStartService();
static bool startService( const std::wstring& serviceName, ServiceC
allback startService ); /**
static bool reportStatus( DWORD reportState, DWORD waitHint = 0 ); * Start the service. Never returns.
*/
static void WINAPI initService( DWORD argc, LPTSTR *argv ); MONGO_COMPILER_NORETURN void startService();
static void WINAPI serviceCtrl( DWORD ctrlCode );
bool reportStatus(DWORD reportState, DWORD waitHint = 0);
protected:
static std::wstring _serviceName;
static SERVICE_STATUS_HANDLE _statusHandle;
static ServiceCallback _serviceCallback;
};
} // namespace mongo } // namespace ntservice
} // namespace mongo
#endif #endif // defined(_WIN32)
 End of changes. 7 change blocks. 
45 lines changed or deleted 53 lines changed or added


 oid.h   oid.h 
skipping to change at line 46 skipping to change at line 46
Typical contents of the BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp (seconds since epoch), Typical contents of the BSON ObjectID is a 12-byte value consisting of a 4-byte timestamp (seconds since epoch),
a 3-byte machine id, a 2-byte process id, and a 3-byte counter. Not e that the timestamp and counter fields must a 3-byte machine id, a 2-byte process id, and a 3-byte counter. Not e that the timestamp and counter fields must
be stored big endian unlike the rest of BSON. This is because they are compared byte-by-byte and we want to ensure be stored big endian unlike the rest of BSON. This is because they are compared byte-by-byte and we want to ensure
a mostly increasing order. a mostly increasing order.
*/ */
class OID { class OID {
public: public:
OID() : a(0), b(0) { } OID() : a(0), b(0) { }
enum {
kOIDSize = 12
};
/** init from a 24 char hex string */ /** init from a 24 char hex string */
explicit OID(const std::string &s) { init(s); } explicit OID(const std::string &s) { init(s); }
/** init from a reference to a 12-byte array */ /** init from a reference to a 12-byte array */
explicit OID(const unsigned char (&arr)[12]) { explicit OID(const unsigned char (&arr)[kOIDSize]) {
memcpy(data, arr, 12); memcpy(data, arr, sizeof(arr));
} }
/** initialize to 'null' */ /** initialize to 'null' */
void clear() { a = 0; b = 0; } void clear() { a = 0; b = 0; }
const unsigned char *getData() const { return data; } const unsigned char *getData() const { return data; }
bool operator==(const OID& r) const { return a==r.a && b==r.b; } bool operator==(const OID& r) const { return a==r.a && b==r.b; }
bool operator!=(const OID& r) const { return a!=r.a || b!=r.b; } bool operator!=(const OID& r) const { return a!=r.a || b!=r.b; }
int compare( const OID& other ) const { return memcmp( data , other .data , 12 ); } int compare( const OID& other ) const { return memcmp( data , other .data , kOIDSize ); }
bool operator<( const OID& other ) const { return compare( other ) < 0; } bool operator<( const OID& other ) const { return compare( other ) < 0; }
bool operator<=( const OID& other ) const { return compare( other ) <= 0; } bool operator<=( const OID& other ) const { return compare( other ) <= 0; }
/** @return the object ID output as 24 hex digits */ /** @return the object ID output as 24 hex digits */
std::string str() const { return toHexLower(data, 12); } std::string str() const { return toHexLower(data, kOIDSize); }
std::string toString() const { return str(); } std::string toString() const { return str(); }
static OID gen() { OID o; o.init(); return o; } static OID gen() { OID o; o.init(); return o; }
/** sets the contents to a new oid / randomized value */ /** sets the contents to a new oid / randomized value */
void init(); void init();
/** sets the contents to a new oid /** sets the contents to a new oid
* guaranteed to be sequential * guaranteed to be sequential
* NOT guaranteed to be globally unique * NOT guaranteed to be globally unique
skipping to change at line 130 skipping to change at line 134
unsigned b; unsigned b;
}; };
struct { struct {
// TODO: get rid of this eventually // TODO: get rid of this eventually
// this is a hack because of hash_combine with older versions of boost // this is a hack because of hash_combine with older versions of boost
// on 32-bit platforms // on 32-bit platforms
int x; int x;
int y; int y;
int z; int z;
}; };
unsigned char data[12]; unsigned char data[kOIDSize];
}; };
static unsigned ourPid(); static unsigned ourPid();
static void foldInPid(MachineAndPid& x); static void foldInPid(MachineAndPid& x);
static MachineAndPid genMachineAndPid(); static MachineAndPid genMachineAndPid();
}; };
#pragma pack() #pragma pack()
std::ostream& operator<<( std::ostream &s, const OID &o ); std::ostream& operator<<( std::ostream &s, const OID &o );
inline StringBuilder& operator<< (StringBuilder& s, const OID& o) { ret urn (s << o.str()); } inline StringBuilder& operator<< (StringBuilder& s, const OID& o) { ret urn (s << o.str()); }
 End of changes. 5 change blocks. 
5 lines changed or deleted 9 lines changed or added


 parallel.h   parallel.h 
skipping to change at line 27 skipping to change at line 27
/** /**
tools for working in parallel/sharded/clustered environment tools for working in parallel/sharded/clustered environment
*/ */
#pragma once #pragma once
#include "mongo/db/dbmessage.h" #include "mongo/db/dbmessage.h"
#include "mongo/db/matcher.h" #include "mongo/db/matcher.h"
#include "mongo/db/namespacestring.h" #include "mongo/db/namespacestring.h"
#include "mongo/s/shard.h"
#include "mongo/s/util.h" #include "mongo/s/util.h"
#include "mongo/util/concurrency/mvar.h" #include "mongo/util/concurrency/mvar.h"
namespace mongo { namespace mongo {
/** /**
* holder for a server address and a query to run * holder for a server address and a query to run
*/ */
class ServerAndQuery { class ServerAndQuery {
public: public:
skipping to change at line 252 skipping to change at line 253
bool isEmpty(){ bool isEmpty(){
return versionedNS.size() == 0; return versionedNS.size() == 0;
} }
string toString() const { string toString() const {
return str::stream() << "CInfo " << BSON( "v_ns" << versionedNS << "filter" << cmdFilter ); return str::stream() << "CInfo " << BSON( "v_ns" << versionedNS << "filter" << cmdFilter );
} }
}; };
class ShardConnection;
typedef shared_ptr<ShardConnection> ShardConnectionPtr; typedef shared_ptr<ShardConnection> ShardConnectionPtr;
class DBClientCursor; class DBClientCursor;
typedef shared_ptr<DBClientCursor> DBClientCursorPtr; typedef shared_ptr<DBClientCursor> DBClientCursorPtr;
class Shard;
typedef shared_ptr<Shard> ShardPtr;
class ChunkManager;
typedef shared_ptr<const ChunkManager> ChunkManagerPtr;
class ParallelConnectionState { class ParallelConnectionState {
public: public:
ParallelConnectionState() : ParallelConnectionState() :
count( 0 ), done( false ) { } count( 0 ), done( false ) { }
ShardConnectionPtr conn; ShardConnectionPtr conn;
DBClientCursorPtr cursor; DBClientCursorPtr cursor;
// Version information // Version information
 End of changes. 3 change blocks. 
7 lines changed or deleted 1 lines changed or added


 paths.h   paths.h 
skipping to change at line 112 skipping to change at line 112
#ifdef __linux__ // this isn't needed elsewhere #ifdef __linux__ // this isn't needed elsewhere
// if called without a fully qualified path it asserts; that makes mongoperf fail. so make a warning. need a better solution longer term. // if called without a fully qualified path it asserts; that makes mongoperf fail. so make a warning. need a better solution longer term.
// massert(13652, str::stream() << "Couldn't find parent dir for fi le: " << file.string(), ); // massert(13652, str::stream() << "Couldn't find parent dir for fi le: " << file.string(), );
if( !file.has_branch_path() ) { if( !file.has_branch_path() ) {
log() << "warning flushMYDirectory couldn't find parent dir for file: " << file.string() << endl; log() << "warning flushMYDirectory couldn't find parent dir for file: " << file.string() << endl;
return; return;
} }
boost::filesystem::path dir = file.branch_path(); // parent_path in new boosts boost::filesystem::path dir = file.branch_path(); // parent_path in new boosts
log(1) << "flushing directory " << dir.string() << endl; LOG(1) << "flushing directory " << dir.string() << endl;
int fd = ::open(dir.string().c_str(), O_RDONLY); // DO NOT THROW OR ASSERT BEFORE CLOSING int fd = ::open(dir.string().c_str(), O_RDONLY); // DO NOT THROW OR ASSERT BEFORE CLOSING
massert(13650, str::stream() << "Couldn't open directory '" << dir. string() << "' for flushing: " << errnoWithDescription(), fd >= 0); massert(13650, str::stream() << "Couldn't open directory '" << dir. string() << "' for flushing: " << errnoWithDescription(), fd >= 0);
if (fsync(fd) != 0){ if (fsync(fd) != 0){
int e = errno; int e = errno;
close(fd); close(fd);
massert(13651, str::stream() << "Couldn't fsync directory '" << dir.string() << "': " << errnoWithDescription(e), false); massert(13651, str::stream() << "Couldn't fsync directory '" << dir.string() << "': " << errnoWithDescription(e), false);
} }
close(fd); close(fd);
#endif #endif
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 pdfile.h   pdfile.h 
skipping to change at line 36 skipping to change at line 36
#pragma once #pragma once
#include "mongo/db/client.h" #include "mongo/db/client.h"
#include "mongo/db/diskloc.h" #include "mongo/db/diskloc.h"
#include "mongo/db/jsobjmanipulator.h" #include "mongo/db/jsobjmanipulator.h"
#include "mongo/db/memconcept.h" #include "mongo/db/memconcept.h"
#include "mongo/db/mongommf.h" #include "mongo/db/mongommf.h"
#include "mongo/db/namespace-inl.h" #include "mongo/db/namespace-inl.h"
#include "mongo/db/namespace_details-inl.h" #include "mongo/db/namespace_details-inl.h"
#include "mongo/db/namespacestring.h" #include "mongo/db/namespacestring.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 DataFileHeader; class DataFileHeader;
skipping to change at line 103 skipping to change at line 104
/** only use fore debugging */ /** only use fore debugging */
Extent* debug_getExtent(DiskLoc loc) { return _getExtent( loc ); } Extent* debug_getExtent(DiskLoc loc) { return _getExtent( loc ); }
private: private:
void badOfs(int) const; void badOfs(int) const;
void badOfs2(int) const; void badOfs2(int) const;
int defaultSize( const char *filename ) const; int defaultSize( const char *filename ) const;
Extent* getExtent(DiskLoc loc) const; Extent* getExtent(DiskLoc loc) const;
Extent* _getExtent(DiskLoc loc) const; Extent* _getExtent(DiskLoc loc) const;
Record* recordAt(DiskLoc dl); Record* recordAt(DiskLoc dl) const;
Record* makeRecord(DiskLoc dl, int size);
void grow(DiskLoc dl, int size); void grow(DiskLoc dl, int size);
char* p() const { return (char *) _mb; } char* p() const { return (char *) _mb; }
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;
}; };
skipping to change at line 135 skipping to change at line 135
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 wo /**
uld like to see the final object * insert() will add an _id to the object if not present. If you w
after such an addition, use this method. ould like to see the
@param o both and in and out param * final object after such an addition, use this method.
*/ * @param o both and in and out param
DiskLoc insertWithObjMod(const char *ns, BSONObj & /*out*/o, bool g * @param mayInterrupt When true, killop may interrupt the function
od = false); call.
*/
DiskLoc insertWithObjMod(const char* ns,
BSONObj& /*out*/o,
bool mayInterrupt = false,
bool god = false);
/** @param obj in value only for this version. */ /** @param obj in value only for this version. */
void insertNoReturnVal(const char *ns, BSONObj o, bool god = false) ; void insertNoReturnVal(const char *ns, BSONObj o, bool god = false) ;
DiskLoc insert(const char *ns, const void *buf, int len, bool god = /**
false, bool mayAddIndex = true, bool *addedID = 0); * Insert the contents of @param buf with length @param len into na
mespace @param ns.
* @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
* 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
* command.
* @param addedID if not null, set to true if adding _id element.
You must assure false
* before calling if using.
*/
DiskLoc insert(const char* ns,
const void* buf,
int32_t len,
bool mayInterrupt = false,
bool god = false,
bool mayAddIndex = true,
bool* addedID = 0);
static shared_ptr<Cursor> findAll(const char *ns, const DiskLoc &st artLoc = DiskLoc()); static shared_ptr<Cursor> findAll(const char *ns, const DiskLoc &st artLoc = 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* makeDeletedRecord(const DiskLoc& dl, int len) ; 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);
private: private:
vector<MongoDataFile *> files; vector<MongoDataFile *> files;
skipping to change at line 495 skipping to change at line 516
memconcept::is(e, memconcept::concept::extent); memconcept::is(e, memconcept::concept::extent);
return e; return e;
} }
} // namespace mongo } // namespace mongo
#include "cursor.h" #include "cursor.h"
namespace mongo { namespace mongo {
inline Record* MongoDataFile::recordAt(DiskLoc dl) { inline Record* MongoDataFile::recordAt(DiskLoc dl) const {
int ofs = dl.getOfs();
if( ofs < DataFileHeader::HeaderSize ) badOfs(ofs); // will uassert
- external call to keep out of the normal code path
return (Record*) (p()+ofs);
}
inline Record* MongoDataFile::makeRecord(DiskLoc dl, int size) {
int ofs = dl.getOfs(); int ofs = dl.getOfs();
if( ofs < DataFileHeader::HeaderSize ) badOfs(ofs); // will uassert if (ofs < DataFileHeader::HeaderSize) {
- external call to keep out of the normal code path badOfs(ofs); // will uassert - external call to keep out of the
return (Record*) (p()+ofs); normal code path
}
return reinterpret_cast<Record*>(p() + ofs);
} }
inline DiskLoc Record::getNext(const DiskLoc& myLoc) { inline DiskLoc Record::getNext(const DiskLoc& myLoc) {
_accessing(); _accessing();
if ( _nextOfs != DiskLoc::NullOfs ) { if ( _nextOfs != DiskLoc::NullOfs ) {
/* defensive */ /* defensive */
if ( _nextOfs >= 0 && _nextOfs < 10 ) { if ( _nextOfs >= 0 && _nextOfs < 10 ) {
logContext("Assertion failure - Record::getNext() referenci ng a deleted record?"); logContext("Assertion failure - Record::getNext() referenci ng a deleted record?");
return DiskLoc(); return DiskLoc();
} }
skipping to change at line 602 skipping to change at line 619
} }
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 );
return cc().database()->getFile(dl.a())->getExtent(dl); return cc().database()->getFile(dl.a())->getExtent(dl);
} }
inline Record* DataFileMgr::getRecord(const DiskLoc& dl) { inline Record* DataFileMgr::getRecord(const DiskLoc& dl) {
verify( dl.a() != -1 ); verify(dl.a() != -1);
Record* r = cc().database()->getFile(dl.a())->recordAt(dl); return cc().database()->getFile(dl.a())->recordAt(dl);
return r;
} }
BOOST_STATIC_ASSERT( 16 == sizeof(DeletedRecord) ); BOOST_STATIC_ASSERT( 16 == sizeof(DeletedRecord) );
inline DeletedRecord* DataFileMgr::makeDeletedRecord(const DiskLoc& dl, inline DeletedRecord* DataFileMgr::getDeletedRecord(const DiskLoc& dl)
int len) { {
verify( dl.a() != -1 ); return reinterpret_cast<DeletedRecord*>(getRecord(dl));
return (DeletedRecord*) cc().database()->getFile(dl.a())->makeRecor
d(dl, sizeof(DeletedRecord));
} }
void ensureHaveIdIndex(const char *ns);
inline BSONObj BSONObj::make(const Record* r ) { inline BSONObj BSONObj::make(const Record* r ) {
return BSONObj( r->data() ); return BSONObj( r->data() );
} }
DiskLoc allocateSpaceForANewRecord(const char* ns,
NamespaceDetails* d,
int32_t lenWHdr,
bool god);
void addRecordToRecListInExtent(Record* r, DiskLoc loc);
} // namespace mongo } // namespace mongo
 End of changes. 11 change blocks. 
33 lines changed or deleted 56 lines changed or added


 port.h   port.h 
/* Copyright (c) 2007, Google Inc. //
* All rights reserved. // Copyright (C) 1999 and onwards Google, Inc.
* //
* Redistribution and use in source and binary forms, with or without //
* modification, are permitted provided that the following conditions are // These are weird things we need to do to get this compiling on
* met: // random systems (and on SWIG).
*
* * Redistributions of source code must retain the above copyright #ifndef BASE_PORT_H_
* notice, this list of conditions and the following disclaimer. #define BASE_PORT_H_
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer #include "base/definer.h"
* in the documentation and/or other materials provided with the
* distribution. #include <limits.h> // So we can set the bounds of our types
* * Neither the name of Google Inc. nor the names of its #include <string.h> // for memcpy()
* contributors may be used to endorse or promote products derived from #include <stdlib.h> // for free()
* this software without specific prior written permission.
* #if defined(OS_MACOSX)
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS #include <unistd.h> // for getpagesize() on mac
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT #elif defined(OS_CYGWIN)
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR #include <malloc.h> // for memalign()
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ---
* Author: Craig Silverstein
*
* These are some portability typedefs and defines to make it a bit
* easier to compile this code under VC++.
*
* Several of these are taken from glib:
* http://developer.gnome.org/doc/API/glib/glib-windows-compatability-fu
nctions.html
*/
#ifndef GOOGLE_BASE_WINDOWS_H_
#define GOOGLE_BASE_WINDOWS_H_
/* You should never include this file directly, but always include it
from either config.h (MSVC) or mingw.h (MinGW/msys). */
#if !defined(GOOGLE_PERFTOOLS_WINDOWS_CONFIG_H_) && \
!defined(GOOGLE_PERFTOOLS_WINDOWS_MINGW_H_)
# error "port.h should only be included from config.h or mingw.h"
#endif #endif
#ifdef _WIN32 #include "integral_types.h"
#ifndef WIN32_LEAN_AND_MEAN // Must happens before inttypes.h inclusion */
#define WIN32_LEAN_AND_MEAN /* We always want minimal includes */ #if defined(OS_MACOSX)
/* From MacOSX's inttypes.h:
* "C++ implementations should define these macros only when
* __STDC_FORMAT_MACROS is defined before <inttypes.h> is included." */
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif /* __STDC_FORMAT_MACROS */
#endif /* OS_MACOSX */
/* Default for most OSes */
/* We use SIGPWR since that seems unlikely to be used for other reasons. */
#define GOOGLE_OBSCURE_SIGNAL SIGPWR
#if defined OS_LINUX || defined OS_CYGWIN
// _BIG_ENDIAN
#include <endian.h>
// The uint mess:
// mysql.h sets _GNU_SOURCE which sets __USE_MISC in <features.h>
// sys/types.h typedefs uint if __USE_MISC
// mysql typedefs uint if HAVE_UINT not set
// The following typedef is carefully considered, and should not cause
// any clashes
#if !defined(__USE_MISC)
#if !defined(HAVE_UINT)
#define HAVE_UINT 1
typedef unsigned int uint;
#endif
#if !defined(HAVE_USHORT)
#define HAVE_USHORT 1
typedef unsigned short ushort;
#endif
#if !defined(HAVE_ULONG)
#define HAVE_ULONG 1
typedef unsigned long ulong;
#endif
#endif #endif
#include <windows.h>
#include <io.h> /* because we so often use open/close/etc */
#include <direct.h> /* for _getcwd */
#include <process.h> /* for _getpid */
#include <limits.h> /* for PATH_MAX */
#include <stdarg.h> /* for va_list */
#include <stdio.h> /* need this to override stdio's (v)snprintf *
/
#include <sys/types.h> /* for _off_t */
#include <assert.h>
#include <stdlib.h> /* for rand, srand, _strtoxxx */
/* #if defined(__cplusplus)
* 4018: signed/unsigned mismatch is common (and ok for signed_i < unsigned #include <cstddef> // For _GLIBCXX macros
_i)
* 4244: otherwise we get problems when subtracting two size_t's to an int
* 4288: VC++7 gets confused when a var is defined in a loop and then after
it
* 4267: too many false positives for "conversion gives possible data loss"
* 4290: it's ok windows ignores the "throw" directive
* 4996: Yes, we're ok using "unsafe" functions like vsnprintf and getenv()
* 4146: internal_logging.cc intentionally negates an unsigned value
*/
#ifdef _MSC_VER
#pragma warning(disable:4018 4244 4288 4267 4290 4996 4146)
#endif
#ifndef __cplusplus
/* MSVC does not support C99 */
# if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
# ifdef _MSC_VER
# define inline __inline
# else
# define inline static
# endif
# endif
#endif #endif
#ifdef __cplusplus #if !defined(HAVE_TLS) && defined(_GLIBCXX_HAVE_TLS) && defined(ARCH_K8)
# define EXTERN_C extern "C" #define HAVE_TLS 1
#endif
#elif defined OS_FREEBSD
// _BIG_ENDIAN
#include <machine/endian.h>
#elif defined OS_SOLARIS
// _BIG_ENDIAN
#include <sys/isa_defs.h>
// Solaris doesn't define sig_t (function taking an int, returning void)
typedef void (*sig_t)(int);
// Solaris only defines strtoll, not strtoq
#define strtoq strtoll
#define strtouq strtoull
// It doesn't define the posix-standard(?) u_int_16
#include <sys/int_types.h>
typedef uint16_t u_int16_t;
#elif defined OS_MACOSX
// BIG_ENDIAN
#include <machine/endian.h>
/* Let's try and follow the Linux convention */
#define __BYTE_ORDER BYTE_ORDER
#define __LITTLE_ENDIAN LITTLE_ENDIAN
#define __BIG_ENDIAN BIG_ENDIAN
#endif
#if defined __sunos__ || defined __freebsd__
#ifdef _LITTLE_ENDIAN
#define IS_LITTLE_ENDIAN
#elif defined _BIG_ENDIAN
#define IS_BIG_ENDIAN
#endif
#endif
// The following guarenty declaration of the byte swap functions, and
// define __BYTE_ORDER for MSVC
#ifdef OS_WINDOWS
#include <stdlib.h>
#define __BYTE_ORDER __LITTLE_ENDIAN
#define bswap_16(x) _byteswap_ushort(x)
#define bswap_32(x) _byteswap_ulong(x)
#define bswap_64(x) _byteswap_uint64(x)
#elif defined(OS_MACOSX)
// Mac OS X / Darwin features
#include <libkern/OSByteOrder.h>
#define bswap_16(x) OSSwapInt16(x)
#define bswap_32(x) OSSwapInt32(x)
#define bswap_64(x) OSSwapInt64(x)
#elif defined __sunos__
#include <sys/byteorder.h>
#define bswap_16(x) BSWAP_16(x)
#define bswap_32(x) BSWAP_32(x)
#define bswap_64(x) BSWAP_64(x)
#elif defined __freebsd__
#include <sys/endian.h>
#define bswap_16(x) bswap16(x)
#define bswap_32(x) bswap32(x)
#define bswap_64(x) bswap64(x)
#else #else
# define EXTERN_C extern #include <byteswap.h>
#endif #endif
/* ----------------------------------- BASIC TYPES */ // define the macros IS_LITTLE_ENDIAN or IS_BIG_ENDIAN
// using the above endian defintions from endian.h if
// endian.h was included
#ifdef __BYTE_ORDER
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define IS_LITTLE_ENDIAN
#endif
#ifndef HAVE_STDINT_H #if __BYTE_ORDER == __BIG_ENDIAN
#ifndef HAVE___INT64 /* we need to have all the __intX names */ #define IS_BIG_ENDIAN
# error Do not know how to set up type aliases. Edit port.h for your syst
em.
#endif #endif
typedef __int8 int8_t; #else
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
#endif /* #ifndef HAVE_STDINT_H */
/* I guess MSVC's <types.h> doesn't include ssize_t by default? */ #if defined(__LITTLE_ENDIAN__)
#ifdef _MSC_VER #define IS_LITTLE_ENDIAN
typedef intptr_t ssize_t; #elif defined(__BIG_ENDIAN__)
#define IS_BIG_ENDIAN
#endif #endif
/* ----------------------------------- THREADS */ // there is also PDP endian ...
#ifndef HAVE_PTHREAD /* not true for MSVC, but may be true for MSYS */ #endif // __BYTE_ORDER
typedef DWORD pthread_t;
typedef DWORD pthread_key_t;
typedef LONG pthread_once_t;
enum { PTHREAD_ONCE_INIT = 0 }; /* important that this be 0! for SpinLock
*/
inline pthread_t pthread_self(void) { // Define the OS's path separator
return GetCurrentThreadId(); #ifdef __cplusplus // C won't merge duplicate const variables at link time
} // Some headers provide a macro for this (GCC's system.h), remove it so tha
t we
// can use our own.
#undef PATH_SEPARATOR
#ifdef OS_WINDOWS
const char PATH_SEPARATOR = '\\';
#else
const char PATH_SEPARATOR = '/';
#endif
#endif
#ifdef __cplusplus // Windows has O_BINARY as a flag to open() (like "b" for fopen).
inline bool pthread_equal(pthread_t left, pthread_t right) { // Linux doesn't need make this distinction.
return left == right; #if defined OS_LINUX && !defined O_BINARY
#define O_BINARY 0
#endif
// va_copy portability definitions
#ifdef COMPILER_MSVC
// MSVC doesn't have va_copy yet.
// This is believed to work for 32-bit msvc. This may not work at all for
// other platforms.
// If va_list uses the single-element-array trick, you will probably get
// a compiler error here.
//
#include <stdarg.h>
inline void va_copy(va_list& a, va_list& b) {
a = b;
} }
/* This replaces maybe_threads.{h,cc} */ // Nor does it have uid_t
EXTERN_C pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)); /* port. typedef int uid_t;
cc */
inline int perftools_pthread_key_create(pthread_key_t *pkey, #endif
void (*destructor)(void*)) {
pthread_key_t key = PthreadKeyCreate(destructor);
if (key != TLS_OUT_OF_INDEXES) {
*(pkey) = key;
return 0;
} else {
return GetLastError();
}
}
inline void* perftools_pthread_getspecific(DWORD key) { // Mac OS X / Darwin features
DWORD err = GetLastError();
void* rv = TlsGetValue(key);
if (err) SetLastError(err);
return rv;
}
inline int perftools_pthread_setspecific(pthread_key_t key, const void *val #if defined(OS_MACOSX)
ue) {
if (TlsSetValue(key, (LPVOID)value))
return 0;
else
return GetLastError();
}
EXTERN_C int perftools_pthread_once(pthread_once_t *once_control, // For mmap, Linux defines both MAP_ANONYMOUS and MAP_ANON and says MAP_ANO
void (*init_routine)(void)); N is
// deprecated. In Darwin, MAP_ANON is all there is.
#if !defined MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
#endif /* __cplusplus */ // Linux has this in <sys/cdefs.h>
#endif /* HAVE_PTHREAD */ #define __ptr_t void *
inline void sched_yield(void) { // Linux has this in <linux/errno.h>
Sleep(0); #define EXFULL ENOMEM // not really that great a translation...
}
// Mach-O supports sections (albeit with small names), but doesn't have
/* // vars at the beginning and end. Instead you should call the function
* __declspec(thread) isn't usable in a dll opened via LoadLibrary(). // getsectdata("__DATA", name, &size).
* But it doesn't work to LoadLibrary() us anyway, because of all the #define HAVE_ATTRIBUTE_SECTION 1
* things we need to do before main()! So this kind of TLS is safe for us.
*/ // Any function with ATTRIBUTE_SECTION must not be inlined, or it will
#define __thread __declspec(thread) // be placed into whatever section its caller is placed into.
#define ATTRIBUTE_SECTION(name) \
/* __attribute__ ((section ("__DATA, " #name))) __attribute__ ((noinline))
* This code is obsolete, but I keep it around in case we are ever in
* an environment where we can't or don't want to use google spinlocks #define ENUM_DYLD_BOOL // so that we don't pollute the global namespace
* (from base/spinlock.{h,cc}). In that case, uncommenting this out, extern "C" {
* and removing spinlock.cc from the build, should be enough to revert #include <mach-o/getsect.h>
* back to using native spinlocks. #include <mach-o/dyld.h>
*/ }
#if 0 class AssignAttributeStartEnd {
// Windows uses a spinlock internally for its mutexes, making our life easy
!
// However, the Windows spinlock must always be initialized, making life ha
rd,
// since we want LINKER_INITIALIZED. We work around this by having the
// linker initialize a bool to 0, and check that before accessing the mutex
.
// This replaces spinlock.{h,cc}, and all the stuff it depends on (atomicop
s)
#ifdef __cplusplus
class SpinLock {
public: public:
SpinLock() : initialize_token_(PTHREAD_ONCE_INIT) {} AssignAttributeStartEnd(const char* name, char** pstart, char** pend) {
// Used for global SpinLock vars (see base/spinlock.h for more details). // Find out what dynamic library name is defined in
enum StaticInitializer { LINKER_INITIALIZED }; for (int i = _dyld_image_count() - 1; i >= 0; --i) {
explicit SpinLock(StaticInitializer) : initialize_token_(PTHREAD_ONCE_INI const mach_header* hdr = _dyld_get_image_header(i);
T) { uint32_t len;
perftools_pthread_once(&initialize_token_, InitializeMutex); *pstart = getsectdatafromheader(hdr, "__DATA", name, &len);
if (*pstart) { // NULL if not defined in this dynamic library
*pstart += _dyld_get_image_vmaddr_slide(i); // correct for reloc
*pend = *pstart + len;
return;
}
}
// If we get here, not defined in a dll at all. See if defined statica
lly.
unsigned long len; // don't ask me why this type isn't uint32_t too.
..
*pstart = getsectdata("__DATA", name, &len);
*pend = *pstart + len;
} }
};
// It's important SpinLock not have a destructor: otherwise we run // 1) DEFINE_ATTRIBUTE_SECTION_VARS: must be called once per unique
// into problems when the main thread has exited, but other threads // name. You want to make sure this is executed before any
// are still running and try to access a main-thread spinlock. This // DECLARE_ATTRIBUTE_SECTION_VARS; the easiest way is to put them
// means we leak mutex_ (we should call DeleteCriticalSection() // in the same .cc file. Put this call at the global level.
// here). However, I've verified that all SpinLocks used in // 2) INIT_ATTRIBUTE_SECTION_VARS: you can scatter calls to this in
// perftools have program-long scope anyway, so the leak is // multiple places to help ensure execution before any
// perfectly fine. But be aware of this for the future! // DECLARE_ATTRIBUTE_SECTION_VARS. You must have at least one
// DEFINE, but you can have many INITs. Put each in its own scope.
void Lock() { // 3) DECLARE_ATTRIBUTE_SECTION_VARS: must be called before using
// You'd thionk this would be unnecessary, since we call // ATTRIBUTE_SECTION_START or ATTRIBUTE_SECTION_STOP on a name.
// InitializeMutex() in our constructor. But sometimes Lock() can // Put this call at the global level.
// be called before our constructor is! This can only happen in #define DECLARE_ATTRIBUTE_SECTION_VARS(name) \
// global constructors, when this is a global. If we live in extern char* __start_##name; \
// bar.cc, and some global constructor in foo.cc calls a routine extern char* __stop_##name;
// in bar.cc that calls this->Lock(), then Lock() may well run
// before our global constructor does. To protect against that, #define INIT_ATTRIBUTE_SECTION_VARS(name) \
// we do this check. For SpinLock objects created after main() DECLARE_ATTRIBUTE_SECTION_VARS(name); \
// has started, this pthread_once call will always be a noop. static const AssignAttributeStartEnd __assign_##name( \
perftools_pthread_once(&initialize_token_, InitializeMutex); #name, &__start_##name, &__stop_##name)
EnterCriticalSection(&mutex_);
} #define DEFINE_ATTRIBUTE_SECTION_VARS(name) \
void Unlock() { char* __start_##name, *__stop_##name; \
LeaveCriticalSection(&mutex_); INIT_ATTRIBUTE_SECTION_VARS(name)
}
// Darwin doesn't have strnlen. No comment.
inline size_t strnlen(const char *s, size_t maxlen) {
const char* end = (const char *)memchr(s, '\0', maxlen);
if (end)
return end - s;
return maxlen;
}
using namespace std; // just like VC++, we need a using here
// Doesn't exist on OSX; used in google.cc for send() to mean "no flags".
#define MSG_NOSIGNAL 0
// No SIGPWR on MacOSX. SIGINFO seems suitably obscure.
#undef GOOGLE_OBSCURE_SIGNAL
#define GOOGLE_OBSCURE_SIGNAL SIGINFO
// Used in assertion checks: assert(lock.IsHeld()) (see base/spinlock.h). #elif defined(OS_CYGWIN) // Cygwin-specific behavior.
inline bool IsHeld() const {
// This works, but probes undocumented internals, so I've commented it
out.
// c.f. http://msdn.microsoft.com/msdnmag/issues/03/12/CriticalSections
/
//return mutex_.LockCount>=0 && mutex_.OwningThread==GetCurrentThreadId
();
return true;
}
private:
void InitializeMutex() { InitializeCriticalSection(&mutex_); }
pthread_once_t initialize_token_; #if defined(__CYGWIN32__)
CRITICAL_SECTION mutex_; #define __WORDSIZE 32
}; #else
// It's probably possible to support 64-bit, but the #defines will need che
cked.
#error "Cygwin is currently only 32-bit."
#endif
class SpinLockHolder { // Acquires a spinlock for as long as the scope las // No signalling on Windows.
ts #undef GOOGLE_OBSCURE_SIGNAL
private: #define GOOGLE_OBSCURE_SIGNAL 0
SpinLock* lock_;
public: struct stack_t {
inline explicit SpinLockHolder(SpinLock* l) : lock_(l) { l->Lock(); } void* ss_sp;
inline ~SpinLockHolder() { lock_->Unlock(); } int ss_flags;
size_t ss_size;
}; };
#endif // #ifdef __cplusplus inline int sigaltstack(stack_t* ss, stack_t* oss) { return 0; }
#define PTHREAD_STACK_MIN 0 // Not provided by cygwin
// Scans memory for a character.
// memrchr is used in a few places, but it's linux-specific.
inline void* memrchr(const void* bytes, int find_char, size_t len) {
const unsigned char* cursor =
reinterpret_cast<const unsigned char*>(bytes) + len - 1;
unsigned char actual_char = find_char;
for (; cursor >= bytes; --cursor) {
if (*cursor == actual_char) {
return const_cast<void*>(reinterpret_cast<const void*>(cursor));
}
}
return NULL;
}
#endif
// Klocwork static analysis tool's C/C++ complier kwcc
#if defined(__KLOCWORK__)
#define STATIC_ANALYSIS
#endif // __KLOCWORK__
// GCC-specific features
#if (defined(COMPILER_GCC3) || defined(COMPILER_ICC) || defined(OS_MACOSX))
&& !defined(SWIG)
//
// Tell the compiler to do printf format string checking if the
// compiler supports it; see the 'format' attribute in
// <http://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Function-Attributes.html>.
//
// N.B.: As the GCC manual states, "[s]ince non-static C++ methods
// have an implicit 'this' argument, the arguments of such methods
// should be counted from two, not one."
//
#define PRINTF_ATTRIBUTE(string_index, first_to_check) \
__attribute__((__format__ (__printf__, string_index, first_to_check)))
#define SCANF_ATTRIBUTE(string_index, first_to_check) \
__attribute__((__format__ (__scanf__, string_index, first_to_check)))
//
// Prevent the compiler from padding a structure to natural alignment
//
#define PACKED __attribute__ ((packed))
// Cache line alignment
#if defined(__i386__) || defined(__x86_64__)
#define CACHELINE_SIZE 64
#define CACHELINE_ALIGNED __attribute__((aligned(CACHELINE_SIZE)))
#elif defined(__ARM_ARCH_5T__)
#define CACHELINE_SIZE 32
#define CACHELINE_ALIGNED
#else
#define CACHELINE_ALIGNED
#endif
//
// Prevent the compiler from complaining about or optimizing away variables
// that appear unused
// (careful, others e.g. third_party/libxml/xmlversion.h also define this)
#undef ATTRIBUTE_UNUSED
#define ATTRIBUTE_UNUSED __attribute__ ((unused))
//
// For functions we want to force inline or not inline.
// Introduced in gcc 3.1.
#define ATTRIBUTE_ALWAYS_INLINE __attribute__ ((always_inline))
#define HAVE_ATTRIBUTE_ALWAYS_INLINE 1
#define ATTRIBUTE_NOINLINE __attribute__ ((noinline))
#define HAVE_ATTRIBUTE_NOINLINE 1
// For weak functions
#undef ATTRIBUTE_WEAK
#define ATTRIBUTE_WEAK __attribute__ ((weak))
#define HAVE_ATTRIBUTE_WEAK 1
// Tell the compiler to use "initial-exec" mode for a thread-local variable
.
// See http://people.redhat.com/drepper/tls.pdf for the gory details.
#define ATTRIBUTE_INITIAL_EXEC __attribute__ ((tls_model ("initial-exec")))
//
// Tell the compiler that a given function never returns
//
#define ATTRIBUTE_NORETURN __attribute__((noreturn))
// For deprecated functions, variables, and types.
// gcc 3.1.1 and later provide this attribute.
// gcc 3.1.1 and later provide -Wdeprecated-declarations, on by default,
// and then -Werror converts such warning to an error
// gcc 4.2.1 and later provide -Wno-error=deprecated-declarations,
// so that use of a deprecated entity is a warning but not an error
//
// gcc 4.2.1 and gcc 4.2.2 ignore ATTRIBUTE_DEPRECATED on virtual functions
.
// this is fixed in gcc 4.3.1 (crosstool v12). -- mec, 2008-10-21
//
// 2010-05-19(mec): Failed.
// Too many people started deprecations and then stopped working on them.
// The deprecation messages just became build noise.
// The two-part deletion plan:
// change definition of ATTRIBUTE_DEPRECATED to an empty macro
// then global change: ATTRIBUTE_DEPRECATED -> /* deprecated */
// We may introduce a new facility like this in the future,
// probably with a different name. See message from iant to c-style:
#define ATTRIBUTE_DEPRECATED
#ifndef HAVE_ATTRIBUTE_SECTION // may have been pre-set to 0, e.g. for Dar
win
#define HAVE_ATTRIBUTE_SECTION 1
#endif
#if HAVE_ATTRIBUTE_SECTION // define section support for the case of GCC
//
// Tell the compiler/linker to put a given function into a section and defi
ne
// "__start_ ## name" and "__stop_ ## name" symbols to bracket the section.
// Sections can not span more than none compilation unit.
// This functionality is supported by GNU linker.
// Any function with ATTRIBUTE_SECTION must not be inlined, or it will
// be placed into whatever section its caller is placed into.
//
#ifndef ATTRIBUTE_SECTION
#define ATTRIBUTE_SECTION(name) \
__attribute__ ((section (#name))) __attribute__ ((noinline))
#endif
// This keeps us from using base/spinlock.h's implementation of SpinLock. //
#define BASE_SPINLOCK_H_ 1 // Weak section declaration to be used as a global declaration
// for ATTRIBUTE_SECTION_START|STOP(name) to compile and link
// even without functions with ATTRIBUTE_SECTION(name).
// DEFINE_ATTRIBUTE_SECTION should be in the exactly one file; it's
// a no-op on ELF but not on Mach-O.
//
#ifndef DECLARE_ATTRIBUTE_SECTION_VARS
#define DECLARE_ATTRIBUTE_SECTION_VARS(name) \
extern char __start_##name[] ATTRIBUTE_WEAK; \
extern char __stop_##name[] ATTRIBUTE_WEAK
#endif
#ifndef DEFINE_ATTRIBUTE_SECTION_VARS
#define INIT_ATTRIBUTE_SECTION_VARS(name)
#define DEFINE_ATTRIBUTE_SECTION_VARS(name)
#endif
#endif /* #if 0 */ //
// Return void* pointers to start/end of a section of code with
// functions having ATTRIBUTE_SECTION(name).
// Returns 0 if no such functions exits.
// One must DECLARE_ATTRIBUTE_SECTION_VARS(name) for this to compile and li
nk.
//
#define ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void*>(__start_##na
me))
#define ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void*>(__stop_##name
))
#endif // HAVE_ATTRIBUTE_SECTION
//
// The legacy prod71 libc does not provide the stack alignment required for
use
// of SSE intrinsics. In order to properly use the intrinsics you need to
use
// a trampoline function which aligns the stack prior to calling your code,
// or as of crosstool v10 with gcc 4.2.0 there is an attribute which asks
// gcc to do this for you.
//
// It has also been discovered that crosstool up to and including v10 does
not
// provide proper alignment for pthread_once() functions in x86-64 code eit
her.
// Unfortunately gcc does not provide force_align_arg_pointer as an option
in
// x86-64 code, so this requires us to always have a trampoline.
//
// For an example of using this see util/hash/adler32*
#if defined(__i386__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__
>= 2))
#define ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC __attribute__((force_align_arg_p
ointer))
#define REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
#elif defined(__i386__) || defined(__x86_64__)
#define REQUIRE_STACK_ALIGN_TRAMPOLINE (1)
#define ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
#else
#define REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
#define ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
#endif
/* ----------------------------------- MMAP and other memory allocation */ //
// Tell the compiler to warn about unused return values for functions decla
red
// with this macro. The macro should be used on function declarations
// following the argument list:
//
// Sprocket* AllocateSprocket() MUST_USE_RESULT;
//
#undef MUST_USE_RESULT
#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) \
&& !defined(COMPILER_ICC)
#define MUST_USE_RESULT __attribute__ ((warn_unused_result))
#else
#define MUST_USE_RESULT
#endif
#ifndef HAVE_MMAP /* not true for MSVC, but may be true for msys */ #if (defined(COMPILER_ICC) || defined(COMPILER_GCC3) || defined(__llvm__))
#define MAP_FAILED 0 // Defined behavior on some of the uarchs:
#define MREMAP_FIXED 2 /* the value in linux, though it doesn't really ma // PREFETCH_HINT_T0:
tter */ // prefetch to all levels of the hierarchy (except on p4: prefetch to L2)
/* These, when combined with the mmap invariants below, yield the proper ac // PREFETCH_HINT_NTA:
tion */ // p4: fetch to L2, but limit to 1 way (out of the 8 ways)
#define PROT_READ PAGE_READWRITE // core: skip L2, go directly to L1
#define PROT_WRITE PAGE_READWRITE // k8 rev E and later: skip L2, can go to either of the 2-ways in L1
#define MAP_ANONYMOUS MEM_RESERVE enum PrefetchHint {
#define MAP_PRIVATE MEM_COMMIT PREFETCH_HINT_T0 = 3, // More temporal locality
#define MAP_SHARED MEM_RESERVE /* value of this #define is 100% arbit PREFETCH_HINT_T1 = 2,
rary */ PREFETCH_HINT_T2 = 1, // Less temporal locality
PREFETCH_HINT_NTA = 0 // No temporal locality
#if __STDC__ && !defined(__MINGW32__) };
typedef _off_t off_t; #else
#endif // prefetch is a no-op for this target. Feel free to add more sections abov
e.
/* VirtualAlloc only replaces for mmap when certain invariants are kept. */ #endif
inline void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset) { extern inline void prefetch(const char *x, int hint) {
if (addr == NULL && fd == -1 && offset == 0 && #if defined(COMPILER_ICC) || defined(__llvm__)
prot == (PROT_READ|PROT_WRITE) && flags == (MAP_PRIVATE|MAP_ANONYMOUS // In the gcc version of prefetch(), hint is only a constant _after_ inli
)) { ning
return VirtualAlloc(0, length, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE // (assumed to have been successful). icc views things differently, and
); // checks constant-ness _before_ inlining. This leads to compilation err
ors
// with the gcc version in icc.
//
// One way round this is to use a switch statement to explicitly match
// prefetch hint enumerations, and invoke __builtin_prefetch for each val
id
// value. icc's optimization removes the switch and unused case statemen
ts
// after inlining, so that this boils down in the end to the same as for
gcc;
// that is, a single inlined prefetchX instruction. Demonstrate by compi
ling
// with icc options -xK -O2 and viewing assembly language output.
//
// Note that this version of prefetch() cannot verify constant-ness of hi
nt.
// If client code calls prefetch() with a variable value for hint, it wil
l
// receive the full expansion of the switch below, perhaps also not inlin
ed.
// This should however not be a problem in the general case of well behav
ed
// caller code that uses the supplied prefetch hint enumerations.
switch (hint) {
case PREFETCH_HINT_T0:
__builtin_prefetch(x, 0, PREFETCH_HINT_T0);
break;
case PREFETCH_HINT_T1:
__builtin_prefetch(x, 0, PREFETCH_HINT_T1);
break;
case PREFETCH_HINT_T2:
__builtin_prefetch(x, 0, PREFETCH_HINT_T2);
break;
case PREFETCH_HINT_NTA:
__builtin_prefetch(x, 0, PREFETCH_HINT_NTA);
break;
default:
__builtin_prefetch(x);
break;
}
#elif defined(COMPILER_GCC3)
#if !defined(ARCH_PIII) || defined(__SSE__)
if (__builtin_constant_p(hint)) {
__builtin_prefetch(x, 0, hint);
} else { } else {
return NULL; // Defaults to PREFETCH_HINT_T0
__builtin_prefetch(x);
} }
#else
// We want a __builtin_prefetch, but we build with the default -march=i38
6
// where __builtin_prefetch quietly turns into nothing.
// Once we crank up to -march=pentium3 or higher the __SSE__
// clause above will kick in with the builtin.
// -- mec 2006-06-06
if (hint == PREFETCH_HINT_NTA)
__asm__ __volatile__("prefetchnta (%0)" : : "r"(x));
#endif
#else
// You get no effect. Feel free to add more sections above.
#endif
} }
inline int munmap(void *addr, size_t length) { #ifdef __cplusplus
return VirtualFree(addr, 0, MEM_RELEASE) ? 0 : -1; // prefetch intrinsic (bring data to L1 without polluting L2 cache)
} extern inline void prefetch(const char *x) {
#endif /* HAVE_MMAP */ return prefetch(x, 0);
}
#endif // ifdef __cplusplus
//
// GCC can be told that a certain branch is not likely to be taken (for
// instance, a CHECK failure), and use that information in static analysis.
// Giving it this information can help it optimize for the common case in
// the absence of better information (ie. -fprofile-arcs).
//
#if defined(COMPILER_GCC3)
#define PREDICT_FALSE(x) (__builtin_expect(x, 0))
#define PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
#else
#define PREDICT_FALSE(x) x
#define PREDICT_TRUE(x) x
#endif
/* We could maybe use VirtualAlloc for sbrk as well, but no need */ #define FTELLO ftello
inline void *sbrk(intptr_t increment) { #define FSEEKO fseeko
// sbrk returns -1 on failure
return (void*)-1;
}
/* ----------------------------------- STRING ROUTINES */ #if !defined(__cplusplus) && !defined(OS_MACOSX) && !defined(OS_CYGWIN)
// stdlib.h only declares this in C++, not in C, so we declare it here.
// Also make sure to avoid declaring it on platforms which don't support it
.
extern int posix_memalign(void **memptr, size_t alignment, size_t size);
#endif
/* inline void *aligned_malloc(size_t size, int minimum_alignment) {
* We can't just use _vsnprintf and _snprintf as drop-in-replacements, #if defined(OS_MACOSX)
* because they don't always NUL-terminate. :-( We also can't use the // mac lacks memalign(), posix_memalign(), however, according to
* name vsnprintf, since windows defines that (but not snprintf (!)). // http://stackoverflow.com/questions/196329/osx-lacks-memalign
*/ // mac allocs are already 16-byte aligned.
#if defined(_MSC_VER) && _MSC_VER >= 1400 if (minimum_alignment <= 16)
/* We can use safe CRT functions, which the required functionality */ return malloc(size);
inline int perftools_vsnprintf(char *str, size_t size, const char *format, // next, try to return page-aligned memory. perhaps overkill
va_list ap) { if (minimum_alignment <= getpagesize())
return vsnprintf_s(str, size, _TRUNCATE, format, ap); return valloc(size);
// give up
return NULL;
#elif defined(OS_CYGWIN)
return memalign(minimum_alignment, size);
#else // !OS_MACOSX && !OS_CYGWIN
void *ptr = NULL;
if (posix_memalign(&ptr, minimum_alignment, size) != 0)
return NULL;
else
return ptr;
#endif
} }
#else
inline int perftools_vsnprintf(char *str, size_t size, const char *format, inline void aligned_free(void *aligned_memory) {
va_list ap) { free(aligned_memory);
if (size == 0) /* not even room for a \0? */
return -1; /* not what C99 says to do, but what windows does */
str[size-1] = '\0';
return _vsnprintf(str, size-1, format, ap);
} }
#else // not GCC
#define PRINTF_ATTRIBUTE(string_index, first_to_check)
#define SCANF_ATTRIBUTE(string_index, first_to_check)
#define PACKED
#define CACHELINE_ALIGNED
#define ATTRIBUTE_UNUSED
#define ATTRIBUTE_ALWAYS_INLINE
#define ATTRIBUTE_NOINLINE
#define ATTRIBUTE_WEAK
#define HAVE_ATTRIBUTE_WEAK 0
#define ATTRIBUTE_INITIAL_EXEC
#define ATTRIBUTE_NORETURN
#define ATTRIBUTE_DEPRECATED
#define HAVE_ATTRIBUTE_SECTION 0
#define ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
#define REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
#define MUST_USE_RESULT
extern inline void prefetch(const char *x) {}
#define PREDICT_FALSE(x) x
#define PREDICT_TRUE(x) x
// These should be redefined appropriately if better alternatives to
// ftell/fseek exist in the compiler
#define FTELLO ftell
#define FSEEKO fseek
#endif // GCC
#if !HAVE_ATTRIBUTE_SECTION // provide dummy definitions
#define ATTRIBUTE_SECTION(name)
#define INIT_ATTRIBUTE_SECTION_VARS(name)
#define DEFINE_ATTRIBUTE_SECTION_VARS(name)
#define DECLARE_ATTRIBUTE_SECTION_VARS(name)
#define ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void*>(0))
#define ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void*>(0))
#endif // !HAVE_ATTRIBUTE_SECTION
#if defined __sunos__
#define drem remainder
#endif #endif
#ifndef HAVE_SNPRINTF // HK's fun windows fixer-upper defines go here! Woo.
inline int snprintf(char *str, size_t size, const char *format, ...) { #ifdef _WIN32
va_list ap; inline double drem(double x, double y) {
int r; double quot = x/y;
va_start(ap, format); if (quot > 0) {
r = perftools_vsnprintf(str, size, format, ap); quot = quot + 0.5;
va_end(ap); } else {
return r; quot = quot - 0.5;
}
int iquot = quot;
return x - iquot * y;
}
#define strtoll _strtoi64
#define strtoull _strtoui64
#define safe_vsnprintf _vsnprintf
#define snprintf _snprintf
inline void va_copy(va_list& a, va_list& b) {
a = b;
}
using namespace std;
#define isnan _isnan
#define snprintf _snprintf
#include "float.h"
inline double sqrt(int x) { return sqrt((double)x); }
inline int isinf(double x) {
const int float_point_class =_fpclass(x);
if (float_point_class == _FPCLASS_PINF) return 1;
if (float_point_class == _FPCLASS_NINF) return -1;
return 0;
} }
#endif #endif
#define PRIx64 "I64x" #ifdef COMPILER_MSVC /* if Visual C++ */
#define SCNx64 "I64x"
#define PRId64 "I64d" // This compiler flag can be easily overlooked on MSVC.
#define SCNd64 "I64d" // _CHAR_UNSIGNED gets set with the /J flag.
#define PRIu64 "I64u" #ifndef _CHAR_UNSIGNED
#ifdef _WIN64 #error chars must be unsigned! Use the /J flag on the compiler command lin
# define PRIuPTR "llu" e.
# define PRIxPTR "llx"
#else
# define PRIuPTR "lu"
# define PRIxPTR "lx"
#endif #endif
/* ----------------------------------- FILE IO */ // MSVC is a little hyper-active in it's warnings
// Signed vs. unsigned comparison is ok.
#pragma warning(disable : 4018 )
// We know casting from a long to a char may lose data
#pragma warning(disable : 4244 )
// Don't need performance warnings about converting ints to bools
#pragma warning(disable : 4800 )
// Integral constant overflow is apparently ok too
// for example:
// short k; int n;
// k = k + n;
#pragma warning(disable : 4307 )
// It's ok to use this* in constructor
// Example:
// class C {
// Container cont_;
// C() : cont_(this) { ...
#pragma warning(disable : 4355 )
// Truncating from double to float is ok
#pragma warning(disable : 4305 )
#ifndef PATH_MAX #include <winsock2.h>
#define PATH_MAX 1024 #include <assert.h>
#endif #include <windows.h>
#ifndef __MINGW32__ #undef ERROR
enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 };
#include <float.h> // for nextafter functionality on windows
#include <math.h> // for HUGE_VAL
#ifndef HUGE_VALF
#define HUGE_VALF (static_cast<float>(HUGE_VAL))
#endif #endif
#ifndef O_RDONLY
#define O_RDONLY _O_RDONLY using namespace std;
// VC++ doesn't understand "uint"
#ifndef HAVE_UINT
#define HAVE_UINT 1
typedef unsigned int uint;
#endif #endif
#if __STDC__ && !defined(__MINGW32__) #define strtoq _strtoi64
/* These functions are considered non-standard */ #define strtouq _strtoui64
inline int access(const char *pathname, int mode) { #define strtoll _strtoi64
return _access(pathname, mode); #define strtoull _strtoui64
} #define atoll _atoi64
inline int open(const char *pathname, int flags, int mode = 0) {
return _open(pathname, flags, mode); // VC++ 6 and before ship without an ostream << operator for 64-bit ints
} #if (_MSC_VER <= 1200)
inline int close(int fd) { #include <iosfwd>
return _close(fd); using std::ostream;
}
inline ssize_t read(int fd, void *buf, size_t count) { inline ostream& operator<< (ostream& os, const unsigned __int64& num ) {
return _read(fd, buf, count); // Fake operator; doesn't actually do anything.
LOG(FATAL) << "64-bit ostream operator << not supported in VC++ 6";
return os;
} }
inline ssize_t write(int fd, const void *buf, size_t count) { #endif
return _write(fd, buf, count);
} // You say tomato, I say atotom
inline off_t lseek(int fd, off_t offset, int whence) { #define PATH_MAX MAX_PATH
return _lseek(fd, offset, whence);
} // You say tomato, I say _tomato
inline char *getcwd(char *buf, size_t size) { #define vsnprintf _vsnprintf
return _getcwd(buf, size); #define snprintf _snprintf
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#define nextafter _nextafter
#define hypot _hypot
#define hypotf _hypotf
#define strdup _strdup
#define tempnam _tempnam
#define chdir _chdir
#define getcwd _getcwd
#define putenv _putenv
// You say tomato, I say toma
#define random() rand()
#define srandom(x) srand(x)
// You say juxtapose, I say transpose
#define bcopy(s, d, n) memcpy(d, s, n)
inline void *aligned_malloc(size_t size, int minimum_alignment) {
return _aligned_malloc(size, minimum_alignment);
} }
inline int mkdir(const char *pathname, int) {
return _mkdir(pathname); inline void aligned_free(void *aligned_memory) {
_aligned_free(aligned_memory);
} }
inline FILE *popen(const char *command, const char *type) { // ----- BEGIN VC++ STUBS & FAKE DEFINITIONS ------------------------------
return _popen(command, type); ---
// See http://en.wikipedia.org/wiki/IEEE_754 for details of
// floating point format.
enum {
FP_NAN, // is "Not a Number"
FP_INFINITE, // is either plus or minus infinity.
FP_ZERO,
FP_SUBNORMAL, // is too small to be represented in normalized format.
FP_NORMAL // if nothing of the above is correct that it must be a
// normal floating-point number.
};
inline int fpclassify_double(double x) {
const int float_point_class =_fpclass(x);
int c99_class;
switch (float_point_class) {
case _FPCLASS_SNAN: // Signaling NaN
case _FPCLASS_QNAN: // Quiet NaN
c99_class = FP_NAN;
break;
case _FPCLASS_NZ: // Negative zero ( -0)
case _FPCLASS_PZ: // Positive 0 (+0)
c99_class = FP_ZERO;
break;
case _FPCLASS_NINF: // Negative infinity ( -INF)
case _FPCLASS_PINF: // Positive infinity (+INF)
c99_class = FP_INFINITE;
break;
case _FPCLASS_ND: // Negative denormalized
case _FPCLASS_PD: // Positive denormalized
c99_class = FP_SUBNORMAL;
break;
case _FPCLASS_NN: // Negative normalized non-zero
case _FPCLASS_PN: // Positive normalized non-zero
c99_class = FP_NORMAL;
break;
default:
c99_class = FP_NAN; // Should never happen
break;
}
return c99_class;
} }
inline int pclose(FILE *stream) {
return _pclose(stream); // This function handle the special subnormal case for float; it will
// become a normal number while casting to double.
// bit_cast is avoided to simplify dependency and to create a code that is
// easy to deploy in C code
inline int fpclassify_float(float x) {
uint32 bitwise_representation;
memcpy(&bitwise_representation, &x, 4);
if ((bitwise_representation & 0x7f800000) == 0 &&
(bitwise_representation & 0x007fffff) != 0)
return FP_SUBNORMAL;
return fpclassify_double(x);
}
//
// This define takes care of the denormalized float; the casting to
// double make it a normal number
#define fpclassify(x) ((sizeof(x) == sizeof(float)) ? fpclassify_float(x) :
fpclassify_double(x))
#define isnan _isnan
inline int isinf(double x) {
const int float_point_class =_fpclass(x);
if (float_point_class == _FPCLASS_PINF) return 1;
if (float_point_class == _FPCLASS_NINF) return -1;
return 0;
} }
#endif
EXTERN_C PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len); // #include "conflict-signal.h"
typedef void (*sig_t)(int);
/* ----------------------------------- SYSTEM/PROCESS */ // These actually belong in errno.h but there's a name confilict in errno
// on WinNT. They (and a ton more) are also found in Winsock2.h, but
// if'd out under NT. We need this subset at minimum.
#define EXFULL ENOMEM // not really that great a translation...
//#define EWOULDBLOCK WSAEWOULDBLOCK
//#ifndef PTHREADS_REDHAT_WIN32
//#define ETIMEDOUT WSAETIMEDOUT
//#endif
//#define ENOTSOCK WSAENOTSOCK
//#define EINPROGRESS WSAEINPROGRESS
//#define ECONNRESET WSAECONNRESET
#include <utility>
using std::pair;
using std::make_pair;
#include <vector>
using std::vector;
typedef vector<pair<const char*, const char*> > KeyValVec;
//
// Really from <string.h>
//
inline void bzero(void *s, int n) {
memset(s, 0, n);
}
// From glob.h
#define __ptr_t void *
// Defined all over the place.
typedef int pid_t; typedef int pid_t;
#if __STDC__ && !defined(__MINGW32__)
inline pid_t getpid(void) { return _getpid(); } // From stat.h
typedef unsigned int mode_t;
// u_int16_t, int16_t don't exist in MSVC
typedef unsigned short u_int16_t;
typedef short int16_t;
// ----- END VC++ STUBS & FAKE DEFINITIONS --------------------------------
--
#endif // COMPILER_MSVC
#ifdef STL_MSVC // not always the same as COMPILER_MSVC
#include "base/port_hash.h"
#else
struct PortableHashBase { };
#endif #endif
inline pid_t getppid(void) { return 0; }
/* Handle case when poll is used to simulate sleep. */ // The SWIGged version of an abstract class must be concrete if any methods
inline int poll(struct pollfd* fds, int nfds, int timeout) { // return objects of the abstract type.
assert(fds == NULL); //
assert(nfds == 0); // This location is deprecated, the new preferred location is in base/macro
Sleep(timeout); s.h.
return 0; #ifndef SWIG
} #define ABSTRACT = 0
#endif
EXTERN_C int getpagesize(); /* in port.cc */ #if defined(OS_WINDOWS) || defined(OS_MACOSX)
// gethostbyname() *is* thread-safe for Windows native threads. It is also
// safe on Mac OS X, where it uses thread-local storage, even though the
// manpages claim otherwise. For details, see
// http://lists.apple.com/archives/Darwin-dev/2006/May/msg00008.html
#else
// gethostbyname() is not thread-safe. So disallow its use. People
// should either use the HostLookup::Lookup*() methods, or gethostbyname_r(
)
#define gethostbyname gethostbyname_is_not_thread_safe_DO_NOT_USE
#endif
/* ----------------------------------- OTHER */ // create macros in which the programmer should enclose all specializations
// for hash_maps and hash_sets. This is necessary since these classes are n
ot
// STL standardized. Depending on the STL implementation they are in differ
ent
// namespaces. Right now the right namespace is passed by the Makefile
// Examples: gcc3: -DHASH_NAMESPACE=__gnu_cxx
// icc: -DHASH_NAMESPACE=std
// gcc2: empty
#ifndef HASH_NAMESPACE
# define HASH_NAMESPACE_DECLARATION_START
# define HASH_NAMESPACE_DECLARATION_END
#else
# define HASH_NAMESPACE_DECLARATION_START namespace HASH_NAMESPACE {
# define HASH_NAMESPACE_DECLARATION_END }
#endif
inline void srandom(unsigned int seed) { srand(seed); } // Our STL-like classes use __STD.
inline long random(void) { return rand(); } #if defined(COMPILER_GCC3) || defined(COMPILER_ICC) || defined(OS_MACOSX) |
inline unsigned int sleep(unsigned int seconds) { | defined(COMPILER_MSVC)
Sleep(seconds * 1000); #define __STD std
return 0; #endif
}
// mingw64 seems to define timespec (though mingw.org mingw doesn't), #if defined COMPILER_GCC3 || defined COMPILER_ICC
// protected by the _TIMESPEC_DEFINED macro. #define STREAM_SET(s, bit) (s).setstate(ios_base::bit)
#ifndef _TIMESPEC_DEFINED #define STREAM_SETF(s, flag) (s).setf(ios_base::flag)
struct timespec { #else
int tv_sec; #define STREAM_SET(s, bit) (s).set(ios::bit)
int tv_nsec; #define STREAM_SETF(s, flag) (s).setf(ios::flag)
};
#endif #endif
inline int nanosleep(const struct timespec *req, struct timespec *rem) { // Portable handling of unaligned loads and stores
Sleep(req->tv_sec * 1000 + req->tv_nsec / 1000000);
return 0; #if defined(ARCH_PIII) || defined(ARCH_ATHLON) || defined(ARCH_K8) || defin
} ed(_ARCH_PPC)
#ifndef __MINGW32__ // x86 and x86-64 can perform unaligned loads/stores directly;
inline long long int strtoll(const char *nptr, char **endptr, int base) { // modern PowerPC hardware can also do unaligned integer loads and stores;
return _strtoi64(nptr, endptr, base); // but note: the FPU still sends unaligned loads and stores to a trap handl
er!
#define UNALIGNED_LOAD16(_p) (*reinterpret_cast<const uint16 *>(_p))
#define UNALIGNED_LOAD32(_p) (*reinterpret_cast<const uint32 *>(_p))
#define UNALIGNED_LOAD64(_p) (*reinterpret_cast<const uint64 *>(_p))
#define UNALIGNED_STORE16(_p, _val) (*reinterpret_cast<uint16 *>(_p) = (_va
l))
#define UNALIGNED_STORE32(_p, _val) (*reinterpret_cast<uint32 *>(_p) = (_va
l))
#define UNALIGNED_STORE64(_p, _val) (*reinterpret_cast<uint64 *>(_p) = (_va
l))
#else
#define NEED_ALIGNED_LOADS
// These functions are provided for architectures that don't support
// unaligned loads and stores.
inline uint16 UNALIGNED_LOAD16(const void *p) {
uint16 t;
memcpy(&t, p, sizeof t);
return t;
} }
inline unsigned long long int strtoull(const char *nptr, char **endptr,
int base) { inline uint32 UNALIGNED_LOAD32(const void *p) {
return _strtoui64(nptr, endptr, base); uint32 t;
memcpy(&t, p, sizeof t);
return t;
} }
inline long long int strtoq(const char *nptr, char **endptr, int base) {
return _strtoi64(nptr, endptr, base); inline uint64 UNALIGNED_LOAD64(const void *p) {
uint64 t;
memcpy(&t, p, sizeof t);
return t;
} }
inline unsigned long long int strtouq(const char *nptr, char **endptr,
int base) { inline void UNALIGNED_STORE16(void *p, uint16 v) {
return _strtoui64(nptr, endptr, base); memcpy(p, &v, sizeof v);
} }
inline long long atoll(const char *nptr) {
return _atoi64(nptr); inline void UNALIGNED_STORE32(void *p, uint32 v) {
memcpy(p, &v, sizeof v);
} }
#endif
#define __THROW throw() inline void UNALIGNED_STORE64(void *p, uint64 v) {
memcpy(p, &v, sizeof v);
}
/* ----------------------------------- TCMALLOC-SPECIFIC */ #endif
/* tcmalloc.cc calls this so we can patch VirtualAlloc() et al. */ #ifdef _LP64
extern void PatchWindowsFunctions(); #define UNALIGNED_LOADW(_p) UNALIGNED_LOAD64(_p)
#define UNALIGNED_STOREW(_p, _val) UNALIGNED_STORE64(_p, _val)
#else
#define UNALIGNED_LOADW(_p) UNALIGNED_LOAD32(_p)
#define UNALIGNED_STOREW(_p, _val) UNALIGNED_STORE32(_p, _val)
#endif
// ----------------------------------- BUILD-SPECIFIC // printf macros for size_t, in the style of inttypes.h
#ifdef _LP64
#define __PRIS_PREFIX "z"
#else
#define __PRIS_PREFIX
#endif
/* // Use these macros after a % in a printf format string
* windows/port.h defines compatibility APIs for several .h files, which // to get correct 32/64 bit behavior, like this:
* we therefore shouldn't be #including directly. This hack keeps us from // size_t size = records.size();
* doing so. TODO(csilvers): do something more principled. // printf("%"PRIuS"\n", size);
*/
#define GOOGLE_MAYBE_THREADS_H_ 1 #define PRIdS __PRIS_PREFIX "d"
#define PRIxS __PRIS_PREFIX "x"
#define PRIuS __PRIS_PREFIX "u"
#define PRIXS __PRIS_PREFIX "X"
#define PRIoS __PRIS_PREFIX "o"
#define GPRIuPTHREAD "lu"
#define GPRIxPTHREAD "lx"
#ifdef OS_CYGWIN
#define PRINTABLE_PTHREAD(pthreadt) reinterpret_cast<uintptr_t>(pthreadt)
#else
#define PRINTABLE_PTHREAD(pthreadt) pthreadt
#endif
#endif /* _WIN32 */ #define SIZEOF_MEMBER(t, f) sizeof(((t*) 4096)->f)
#undef inline #define OFFSETOF_MEMBER(t, f) \
#undef EXTERN_C (reinterpret_cast<char*>( \
&reinterpret_cast<t*>(16)->f) - \
reinterpret_cast<char*>(16))
#ifdef PTHREADS_REDHAT_WIN32
#include <iosfwd>
using std::ostream;
#include <pthread.h>
// pthread_t is not a simple integer or pointer on Win32
std::ostream& operator << (std::ostream& out, const pthread_t& thread_id);
#endif
#endif /* GOOGLE_BASE_WINDOWS_H_ */ #endif // BASE_PORT_H_
 End of changes. 77 change blocks. 
403 lines changed or deleted 1055 lines changed or added


 principal_set.h   principal_set.h 
skipping to change at line 48 skipping to change at line 48
// 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); Status removeByName(const std::string& name);
// Returns NULL if not found // Returns 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.
const Principal* lookup(const std::string& name) const; Principal* lookup(const std::string& name) const;
private: private:
// Key is principal name. // 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; unordered_map<std::string, Principal*> _principals;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 processinfo.h   processinfo.h 
skipping to change at line 80 skipping to change at line 80
* Get the total amount of system memory in MB * Get the total amount of system memory in MB
*/ */
const unsigned long long getMemSizeMB() const { return sysInfo().me mSize / (1024 * 1024); } const unsigned long long getMemSizeMB() const { return sysInfo().me mSize / (1024 * 1024); }
/** /**
* Get the number of CPUs * Get the number of CPUs
*/ */
const unsigned getNumCores() const { return sysInfo().numCores; } const unsigned getNumCores() const { return sysInfo().numCores; }
/** /**
* Get the system page size in bytes.
*/
static unsigned long long getPageSize() { return systemInfo->pageSi
ze; }
/**
* Get the CPU architecture (e.g. x86, x86_64) * Get the CPU architecture (e.g. x86, x86_64)
*/ */
const string& getArch() const { return sysInfo().cpuArch; } const string& getArch() const { return sysInfo().cpuArch; }
/** /**
* Determine if NUMA is enabled (interleaved) for this process * Determine if NUMA is enabled (interleaved) for this process
*/ */
bool hasNumaEnabled() const { return sysInfo().hasNuma; } bool hasNumaEnabled() const { return sysInfo().hasNuma; }
/** /**
skipping to change at line 105 skipping to change at line 110
/** /**
* Append platform-specific data to obj * Append platform-specific data to obj
*/ */
void getExtraInfo( BSONObjBuilder& info ); void getExtraInfo( BSONObjBuilder& info );
bool supported(); bool supported();
static bool blockCheckSupported(); static bool blockCheckSupported();
static bool blockInMemory( char * start ); static bool blockInMemory(const void* start);
/**
* @return a pointer aligned to the start of the page the provided
pointer belongs to.
*
* NOTE requires blockCheckSupported() == true
*/
inline static const void* alignToStartOfPage(const void* ptr) {
return reinterpret_cast<const void*>(
reinterpret_cast<unsigned long long>(ptr) & ~(getPageSi
ze() - 1));
}
/**
* Sets i-th element of 'out' to non-zero if the i-th page starting
from the one containing
* 'start' is in memory.
* The 'out' vector will be resized to fit the requested number of
pages.
* @return true on success, false otherwise
*
* NOTE: requires blockCheckSupported() == true
*/
static bool pagesInMemory(const void* start, size_t numPages, vecto
r<char>* out);
private: private:
/** /**
* Host and operating system info. Does not change over time. * Host and operating system info. Does not change over time.
*/ */
class SystemInfo { class SystemInfo {
public: public:
string osType; string osType;
string osName; string osName;
string osVersion; string osVersion;
unsigned addrSize; unsigned addrSize;
unsigned long long memSize; unsigned long long memSize;
unsigned numCores; unsigned numCores;
unsigned long long pageSize;
string cpuArch; string cpuArch;
bool hasNuma; bool hasNuma;
BSONObj _extraStats; BSONObj _extraStats;
SystemInfo() : SystemInfo() :
addrSize( 0 ), addrSize( 0 ),
memSize( 0 ), memSize( 0 ),
numCores( 0 ), numCores( 0 ),
pageSize( 0 ),
hasNuma( false ) { hasNuma( false ) {
// populate SystemInfo during construction // populate SystemInfo during construction
collectSystemInfo(); collectSystemInfo();
} }
private: private:
/** Collect host system info */ /** Collect host system info */
void collectSystemInfo(); void collectSystemInfo();
}; };
pid_t _pid; pid_t _pid;
static mongo::mutex _sysInfoLock; static mongo::mutex _sysInfoLock;
static bool checkNumaEnabled(); static bool checkNumaEnabled();
const SystemInfo& sysInfo() const { static ProcessInfo::SystemInfo* systemInfo;
// initialize and collect sysInfo on first call
// TODO: SERVER-5112 inline const SystemInfo& sysInfo() const {
static ProcessInfo::SystemInfo *initSysInfo = NULL; return *systemInfo;
if ( ! initSysInfo ) {
scoped_lock lk( _sysInfoLock );
if ( ! initSysInfo ) {
initSysInfo = new SystemInfo();
}
}
return *initSysInfo;
} }
public:
static void initializeSystemInfo();
}; };
void writePidFile( const std::string& path ); void writePidFile( const std::string& path );
void printMemInfo( const char * whereContextStr = 0 ); void printMemInfo( const char * whereContextStr = 0 );
} }
 End of changes. 6 change blocks. 
12 lines changed or deleted 41 lines changed or added


 progress_meter.h   progress_meter.h 
skipping to change at line 97 skipping to change at line 97
ProgressMeterHolder( ProgressMeter& pm ) ProgressMeterHolder( ProgressMeter& pm )
: _pm( pm ) { : _pm( pm ) {
} }
~ProgressMeterHolder() { ~ProgressMeterHolder() {
_pm.finished(); _pm.finished();
} }
ProgressMeter* operator->() { return &_pm; } ProgressMeter* operator->() { return &_pm; }
ProgressMeter* get() { return &_pm; }
bool hit( int n = 1 ) { return _pm.hit( n ); } bool hit( int n = 1 ) { return _pm.hit( n ); }
void finished() { _pm.finished(); } void finished() { _pm.finished(); }
bool operator==( const ProgressMeter& other ) { return _pm == other ; } bool operator==( const ProgressMeter& other ) { return _pm == other ; }
private: private:
ProgressMeter& _pm; ProgressMeter& _pm;
}; };
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 projection.h   projection.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 "mongo/pch.h" #include "mongo/pch.h"
#include "mongo/util/string_map.h"
#include "jsobj.h" #include "jsobj.h"
namespace mongo { namespace mongo {
// fwd decls // fwd decls
class Matcher; class Matcher;
class MatchDetails; class MatchDetails;
/** /**
* given a document and a projection specification * given a document and a projection specification
skipping to change at line 141 skipping to change at line 142
const ArrayOpType arrayOpType = ARRAY_OP_NORMAL ) cons t; const ArrayOpType arrayOpType = ARRAY_OP_NORMAL ) cons t;
void add( const string& field, bool include ); void add( const string& field, bool include );
void add( const string& field, int skip, int limit ); void add( const string& field, int skip, int limit );
void appendArray( BSONObjBuilder& b , const BSONObj& a , bool neste d=false) const; void appendArray( BSONObjBuilder& b , const BSONObj& a , bool neste d=false) const;
bool _include; // true if default at this level is to include bool _include; // true if default at this level is to include
bool _special; // true if this level can't be skipped or included w ithout recursing bool _special; // true if this level can't be skipped or included w ithout recursing
//TODO: benchmark vector<pair> vs map //TODO: benchmark vector<pair> vs map
typedef map<string, boost::shared_ptr<Projection> > FieldMap; typedef StringMap<boost::shared_ptr<Projection> > FieldMap;
FieldMap _fields; FieldMap _fields;
BSONObj _source; BSONObj _source;
bool _includeID; bool _includeID;
// used for $slice operator // used for $slice operator
int _skip; int _skip;
int _limit; int _limit;
// used for $elemMatch and positional operator ($) // used for $elemMatch and positional operator ($)
typedef map<string, shared_ptr<Matcher> > Matchers; typedef StringMap<boost::shared_ptr<Matcher> > Matchers;
Matchers _matchers; Matchers _matchers;
ArrayOpType _arrayOpType; ArrayOpType _arrayOpType;
bool _hasNonSimple; bool _hasNonSimple;
}; };
} }
 End of changes. 3 change blocks. 
2 lines changed or deleted 3 lines changed or added


 queryoptimizer.h   queryoptimizer.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 "cursor.h" #include "mongo/base/disallow_copying.h"
#include "queryutil.h" #include "mongo/db/clientcursor.h"
#include "matcher.h" #include "mongo/db/cursor.h"
#include "explain.h" #include "mongo/db/explain.h"
#include "../util/net/listen.h" #include "mongo/db/matcher.h"
#include "mongo/db/queryoptimizercursor.h"
#include "mongo/db/querypattern.h" #include "mongo/db/querypattern.h"
#include "mongo/db/queryutil.h"
#include "mongo/util/elapsed_tracker.h"
namespace mongo { namespace mongo {
static const int OutOfOrderDocumentsAssertionCode = 14810;
class IndexDetails; class IndexDetails;
class IndexType; class IndexType;
class QueryPlanSummary; class QueryPlanSummary;
/** /**
* A plan for executing a query using the given index spec and FieldRan geSet. An object of this * A plan for executing a query using the given index spec and FieldRan geSet. An object of this
* class may only be used by one thread at a time. * class may only be used by one thread at a time.
*/ */
class QueryPlan : boost::noncopyable { class QueryPlan : boost::noncopyable {
public: public:
skipping to change at line 73 skipping to change at line 78
Unhelpful, // Should not be considered. Unhelpful, // Should not be considered.
Disallowed // Must not be considered unless explicitly hinted. May produce a Disallowed // Must not be considered unless explicitly hinted. May produce a
// semantically incorrect result set. // semantically incorrect result set.
}; };
Utility utility() const { return _utility; } Utility utility() const { return _utility; }
/** @return true if ScanAndOrder processing will be required for re sult set. */ /** @return true if ScanAndOrder processing will be required for re sult set. */
bool scanAndOrderRequired() const { return _scanAndOrderRequired; } bool scanAndOrderRequired() const { return _scanAndOrderRequired; }
/** /**
* @return true if the index we are using has keys such that it can * @return false if document matching can be determined entirely us
completely resolve the ing index keys and the
* query expression to match by itself without ever checking the ma * FieldRangeSetPair generated for the query, without using a Match
in object. er. This function may
* return false positives but not false negatives. For example, if
the field range set's
* mustBeExactMatchRepresentation() returns a false negative, this
function will return a
* false positive.
*/ */
bool exactKeyMatch() const { return _exactKeyMatch; } bool mayBeMatcherNecessary() const { return _matcherNecessary; }
/** @return true if this QueryPlan would perform an unindexed scan. */ /** @return true if this QueryPlan would perform an unindexed scan. */
bool willScanTable() const { return _idxNo < 0 && ( _utility != Imp ossible ); } bool willScanTable() const { return _idxNo < 0 && ( _utility != Imp ossible ); }
/** @return 'special' attribute of the plan, which was either set e xplicitly or generated from the index. */ /** @return 'special' attribute of the plan, which was either set e xplicitly or generated from the index. */
const string &special() const { return _special; } const string &special() const { return _special; }
/** @return a new cursor based on this QueryPlan's index and FieldR angeSet. */ /** @return a new cursor based on this QueryPlan's index and FieldR angeSet. */
shared_ptr<Cursor> newCursor( const DiskLoc &startLoc = DiskLoc() ) shared_ptr<Cursor> newCursor( const DiskLoc& startLoc = DiskLoc(),
const; bool requestIntervalCursor = false )
const;
/** @return a new reverse cursor if this is an unindexed plan. */ /** @return a new reverse cursor if this is an unindexed plan. */
shared_ptr<Cursor> newReverseCursor() const; shared_ptr<Cursor> newReverseCursor() const;
/** Register this plan as a winner for its QueryPattern, with speci fied 'nscanned'. */ /** Register this plan as a winner for its QueryPattern, with speci fied 'nscanned'. */
void registerSelf( long long nScanned, CandidatePlanCharacter candi datePlans ) const; void registerSelf( long long nScanned, CandidatePlanCharacter candi datePlans ) const;
int direction() const { return _direction; } int direction() const { return _direction; }
BSONObj indexKey() const; BSONObj indexKey() const;
bool indexed() const { return _index != 0; } bool indexed() const { return _index != 0; }
const IndexDetails *index() const { return _index; } const IndexDetails *index() const { return _index; }
int idxNo() const { return _idxNo; } int idxNo() const { return _idxNo; }
skipping to change at line 143 skipping to change at line 152
NamespaceDetails * _d; NamespaceDetails * _d;
int _idxNo; int _idxNo;
const FieldRangeSet &_frs; const FieldRangeSet &_frs;
const FieldRangeSet &_frsMulti; const FieldRangeSet &_frsMulti;
const BSONObj _originalQuery; const BSONObj _originalQuery;
const BSONObj _order; const BSONObj _order;
shared_ptr<const ParsedQuery> _parsedQuery; shared_ptr<const ParsedQuery> _parsedQuery;
const IndexDetails * _index; const IndexDetails * _index;
bool _scanAndOrderRequired; bool _scanAndOrderRequired;
bool _exactKeyMatch; bool _matcherNecessary;
int _direction; int _direction;
shared_ptr<FieldRangeVector> _frv; shared_ptr<FieldRangeVector> _frv;
shared_ptr<FieldRangeVector> _originalFrv; shared_ptr<FieldRangeVector> _originalFrv;
BSONObj _startKey; BSONObj _startKey;
BSONObj _endKey; BSONObj _endKey;
bool _endKeyInclusive; bool _endKeyInclusive;
Utility _utility; Utility _utility;
string _special; string _special;
IndexType * _type; IndexType * _type;
bool _startOrEndSpec; bool _startOrEndSpec;
skipping to change at line 181 skipping to change at line 190
_keyFieldsOnly( queryPlan.keyFieldsOnly() ), _keyFieldsOnly( queryPlan.keyFieldsOnly() ),
_scanAndOrderRequired( queryPlan.scanAndOrderRequired() ) { _scanAndOrderRequired( queryPlan.scanAndOrderRequired() ) {
} }
bool valid() const { return _fieldRangeSetMulti; } bool valid() const { return _fieldRangeSetMulti; }
shared_ptr<FieldRangeSet> _fieldRangeSetMulti; shared_ptr<FieldRangeSet> _fieldRangeSetMulti;
shared_ptr<Projection::KeyOnly> _keyFieldsOnly; shared_ptr<Projection::KeyOnly> _keyFieldsOnly;
bool _scanAndOrderRequired; bool _scanAndOrderRequired;
}; };
/** /**
* NOTE This interface is deprecated and will be replaced by a special * Helper class for a QueryPlanRunner to cache and count matches. One
purpose delegation class object of this type is
* for the query optimizer cursor (QueryOptimizerCursorOp). * used per candidate QueryPlan (as there is one QueryPlanRunner per Qu
eryPlan).
* *
* Inherit from this interface to implement a new query operation. * Typical usage:
* The query optimizer will clone the QueryOp that is provided, giving * 1) resetMatch() - reset stored match value to Unkonwn.
* each clone its own query plan. * 2) setMatch() - set match value to a definite true/false value.
* 3) knowMatch() - check if setMatch() has been called.
* 4) incMatch() - increment count if match is true.
*/
class CachedMatchCounter {
public:
/**
* @param aggregateNscanned - shared count of nscanned for this and
other plans.
* @param cumulativeCount - starting point for accumulated count ov
er a series of plans.
*/
CachedMatchCounter( long long& aggregateNscanned, int cumulativeCou
nt );
/** Set whether dup checking is enabled when counting. */
void setCheckDups( bool checkDups ) { _checkDups = checkDups; }
void resetMatch();
/** @return true if the match was not previously recorded. */
bool setMatch( bool match );
bool knowMatch() const { return _match != Unknown; }
void incMatch( const DiskLoc& loc );
bool wouldIncMatch( const DiskLoc& loc ) const;
bool enoughCumulativeMatchesToChooseAPlan() const;
bool enoughMatchesToRecordPlan() const;
int cumulativeCount() const { return _cumulativeCount; }
int count() const { return _count; }
/** Update local and aggregate nscanned counts. */
void updateNscanned( long long nscanned );
long long nscanned() const { return _nscanned; }
long long& aggregateNscanned() const { return _aggregateNscanned; }
private:
bool getsetdup( const DiskLoc& loc );
bool getdup( const DiskLoc& loc ) const;
long long& _aggregateNscanned;
long long _nscanned;
int _cumulativeCount;
int _count;
bool _checkDups;
enum MatchState { Unknown, False, True };
MatchState _match;
bool _counted;
set<DiskLoc> _dups;
};
/**
* Iterates through a QueryPlan's candidate matches, keeping track of a
ccumulated nscanned.
* Generally used along with runners for other QueryPlans in a QueryPla
nRunnerQueue priority
* queue. Eg if there are three candidate QueryPlans evaluated in para
llel, there are three
* QueryPlanRunners, one checking for matches on each query.
* *
* Normal sequence of events: * Typical usage:
* 1) A new QueryOp is generated using createChild(). * 1) A new QueryPlanRunner is generated using createChild().
* 2) A QueryPlan is assigned to this QueryOp with setQueryPlan(). * 2) A QueryPlan is assigned using setQueryPlan().
* 3) _init() is called on the QueryPlan. * 3) init() is called to initialize the runner.
* 4) next() is called repeatedly, with nscanned() checked after each c all. * 4) next() is called repeatedly, with nscanned() checked after each c all.
* 5) In one of these calls to next(), setComplete() is called. * 5) In one of these calls to next(), setComplete() is called internal
* 6) The QueryPattern for the QueryPlan may be recorded as a winner. ly.
* 6) The QueryPattern for the QueryPlan may be recorded as a winning p
lan.
*/ */
class QueryOp : private boost::noncopyable { class QueryPlanRunner {
MONGO_DISALLOW_COPYING( QueryPlanRunner );
public: public:
QueryOp() : _complete(), _stopRequested(), _queryPlan(), _error() { /**
} * @param aggregateNscanned Shared long long counting total nscanne
d for runners for all
virtual ~QueryOp() {} * cursors.
* @param selectionPolicy Characterizes the set of QueryPlans allow
ed for this operation.
* See queryoptimizercursor.h for more information.
* @param requireOrder Whether only ordered plans are allowed.
* @param alwaysCountMatches Whether matches are to be counted rega
rdless of ordering.
* @param cumulativeCount Total count.
*/
QueryPlanRunner( long long& aggregateNscanned,
const QueryPlanSelectionPolicy& selectionPolicy,
const bool& requireOrder,
bool alwaysCountMatches,
int cumulativeCount = 0 );
/** @return QueryPlan assigned to this runner by the query optimize
r. */
const QueryPlan& queryPlan() const { return *_queryPlan; }
/** @return QueryPlan assigned to this QueryOp by the query optimiz /** Advance to the next potential matching document (eg using a cur
er. */ sor). */
const QueryPlan &queryPlan() const { return *_queryPlan; } void next();
/** Advance to next potential matching document (eg using a cursor)
. */
virtual void next() = 0;
/** /**
* @return current 'nscanned' metric for this QueryOp. Used to com * @return current 'nscanned' metric for this runner. Used to comp
pare are cost to other
* cost to other QueryOps. * runners.
*/ */
virtual long long nscanned() = 0; long long nscanned() const;
/** Take any steps necessary before the db mutex is yielded. */ /** Take any steps necessary before the db mutex is yielded. */
virtual void prepareToYield() = 0; void prepareToYield();
/** Recover once the db mutex is regained. */ /** Recover once the db mutex is regained. */
virtual void recoverFromYield() = 0; void recoverFromYield();
/** Take any steps necessary before an earlier iterate of the curso
r is modified. */
void prepareToTouchEarlierIterate();
/** Recover after the earlier iterate is modified. */
void recoverFromTouchingEarlierIterate();
DiskLoc currLoc() const { return _c ? _c->currLoc() : DiskLoc(); }
BSONObj currKey() const { return _c ? _c->currKey() : BSONObj(); }
bool currentMatches( MatchDetails* details );
/** /**
* @return true iff the QueryPlan for this QueryOp may be registere d * @return true iff the QueryPlan for this runner may be registered
* as a winning plan. * as a winning plan.
*/ */
virtual bool mayRecordPlan() const = 0; bool mayRecordPlan() const;
shared_ptr<Cursor> cursor() const { return _c; }
/** @return true iff the implementation called setComplete() or set Stop(). */ /** @return true iff the implementation called setComplete() or set Stop(). */
bool complete() const { return _complete; } bool complete() const { return _complete; }
/** @return true iff the implementation called steStop(). */ /** @return true iff the implementation called setStop(). */
bool stopRequested() const { return _stopRequested; } bool stopRequested() const { return _stopRequested; }
bool completeWithoutStop() const { return complete() && !stopReques ted(); } bool completeWithoutStop() const { return complete() && !stopReques ted(); }
/** @return true iff the implementation threw an exception. */ /** @return true iff the implementation errored out. */
bool error() const { return _error; } bool error() const { return _error; }
/** @return the exception thrown by implementation if one was throw n. */ /** @return the error information. */
ExceptionInfo exception() const { return _exception; } ExceptionInfo exception() const { return _exception; }
/** To be called by QueryPlanSet::Runner only. */ /** To be called by QueryPlanSet::Runner only. */
/** /**
* @return a copy of the inheriting class, which will be run with i ts own query plan. The * @return a copy of the inheriting class, which will be run with i ts own query plan. The
* child QueryOp will assume its parent QueryOp has completed execu tion. * child runner will assume its parent runner has completed executi on.
*/ */
virtual QueryOp *createChild() const = 0; QueryPlanRunner* createChild() const;
void setQueryPlan( const QueryPlan *queryPlan ) {
_queryPlan = queryPlan; void setQueryPlan( const QueryPlan* queryPlan );
verify( _queryPlan != NULL );
}
/** Handle initialization after a QueryPlan has been set. */ /** Handle initialization after a QueryPlan has been set. */
virtual void init() = 0; void init();
void setException( const DBException &e ) {
_error = true; void setException( const DBException& e );
_exception = e.getInfo();
}
/** @return an ExplainPlanInfo object that will be updated as the q uery runs. */ /** @return an ExplainPlanInfo object that will be updated as the q uery runs. */
virtual shared_ptr<ExplainPlanInfo> generateExplainInfo() { shared_ptr<ExplainPlanInfo> generateExplainInfo();
return shared_ptr<ExplainPlanInfo>( new ExplainPlanInfo() ); shared_ptr<ExplainPlanInfo> explainInfo() const { return _explainPl
anInfo; }
const Projection::KeyOnly* keyFieldsOnly() const {
return queryPlan().keyFieldsOnly().get();
} }
protected: private:
/** Call if all results have been found. */ /** Call if all results have been found. */
void setComplete() { _complete = true; } void setComplete() { _complete = true; }
/** Call if the scan is complete even if not all results have been found. */ /** Call if the scan is complete even if not all results have been found. */
void setStop() { setComplete(); _stopRequested = true; } void setStop() { setComplete(); _stopRequested = true; }
private: void mayAdvance();
bool countingMatches();
bool countMatches() const;
/**
* @return true if the results generated by this query plan will be
loaded from the record
* store (not built from an index entry).
*/
bool hasDocumentLoadingQueryPlan() const;
void recordCursorLocation();
void checkCursorAdvanced();
void handleCursorAdvanced();
void checkCursorOrdering();
bool _complete; bool _complete;
bool _stopRequested; bool _stopRequested;
ExceptionInfo _exception; ExceptionInfo _exception;
const QueryPlan *_queryPlan; const QueryPlan* _queryPlan;
bool _error; bool _error;
CachedMatchCounter _matchCounter;
bool _countingMatches;
bool _mustAdvance;
bool _capped;
shared_ptr<Cursor> _c;
ClientCursor::Holder _cc;
DiskLoc _posBeforeYield;
ClientCursor::YieldData _yieldData;
const QueryPlanSelectionPolicy& _selectionPolicy;
const bool& _requireOrder; // TODO don't use a ref for this, but si
gnal change explicitly
shared_ptr<ExplainPlanInfo> _explainPlanInfo;
bool _alwaysCountMatches;
}; };
// temp. this class works if T::operator< is variant unlike a regular /**
stl priority queue. * This class works if T::operator< is variant unlike a regular stl pri
// but it's very slow. however if v.size() is always very small, it wo ority queue, but it's
uld be fine, * very slow. However if _vec.size() is always very small, it would be
// maybe even faster than a smart impl that does more memory allocation fine, maybe even faster
s. * than a smart impl that does more memory allocations.
* TODO Clean up this temporary code.
*/
template<class T> template<class T>
class our_priority_queue : boost::noncopyable { class PriorityQueue {
vector<T> v; MONGO_DISALLOW_COPYING( PriorityQueue );
public: public:
our_priority_queue() { PriorityQueue() {
v.reserve(4); _vec.reserve(4);
} }
int size() const { return v.size(); } int size() const { return _vec.size(); }
bool empty() const { return v.empty(); } bool empty() const { return _vec.empty(); }
void push(const T & x) { void push(const T & x) {
v.push_back(x); _vec.push_back(x);
} }
T pop() { T pop() {
size_t t = 0; size_t t = 0;
for( size_t i = 1; i < v.size(); i++ ) { for( size_t i = 1; i < _vec.size(); i++ ) {
if( v[t] < v[i] ) if( _vec[t] < _vec[i] )
t = i; t = i;
} }
T ret = v[t]; T ret = _vec[t];
v.erase(v.begin()+t); _vec.erase(_vec.begin()+t);
return ret; return ret;
} }
private:
vector<T> _vec;
}; };
class QueryPlanSet; class QueryPlanSet;
/** Populates a provided QueryPlanSet with candidate query plans, when requested. */ /** Populates a provided QueryPlanSet with candidate query plans, when requested. */
class QueryPlanGenerator { class QueryPlanGenerator {
public: public:
/** Policies for utilizing recorded plans. */ /** Policies for utilizing recorded plans. */
typedef enum { typedef enum {
skipping to change at line 351 skipping to change at line 475
QueryPlanSet &_qps; QueryPlanSet &_qps;
auto_ptr<FieldRangeSetPair> _originalFrsp; auto_ptr<FieldRangeSetPair> _originalFrsp;
shared_ptr<const ParsedQuery> _parsedQuery; shared_ptr<const ParsedQuery> _parsedQuery;
BSONObj _hint; BSONObj _hint;
RecordedPlanPolicy _recordedPlanPolicy; RecordedPlanPolicy _recordedPlanPolicy;
BSONObj _min; BSONObj _min;
BSONObj _max; BSONObj _max;
bool _allowSpecial; bool _allowSpecial;
}; };
/** /** A set of candidate query plans for a query. */
* A set of candidate query plans for a query. This class can return a
best guess plan or run a
* QueryOp on all the plans.
*/
class QueryPlanSet { class QueryPlanSet {
public: public:
typedef boost::shared_ptr<QueryPlan> QueryPlanPtr; typedef boost::shared_ptr<QueryPlan> QueryPlanPtr;
typedef vector<QueryPlanPtr> PlanSet; typedef vector<QueryPlanPtr> PlanVector;
/** /**
* @param originalFrsp - original constraints for this query clause ; if null, frsp will be * @param originalFrsp - original constraints for this query clause ; if null, frsp will be
* used. * used.
*/ */
static QueryPlanSet* make( const char* ns, static QueryPlanSet* make( const char* ns,
auto_ptr<FieldRangeSetPair> frsp, auto_ptr<FieldRangeSetPair> frsp,
auto_ptr<FieldRangeSetPair> originalFrsp , auto_ptr<FieldRangeSetPair> originalFrsp ,
const BSONObj& originalQuery, const BSONObj& originalQuery,
const BSONObj& order, const BSONObj& order,
skipping to change at line 412 skipping to change at line 533
string toString() const; string toString() const;
/** Configure a single query plan if one has not already been provi ded. */ /** Configure a single query plan if one has not already been provi ded. */
void setSinglePlan( const QueryPlanPtr &plan ); void setSinglePlan( const QueryPlanPtr &plan );
/** Configure a query plan from the plan cache. */ /** Configure a query plan from the plan cache. */
void setCachedPlan( const QueryPlanPtr &plan, const CachedQueryPlan &cachedPlan ); void setCachedPlan( const QueryPlanPtr &plan, const CachedQueryPlan &cachedPlan );
/** Add a candidate query plan, potentially one of many. */ /** Add a candidate query plan, potentially one of many. */
void addCandidatePlan( const QueryPlanPtr &plan ); void addCandidatePlan( const QueryPlanPtr &plan );
const PlanVector& plans() const { return _plans; }
bool mayRecordPlan() const { return _mayRecordPlan; }
int oldNScanned() const { return _oldNScanned; }
void addFallbackPlans();
void setUsingCachedPlan( bool usingCachedPlan ) { _usingCachedPlan
= usingCachedPlan; }
//for testing //for testing
bool modifiedKeys() const; bool modifiedKeys() const;
bool hasMultiKey() const; bool hasMultiKey() const;
class Runner {
public:
Runner( QueryPlanSet &plans, QueryOp &op );
/**
* Advance the runner, if it is not done().
* @return the next non error op if there is one, otherwise an
error op.
* If the returned op is complete() or error(), the Runner beco
mes done().
*/
shared_ptr<QueryOp> next();
/** @return true if done iterating. */
bool done() const { return _done; }
void prepareToYield();
void recoverFromYield();
/** @return an ExplainClauseInfo object that will be updated as
the query runs. */
shared_ptr<ExplainClauseInfo> generateExplainInfo() {
_explainClauseInfo.reset( new ExplainClauseInfo() );
return _explainClauseInfo;
}
private:
QueryOp &_op;
QueryPlanSet &_plans;
static void initOp( QueryOp &op );
static void nextOp( QueryOp &op );
static void prepareToYieldOp( QueryOp &op );
static void recoverFromYieldOp( QueryOp &op );
/** Initialize the Runner. */
shared_ptr<QueryOp> init();
/** Move the Runner forward one iteration, and @return the plan
for the iteration. */
shared_ptr<QueryOp> _next();
vector<shared_ptr<QueryOp> > _ops;
struct OpHolder {
OpHolder( const shared_ptr<QueryOp> &op ) : _op( op ), _off
set() {}
shared_ptr<QueryOp> _op;
long long _offset;
bool operator<( const OpHolder &other ) const {
return _op->nscanned() + _offset > other._op->nscanned(
) + other._offset;
}
};
our_priority_queue<OpHolder> _queue;
shared_ptr<ExplainClauseInfo> _explainClauseInfo;
bool _done;
};
private: private:
QueryPlanSet( const char *ns, QueryPlanSet( const char *ns,
auto_ptr<FieldRangeSetPair> frsp, auto_ptr<FieldRangeSetPair> frsp,
auto_ptr<FieldRangeSetPair> originalFrsp, auto_ptr<FieldRangeSetPair> originalFrsp,
const BSONObj &originalQuery, const BSONObj &originalQuery,
const BSONObj &order, const BSONObj &order,
const shared_ptr<const ParsedQuery> &parsedQuery, const shared_ptr<const ParsedQuery> &parsedQuery,
const BSONObj &hint, const BSONObj &hint,
QueryPlanGenerator::RecordedPlanPolicy recordedPlanPol icy, QueryPlanGenerator::RecordedPlanPolicy recordedPlanPol icy,
const BSONObj &min, const BSONObj &min,
const BSONObj &max, const BSONObj &max,
bool allowSpecial ); bool allowSpecial );
void init(); void init();
void addFallbackPlans();
void pushPlan( const QueryPlanPtr& plan ); void pushPlan( const QueryPlanPtr& plan );
QueryPlanGenerator _generator; QueryPlanGenerator _generator;
BSONObj _originalQuery; BSONObj _originalQuery;
auto_ptr<FieldRangeSetPair> _frsp; auto_ptr<FieldRangeSetPair> _frsp;
PlanSet _plans; PlanVector _plans;
bool _mayRecordPlan; bool _mayRecordPlan;
bool _usingCachedPlan; bool _usingCachedPlan;
CandidatePlanCharacter _cachedPlanCharacter; CandidatePlanCharacter _cachedPlanCharacter;
BSONObj _order; BSONObj _order;
long long _oldNScanned; long long _oldNScanned;
ElapsedTracker _yieldSometimesTracker; ElapsedTracker _yieldSometimesTracker;
bool _allowSpecial; bool _allowSpecial;
}; };
/**
* A priority queue of QueryPlanRunners ordered by their nscanned value
s. The QueryPlanRunners
* are iterated sequentially and reinserted into the queue until one ru
nner completes or all
* runners error out.
*/
class QueryPlanRunnerQueue {
public:
QueryPlanRunnerQueue( QueryPlanSet& plans, const QueryPlanRunner& p
rototypeRunner );
/**
* Pull a runner from the priority queue, advance it if possible, r
e-insert it into the
* queue if it is not done, and return it. But if this runner erro
rs out, retry with
* another runner until a non error runner is found or all runners
have errored out.
* @return the next non error runner if there is one, otherwise an
error runner.
* If the returned runner is complete() or error(), this queue beco
mes done().
*/
shared_ptr<QueryPlanRunner> next();
/** @return true if done iterating. */
bool done() const { return _done; }
/** Prepare all runners for a database mutex yield. */
void prepareToYield();
/** Restore all runners after a database mutex yield. */
void recoverFromYield();
/** @return an ExplainClauseInfo object that will be updated as the
query runs. */
shared_ptr<ExplainClauseInfo> generateExplainInfo() {
_explainClauseInfo.reset( new ExplainClauseInfo() );
return _explainClauseInfo;
}
private:
const QueryPlanRunner& _prototypeRunner;
QueryPlanSet& _plans;
static void initRunner( QueryPlanRunner& runner );
static void nextRunner( QueryPlanRunner& runner );
static void prepareToYieldRunner( QueryPlanRunner& runner );
static void recoverFromYieldRunner( QueryPlanRunner& runner );
/** Initialize the Runner. */
shared_ptr<QueryPlanRunner> init();
/** Move the Runner forward one iteration, and @return the plan for
the iteration. */
shared_ptr<QueryPlanRunner> _next();
vector<shared_ptr<QueryPlanRunner> > _runners;
struct RunnerHolder {
RunnerHolder( const shared_ptr<QueryPlanRunner>& runner ) :
_runner( runner ),
_offset() {
}
shared_ptr<QueryPlanRunner> _runner;
long long _offset;
bool operator<( const RunnerHolder& other ) const {
return _runner->nscanned() + _offset > other._runner->nscan
ned() + other._offset;
}
};
PriorityQueue<RunnerHolder> _queue;
shared_ptr<ExplainClauseInfo> _explainClauseInfo;
bool _done;
};
/** Handles $or type queries by generating a QueryPlanSet for each $or clause. */ /** Handles $or type queries by generating a QueryPlanSet for each $or clause. */
class MultiPlanScanner { class MultiPlanScanner {
public: public:
static MultiPlanScanner *make( const char *ns, static MultiPlanScanner *make( const char *ns,
const BSONObj &query, const BSONObj &query,
const BSONObj &order, const BSONObj &order,
const shared_ptr<const ParsedQuery> & parsedQuery = const shared_ptr<const ParsedQuery> & parsedQuery =
shared_ptr<const ParsedQuery>( ), shared_ptr<const ParsedQuery>( ),
const BSONObj &hint = BSONObj(), const BSONObj &hint = BSONObj(),
QueryPlanGenerator::RecordedPlanPolic y recordedPlanPolicy = QueryPlanGenerator::RecordedPlanPolic y recordedPlanPolicy =
QueryPlanGenerator::Use, QueryPlanGenerator::Use,
const BSONObj &min = BSONObj(), const BSONObj &min = BSONObj(),
const BSONObj &max = BSONObj() ); const BSONObj &max = BSONObj() );
/** Set the initial QueryOp for QueryPlanSet iteration. */ /** Set the originalRunner for QueryPlanSet iteration. */
void initialOp( const shared_ptr<QueryOp> &originalOp ) { _baseOp = void initialRunner( const shared_ptr<QueryPlanRunner>& originalRunn
originalOp; } er ) {
_baseRunner = originalRunner;
}
/** /**
* Advance to the next QueryOp, if not doneOps(). * Advance to the next runner, if not doneRunners().
* @return the next non error op if there is one, otherwise an erro * @return the next non error runner if there is one, otherwise an
r op. error runner.
* If the returned op is complete() or error(), the MultiPlanScanne * If the returned runner is complete() or error(), the MultiPlanSc
r becomes doneOps() and anner becomes
* no further QueryOp iteration is possible. * doneRunners() and no further runner iteration is possible.
*/ */
shared_ptr<QueryOp> nextOp(); shared_ptr<QueryPlanRunner> nextRunner();
/** @return true if done with QueryOp iteration. */ /** @return true if done with runner iteration. */
bool doneOps() const { return _doneOps; } bool doneRunners() const { return _doneRunners; }
/** /**
* Advance to the next $or clause; hasMoreClauses() must be true. * Advance to the next $or clause; hasMoreClauses() must be true.
* @param currentPlan QueryPlan of the current $or clause * @param currentPlan QueryPlan of the current $or clause
* @return best guess query plan of the next $or clause, 0 if there is no such plan. * @return best guess query plan of the next $or clause, 0 if there is no such plan.
*/ */
const QueryPlan *nextClauseBestGuessPlan( const QueryPlan &currentP lan ); const QueryPlan *nextClauseBestGuessPlan( const QueryPlan &currentP lan );
/** Add explain information for a new clause. */ /** Add explain information for a new clause. */
void addClauseInfo( const shared_ptr<ExplainClauseInfo> &clauseInfo ) { void addClauseInfo( const shared_ptr<ExplainClauseInfo> &clauseInfo ) {
skipping to change at line 548 skipping to change at line 688
_explainQueryInfo.reset( new ExplainQueryInfo() ); _explainQueryInfo.reset( new ExplainQueryInfo() );
return _explainQueryInfo; return _explainQueryInfo;
} }
/** Yield the runner member. */ /** Yield the runner member. */
void prepareToYield(); void prepareToYield();
void recoverFromYield(); void recoverFromYield();
/** Clear the runner member. */ /** Clear the runner member. */
void clearRunner(); void clearRunnerQueue();
void setRecordedPlanPolicy( QueryPlanGenerator::RecordedPlanPolicy recordedPlanPolicy ) { void setRecordedPlanPolicy( QueryPlanGenerator::RecordedPlanPolicy recordedPlanPolicy ) {
_recordedPlanPolicy = recordedPlanPolicy; _recordedPlanPolicy = recordedPlanPolicy;
} }
int currentNPlans() const; int currentNPlans() const;
/** /**
* @return the query plan that would be used if the scanner would r un a single * @return the query plan that would be used if the scanner would r un a single
* cursor for this query, otherwise 0. The returned plan is invali d if this * cursor for this query, otherwise 0. The returned plan is invali d if this
skipping to change at line 607 skipping to change at line 747
MultiPlanScanner( const char *ns, MultiPlanScanner( const char *ns,
const BSONObj &query, const BSONObj &query,
const shared_ptr<const ParsedQuery> &parsedQuery, const shared_ptr<const ParsedQuery> &parsedQuery,
const BSONObj &hint, const BSONObj &hint,
QueryPlanGenerator::RecordedPlanPolicy recordedPla nPolicy ); QueryPlanGenerator::RecordedPlanPolicy recordedPla nPolicy );
void init( const BSONObj &order, void init( const BSONObj &order,
const BSONObj &min, const BSONObj &min,
const BSONObj &max ); const BSONObj &max );
/** Initialize or iterate a runner generated from @param originalOp . */ /** Initialize or iterate a runner generated from @param originalOp . */
shared_ptr<QueryOp> iterateRunner( QueryOp &originalOp, bool retrie shared_ptr<QueryPlanRunner> iterateRunnerQueue( QueryPlanRunner& or
d = false ); iginalRunner,
bool retried = fals
e );
shared_ptr<QueryOp> nextOpSimple(); shared_ptr<QueryPlanRunner> nextRunnerSimple();
shared_ptr<QueryOp> nextOpOr(); shared_ptr<QueryPlanRunner> nextRunnerOr();
void updateCurrentQps( QueryPlanSet *qps ); void updateCurrentQps( QueryPlanSet *qps );
void assertNotOr() const { void assertNotOr() const {
massert( 13266, "not implemented for $or query", !_or ); massert( 13266, "not implemented for $or query", !_or );
} }
void assertHasMoreClauses() const { void assertHasMoreClauses() const {
massert( 13271, "no more clauses", hasMoreClauses() ); massert( 13271, "no more clauses", hasMoreClauses() );
} }
skipping to change at line 637 skipping to change at line 778
const string _ns; const string _ns;
bool _or; bool _or;
BSONObj _query; BSONObj _query;
shared_ptr<const ParsedQuery> _parsedQuery; shared_ptr<const ParsedQuery> _parsedQuery;
scoped_ptr<OrRangeGenerator> _org; // May be null in certain non $o r query cases. scoped_ptr<OrRangeGenerator> _org; // May be null in certain non $o r query cases.
scoped_ptr<QueryPlanSet> _currentQps; scoped_ptr<QueryPlanSet> _currentQps;
int _i; int _i;
QueryPlanGenerator::RecordedPlanPolicy _recordedPlanPolicy; QueryPlanGenerator::RecordedPlanPolicy _recordedPlanPolicy;
BSONObj _hint; BSONObj _hint;
bool _tableScanned; bool _tableScanned;
shared_ptr<QueryOp> _baseOp; shared_ptr<QueryPlanRunner> _baseRunner;
scoped_ptr<QueryPlanSet::Runner> _runner; scoped_ptr<QueryPlanRunnerQueue> _runnerQueue;
shared_ptr<ExplainQueryInfo> _explainQueryInfo; shared_ptr<ExplainQueryInfo> _explainQueryInfo;
bool _doneOps; bool _doneRunners;
}; };
/** /**
* Provides a cursor interface for serial single Cursor iteration using a MultiPlanScanner. * Provides a cursor interface for serial single Cursor iteration using a MultiPlanScanner.
* Currently used internally by a QueryOptimizerCursor. * Currently used internally by a QueryOptimizerCursor.
* *
* A MultiCursor is backed by one BasicCursor or BtreeCursor at a time and forwards calls for * A MultiCursor is backed by one BasicCursor or BtreeCursor at a time and forwards calls for
* ensuring a consistent state after a write to its backing Cursor. * ensuring a consistent state after a write to its backing Cursor.
*/ */
class MultiCursor : public Cursor { class MultiCursor : public Cursor {
public: public:
/** @param nscanned is the initial nscanned value. */ /** @param nscanned is the initial nscanned value. */
MultiCursor( auto_ptr<MultiPlanScanner> mps, const shared_ptr<Curso r> &c, MultiCursor( auto_ptr<MultiPlanScanner> mps, const shared_ptr<Curso r> &c,
const shared_ptr<CoveredIndexMatcher> &matcher, const shared_ptr<CoveredIndexMatcher> &matcher,
const shared_ptr<ExplainPlanInfo> &explainPlanInfo, const shared_ptr<ExplainPlanInfo> &explainPlanInfo,
const QueryOp &op, long long nscanned ); const QueryPlanRunner& runner, long long nscanned );
virtual bool ok() { return _c->ok(); } virtual bool ok() { return _c->ok(); }
virtual Record* _current() { return _c->_current(); } virtual Record* _current() { return _c->_current(); }
virtual BSONObj current() { return _c->current(); } virtual BSONObj current() { return _c->current(); }
virtual DiskLoc currLoc() { return _c->currLoc(); } virtual DiskLoc currLoc() { return _c->currLoc(); }
virtual bool advance(); virtual bool advance();
virtual BSONObj currKey() const { return _c->currKey(); } virtual BSONObj currKey() const { return _c->currKey(); }
virtual DiskLoc refLoc() { return _c->refLoc(); } virtual DiskLoc refLoc() { return _c->refLoc(); }
virtual void noteLocation() { _c->noteLocation(); } virtual void noteLocation() { _c->noteLocation(); }
virtual void checkLocation() { _c->checkLocation(); } virtual void checkLocation() { _c->checkLocation(); }
 End of changes. 55 change blocks. 
165 lines changed or deleted 328 lines changed or added


 queryoptimizercursor.h   queryoptimizercursor.h 
skipping to change at line 30 skipping to change at line 30
#include "cursor.h" #include "cursor.h"
#include "diskloc.h" #include "diskloc.h"
namespace mongo { namespace mongo {
class QueryPlan; class QueryPlan;
class CandidatePlanCharacter; class CandidatePlanCharacter;
/** /**
* An interface for policies overriding the query optimizer's default q * An interface for policies overriding the query optimizer's default b
uery plan selection ehavior for selecting
* behavior. * query plans and creating cursors.
*/ */
class QueryPlanSelectionPolicy { class QueryPlanSelectionPolicy {
public: public:
virtual ~QueryPlanSelectionPolicy() {} virtual ~QueryPlanSelectionPolicy() {}
virtual string name() const = 0; virtual string name() const = 0;
virtual bool permitOptimalNaturalPlan() const { return true; } virtual bool permitOptimalNaturalPlan() const { return true; }
virtual bool permitOptimalIdPlan() const { return true; } virtual bool permitOptimalIdPlan() const { return true; }
virtual bool permitPlan( const QueryPlan &plan ) const { return tru e; } virtual bool permitPlan( const QueryPlan &plan ) const { return tru e; }
virtual BSONObj planHint( const char *ns ) const { return BSONObj() ; } virtual BSONObj planHint( const char *ns ) const { return BSONObj() ; }
/**
* @return true to request that a created Cursor provide a matcher(
). If false, the
* Cursor's matcher() may be NULL if the Cursor can perform accurat
e query matching
* internally using a non Matcher mechanism. One case where a Matc
her might be requested
* even though not strictly necessary to select matching documents
is if metadata about
* matches may be requested using MatchDetails. NOTE This is a hin
t that the Cursor use a
* Matcher, but the hint may be ignored. In some cases the Cursor
may not provide
* a Matcher even if 'requestMatcher' is true.
*/
virtual bool requestMatcher() const { return true; }
/**
* @return true to request creating an IntervalBtreeCursor rather t
han a BtreeCursor when
* possible. An IntervalBtreeCursor is optimized for counting the
number of documents
* between two endpoints in a btree. NOTE This is a hint to create
an interval cursor, but
* the hint may be ignored. In some cases a different cursor type
may be created even if
* 'requestIntervalCursor' is true.
*/
virtual bool requestIntervalCursor() const { return false; }
/** Allow any query plan selection, permitting the query optimizer' s default behavior. */ /** Allow any query plan selection, permitting the query optimizer' s default behavior. */
static const QueryPlanSelectionPolicy &any(); static const QueryPlanSelectionPolicy &any();
/** Prevent unindexed collection scans. */ /** Prevent unindexed collection scans. */
static const QueryPlanSelectionPolicy &indexOnly(); static const QueryPlanSelectionPolicy &indexOnly();
/** /**
* Generally hints to use the _id plan, falling back to the $natura l plan. However, the * Generally hints to use the _id plan, falling back to the $natura l plan. However, the
* $natural plan will always be used if optimal for the query. * $natural plan will always be used if optimal for the query.
*/ */
 End of changes. 2 change blocks. 
3 lines changed or deleted 33 lines changed or added


 queryoptimizercursorimpl.h   queryoptimizercursorimpl.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 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/db/queryutil.h" #include "mongo/db/queryutil.h"
#include "queryoptimizercursor.h" #include "mongo/db/queryoptimizercursor.h"
#include "mongo/db/querypattern.h"
namespace mongo { namespace mongo {
/** Helper class for caching and counting matches during execution of a class MultiCursor;
QueryPlan. */ class MultiPlanScanner;
class CachedMatchCounter { class QueryPlanRunner;
public: class QueryPlanSummary;
/**
* @param aggregateNscanned - shared count of nscanned for this and
othe plans.
* @param cumulativeCount - starting point for accumulated count ov
er a series of plans.
*/
CachedMatchCounter( long long &aggregateNscanned, int cumulativeCou
nt ) : _aggregateNscanned( aggregateNscanned ), _nscanned(), _cumulativeCou
nt( cumulativeCount ), _count(), _checkDups(), _match( Unknown ), _counted(
) {}
/** Set whether dup checking is enabled when counting. */
void setCheckDups( bool checkDups ) { _checkDups = checkDups; }
/**
* Usual sequence of events:
* 1) resetMatch() - reset stored match value to Unkonwn.
* 2) setMatch() - set match value to a definite true/false value.
* 3) knowMatch() - check if setMatch() has been called.
* 4) countMatch() - increment count if match is true.
*/
void resetMatch() {
_match = Unknown;
_counted = false;
}
/** @return true if the match was not previously recorded. */
bool setMatch( bool match ) {
MatchState oldMatch = _match;
_match = match ? True : False;
return _match == True && oldMatch != True;
}
bool knowMatch() const { return _match != Unknown; }
void countMatch( const DiskLoc &loc ) {
if ( !_counted && _match == True && !getsetdup( loc ) ) {
++_cumulativeCount;
++_count;
_counted = true;
}
}
bool wouldCountMatch( const DiskLoc &loc ) const {
return !_counted && _match == True && !getdup( loc );
}
bool enoughCumulativeMatchesToChooseAPlan() const {
// This is equivalent to the default condition for switching fr
om
// a query to a getMore, which was the historical default match
count for
// choosing a plan.
return _cumulativeCount >= 101;
}
bool enoughMatchesToRecordPlan() const {
// Recording after 50 matches is a historical default (101 defa
ult limit / 2).
return _count > 50;
}
int cumulativeCount() const { return _cumulativeCount; }
int count() const { return _count; }
/** Update local and aggregate nscanned counts. */
void updateNscanned( long long nscanned ) {
_aggregateNscanned += ( nscanned - _nscanned );
_nscanned = nscanned;
}
long long nscanned() const { return _nscanned; }
long long &aggregateNscanned() const { return _aggregateNscanned; }
private:
bool getsetdup( const DiskLoc &loc ) {
if ( !_checkDups ) {
return false;
}
pair<set<DiskLoc>::iterator, bool> p = _dups.insert( loc );
return !p.second;
}
bool getdup( const DiskLoc &loc ) const {
if ( !_checkDups ) {
return false;
}
return _dups.find( loc ) != _dups.end();
}
long long &_aggregateNscanned;
long long _nscanned;
int _cumulativeCount;
int _count;
bool _checkDups;
enum MatchState { Unknown, False, True };
MatchState _match;
bool _counted;
set<DiskLoc> _dups;
};
/** Dup tracking class, optimizing one common case with small set and f ew initial reads. */ /** Dup tracking class, optimizing one common case with small set and f ew initial reads. */
class SmallDupSet { class SmallDupSet {
public: public:
SmallDupSet() : _accesses() { SmallDupSet() : _accesses() {
_vec.reserve( 250 ); _vec.reserve( 250 );
} }
/** @return true if @param 'loc' already added to the set, false if adding to the set in this call. */ /** @return true if @param 'loc' already added to the set, false if adding to the set in this call. */
bool getsetdup( const DiskLoc &loc ) { bool getsetdup( const DiskLoc &loc ) {
access(); access();
skipping to change at line 170 skipping to change at line 88
return !p.second; return !p.second;
} }
bool getdupSet( const DiskLoc &loc ) { bool getdupSet( const DiskLoc &loc ) {
return _set.count( loc ) > 0; return _set.count( loc ) > 0;
} }
vector<DiskLoc> _vec; vector<DiskLoc> _vec;
set<DiskLoc> _set; set<DiskLoc> _set;
long long _accesses; long long _accesses;
}; };
class QueryPlanSummary; /**
class MultiPlanScanner; * This cursor runs a MultiPlanScanner iteratively and returns results
from
* the scanner's cursors as they become available. Once the scanner ch
ooses
* a single plan, this cursor becomes a simple wrapper around that sing
le
* plan's cursor (called the 'takeover' cursor).
*
* A QueryOptimizerCursor employs a delegation strategy to ensure consi
stency after writes
* during its initial phase when multiple delegate Cursors may be activ
e (before _takeover is
* set).
*
* Before takeover, the return value of refLoc() will be isNull(), caus
ing ClientCursor to
* ignore a QueryOptimizerCursor (though not its delegate Cursors) when
a delete occurs.
* Requests to prepareToYield() or recoverFromYield() will be forwarded
to
* prepareToYield()/recoverFromYield() on ClientCursors of delegate Cur
sors. If a delegate
* Cursor becomes eof() or invalid after a yield recovery,
* QueryOptimizerCursor::recoverFromYield() may advance _currRunner to
another delegate Cursor.
*
* Requests to prepareToTouchEarlierIterate() or recoverFromTouchingEar
lierIterate() are
* forwarded as prepareToTouchEarlierIterate()/recoverFromTouchingEarli
erIterate() to the
* delegate Cursor when a single delegate Cursor is active. If multipl
e delegate Cursors are
* active, the advance() call preceeding prepareToTouchEarlierIterate()
may not properly advance
* all delegate Cursors, so the calls are forwarded as prepareToYield()
/recoverFromYield() to a
* ClientCursor for each delegate Cursor.
*
* After _takeover is set, consistency after writes is ensured by deleg
ation to the _takeover
* MultiCursor.
*/
class QueryOptimizerCursorImpl : public QueryOptimizerCursor {
public:
static QueryOptimizerCursorImpl* make( auto_ptr<MultiPlanScanner>&
mps,
const QueryPlanSelectionPoli
cy& planPolicy,
bool requireOrder,
bool explain );
virtual bool ok();
virtual Record* _current();
virtual BSONObj current();
virtual DiskLoc currLoc();
DiskLoc _currLoc() const;
virtual bool advance();
virtual BSONObj currKey() const;
/**
* When return value isNull(), our cursor will be ignored for delet
ions by the ClientCursor
* implementation. In such cases, internal ClientCursors will upda
te the positions of
* component Cursors when necessary.
* !!! Use care if changing this behavior, as some ClientCursor fun
ctionality may not work
* recursively.
*/
virtual DiskLoc refLoc();
virtual BSONObj indexKeyPattern();
virtual bool supportGetMore() { return true; }
virtual bool supportYields() { return true; }
virtual void prepareToTouchEarlierIterate();
virtual void recoverFromTouchingEarlierIterate();
virtual void prepareToYield();
virtual void recoverFromYield();
virtual string toString() { return "QueryOptimizerCursor"; }
virtual bool getsetdup(DiskLoc loc);
/** Matcher needs to know if the the cursor being forwarded to is m
ultikey. */
virtual bool isMultiKey() const;
// TODO fix
virtual bool modifiedKeys() const { return true; }
virtual bool capped() const;
virtual long long nscanned();
virtual CoveredIndexMatcher *matcher() const;
virtual bool currentMatches( MatchDetails* details = 0 );
virtual CandidatePlanCharacter initialCandidatePlans() const {
return _initialCandidatePlans;
}
virtual const FieldRangeSet* initialFieldRangeSet() const;
virtual bool currentPlanScanAndOrderRequired() const;
virtual const Projection::KeyOnly* keyFieldsOnly() const;
virtual bool runningInitialInOrderPlan() const;
virtual bool hasPossiblyExcludedPlans() const;
virtual bool completePlanOfHybridSetScanAndOrderRequired() const {
return _completePlanOfHybridSetScanAndOrderRequired;
}
virtual void clearIndexesForPatterns();
virtual void abortOutOfOrderPlans();
virtual void noteIterate( bool match, bool loadedDocument, bool chu
nkSkip );
virtual void noteYield();
virtual shared_ptr<ExplainQueryInfo> explainQueryInfo() const {
return _explainQueryInfo;
}
private:
QueryOptimizerCursorImpl( auto_ptr<MultiPlanScanner>& mps,
const QueryPlanSelectionPolicy& planPolic
y,
bool requireOrder );
void init( bool explain );
/**
* Advances the QueryPlanSet::Runner.
* @param force - advance even if the current query op is not valid
. The 'force' param should only be specified
* when there are plans left in the runner.
*/
bool _advance( bool force );
/** Forward an exception when the runner errs out. */
void rethrowOnError( const shared_ptr< QueryPlanRunner >& runner );
void assertOk() const {
massert( 14809, "Invalid access for cursor that is not ok()", !
_currLoc().isNull() );
}
/** Insert and check for dups before takeover occurs */
bool getsetdupInternal(const DiskLoc& loc);
/** Just check for dups - after takeover occurs */
bool getdupInternal(const DiskLoc& loc);
bool _requireOrder;
auto_ptr<MultiPlanScanner> _mps;
CandidatePlanCharacter _initialCandidatePlans;
shared_ptr<QueryPlanRunner> _originalRunner;
QueryPlanRunner* _currRunner;
bool _completePlanOfHybridSetScanAndOrderRequired;
shared_ptr<MultiCursor> _takeover;
long long _nscanned;
// Using a SmallDupSet seems a bit hokey, but I've measured a 5% pe
rformance improvement
// with ~100 document non multi key scans.
SmallDupSet _dups;
shared_ptr<ExplainQueryInfo> _explainQueryInfo;
};
/** /**
* Helper class for generating a simple Cursor or QueryOptimizerCursor from a set of query * Helper class for generating a simple Cursor or QueryOptimizerCursor from a set of query
* parameters. This class was refactored from a single function call a nd is not expected to * parameters. This class was refactored from a single function call a nd is not expected to
* outlive its constructor arguments. * outlive its constructor arguments.
*/ */
class CursorGenerator { class CursorGenerator {
public: public:
CursorGenerator( const char *ns, CursorGenerator( const char *ns,
const BSONObj &query, const BSONObj &query,
const BSONObj &order, const BSONObj &order,
const QueryPlanSelectionPolicy &planPolicy, const QueryPlanSelectionPolicy &planPolicy,
bool *simpleEqualityMatch,
const shared_ptr<const ParsedQuery> &parsedQuery, const shared_ptr<const ParsedQuery> &parsedQuery,
bool requireOrder, bool requireOrder,
QueryPlanSummary *singlePlanSummary ); QueryPlanSummary *singlePlanSummary );
shared_ptr<Cursor> generate(); shared_ptr<Cursor> generate();
private: private:
bool snapshot() const { return _parsedQuery && _parsedQuery->isSnap shot(); } bool snapshot() const { return _parsedQuery && _parsedQuery->isSnap shot(); }
bool explain() const { return _parsedQuery && _parsedQuery->isExpla in(); } bool explain() const { return _parsedQuery && _parsedQuery->isExpla in(); }
BSONObj min() const { return _parsedQuery ? _parsedQuery->getMin() : BSONObj(); } BSONObj min() const { return _parsedQuery ? _parsedQuery->getMin() : BSONObj(); }
skipping to change at line 215 skipping to change at line 290
void setArgumentsHint(); void setArgumentsHint();
shared_ptr<Cursor> shortcutCursor() const; shared_ptr<Cursor> shortcutCursor() const;
void setMultiPlanScanner(); void setMultiPlanScanner();
shared_ptr<Cursor> singlePlanCursor(); shared_ptr<Cursor> singlePlanCursor();
const char *_ns; const char *_ns;
BSONObj _query; BSONObj _query;
BSONObj _order; BSONObj _order;
const QueryPlanSelectionPolicy &_planPolicy; const QueryPlanSelectionPolicy &_planPolicy;
bool *_simpleEqualityMatch;
shared_ptr<const ParsedQuery> _parsedQuery; shared_ptr<const ParsedQuery> _parsedQuery;
bool _requireOrder; bool _requireOrder;
QueryPlanSummary *_singlePlanSummary; QueryPlanSummary *_singlePlanSummary;
BSONObj _argumentsHint; BSONObj _argumentsHint;
auto_ptr<MultiPlanScanner> _mps; auto_ptr<MultiPlanScanner> _mps;
}; };
} // namespace mongo } // namespace mongo
 End of changes. 5 change blocks. 
101 lines changed or deleted 193 lines changed or added


 queryutil-inl.h   queryutil-inl.h 
skipping to change at line 77 skipping to change at line 77
if ( e.fieldName() == string( "$natural" ) ) { if ( e.fieldName() == string( "$natural" ) ) {
return true; return true;
} }
if ( range( e.fieldName() ).empty() ) { if ( range( e.fieldName() ).empty() ) {
return false; return false;
} }
} }
return true; return true;
} }
inline unsigned FieldRangeVector::size() { inline unsigned FieldRangeVector::size() const {
unsigned ret = 1; unsigned ret = 1;
for( vector<FieldRange>::const_iterator i = _ranges.begin(); i != _ ranges.end(); ++i ) { for( vector<FieldRange>::const_iterator i = _ranges.begin(); i != _ ranges.end(); ++i ) {
unsigned long long product = unsigned long long product =
(unsigned long long)ret * (unsigned long long)i->interv als().size(); (unsigned long long)ret * (unsigned long long)i->interv als().size();
// Check for overflow SERVER-5415. // Check for overflow SERVER-5415.
verify( ( product >> 32 ) == 0 ); verify( ( product >> 32 ) == 0 );
ret = static_cast<unsigned>( product ); ret = static_cast<unsigned>( product );
} }
return ret; return ret;
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 queryutil.h   queryutil.h 
skipping to change at line 359 skipping to change at line 359
* 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; }
string getSpecial() const { return _special; } const set<string>& 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;
string _special; // Index type name of a non standard (eg '2d') ind set<string> _special; // Index type name of a non standard (eg '2d'
ex required by a parsed ) index required by a
// query operator (eg '$near'). // 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 463 skipping to change at line 463
/** /**
* @return a simplified query from the extreme values of the non un iversal * @return a simplified query from the extreme values of the non un iversal
* fields. * fields.
* @param fields If specified, the fields of the returned object ar e * @param fields If specified, the fields of the returned object ar e
* ordered to match those of 'fields'. * ordered to match those of 'fields'.
*/ */
BSONObj simplifiedQuery( const BSONObj &fields = BSONObj() ) const; BSONObj simplifiedQuery( const BSONObj &fields = BSONObj() ) const;
QueryPattern pattern( const BSONObj &sort = BSONObj() ) const; QueryPattern pattern( const BSONObj &sort = BSONObj() ) const;
string getSpecial() const; set<string> 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 572
/** @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(); }
string getSpecial() const { return _singleKey.getSpecial(); } set<string> 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 621 skipping to change at line 621
class FieldRangeVector { class FieldRangeVector {
public: public:
/** /**
* @param frs The valid ranges for all fields, as defined by the qu ery spec. None of the * @param frs The valid ranges for all fields, as defined by the qu ery spec. None of the
* fields in indexSpec may be empty() ranges of frs. * fields in indexSpec may be empty() ranges of frs.
* @param indexSpec The index spec (key pattern and info) * @param indexSpec The index spec (key pattern and info)
* @param direction The direction of index traversal * @param direction The direction of index traversal
*/ */
FieldRangeVector( const FieldRangeSet &frs, const IndexSpec &indexS pec, int direction ); FieldRangeVector( const FieldRangeSet &frs, const IndexSpec &indexS pec, int direction );
/** @return the number of index ranges represented by 'this' */ /**
unsigned size(); * Methods for identifying compound start and end btree bounds desc
/** @return starting point for an index traversal. */ ribing this field range
* vector.
*
* A FieldRangeVector contains the FieldRange bounds for every fiel
d of an index. A
* FieldRangeVectorIterator may be used to efficiently search for b
tree keys within these
* bounds. Alternatively, a single compound field interval of the
btree may be scanned,
* between a compound field start point and end point. If isSingle
Interval() is true then
* the interval between the start and end points will be an exact d
escription of this
* FieldRangeVector, otherwise the start/end interval will be a sup
erset of this
* FieldRangeVector. For example:
*
* index { a:1 }, query { a:{ $gt:2, $lte:4 } }
* -> frv ( 2, 4 ]
* -> start/end bounds ( { '':2 }, { '':4 } ]
*
* index { a:1, b:1 }, query { a:2, b:{ $gte:7, $lt:9 } }
* -> frv [ 2, 2 ], [ 7, 9 )
* -> start/end bounds [ { '':2, '':7 }, { '':2, '':9 } )
*
* index { a:1, b:-1 }, query { a:2, b:{ $gte:7, $lt:9 } }
* -> frv [ 2, 2 ], ( 9, 7 ]
* -> start/end bounds ( { '':2, '':9 }, { '':2, '':7 } ]
*
* index { a:1, b:1 }, query { a:{ $gte:7, $lt:9 } }
* -> frv [ 7, 9 )
* -> start/end bounds [ { '':7, '':MinKey }, { '':9, '':Mi
nKey } )
*
* index { a:1, b:1 }, query { a:{ $gte:2, $lte:5 }, b:{ $gte:7, $l
te:9 } }
* -> frv [ 2, 5 ], [ 7, 9 ]
* -> start/end bounds [ { '':2, '':7 }, { '':5, '':9 } ]
* (isSingleInterval() == false)
*/
/**
* @return true if this FieldRangeVector represents a single interv
al within a btree,
* comprised of all keys between a single start point and a single
end point.
*/
bool isSingleInterval() const;
/**
* @return a starting point for an index traversal, a lower bound o
n the ranges represented
* by this FieldRangeVector according to the btree's native orderin
g.
*/
BSONObj startKey() const; BSONObj startKey() const;
/** @return end point for an index traversal. */
/** @return true if the startKey() bound is inclusive. */
bool startKeyInclusive() const;
/**
* @return an end point for an index traversal, an upper bound on t
he ranges represented
* by this FieldRangeVector according to the btree's native orderin
g.
*/
BSONObj endKey() const; BSONObj endKey() const;
/** @return true if the endKey() bound is inclusive. */
bool endKeyInclusive() const;
/** @return the number of index ranges represented by 'this' */
unsigned size() const;
/** @return a client readable representation of 'this' */ /** @return a client readable representation of 'this' */
BSONObj obj() const; BSONObj obj() const;
const IndexSpec& getSpec(){ return _indexSpec; } const IndexSpec& getSpec(){ return _indexSpec; }
/** /**
* @return true iff the provided document matches valid ranges on a ll * @return true iff the provided document matches valid ranges on a ll
* of this FieldRangeVector's fields, which is the case iff this do cument * of this FieldRangeVector's fields, which is the case iff this do cument
* would be returned while scanning the index corresponding to this * would be returned while scanning the index corresponding to this
* FieldRangeVector. This function is used for $or clause deduping . * FieldRangeVector. This function is used for $or clause deduping .
*/ */
bool matches( const BSONObj &obj ) const; bool matches( const BSONObj &obj ) const;
/** /**
* @return true if all values in the provided index key are contain
ed within the field
* ranges of their respective fields in this FieldRangeVector.
*
* For example, given a query { a:3, b:4 } and index { a:1, b:1 },
the FieldRangeVector is
* [ [[ 3, 3 ]], [[ 4, 4 ]] ], consisting of field range [[ 3, 3 ]]
on field 'a' and
* [[ 4, 4 ]] on field 'b'. The index key { '':3, '':4 } matches,
but the index key
* { '':3, '':5 } does not match because the value 5 in the second
field is not contained in
* the field range [[ 4, 4 ]] for field 'b'.
*/
bool matchesKey( const BSONObj& key ) const;
/**
* @return first key of 'obj' that would be encountered by a forwar d * @return first key of 'obj' that would be encountered by a forwar d
* index scan using this FieldRangeVector, BSONObj() if no such key . * index scan using this FieldRangeVector, BSONObj() if no such key .
*/ */
BSONObj firstMatch( const BSONObj &obj ) const; BSONObj firstMatch( const BSONObj &obj ) const;
/**
* @return true if all ranges within the field range set on fields
of this index are
* represented in this field range vector. May be false in certain
multikey index cases
* when intervals on two fields cannot both be used, see comments r
elated to SERVER-958 in
* FieldRangeVector().
*/
bool hasAllIndexedRanges() const { return _hasAllIndexedRanges; }
string toString() const; string toString() const;
private: private:
int matchingLowElement( const BSONElement &e, int i, bool direction , bool &lowEquality ) const; int matchingLowElement( const BSONElement &e, int i, bool direction , bool &lowEquality ) const;
bool matchesElement( const BSONElement &e, int i, bool direction ) const; bool matchesElement( const BSONElement &e, int i, bool direction ) const;
bool matchesKey( const BSONObj &key ) const;
vector<FieldRange> _ranges; vector<FieldRange> _ranges;
const IndexSpec _indexSpec; const IndexSpec _indexSpec;
int _direction; int _direction;
vector<BSONObj> _queries; // make sure mem owned vector<BSONObj> _queries; // make sure mem owned
bool _hasAllIndexedRanges;
friend class FieldRangeVectorIterator; friend class FieldRangeVectorIterator;
}; };
/** /**
* Helper class for iterating through an ordered representation of keys * Helper class for iterating through an ordered representation of keys
* to find those keys that match a specified FieldRangeVector. * to find those keys that match a specified FieldRangeVector.
*/ */
class FieldRangeVectorIterator { class FieldRangeVectorIterator {
public: public:
/** /**
skipping to change at line 819 skipping to change at line 894
/** @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;
string getSpecial() const { return _baseSet.getSpecial(); } set<string> 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. 12 change blocks. 
12 lines changed or deleted 111 lines changed or added


 queue.h   queue.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 "mongo/pch.h" #include "mongo/pch.h"
#include <limits> #include <limits>
#include <queue> #include <queue>
#include <boost/thread/condition.hpp>
#include "mongo/util/timer.h" #include "mongo/util/timer.h"
namespace mongo { namespace mongo {
template <typename T> template <typename T>
size_t _getSizeDefault(const T& t) { size_t _getSizeDefault(const T& t) {
return 1; return 1;
} }
/** /**
 End of changes. 1 change blocks. 
0 lines changed or deleted 2 lines changed or added


 race.h   race.h 
skipping to change at line 41 skipping to change at line 41
#endif #endif
#if defined(_DEBUG) #if defined(_DEBUG)
class Block { class Block {
volatile int n; volatile int n;
unsigned ncalls; unsigned ncalls;
const string file; const string file;
const unsigned line; const unsigned line;
void fail() { void fail() {
log() << "\n\n\nrace: synchronization (race condition) fail ure\ncurrent locks this thread (" << getThreadName() << "):\n" log() << "\n\n\nrace: synchronization (race condition) fail ure\ncurrent locks this thread (" << getThreadName() << "):" << endl
<< mutexDebugger.currentlyLocked() << endl; << mutexDebugger.currentlyLocked() << endl;
printStackTrace(); printStackTrace();
::abort(); ::abort();
} }
void enter() { void enter() {
if( ++n != 1 ) fail(); if( ++n != 1 ) fail();
ncalls++; ncalls++;
if( ncalls < 100 ) { if( ncalls < 100 ) {
sleepmillis(0); sleepmillis(0);
} }
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 random.h   random.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
#ifdef _WIN32 #include "mongo/platform/cstdint.h"
#include <cstdint>
#else
#include <inttypes.h>
#endif
#include <cstdlib>
namespace mongo { namespace mongo {
/**
* Uses http://en.wikipedia.org/wiki/Xorshift
*/
class PseudoRandom { class PseudoRandom {
public: public:
PseudoRandom( unsigned seed ) PseudoRandom( int32_t seed );
: _seed( seed ) {
} PseudoRandom( uint32_t seed );
PseudoRandom( int64_t seed );
int32_t nextInt32(); int32_t nextInt32();
int64_t nextInt64();
/** /**
* @return a number between 0 and max * @return a number between 0 and max
*/ */
int32_t nextInt32( int32_t max ) { return nextInt32() % max; } int32_t nextInt32( int32_t max ) { return nextInt32() % max; }
private: private:
unsigned _seed; int32_t _x;
int32_t _y;
int32_t _z;
int32_t _w;
};
/**
* More secure random numbers
* Suitable for nonce/crypto
* Slower than PseudoRandom, so only use when really need
*/
class SecureRandom {
public:
virtual ~SecureRandom();
virtual int64_t nextInt64() = 0;
static SecureRandom* create();
}; };
} }
 End of changes. 5 change blocks. 
11 lines changed or deleted 29 lines changed or added


 redef_macros.h   redef_macros.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.
*/ */
// If you define a new global un-prefixed macro, please add it here and in undef_macros // If you define a new global un-prefixed macro, please add it here and in undef_macros
#define MONGO_MACROS_PUSHED 1 #define MONGO_MACROS_PUSHED 1
// util/allocator.h // util/allocator.h
#ifdef MONGO_MALLOC
#pragma push_macro("malloc") #pragma push_macro("malloc")
#undef malloc #undef malloc
#define malloc MONGO_malloc #define malloc MONGO_malloc
#pragma push_macro("realloc") #pragma push_macro("realloc")
#undef realloc #undef realloc
#define realloc MONGO_realloc #define realloc MONGO_realloc
#endif
// util/assert_util.h // util/assert_util.h
#pragma push_macro("verify") #pragma push_macro("verify")
#undef verify #undef verify
#define verify MONGO_verify #define verify MONGO_verify
#pragma push_macro("dassert") #pragma push_macro("dassert")
#undef dassert #undef dassert
#define dassert MONGO_dassert #define dassert MONGO_dassert
#pragma push_macro("wassert") #pragma push_macro("wassert")
#undef wassert #undef wassert
 End of changes. 2 change blocks. 
0 lines changed or deleted 2 lines changed or added


 repl.h   repl.h 
skipping to change at line 179 skipping to change at line 179
int wait = _sleepAdviceTime - unsigned( time( 0 ) ); int wait = _sleepAdviceTime - unsigned( time( 0 ) );
return wait > 0 ? wait : 0; return wait > 0 ? wait : 0;
} }
static bool throttledForceResyncDead( const char *requester ); static bool throttledForceResyncDead( const char *requester );
static void forceResyncDead( const char *requester ); static void forceResyncDead( const char *requester );
void forceResync( const char *requester ); void forceResync( const char *requester );
}; };
bool anyReplEnabled(); bool anyReplEnabled();
void appendReplicationInfo( BSONObjBuilder& result , bool authed , int level = 0 );
/** /**
* Helper class used to set and query an ignore state for a named datab ase. * Helper class used to set and query an ignore state for a named datab ase.
* The ignore state will expire after a specified OpTime. * The ignore state will expire after a specified OpTime.
*/ */
class DatabaseIgnorer { class DatabaseIgnorer {
public: public:
/** Indicate that operations for 'db' should be ignored until after 'futureOplogTime' */ /** Indicate that operations for 'db' should be ignored until after 'futureOplogTime' */
void doIgnoreUntilAfter( const string &db, const OpTime &futureOplo gTime ); void doIgnoreUntilAfter( const string &db, const OpTime &futureOplo gTime );
/** /**
 End of changes. 1 change blocks. 
1 lines changed or deleted 0 lines changed or added


 replutil.h   replutil.h 
skipping to change at line 40 skipping to change at line 40
/* note we always return true for the "local" namespace. /* note we always return true for the "local" namespace.
we should not allow most operations when not the master we should not allow most operations when not the master
also we report not master if we are "dead". also we report not master if we are "dead".
See also CmdIsMaster. See also CmdIsMaster.
If 'client' is not specified, the current client is used. If 'client' is not specified, the current client is used.
*/ */
inline bool _isMaster() { inline bool _isMaster() {
if ( cc().isGod() )
return true;
if( replSet ) { if( replSet ) {
if( theReplSet ) if( theReplSet )
return theReplSet->isPrimary(); return theReplSet->isPrimary();
return false; return false;
} }
if( ! replSettings.slave ) if( ! replSettings.slave )
return true; return true;
if ( replAllDead ) if ( replAllDead )
return false; return false;
if( replSettings.master ) { if( replSettings.master ) {
// if running with --master --slave, allow. // if running with --master --slave, allow.
return true; return true;
} }
if ( cc().isGod() )
return true;
return false; return false;
} }
inline bool isMaster(const char * dbname = 0) { inline bool isMaster(const char * dbname = 0) {
if( _isMaster() ) if( _isMaster() )
return true; return true;
if ( ! dbname ) { if ( ! dbname ) {
Database *database = cc().database(); Database *database = cc().database();
verify( database ); verify( database );
dbname = database->name.c_str(); dbname = database->name.c_str();
} }
 End of changes. 2 change blocks. 
3 lines changed or deleted 3 lines changed or added


 rs.h   rs.h 
skipping to change at line 341 skipping to change at line 341
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);
/** /**
* 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.
*/ */
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;
void endOldHealthTasks(); void endOldHealthTasks();
void startHealthTaskFor(Member *m); void startHealthTaskFor(Member *m);
Consensus elect; Consensus elect;
void relinquish(); void relinquish();
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 rs_config.h   rs_config.h 
skipping to change at line 173 skipping to change at line 173
/** /**
* Get the timeout to use for heartbeats. * Get the timeout to use for heartbeats.
*/ */
int getHeartbeatTimeout() const; int getHeartbeatTimeout() const;
/** /**
* Default timeout: 10 seconds * Default timeout: 10 seconds
*/ */
static const int DEFAULT_HB_TIMEOUT; static const int DEFAULT_HB_TIMEOUT;
/**
* Returns if replication chaining is allowed.
*/
bool chainingAllowed() const;
private: private:
ReplSetConfig(); ReplSetConfig();
void init(const HostAndPort& h); void init(const HostAndPort& h);
void init(BSONObj cfg, bool force); void init(BSONObj cfg, bool force);
bool _ok; /**
* If replication can be chained. If chaining is disallowed, it can
still be explicitly
* enabled via the replSetSyncFrom command, but it will not happen
automatically.
*/
bool _chainingAllowed;
int _majority; int _majority;
bool _ok;
void from(BSONObj); void from(BSONObj);
void clear(); void clear();
struct TagClause; struct TagClause;
/** /**
* The timeout to use for heartbeats * The timeout to use for heartbeats
*/ */
int _heartbeatTimeout; int _heartbeatTimeout;
 End of changes. 3 change blocks. 
1 lines changed or deleted 13 lines changed or added


 safe_num.h   safe_num.h 
skipping to change at line 26 skipping to change at line 26
#pragma once #pragma once
#include <iosfwd> #include <iosfwd>
#include <string> #include <string>
#include "mongo/bson/bsonelement.h" #include "mongo/bson/bsonelement.h"
#include "mongo/bson/bsonobj.h" #include "mongo/bson/bsonobj.h"
namespace mongo { namespace mongo {
namespace mutablebson {
class Element;
class Document;
}
/** /**
* SafeNum holds and does arithmetic on a number in a safe way, handlin g overflow * SafeNum holds and does arithmetic on a number in a safe way, handlin g overflow
* and casting for the user. 32-bit integers will overflow into 64-bit integers. But * and casting for the user. 32-bit integers will overflow into 64-bit integers. But
* 64-bit integers will NOT overflow to doubles. Also, this class does NOT * 64-bit integers will NOT overflow to doubles. Also, this class does NOT
* downcast. This class should be as conservative as possible about upc asting, but * downcast. This class should be as conservative as possible about upc asting, but
* should never lose precision. * should never lose precision.
* *
* This class does not throw any exceptions, so the user should call ty pe() before * This class does not throw any exceptions, so the user should call ty pe() before
* using a SafeNum to ensure that it is valid. A SafeNum could be inva lid * using a SafeNum to ensure that it is valid. A SafeNum could be inva lid
* from creation (if, for example, a non-numeric BSONElement was passed to the * from creation (if, for example, a non-numeric BSONElement was passed to the
skipping to change at line 107 skipping to change at line 112
* upconvertions and overflow (see class header). * upconvertions and overflow (see class header).
*/ */
SafeNum operator+(const SafeNum& rhs) const; SafeNum operator+(const SafeNum& rhs) const;
SafeNum& operator+=(const SafeNum& rhs); SafeNum& operator+=(const SafeNum& rhs);
// TODO other operations than sum // TODO other operations than sum
// //
// output support // output support
// //
friend class mutablebson::Element;
friend class mutablebson::Document;
// TODO: output to builder // TODO: output to builder
// TODO: output to Paul's class Element
// //
// accessors // accessors
// //
bool isValid() const { return _type != EOO; } bool isValid() const { return _type != EOO; }
BSONType type() const { return _type; } BSONType type() const { return _type; }
std::string debugString() const; std::string debugString() const;
// //
// Below exposed for testing purposes. Treat as private. // Below exposed for testing purposes. Treat as private.
skipping to change at line 158 skipping to change at line 165
static long long getLongLong(const SafeNum& snum); static long long getLongLong(const SafeNum& snum);
/** /**
* Extracts the value of 'snum' in a double format. It assumes 'snu m' is a valid * Extracts the value of 'snum' in a double format. It assumes 'snu m' is a valid
* SafeNum, i.e., that _type is not EOO. * SafeNum, i.e., that _type is not EOO.
*/ */
static double getDouble(const SafeNum& snum); static double getDouble(const SafeNum& snum);
}; };
// Convenience method for unittest code. Please use accessors otherwise . // Convenience method for unittest code. Please use accessors otherwise .
ostream& operator<<(ostream& os, const SafeNum& snum); std::ostream& operator<<(std::ostream& os, const SafeNum& snum);
} // namespace mongo } // namespace mongo
 End of changes. 4 change blocks. 
2 lines changed or deleted 9 lines changed or added


 security.h   security.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 <string> #include <string>
#include "mongo/db/nonce.h"
#include "mongo/db/security_common.h" #include "mongo/db/security_common.h"
#include "mongo/client/authentication_table.h" #include "mongo/client/authentication_table.h"
#include "mongo/client/authlevel.h" #include "mongo/client/authlevel.h"
#include "mongo/util/concurrency/spin_lock.h" #include "mongo/util/concurrency/spin_lock.h"
// this is used by both mongos and mongod // this is used by both mongos and mongod
namespace mongo { namespace mongo {
/** An AuthenticationInfo object is present within every mongo::Client object */ /** An AuthenticationInfo object is present within every mongo::Client object */
skipping to change at line 47 skipping to change at line 46
public: public:
void startRequest(); // need to call at the beginning of each reque st void startRequest(); // need to call at the beginning of each reque st
void setIsALocalHostConnectionWithSpecialAuthPowers(); // called, i f localhost, when conneciton established. void setIsALocalHostConnectionWithSpecialAuthPowers(); // called, i f localhost, when conneciton established.
AuthenticationInfo() { AuthenticationInfo() {
_isLocalHost = false; _isLocalHost = false;
_isLocalHostAndLocalHostIsAuthorizedForAll = false; _isLocalHostAndLocalHostIsAuthorizedForAll = false;
_usingTempAuth = false; _usingTempAuth = false;
} }
~AuthenticationInfo() {} ~AuthenticationInfo() {}
bool isLocalHost() const { return _isLocalHost; } // why are you ca lling this? makes no sense to be externalized bool isLocalHost() const { return _isLocalHost; } // why are you ca lling this? makes no sense to be externalized
bool isSpecialLocalhostAdmin() const;
// -- modifiers ---- // -- modifiers ----
void logout(const std::string& dbname ) { void logout(const std::string& dbname ) {
scoped_spinlock lk(_lock); scoped_spinlock lk(_lock);
_authTable.removeAuth( dbname ); _authTable.removeAuth( dbname );
} }
void authorize(const std::string& dbname , const std::string& user ) { void authorize(const std::string& dbname , const std::string& user ) {
scoped_spinlock lk(_lock); scoped_spinlock lk(_lock);
_authTable.addAuth( dbname, user, Auth::WRITE ); _authTable.addAuth( dbname, user, Auth::WRITE );
 End of changes. 2 change blocks. 
1 lines changed or deleted 1 lines changed or added


 shard.h   shard.h 
skipping to change at line 102 skipping to change at line 102
string toString() const { string toString() const {
return _name + ":" + _addr; return _name + ":" + _addr;
} }
friend ostream& operator << (ostream& out, const Shard& s) { friend ostream& operator << (ostream& out, const Shard& s) {
return (out << s.toString()); return (out << s.toString());
} }
bool operator==( const Shard& s ) const { bool operator==( const Shard& s ) const {
bool n = _name == s._name; if ( _name != s._name )
bool a = _addr == s._addr; return false;
return _cs.sameLogicalEndpoint( s._cs );
verify( n == a ); // names and address are 1 to 1
return n;
} }
bool operator!=( const Shard& s ) const { bool operator!=( const Shard& s ) const {
bool n = _name == s._name; return ! ( *this == s );
bool a = _addr == s._addr;
return ! ( n && a );
} }
bool operator==( const string& s ) const { bool operator==( const string& s ) const {
return _name == s || _addr == s; return _name == s || _addr == s;
} }
bool operator!=( const string& s ) const { bool operator!=( const string& s ) const {
return _name != s && _addr != s; return _name != s && _addr != s;
} }
skipping to change at line 176 skipping to change at line 172
void _setAddr( const string& addr ); void _setAddr( const string& addr );
string _name; string _name;
string _addr; string _addr;
ConnectionString _cs; ConnectionString _cs;
long long _maxSize; // in MBytes, 0 is unlimited long long _maxSize; // in MBytes, 0 is unlimited
bool _isDraining; // shard is currently being removed bool _isDraining; // shard is currently being removed
set<string> _tags; set<string> _tags;
}; };
typedef shared_ptr<Shard> ShardPtr;
class ShardStatus { class ShardStatus {
public: public:
ShardStatus( const Shard& shard , const BSONObj& obj ); ShardStatus( const Shard& shard , const BSONObj& obj );
friend ostream& operator << (ostream& out, const ShardStatus& s) { friend ostream& operator << (ostream& out, const ShardStatus& s) {
out << s.toString(); out << s.toString();
return out; return out;
} }
skipping to change at line 291 skipping to change at line 288
bool ok() const { return _conn > 0; } bool ok() const { return _conn > 0; }
/** /**
this just passes through excpet it checks for stale configs this just passes through excpet it checks for stale configs
*/ */
bool runCommand( const string& db , const BSONObj& cmd , BSONObj& r es ); bool runCommand( const string& db , const BSONObj& cmd , BSONObj& r es );
/** checks all of my thread local connections for the version of th is ns */ /** checks all of my thread local connections for the version of th is ns */
static void checkMyConnectionVersions( const string & ns ); static void checkMyConnectionVersions( const string & ns );
/**
* Clears all connections in the sharded pool, including connection
s in the
* thread local storage pool of the current thread.
*/
static void clearPool();
private: private:
void _init(); void _init();
void _finishInit(); void _finishInit();
bool _finishedInit; bool _finishedInit;
string _addr; string _addr;
string _ns; string _ns;
ChunkManagerPtr _manager; ChunkManagerPtr _manager;
 End of changes. 4 change blocks. 
8 lines changed or deleted 12 lines changed or added


 sock.h   sock.h 
skipping to change at line 40 skipping to change at line 40
#include <errno.h> #include <errno.h>
#ifdef __openbsd__ #ifdef __openbsd__
# include <sys/uio.h> # include <sys/uio.h>
#endif #endif
#endif // _WIN32 #endif // _WIN32
#ifdef MONGO_SSL #ifdef MONGO_SSL
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include "mongo/util/net/ssl_manager.h"
#endif #endif
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)
skipping to change at line 169 skipping to change at line 170
case FAILED_STATE: return "FAILED_STATE"; case FAILED_STATE: return "FAILED_STATE";
case CONNECT_ERROR: return "CONNECT_ERROR"; case CONNECT_ERROR: return "CONNECT_ERROR";
default: return "UNKNOWN"; // should never happe n default: return "UNKNOWN"; // should never happe n
} }
} }
string _server; string _server;
string _extra; string _extra;
}; };
#ifdef MONGO_SSL
class SSLManager : boost::noncopyable {
public:
SSLManager( bool client );
/** @return true if was successful, otherwise false */
bool setupPEM( const string& keyFile , const string& password );
void setupPubPriv( const string& privateKeyFile , const string& pub
licKeyFile );
/**
* creates an SSL context to be used for this file descriptor
* caller should delete
*/
SSL * secure( int fd );
static int password_cb( char *buf,int num, int rwflag,void *userdat
a );
private:
bool _client;
SSL_CTX* _context;
string _password;
};
#endif
/** /**
* thin wrapped around file descriptor and system calls * thin wrapped around file descriptor and system calls
* todo: ssl * todo: ssl
*/ */
class Socket : boost::noncopyable { class Socket : boost::noncopyable {
public: public:
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
skipping to change at line 248 skipping to change at line 225
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 * call this after a fork for server sockets
*/ */
void postFork(); void postFork();
/**
* @return the time when the socket was opened.
*/
uint64_t getSockCreationMicroSec() const {
return _fdCreationMicroSec;
}
private: private:
void _init(); void _init();
/** raw send, same semantics as ::send */ /** raw send, same semantics as ::send */
public: public:
int _send( const char * data , int len ); int _send( const char * data , int len );
private: 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 recv, same semantics as ::recv */ /** raw recv, same semantics as ::recv */
int _recv( char * buf , int max ); int _recv( char * buf , int max );
int _fd; int _fd;
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;
SSLManager * _sslAccepted; SSLManager * _sslAccepted;
#endif #endif
 End of changes. 4 change blocks. 
26 lines changed or deleted 9 lines changed or added


 stats.h   stats.h 
skipping to change at line 28 skipping to change at line 28
#pragma once #pragma once
#include "mongo/pch.h" #include "mongo/pch.h"
#include "../db/stats/counters.h" #include "../db/stats/counters.h"
namespace mongo { namespace mongo {
extern OpCounters opsNonSharded; extern OpCounters opsNonSharded;
extern OpCounters opsSharded; extern OpCounters opsSharded;
extern GenericCounter shardedCursorTypes;
} }
 End of changes. 1 change blocks. 
2 lines changed or deleted 0 lines changed or added


 status.h   status.h 
skipping to change at line 85 skipping to change at line 85
* Otherwise returns false. * Otherwise returns false.
*/ */
bool compareCode(const ErrorCodes::Error other) const; bool compareCode(const ErrorCodes::Error other) const;
bool operator==(const ErrorCodes::Error other) const; bool operator==(const ErrorCodes::Error other) const;
bool operator!=(const ErrorCodes::Error other) const; bool operator!=(const ErrorCodes::Error other) const;
// //
// accessors // accessors
// //
bool isOK() const { return code() == ErrorCodes::OK; }
ErrorCodes::Error code() const { return _error->code; } ErrorCodes::Error code() const { return _error->code; }
const char* codeString() const { return ErrorCodes::errorString(_er ror->code); } const char* codeString() const { return ErrorCodes::errorString(_er ror->code); }
const std::string& reason() const { return _error->reason; } const std::string& reason() const { return _error->reason; }
int location() const { return _error->location; } int location() const { return _error->location; }
// //
// Below interface used for testing code only. // Below interface used for testing code only.
// //
int refCount() const { return _error->refs.load(); } int refCount() const { return _error->refs.load(); }
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 string_data.h   string_data.h 
skipping to change at line 18 skipping to change at line 18
* *
* 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 <cstring> #include <cstring>
#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*' with /**
out * A StringData object wraps a 'const string&' or a 'const char*' witho
* copying its contents. The most common usage is as a function argumen ut copying its
t that * contents. The most common usage is as a function argument that takes
* takes any of the two forms of strings above. Fundamentally, this cla any of the two
ss tries * forms of strings above. Fundamentally, this class tries go around th
* go around the fact that string literals in C++ are char[N]'s. e fact that string
* literals in C++ are char[N]'s.
* *
* Note that the object StringData wraps around must be alive while the * Notes:
StringData *
* is. * + The object StringData wraps around must be alive while the String
*/ Data is.
*
* + Because strings accept null characters, we allow them in StringDa
ta. But this use is
* *strongly* discouraged. One problem this case may encounter is wh
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:
/** Construct a StringData, for the case where the length of
* string is not known. 'c' must be a pointer to a null-terminated /**
string. * Constructs a StringData, for the case where the length of string
is not known. 'c'
* 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(string::npos){}
/** Construct a StringData explicitly, for the case where the lengt /**
h of the string * Constructs a StringData explicitly, for the case where the lengt
* is already known. 'c' must be a pointer to a null-terminated str h of the string is
ing, and strlenOfc * already known. 'c' must be a pointer to a null-terminated string
* must be the length that strlen(c) would return, a.k.a the index , and strlenOfc must
of the * be the length that strlen(c) would return, a.k.a the index of th
* terminator in c. 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) {}
/** Construct a StringData, for the case of a string. */ /** Constructs a StringData, for the case of a string. */
StringData( const std::string& s ) StringData( const std::string& s )
: _data(s.c_str()), _size(s.size()) {} : _data(s.c_str()), _size(s.size()) {}
// Construct a StringData explicitly, for the case of a literal who /**
se size is * Constructs a StringData explicitly, for the case of a literal wh
// known at compile time. ose size is known at
* compile time.
*/
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
* lexicographical order.
*/
int compare(const StringData& other) const {
// Sizes might not have been computed yet.
size();
other.size();
int res = memcmp(_data, other._data, std::min(_size, other._siz
e));
if (res != 0) {
return res > 0 ? 1 : -1;
}
else if (_size == other._size) {
return 0;
}
else {
return _size > other._size ? 1 : -1;
}
}
//
// accessors // accessors
//
const char* data() const { return _data; } const char* data() const { return _data; }
size_t size() const { size_t size() const { fillSize(); return _size; }
if ( _size == string::npos ) bool empty() const { return size() == 0; }
_size = strlen( _data ); string toString() const { return string(data(), size()); }
return _size;
}
private: private:
const char* const _data; // is always null terminated const char* const _data; // is always null terminated, but see "no
mutable size_t _size; // 'size' does not include the null terminat tes" above
or mutable size_t _size; // 'size' does not include the null termi
nator
void fillSize() const {
if (_size == string::npos) {
_size = strlen(_data);
}
}
}; };
inline bool operator==(const StringData& lhs, const StringData& rhs) {
return lhs.compare(rhs) == 0;
}
inline bool operator!=(const StringData& lhs, const StringData& rhs) {
return lhs.compare(rhs) != 0;
}
inline bool operator<(const StringData& lhs, const StringData& rhs) {
return lhs.compare(rhs) < 0 ;
}
inline bool operator<=(const StringData& lhs, const StringData& rhs) {
return lhs.compare(rhs) <= 0;
}
inline bool operator>(const StringData& lhs, const StringData& rhs) {
return lhs.compare(rhs) > 0;
}
inline bool operator>=(const StringData& lhs, const StringData& rhs) {
return lhs.compare(rhs) >= 0;
}
} // namespace mongo } // namespace mongo
 End of changes. 12 change blocks. 
33 lines changed or deleted 103 lines changed or added


 time_support.h   time_support.h 
skipping to change at line 31 skipping to change at line 31
#include <string> #include <string>
#include <boost/thread/xtime.hpp> #include <boost/thread/xtime.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
#include "mongo/bson/util/misc.h" // Date_t #include "mongo/bson/util/misc.h" // Date_t
namespace mongo { namespace mongo {
void time_t_to_Struct(time_t t, struct tm * buf , bool local = false ); void time_t_to_Struct(time_t t, struct tm * buf , bool local = false );
/**
* Gets the current time string (in fixed width) in UTC. Sample format:
*
* Wed Oct 31 13:34:47.996
*
* @param timeStr pointer to the buffer to set the string - should at l
east be
* 24 bytes big.
*/
void curTimeString(char* timeStr);
// uses ISO 8601 dates without trailing Z // uses ISO 8601 dates without trailing Z
// colonsOk should be false when creating filenames // colonsOk should be false when creating filenames
std::string terseCurrentTime(bool colonsOk=true); std::string terseCurrentTime(bool colonsOk=true);
std::string timeToISOString(time_t time); std::string timeToISOString(time_t time);
boost::gregorian::date currentDate(); boost::gregorian::date currentDate();
// parses time of day in "hh:mm" format assuming 'hh' is 00-23 // parses time of day in "hh:mm" format assuming 'hh' is 00-23
bool toPointInTime( const std::string& str , boost::posix_time::ptime* timeOfDay ); bool toPointInTime( const std::string& str , boost::posix_time::ptime* timeOfDay );
 End of changes. 1 change blocks. 
0 lines changed or deleted 11 lines changed or added


 timer-win32-inl.h   timer-win32-inl.h 
skipping to change at line 31 skipping to change at line 31
* measuring time at high resolution. This may be the HPET of the TSC on x 86 systems, * measuring time at high resolution. This may be the HPET of the TSC on x 86 systems,
* but is promised to be synchronized across processors, barring BIOS error s. * but is promised to be synchronized across processors, barring BIOS error s.
* *
* Do not include directly. Include "mongo/util/timer.h". * Do not include directly. Include "mongo/util/timer.h".
*/ */
#pragma once #pragma once
#define MONGO_TIMER_IMPL_WIN32 #define MONGO_TIMER_IMPL_WIN32
#include "mongo/platform/windows_basic.h"
#include "mongo/util/assert_util.h" #include "mongo/util/assert_util.h"
namespace mongo { namespace mongo {
unsigned long long Timer::now() const { unsigned long long Timer::now() const {
LARGE_INTEGER i; LARGE_INTEGER i;
fassert(16161, QueryPerformanceCounter(&i)); fassert(16161, QueryPerformanceCounter(&i));
return i.QuadPart; return i.QuadPart;
} }
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 undef_macros.h   undef_macros.h 
skipping to change at line 25 skipping to change at line 25
* limitations under the License. * limitations under the License.
*/ */
// If you define a new global un-prefixed macro, please add it here and in redef_macros // If you define a new global un-prefixed macro, please add it here and in redef_macros
// #pragma once // this file is intended to be processed multiple times // #pragma once // this file is intended to be processed multiple times
#ifdef MONGO_MACROS_PUSHED #ifdef MONGO_MACROS_PUSHED
// util/allocator.h // util/allocator.h
#ifdef MONGO_MALLOC
#undef malloc #undef malloc
#pragma pop_macro("malloc") #pragma pop_macro("malloc")
#undef realloc #undef realloc
#pragma pop_macro("realloc") #pragma pop_macro("realloc")
#endif
// util/assert_util.h // util/assert_util.h
#undef dassert #undef dassert
#pragma pop_macro("dassert") #pragma pop_macro("dassert")
#undef wassert #undef wassert
#pragma pop_macro("wassert") #pragma pop_macro("wassert")
#undef massert #undef massert
#pragma pop_macro("massert") #pragma pop_macro("massert")
#undef uassert #undef uassert
#pragma pop_macro("uassert") #pragma pop_macro("uassert")
 End of changes. 2 change blocks. 
0 lines changed or deleted 2 lines changed or added


 unittest.h   unittest.h 
skipping to change at line 23 skipping to change at line 23
* 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/>.
*/ */
/* /*
* A C++ unit testing framework. * A C++ unit testing framework.
* *
* For examples of basic usage, see mongo/unittest/unittest_test.cpp. * For examples of basic usage, see mongo/unittest/unittest_test.cpp.
*/ */
#pragma once
#include <cmath>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
skipping to change at line 44 skipping to change at line 47
#include "mongo/util/mongoutils/str.h" #include "mongo/util/mongoutils/str.h"
/** /**
* Fail unconditionally, reporting the given message. * Fail unconditionally, reporting the given message.
*/ */
#define FAIL(MESSAGE) ::mongo::unittest::TestAssertion( __FILE__ , __LINE__ ).fail( (MESSAGE) ) #define FAIL(MESSAGE) ::mongo::unittest::TestAssertion( __FILE__ , __LINE__ ).fail( (MESSAGE) )
/** /**
* Fails unless "EXPRESSION" is true. * Fails unless "EXPRESSION" is true.
*/ */
#define ASSERT_TRUE(EXPRESSION) ::mongo::unittest::TestAssertion( __FILE__, #define ASSERT_TRUE(EXPRESSION) ::mongo::unittest::TestAssertion( __FILE__,
__LINE__ ).failUnless( \ __LINE__ ).failIf( \
(EXPRESSION), "Expected: " #EXPRESSION ) !(EXPRESSION), "Expected: " #EXPRESSION )
#define ASSERT(EXPRESSION) ASSERT_TRUE(EXPRESSION) #define ASSERT(EXPRESSION) ASSERT_TRUE(EXPRESSION)
/** /**
* Assert that a Status code is OK.
*/
#define ASSERT_OK(EXPRESSION) ASSERT_EQUALS(Status::OK(), (EXPRESSION))
/**
* Fails if "EXPRESSION" is true. * Fails if "EXPRESSION" is true.
*/ */
#define ASSERT_FALSE(EXPRESSION) ::mongo::unittest::TestAssertion( __FILE__ , __LINE__ ).failIf( \ #define ASSERT_FALSE(EXPRESSION) ::mongo::unittest::TestAssertion( __FILE__ , __LINE__ ).failIf( \
(EXPRESSION), "Expected: !(" #EXPRESSION ")" ) (EXPRESSION), "Expected: !(" #EXPRESSION ")" )
/* /*
* Binary comparison assertions. * Binary comparison assertions.
*/ */
#define ASSERT_EQUALS(a,b) _ASSERT_COMPARISON(Equal, a, b) #define ASSERT_EQUALS(a,b) _ASSERT_COMPARISON(Equal, a, b)
#define ASSERT_NOT_EQUALS(a,b) _ASSERT_COMPARISON(NotEqual, a, b) #define ASSERT_NOT_EQUALS(a,b) _ASSERT_COMPARISON(NotEqual, a, b)
skipping to change at line 73 skipping to change at line 81
#define ASSERT_LESS_THAN_OR_EQUALS(a, b) ASSERT_NOT_GREATER_THAN(a, b) #define ASSERT_LESS_THAN_OR_EQUALS(a, b) ASSERT_NOT_GREATER_THAN(a, b)
#define ASSERT_GREATER_THAN_OR_EQUALS(a, b) ASSERT_NOT_LESS_THAN(a, b) #define ASSERT_GREATER_THAN_OR_EQUALS(a, b) ASSERT_NOT_LESS_THAN(a, b)
/** /**
* Binary comparison utility macro. Do not use directly. * Binary comparison utility macro. Do not use directly.
*/ */
#define _ASSERT_COMPARISON(COMPARISON, a, b) mongo::unittest::ComparisonAss ertion( \ #define _ASSERT_COMPARISON(COMPARISON, a, b) mongo::unittest::ComparisonAss ertion( \
#a, #b , __FILE__ , __LINE__ ).assert##COMPARISON( (a), (b) ) #a, #b , __FILE__ , __LINE__ ).assert##COMPARISON( (a), (b) )
/** /**
* Approximate equality assertion. Useful for comparisons on limited precis
ion floating point
* values.
*/
#define ASSERT_APPROX_EQUAL(a,b,ABSOLUTE_ERR) ::mongo::unittest::assertAppr
oxEqual( \
#a, #b, a, b, ABSOLUTE_ERR, __FILE__, __LINE__)
/**
* Verify that the evaluation of "EXPRESSION" throws an exception of type E XCEPTION_TYPE. * Verify that the evaluation of "EXPRESSION" throws an exception of type E XCEPTION_TYPE.
* *
* If "EXPRESSION" throws no exception, or one that is neither of type "EXC EPTION_TYPE" nor * If "EXPRESSION" throws no exception, or one that is neither of type "EXC EPTION_TYPE" nor
* of a subtype of "EXCEPTION_TYPE", the test is considered a failure and f urther evaluation * of a subtype of "EXCEPTION_TYPE", the test is considered a failure and f urther evaluation
* halts. * halts.
*/ */
#define ASSERT_THROWS(EXPRESSION, EXCEPTION_TYPE) \ #define ASSERT_THROWS(EXPRESSION, EXCEPTION_TYPE) \
do { \ do { \
bool threw = false; \ bool threw = false; \
::mongo::unittest::TestAssertion _testAssertion( __FILE__, __LINE__ ); \ ::mongo::unittest::TestAssertion _testAssertion( __FILE__, __LINE__ ); \
skipping to change at line 337 skipping to change at line 352
class TestAssertion : private boost::noncopyable { class TestAssertion : private boost::noncopyable {
public: public:
TestAssertion( const std::string& file, unsigned line ); TestAssertion( const std::string& file, unsigned line );
~TestAssertion(); ~TestAssertion();
void fail( const std::string& message) const; void fail( const std::string& message) const;
void failIf( bool flag, const std::string &message ) const { void failIf( bool flag, const std::string &message ) const {
if ( flag ) fail( message ); if ( flag ) fail( message );
} }
void failUnless( bool flag, const std::string& message ) const
{
failIf( !flag, message );
}
private: private:
const std::string _file; const std::string _file;
const unsigned _line; const unsigned _line;
}; };
/** /**
* Specialization of TestAssertion for binary comparisons. * Specialization of TestAssertion for binary comparisons.
*/ */
class ComparisonAssertion : private TestAssertion { class ComparisonAssertion : private TestAssertion {
public: public:
ComparisonAssertion( const std::string& aexp , const std::strin g& bexp , ComparisonAssertion( const std::string& aexp , const std::strin g& bexp ,
const std::string& file , unsigned line ); const std::string& file , unsigned line );
template<typename A,typename B> template<typename A,typename B>
void assertEqual( const A& a , const B& b ) { void assertEqual( const A& a , const B& b ) {
failUnless(a == b, getComparisonFailureMessage("==", a, b)) if ( a == b )
; return;
fail(getComparisonFailureMessage("==", a, b));
} }
template<typename A,typename B> template<typename A,typename B>
void assertNotEqual( const A& a , const B& b ) { void assertNotEqual( const A& a , const B& b ) {
failUnless(a != b, getComparisonFailureMessage("!=", a, b)) if ( a != b )
; return;
fail(getComparisonFailureMessage("!=", a, b));
} }
template<typename A,typename B> template<typename A,typename B>
void assertLessThan( const A& a , const B& b ) { void assertLessThan( const A& a , const B& b ) {
failUnless(a < b, getComparisonFailureMessage("<", a, b)); if ( a < b )
return;
fail(getComparisonFailureMessage("<", a, b));
} }
template<typename A,typename B> template<typename A,typename B>
void assertNotLessThan( const A& a , const B& b ) { void assertNotLessThan( const A& a , const B& b ) {
failUnless(a >= b, getComparisonFailureMessage(">=", a, b)) if ( a >= b )
; return;
fail(getComparisonFailureMessage(">=", a, b));
} }
template<typename A,typename B> template<typename A,typename B>
void assertGreaterThan( const A& a , const B& b ) { void assertGreaterThan( const A& a , const B& b ) {
failUnless(a > b, getComparisonFailureMessage(">", a, b)); if ( a > b )
return;
fail(getComparisonFailureMessage(">", a, b));
} }
template<typename A,typename B> template<typename A,typename B>
void assertNotGreaterThan( const A& a , const B& b ) { void assertNotGreaterThan( const A& a , const B& b ) {
failUnless(a <= b, getComparisonFailureMessage("<=", a, b)) if ( a <= b )
; return;
fail(getComparisonFailureMessage("<=", a, b));
} }
private: private:
template< typename A, typename B> template< typename A, typename B>
std::string getComparisonFailureMessage(const std::string &theO perator, std::string getComparisonFailureMessage(const std::string &theO perator,
const A& a, const B& b) ; const A& a, const B& b) ;
std::string _aexp; std::string _aexp;
std::string _bexp; std::string _bexp;
}; };
/** /**
* Helper for ASSERT_APPROX_EQUAL to ensure that the arguments are
evaluated only once.
*/
template < typename A, typename B, typename ABSOLUTE_ERR >
inline void assertApproxEqual(const std::string& aexp, const std::s
tring& bexp,
const A& a, const B& b, const ABSOLUT
E_ERR& absoluteErr,
const std::string& file , unsigned li
ne) {
if (std::abs(a - b) <= absoluteErr)
return;
TestAssertion(file, line).fail(mongoutils::str::stream()
<< "Expected " << aexp << " and " << bexp << " to be wi
thin " << absoluteErr
<< " of each other ((" << a << ") - (" << b << ") = " <
< (a - b) << ")");
}
/**
* Hack to support the runaway test observer in dbtests. This is a hook that * Hack to support the runaway test observer in dbtests. This is a hook that
* unit test running harnesses (unittest_main and dbtests) must imp lement. * unit test running harnesses (unittest_main and dbtests) must imp lement.
*/ */
void onCurrentTestNameChange( const std::string& testName ); void onCurrentTestNameChange( const std::string& testName );
/** /**
* Return a list of suite names. * Return a list of suite names.
*/ */
std::vector<std::string> getAllSuiteNames(); std::vector<std::string> getAllSuiteNames();
 End of changes. 12 change blocks. 
17 lines changed or deleted 58 lines changed or added


 unordered_map.h   unordered_map.h 
skipping to change at line 18 skipping to change at line 18
* *
* 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(_MSC_VER) && _MSC_VER >= 1500 // NOTE(acm): Before gcc-4.7, __cplusplus is always defined to be 1,
// so we can't reliably detect C++11 support by exclusively checking
// the value of __cplusplus.
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
#include <unordered_map>
namespace mongo {
using std::unordered_map;
} // namespace mongo
#elif defined(_MSC_VER) && _MSC_VER >= 1500
#include <unordered_map> #include <unordered_map>
namespace mongo { namespace mongo {
#if _MSC_VER >= 1600 /* Visual Studio 2010+ */ #if _MSC_VER >= 1600 /* Visual Studio 2010+ */
using std::unordered_map; using std::unordered_map;
#else #else
using std::tr1::unordered_map; using std::tr1::unordered_map;
#endif #endif
 End of changes. 1 change blocks. 
1 lines changed or deleted 14 lines changed or added


 unordered_set.h   unordered_set.h 
skipping to change at line 18 skipping to change at line 18
* *
* 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(_MSC_VER) && _MSC_VER >= 1500 // NOTE(acm): Before gcc-4.7, __cplusplus is always defined to be 1,
// so we can't reliably detect C++11 support by exclusively checking
// the value of __cplusplus.
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
#include <unordered_set>
namespace mongo {
using std::unordered_set;
} // namespace mongo
#elif defined(_MSC_VER) && _MSC_VER >= 1500
#include <unordered_set> #include <unordered_set>
namespace mongo { namespace mongo {
#if _MSC_VER >= 1600 /* Visual Studio 2010+ */ #if _MSC_VER >= 1600 /* Visual Studio 2010+ */
using std::unordered_set; using std::unordered_set;
#else #else
using std::tr1::unordered_set; using std::tr1::unordered_set;
#endif #endif
 End of changes. 1 change blocks. 
1 lines changed or deleted 14 lines changed or added


 util.h   util.h 
// util.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 "mongo/pch.h" #include "mongo/pch.h"
#include "mongo/db/jsobj.h" #include "mongo/db/jsobj.h"
#include "mongo/util/mongoutils/str.h" #include "mongo/util/mongoutils/str.h"
/** /**
some generic sharding utils that can be used in mongod or mongos some generic sharding utils that can be used in mongod or mongos
*/ */
namespace mongo { namespace mongo {
// //
// ShardChunkVersions consist of a major/minor version scoped to a vers ion epoch // ShardChunkVersions consist of a major/minor version scoped to a vers ion epoch
// //
struct ShardChunkVersion { struct ShardChunkVersion {
skipping to change at line 235 skipping to change at line 235
return fromBSON( obj, prefix, &canParse ); return fromBSON( obj, prefix, &canParse );
} }
static ShardChunkVersion fromBSON( const BSONObj& obj, static ShardChunkVersion fromBSON( const BSONObj& obj,
const string& prefixIn, const string& prefixIn,
bool* canParse ) bool* canParse )
{ {
*canParse = true; *canParse = true;
string prefix = prefixIn; string prefix = prefixIn;
// "version" doesn't have a "cluster constanst" because that fi
eld is never
// written to the config.
if( prefixIn == "" && ! obj[ "version" ].eoo() ){ if( prefixIn == "" && ! obj[ "version" ].eoo() ){
prefix = (string)"version"; prefix = (string)"version";
} }
else if( prefixIn == "" && ! obj[ "lastmod" ].eoo() ){ /// TODO: use ChunkFields::lastmod()
else if( prefixIn == "" && ! obj["lastmod"].eoo() ){
prefix = (string)"lastmod"; prefix = (string)"lastmod";
} }
ShardChunkVersion version = fromBSON( obj[ prefix ], prefixIn, canParse ); ShardChunkVersion version = fromBSON( obj[ prefix ], prefixIn, canParse );
if( obj[ prefix + "Epoch" ].type() == jstOID ){ if( obj[ prefix + "Epoch" ].type() == jstOID ){
version._epoch = obj[ prefix + "Epoch" ].OID(); version._epoch = obj[ prefix + "Epoch" ].OID();
*canParse = true; *canParse = true;
} }
 End of changes. 5 change blocks. 
3 lines changed or deleted 7 lines changed or added


 v8_db.h   v8_db.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 <v8.h> #include <boost/function.hpp>
#include <cstring>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring>
#include <v8.h>
#include "engine_v8.h" #include "mongo/scripting/engine_v8.h"
namespace mongo { namespace mongo {
class DBClientBase; class DBClientBase;
// These functions may depend on the caller creating a handle scope and context scope. // These functions may depend on the caller creating a handle scope and context scope.
v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate( V8Scope * sc ope, bool local ); 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::ObjectTemplate>& global );
void installDBTypes( V8Scope * scope, v8::Handle<v8::Object>& global ); void installDBTypes( V8Scope * scope, v8::Handle<v8::Object>& global );
// the actual globals // the actual globals
skipping to change at line 93 skipping to change at line 94
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& args ); v8::Handle<v8::Value> dbQueryInit( V8Scope* scope, const v8::Arguments& args );
v8::Handle<v8::Value> dbQueryIndexAccess( ::uint32_t index , const v8:: AccessorInfo& info ); v8::Handle<v8::Value> dbQueryIndexAccess( ::uint32_t index , const v8:: AccessorInfo& info );
v8::Handle<v8::Value> collectionGetter( v8::Local<v8::String> name, con st v8::AccessorInfo &info); v8::Handle<v8::Value> collectionGetter( v8::Local<v8::String> name, con st v8::AccessorInfo &info);
v8::Handle<v8::Value> collectionSetter( Local<v8::String> name, Local<V alue> value, const AccessorInfo& info ); v8::Handle<v8::Value> collectionSetter( Local<v8::String> name, Local<V alue> value, const AccessorInfo& info );
v8::Handle<v8::Value> bsonsize( V8Scope* scope, const v8::Arguments& ar gs ); v8::Handle<v8::Value> bsonsize( V8Scope* scope, const v8::Arguments& ar gs );
typedef boost::function<void (V8Scope*, const v8::Handle<v8::FunctionTe
mplate>&)>
V8FunctionPrototypeManipulatorFn;
void v8RegisterMongoPrototypeManipulator(const V8FunctionPrototypeManip
ulatorFn& manipulator);
} }
 End of changes. 4 change blocks. 
3 lines changed or deleted 9 lines changed or added


 v8_utils.h   v8_utils.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 <v8.h>
#include <cstring>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <assert.h>
#include <iostream> #include <iostream>
#include <string>
#include <v8.h>
namespace mongo { namespace mongo {
void ReportException(v8::TryCatch* handler); void ReportException(v8::TryCatch* handler);
#define jsassert(x,msg) verify(x) #define jsassert(x,msg) verify(x)
std::ostream& operator<<( std::ostream &s, const v8::Handle<v8::Value> & o ); std::ostream& operator<<( std::ostream &s, const v8::Handle<v8::Value> & o );
std::ostream& operator<<( std::ostream &s, const v8::Handle<v8::TryCatc h> * try_catch ); std::ostream& operator<<( std::ostream &s, const v8::Handle<v8::TryCatc h> * try_catch );
 End of changes. 3 change blocks. 
4 lines changed or deleted 2 lines changed or added


 v8_wrapper.h   v8_wrapper.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 <v8.h> #include <v8.h>
#include <cstring>
#include <cstdio> #include "mongo/db/jsobj.h"
#include <cstdlib> #include "mongo/scripting/engine_v8.h"
#include "../db/jsobj.h"
#include "engine_v8.h"
namespace mongo { namespace mongo {
v8::Handle<v8::FunctionTemplate> getObjectWrapperTemplate(V8Scope* scop e); v8::Handle<v8::FunctionTemplate> getObjectWrapperTemplate(V8Scope* scop e);
class WrapperHolder; class WrapperHolder;
WrapperHolder * createWrapperHolder( V8Scope* scope, const BSONObj * o WrapperHolder* createWrapperHolder(V8Scope* scope,
, bool readOnly , bool iDelete ); const BSONObj* o,
bool readOnly,
bool iDelete);
} }
 End of changes. 2 change blocks. 
8 lines changed or deleted 7 lines changed or added


 valgrind.h   valgrind.h 
skipping to change at line 15 skipping to change at line 15
file (valgrind.h) only. The rest of Valgrind is licensed under the file (valgrind.h) only. The rest of Valgrind is licensed under the
terms of the GNU General Public License, version 2, unless terms of the GNU General Public License, version 2, unless
otherwise indicated. See the COPYING file in the source otherwise indicated. See the COPYING file in the source
distribution for details. distribution for details.
---------------------------------------------------------------- ----------------------------------------------------------------
This file is part of Valgrind, a dynamic binary instrumentation This file is part of Valgrind, a dynamic binary instrumentation
framework. framework.
Copyright (C) 2000-2008 Julian Seward. All rights reserved. Copyright (C) 2000-2010 Julian Seward. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions modification, are permitted provided that the following conditions
are met: are met:
1. Redistributions of source code must retain the above copyright 1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer. notice, this list of conditions and the following disclaimer.
2. The origin of this software must not be misrepresented; you must 2. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this not claim that you wrote the original software. If you use this
skipping to change at line 75 skipping to change at line 75
unchanged. When not running on valgrind, each client request unchanged. When not running on valgrind, each client request
consumes very few (eg. 7) instructions, so the resulting performance consumes very few (eg. 7) instructions, so the resulting performance
loss is negligible unless you plan to execute client requests loss is negligible unless you plan to execute client requests
millions of times per second. Nevertheless, if that is still a millions of times per second. Nevertheless, if that is still a
problem, you can compile with the NVALGRIND symbol defined (gcc problem, you can compile with the NVALGRIND symbol defined (gcc
-DNVALGRIND) so that client requests are not even compiled in. */ -DNVALGRIND) so that client requests are not even compiled in. */
#ifndef __VALGRIND_H #ifndef __VALGRIND_H
#define __VALGRIND_H #define __VALGRIND_H
/* ------------------------------------------------------------------ */
/* VERSION NUMBER OF VALGRIND */
/* ------------------------------------------------------------------ */
/* Specify Valgrind's version number, so that user code can
conditionally compile based on our version number. Note that these
were introduced at version 3.6 and so do not exist in version 3.5
or earlier. The recommended way to use them to check for "version
X.Y or later" is (eg)
#if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__) \
&& (__VALGRIND_MAJOR__ > 3 \
|| (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6))
*/
#define __VALGRIND_MAJOR__ 3
#define __VALGRIND_MINOR__ 6
#include <stdarg.h> #include <stdarg.h>
#include <stdint.h>
/* Nb: this file might be included in a file compiled with -ansi. So /* Nb: this file might be included in a file compiled with -ansi. So
we can't use C++ style "//" comments nor the "asm" keyword (instead we can't use C++ style "//" comments nor the "asm" keyword (instead
use "__asm__"). */ use "__asm__"). */
/* Derive some tags indicating what the target platform is. Note /* Derive some tags indicating what the target platform is. Note
that in this file we're using the compiler's CPP symbols for that in this file we're using the compiler's CPP symbols for
identifying architectures, which are different to the ones we use identifying architectures, which are different to the ones we use
within the rest of Valgrind. Note, __powerpc__ is active for both within the rest of Valgrind. Note, __powerpc__ is active for both
32 and 64-bit PPC, whereas __powerpc64__ is only active for the 32 and 64-bit PPC, whereas __powerpc64__ is only active for the
latter (on Linux, that is). */ latter (on Linux, that is).
Misc note: how to find out what's predefined in gcc by default:
gcc -Wp,-dM somefile.c
*/
#undef PLAT_x86_darwin
#undef PLAT_amd64_darwin
#undef PLAT_x86_win32
#undef PLAT_x86_linux #undef PLAT_x86_linux
#undef PLAT_amd64_linux #undef PLAT_amd64_linux
#undef PLAT_ppc32_linux #undef PLAT_ppc32_linux
#undef PLAT_ppc64_linux #undef PLAT_ppc64_linux
#undef PLAT_ppc32_aix5 #undef PLAT_arm_linux
#undef PLAT_ppc64_aix5 #undef PLAT_s390x_linux
#if !defined(_AIX) && defined(__i386__) #if defined(__APPLE__) && defined(__i386__)
# define PLAT_x86_darwin 1
#elif defined(__APPLE__) && defined(__x86_64__)
# define PLAT_amd64_darwin 1
#elif defined(__MINGW32__) || defined(__CYGWIN32__) \
|| (defined(_WIN32) && defined(_M_IX86))
# define PLAT_x86_win32 1
#elif defined(__linux__) && defined(__i386__)
# define PLAT_x86_linux 1 # define PLAT_x86_linux 1
#elif !defined(_AIX) && defined(__x86_64__) #elif defined(__linux__) && defined(__x86_64__)
# define PLAT_amd64_linux 1 # define PLAT_amd64_linux 1
#elif !defined(_AIX) && defined(__powerpc__) && !defined(__powerpc64__) #elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__)
# define PLAT_ppc32_linux 1 # define PLAT_ppc32_linux 1
#elif !defined(_AIX) && defined(__powerpc__) && defined(__powerpc64__) #elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__)
# define PLAT_ppc64_linux 1 # define PLAT_ppc64_linux 1
#elif defined(_AIX) && defined(__64BIT__) #elif defined(__linux__) && defined(__arm__)
# define PLAT_ppc64_aix5 1 # define PLAT_arm_linux 1
#elif defined(_AIX) && !defined(__64BIT__) #elif defined(__linux__) && defined(__s390__) && defined(__s390x__)
# define PLAT_ppc32_aix5 1 # define PLAT_s390x_linux 1
#endif #else
/* If we're not compiling for our target platform, don't generate /* If we're not compiling for our target platform, don't generate
any inline asms. */ any inline asms. */
#if !defined(PLAT_x86_linux) && !defined(PLAT_amd64_linux) \
&& !defined(PLAT_ppc32_linux) && !defined(PLAT_ppc64_linux) \
&& !defined(PLAT_ppc32_aix5) && !defined(PLAT_ppc64_aix5)
# if !defined(NVALGRIND) # if !defined(NVALGRIND)
# define NVALGRIND 1 # define NVALGRIND 1
# endif # endif
#endif #endif
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
/* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS. There is nothing */ /* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS. There is nothing */
/* in here of use to end-users -- skip to the next section. */ /* in here of use to end-users -- skip to the next section. */
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
/*
* VALGRIND_DO_CLIENT_REQUEST(): a statement that invokes a Valgrind client
* request. Accepts both pointers and integers as arguments.
*
* VALGRIND_DO_CLIENT_REQUEST_EXPR(): a C expression that invokes a Valgrin
d
* client request and whose value equals the client request result. Accepts
* both pointers and integers as arguments.
*/
#define VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, \
_zzq_request, _zzq_arg1, _zzq_arg2, \
_zzq_arg3, _zzq_arg4, _zzq_arg5) \
{ (_zzq_rlval) = VALGRIND_DO_CLIENT_REQUEST_EXPR((_zzq_default), \
(_zzq_request), (_zzq_arg1), (_zzq_arg2), \
(_zzq_arg3), (_zzq_arg4), (_zzq_arg5)); }
#if defined(NVALGRIND) #if defined(NVALGRIND)
/* Define NVALGRIND to completely remove the Valgrind magic sequence /* Define NVALGRIND to completely remove the Valgrind magic sequence
from the compiled code (analogous to NDEBUG's effects on from the compiled code (analogous to NDEBUG's effects on
assert()) */ assert()) */
#define VALGRIND_DO_CLIENT_REQUEST( \ #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
_zzq_rlval, _zzq_default, _zzq_request, \ _zzq_default, _zzq_request, \
_zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
{ \ (_zzq_default)
(_zzq_rlval) = (_zzq_default); \
}
#else /* ! NVALGRIND */ #else /* ! NVALGRIND */
/* The following defines the magic code sequences which the JITter /* The following defines the magic code sequences which the JITter
spots and handles magically. Don't look too closely at them as spots and handles magically. Don't look too closely at them as
they will rot your brain. they will rot your brain.
The assembly code sequences for all architectures is in this one The assembly code sequences for all architectures is in this one
file. This is because this file must be stand-alone, and we don't file. This is because this file must be stand-alone, and we don't
want to have multiple files. want to have multiple files.
skipping to change at line 172 skipping to change at line 214
information is abstracted into a user-visible type, OrigFn. information is abstracted into a user-visible type, OrigFn.
VALGRIND_CALL_NOREDIR_* behaves the same as the following on the VALGRIND_CALL_NOREDIR_* behaves the same as the following on the
guest, but guarantees that the branch instruction will not be guest, but guarantees that the branch instruction will not be
redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64: redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64:
branch-and-link-to-r11. VALGRIND_CALL_NOREDIR is just text, not a branch-and-link-to-r11. VALGRIND_CALL_NOREDIR is just text, not a
complete inline asm, since it needs to be combined with more magic complete inline asm, since it needs to be combined with more magic
inline asm stuff to be useful. inline asm stuff to be useful.
*/ */
/* ------------------------- x86-linux ------------------------- */ /* ------------------------- x86-{linux,darwin} ---------------- */
#if defined(PLAT_x86_linux) #if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \
|| (defined(PLAT_x86_win32) && defined(__GNUC__))
typedef typedef
struct { struct {
unsigned int nraddr; /* where's the code? */ unsigned int nraddr; /* where's the code? */
} }
OrigFn; OrigFn;
#define __SPECIAL_INSTRUCTION_PREAMBLE \ #define __SPECIAL_INSTRUCTION_PREAMBLE \
"roll $3, %%edi ; roll $13, %%edi\n\t" \ "roll $3, %%edi ; roll $13, %%edi\n\t" \
"roll $29, %%edi ; roll $19, %%edi\n\t" "roll $29, %%edi ; roll $19, %%edi\n\t"
#define VALGRIND_DO_CLIENT_REQUEST( \ #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
_zzq_rlval, _zzq_default, _zzq_request, \ _zzq_default, _zzq_request, \
_zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
{ volatile unsigned int _zzq_args[6]; \ __extension__ \
({volatile unsigned int _zzq_args[6]; \
volatile unsigned int _zzq_result; \ volatile unsigned int _zzq_result; \
_zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[0] = (unsigned int)(_zzq_request); \
_zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \
_zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \
_zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \
_zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \
_zzq_args[5] = (unsigned int)(_zzq_arg5); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \
__asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
/* %EDX = client_request ( %EAX ) */ \ /* %EDX = client_request ( %EAX ) */ \
"xchgl %%ebx,%%ebx" \ "xchgl %%ebx,%%ebx" \
: "=d" (_zzq_result) \ : "=d" (_zzq_result) \
: "a" (&_zzq_args[0]), "0" (_zzq_default) \ : "a" (&_zzq_args[0]), "0" (_zzq_default) \
: "cc", "memory" \ : "cc", "memory" \
); \ ); \
_zzq_rlval = _zzq_result; \ _zzq_result; \
} })
#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
{ volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
volatile unsigned int __addr; \ volatile unsigned int __addr; \
__asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
/* %EAX = guest_NRADDR */ \ /* %EAX = guest_NRADDR */ \
"xchgl %%ecx,%%ecx" \ "xchgl %%ecx,%%ecx" \
: "=a" (__addr) \ : "=a" (__addr) \
: \ : \
: "cc", "memory" \ : "cc", "memory" \
); \ ); \
_zzq_orig->nraddr = __addr; \ _zzq_orig->nraddr = __addr; \
} }
#define VALGRIND_CALL_NOREDIR_EAX \ #define VALGRIND_CALL_NOREDIR_EAX \
__SPECIAL_INSTRUCTION_PREAMBLE \ __SPECIAL_INSTRUCTION_PREAMBLE \
/* call-noredir *%EAX */ \ /* call-noredir *%EAX */ \
"xchgl %%edx,%%edx\n\t" "xchgl %%edx,%%edx\n\t"
#endif /* PLAT_x86_linux */ #endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__)
*/
/* ------------------------- x86-Win32 ------------------------- */
#if defined(PLAT_x86_win32) && !defined(__GNUC__)
typedef
struct {
unsigned int nraddr; /* where's the code? */
}
OrigFn;
#if defined(_MSC_VER)
#define __SPECIAL_INSTRUCTION_PREAMBLE \
__asm rol edi, 3 __asm rol edi, 13 \
__asm rol edi, 29 __asm rol edi, 19
#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
_zzq_default, _zzq_request, \
_zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
valgrind_do_client_request_expr((uintptr_t)(_zzq_default), \
(uintptr_t)(_zzq_request), (uintptr_t)(_zzq_arg1), \
(uintptr_t)(_zzq_arg2), (uintptr_t)(_zzq_arg3), \
(uintptr_t)(_zzq_arg4), (uintptr_t)(_zzq_arg5))
static __inline uintptr_t
valgrind_do_client_request_expr(uintptr_t _zzq_default, uintptr_t _zzq_requ
est,
uintptr_t _zzq_arg1, uintptr_t _zzq_arg2,
uintptr_t _zzq_arg3, uintptr_t _zzq_arg4,
uintptr_t _zzq_arg5)
{
volatile uintptr_t _zzq_args[6];
volatile unsigned int _zzq_result;
_zzq_args[0] = (uintptr_t)(_zzq_request);
_zzq_args[1] = (uintptr_t)(_zzq_arg1);
_zzq_args[2] = (uintptr_t)(_zzq_arg2);
_zzq_args[3] = (uintptr_t)(_zzq_arg3);
_zzq_args[4] = (uintptr_t)(_zzq_arg4);
_zzq_args[5] = (uintptr_t)(_zzq_arg5);
__asm { __asm lea eax, _zzq_args __asm mov edx, _zzq_default
__SPECIAL_INSTRUCTION_PREAMBLE
/* %EDX = client_request ( %EAX ) */
__asm xchg ebx,ebx
__asm mov _zzq_result, edx
}
return _zzq_result;
}
#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
{ volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
volatile unsigned int __addr; \
__asm { __SPECIAL_INSTRUCTION_PREAMBLE \
/* %EAX = guest_NRADDR */ \
__asm xchg ecx,ecx \
__asm mov __addr, eax \
} \
_zzq_orig->nraddr = __addr; \
}
#define VALGRIND_CALL_NOREDIR_EAX ERROR
#else
#error Unsupported compiler.
#endif
/* ------------------------ amd64-linux ------------------------ */ #endif /* PLAT_x86_win32 */
#if defined(PLAT_amd64_linux) /* ------------------------ amd64-{linux,darwin} --------------- */
#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin)
typedef typedef
struct { struct {
unsigned long long int nraddr; /* where's the code? */ uint64_t nraddr; /* where's the code? */
} }
OrigFn; OrigFn;
#define __SPECIAL_INSTRUCTION_PREAMBLE \ #define __SPECIAL_INSTRUCTION_PREAMBLE \
"rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \ "rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \
"rolq $61, %%rdi ; rolq $51, %%rdi\n\t" "rolq $61, %%rdi ; rolq $51, %%rdi\n\t"
#define VALGRIND_DO_CLIENT_REQUEST( \ #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
_zzq_rlval, _zzq_default, _zzq_request, \ _zzq_default, _zzq_request, \
_zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
{ volatile unsigned long long int _zzq_args[6]; \ __extension__ \
volatile unsigned long long int _zzq_result; \ ({ volatile uint64_t _zzq_args[6]; \
_zzq_args[0] = (unsigned long long int)(_zzq_request); \ volatile uint64_t _zzq_result; \
_zzq_args[1] = (unsigned long long int)(_zzq_arg1); \ _zzq_args[0] = (uint64_t)(_zzq_request); \
_zzq_args[2] = (unsigned long long int)(_zzq_arg2); \ _zzq_args[1] = (uint64_t)(_zzq_arg1); \
_zzq_args[3] = (unsigned long long int)(_zzq_arg3); \ _zzq_args[2] = (uint64_t)(_zzq_arg2); \
_zzq_args[4] = (unsigned long long int)(_zzq_arg4); \ _zzq_args[3] = (uint64_t)(_zzq_arg3); \
_zzq_args[5] = (unsigned long long int)(_zzq_arg5); \ _zzq_args[4] = (uint64_t)(_zzq_arg4); \
_zzq_args[5] = (uint64_t)(_zzq_arg5); \
__asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
/* %RDX = client_request ( %RAX ) */ \ /* %RDX = client_request ( %RAX ) */ \
"xchgq %%rbx,%%rbx" \ "xchgq %%rbx,%%rbx" \
: "=d" (_zzq_result) \ : "=d" (_zzq_result) \
: "a" (&_zzq_args[0]), "0" (_zzq_default) \ : "a" (&_zzq_args[0]), "0" (_zzq_default) \
: "cc", "memory" \ : "cc", "memory" \
); \ ); \
_zzq_rlval = _zzq_result; \ _zzq_result; \
} })
#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
{ volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
volatile unsigned long long int __addr; \ volatile uint64_t __addr; \
__asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
/* %RAX = guest_NRADDR */ \ /* %RAX = guest_NRADDR */ \
"xchgq %%rcx,%%rcx" \ "xchgq %%rcx,%%rcx" \
: "=a" (__addr) \ : "=a" (__addr) \
: \ : \
: "cc", "memory" \ : "cc", "memory" \
); \ ); \
_zzq_orig->nraddr = __addr; \ _zzq_orig->nraddr = __addr; \
} }
#define VALGRIND_CALL_NOREDIR_RAX \ #define VALGRIND_CALL_NOREDIR_RAX \
__SPECIAL_INSTRUCTION_PREAMBLE \ __SPECIAL_INSTRUCTION_PREAMBLE \
/* call-noredir *%RAX */ \ /* call-noredir *%RAX */ \
"xchgq %%rdx,%%rdx\n\t" "xchgq %%rdx,%%rdx\n\t"
#endif /* PLAT_amd64_linux */ #endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
/* ------------------------ ppc32-linux ------------------------ */ /* ------------------------ ppc32-linux ------------------------ */
#if defined(PLAT_ppc32_linux) #if defined(PLAT_ppc32_linux)
typedef typedef
struct { struct {
unsigned int nraddr; /* where's the code? */ unsigned int nraddr; /* where's the code? */
} }
OrigFn; OrigFn;
#define __SPECIAL_INSTRUCTION_PREAMBLE \ #define __SPECIAL_INSTRUCTION_PREAMBLE \
"rlwinm 0,0,3,0,0 ; rlwinm 0,0,13,0,0\n\t" \ "rlwinm 0,0,3,0,0 ; rlwinm 0,0,13,0,0\n\t" \
"rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t" "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t"
#define VALGRIND_DO_CLIENT_REQUEST( \ #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
_zzq_rlval, _zzq_default, _zzq_request, \ _zzq_default, _zzq_request, \
_zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
\ \
{ unsigned int _zzq_args[6]; \ __extension__ \
({ unsigned int _zzq_args[6]; \
unsigned int _zzq_result; \ unsigned int _zzq_result; \
unsigned int* _zzq_ptr; \ unsigned int* _zzq_ptr; \
_zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[0] = (unsigned int)(_zzq_request); \
_zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \
_zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \
_zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \
_zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \
_zzq_args[5] = (unsigned int)(_zzq_arg5); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \
_zzq_ptr = _zzq_args; \ _zzq_ptr = _zzq_args; \
__asm__ volatile("mr 3,%1\n\t" /*default*/ \ __asm__ volatile("mr 3,%1\n\t" /*default*/ \
"mr 4,%2\n\t" /*ptr*/ \ "mr 4,%2\n\t" /*ptr*/ \
__SPECIAL_INSTRUCTION_PREAMBLE \ __SPECIAL_INSTRUCTION_PREAMBLE \
/* %R3 = client_request ( %R4 ) */ \ /* %R3 = client_request ( %R4 ) */ \
"or 1,1,1\n\t" \ "or 1,1,1\n\t" \
"mr %0,3" /*result*/ \ "mr %0,3" /*result*/ \
: "=b" (_zzq_result) \ : "=b" (_zzq_result) \
: "b" (_zzq_default), "b" (_zzq_ptr) \ : "b" (_zzq_default), "b" (_zzq_ptr) \
: "cc", "memory", "r3", "r4"); \ : "cc", "memory", "r3", "r4"); \
_zzq_rlval = _zzq_result; \ _zzq_result; \
} })
#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
{ volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
unsigned int __addr; \ unsigned int __addr; \
__asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
/* %R3 = guest_NRADDR */ \ /* %R3 = guest_NRADDR */ \
"or 2,2,2\n\t" \ "or 2,2,2\n\t" \
"mr %0,3" \ "mr %0,3" \
: "=b" (__addr) \ : "=b" (__addr) \
: \ : \
skipping to change at line 346 skipping to change at line 458
/* branch-and-link-to-noredir *%R11 */ \ /* branch-and-link-to-noredir *%R11 */ \
"or 3,3,3\n\t" "or 3,3,3\n\t"
#endif /* PLAT_ppc32_linux */ #endif /* PLAT_ppc32_linux */
/* ------------------------ ppc64-linux ------------------------ */ /* ------------------------ ppc64-linux ------------------------ */
#if defined(PLAT_ppc64_linux) #if defined(PLAT_ppc64_linux)
typedef typedef
struct { struct {
unsigned long long int nraddr; /* where's the code? */ uint64_t nraddr; /* where's the code? */
unsigned long long int r2; /* what tocptr do we need? */ uint64_t r2; /* what tocptr do we need? */
} }
OrigFn; OrigFn;
#define __SPECIAL_INSTRUCTION_PREAMBLE \ #define __SPECIAL_INSTRUCTION_PREAMBLE \
"rotldi 0,0,3 ; rotldi 0,0,13\n\t" \ "rotldi 0,0,3 ; rotldi 0,0,13\n\t" \
"rotldi 0,0,61 ; rotldi 0,0,51\n\t" "rotldi 0,0,61 ; rotldi 0,0,51\n\t"
#define VALGRIND_DO_CLIENT_REQUEST( \ #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
_zzq_rlval, _zzq_default, _zzq_request, \ _zzq_default, _zzq_request, \
_zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
\ \
{ unsigned long long int _zzq_args[6]; \ __extension__ \
register unsigned long long int _zzq_result __asm__("r3"); \ ({ uint64_t _zzq_args[6]; \
register unsigned long long int* _zzq_ptr __asm__("r4"); \ register uint64_t _zzq_result __asm__("r3"); \
_zzq_args[0] = (unsigned long long int)(_zzq_request); \ register uint64_t* _zzq_ptr __asm__("r4"); \
_zzq_args[1] = (unsigned long long int)(_zzq_arg1); \ _zzq_args[0] = (uint64_t)(_zzq_request); \
_zzq_args[2] = (unsigned long long int)(_zzq_arg2); \ _zzq_args[1] = (uint64_t)(_zzq_arg1); \
_zzq_args[3] = (unsigned long long int)(_zzq_arg3); \ _zzq_args[2] = (uint64_t)(_zzq_arg2); \
_zzq_args[4] = (unsigned long long int)(_zzq_arg4); \ _zzq_args[3] = (uint64_t)(_zzq_arg3); \
_zzq_args[5] = (unsigned long long int)(_zzq_arg5); \ _zzq_args[4] = (uint64_t)(_zzq_arg4); \
_zzq_args[5] = (uint64_t)(_zzq_arg5); \
_zzq_ptr = _zzq_args; \ _zzq_ptr = _zzq_args; \
__asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
/* %R3 = client_request ( %R4 ) */ \ /* %R3 = client_request ( %R4 ) */ \
"or 1,1,1" \ "or 1,1,1" \
: "=r" (_zzq_result) \ : "=r" (_zzq_result) \
: "0" (_zzq_default), "r" (_zzq_ptr) \ : "0" (_zzq_default), "r" (_zzq_ptr) \
: "cc", "memory"); \ : "cc", "memory"); \
_zzq_rlval = _zzq_result; \ _zzq_result; \
} })
#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
{ volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
register unsigned long long int __addr __asm__("r3"); \ register uint64_t __addr __asm__("r3"); \
__asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
/* %R3 = guest_NRADDR */ \ /* %R3 = guest_NRADDR */ \
"or 2,2,2" \ "or 2,2,2" \
: "=r" (__addr) \ : "=r" (__addr) \
: \ : \
: "cc", "memory" \ : "cc", "memory" \
); \ ); \
_zzq_orig->nraddr = __addr; \ _zzq_orig->nraddr = __addr; \
__asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
/* %R3 = guest_NRADDR_GPR2 */ \ /* %R3 = guest_NRADDR_GPR2 */ \
skipping to change at line 406 skipping to change at line 519
_zzq_orig->r2 = __addr; \ _zzq_orig->r2 = __addr; \
} }
#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
__SPECIAL_INSTRUCTION_PREAMBLE \ __SPECIAL_INSTRUCTION_PREAMBLE \
/* branch-and-link-to-noredir *%R11 */ \ /* branch-and-link-to-noredir *%R11 */ \
"or 3,3,3\n\t" "or 3,3,3\n\t"
#endif /* PLAT_ppc64_linux */ #endif /* PLAT_ppc64_linux */
/* ------------------------ ppc32-aix5 ------------------------- */ /* ------------------------- arm-linux ------------------------- */
#if defined(PLAT_ppc32_aix5) #if defined(PLAT_arm_linux)
typedef typedef
struct { struct {
unsigned int nraddr; /* where's the code? */ unsigned int nraddr; /* where's the code? */
unsigned int r2; /* what tocptr do we need? */
} }
OrigFn; OrigFn;
#define __SPECIAL_INSTRUCTION_PREAMBLE \ #define __SPECIAL_INSTRUCTION_PREAMBLE \
"rlwinm 0,0,3,0,0 ; rlwinm 0,0,13,0,0\n\t" \ "mov r12, r12, ror #3 ; mov r12, r12, ror #13 \n\t" \
"rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t" "mov r12, r12, ror #29 ; mov r12, r12, ror #19 \n\t"
#define VALGRIND_DO_CLIENT_REQUEST( \ #define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
_zzq_rlval, _zzq_default, _zzq_request, \ _zzq_default, _zzq_request, \
_zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
\ \
{ unsigned int _zzq_args[7]; \ __extension__ \
register unsigned int _zzq_result; \ ({volatile unsigned int _zzq_args[6]; \
register unsigned int* _zzq_ptr; \ volatile unsigned int _zzq_result; \
_zzq_args[0] = (unsigned int)(_zzq_request); \ _zzq_args[0] = (unsigned int)(_zzq_request); \
_zzq_args[1] = (unsigned int)(_zzq_arg1); \ _zzq_args[1] = (unsigned int)(_zzq_arg1); \
_zzq_args[2] = (unsigned int)(_zzq_arg2); \ _zzq_args[2] = (unsigned int)(_zzq_arg2); \
_zzq_args[3] = (unsigned int)(_zzq_arg3); \ _zzq_args[3] = (unsigned int)(_zzq_arg3); \
_zzq_args[4] = (unsigned int)(_zzq_arg4); \ _zzq_args[4] = (unsigned int)(_zzq_arg4); \
_zzq_args[5] = (unsigned int)(_zzq_arg5); \ _zzq_args[5] = (unsigned int)(_zzq_arg5); \
_zzq_args[6] = (unsigned int)(_zzq_default); \ __asm__ volatile("mov r3, %1\n\t" /*default*/ \
_zzq_ptr = _zzq_args; \ "mov r4, %2\n\t" /*ptr*/ \
__asm__ volatile("mr 4,%1\n\t" \
"lwz 3, 24(4)\n\t" \
__SPECIAL_INSTRUCTION_PREAMBLE \ __SPECIAL_INSTRUCTION_PREAMBLE \
/* %R3 = client_request ( %R4 ) */ \ /* R3 = client_request ( R4 ) */ \
"or 1,1,1\n\t" \ "orr r10, r10, r10\n\t" \
"mr %0,3" \ "mov %0, r3" /*result*/ \
: "=b" (_zzq_result) \ : "=r" (_zzq_result) \
: "b" (_zzq_ptr) \ : "r" (_zzq_default), "r" (&_zzq_args[0]) \
: "r3", "r4", "cc", "memory"); \ : "cc","memory", "r3", "r4"); \
_zzq_rlval = _zzq_result; \ _zzq_result; \
} })
#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \ #define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
{ volatile OrigFn* _zzq_orig = &(_zzq_rlval); \ { volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
register unsigned int __addr; \ unsigned int __addr; \
__asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
/* %R3 = guest_NRADDR */ \ /* R3 = guest_NRADDR */ \
"or 2,2,2\n\t" \ "orr r11, r11, r11\n\t" \
"mr %0,3" \ "mov %0, r3" \
: "=b" (__addr) \ : "=r" (__addr) \
: \ : \
: "r3", "cc", "memory" \ : "cc", "memory", "r3" \
); \ ); \
_zzq_orig->nraddr = __addr; \ _zzq_orig->nraddr = __addr; \
__asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
/* %R3 = guest_NRADDR_GPR2 */ \
"or 4,4,4\n\t" \
"mr %0,3" \
: "=b" (__addr) \
: \
: "r3", "cc", "memory" \
); \
_zzq_orig->r2 = __addr; \
} }
#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ #define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
__SPECIAL_INSTRUCTION_PREAMBLE \ __SPECIAL_INSTRUCTION_PREAMBLE \
/* branch-and-link-to-noredir *%R11 */ \ /* branch-and-link-to-noredir *%R4 */ \
"or 3,3,3\n\t" "orr r12, r12, r12\n\t"
#endif /* PLAT_ppc32_aix5 */ #endif /* PLAT_arm_linux */
/* ------------------------ ppc64-aix5 ------------------------- */ /* ------------------------ s390x-linux ------------------------ */
#if defined(PLAT_ppc64_aix5) #if defined(PLAT_s390x_linux)
typedef typedef
struct { struct {
unsigned long long int nraddr; /* where's the code? */ uint64_t nraddr; /* where's the code? */
unsigned long long int r2; /* what tocptr do we need? */
}
OrigFn;
#define __SPECIAL_INSTRUCTION_PREAMBLE \
"rotldi 0,0,3 ; rotldi 0,0,13\n\t" \
"rotldi 0,0,61 ; rotldi 0,0,51\n\t"
#define VALGRIND_DO_CLIENT_REQUEST( \
_zzq_rlval, _zzq_default, _zzq_request, \
_zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
\
{ unsigned long long int _zzq_args[7]; \
register unsigned long long int _zzq_result; \
register unsigned long long int* _zzq_ptr; \
_zzq_args[0] = (unsigned int long long)(_zzq_request); \
_zzq_args[1] = (unsigned int long long)(_zzq_arg1); \
_zzq_args[2] = (unsigned int long long)(_zzq_arg2); \
_zzq_args[3] = (unsigned int long long)(_zzq_arg3); \
_zzq_args[4] = (unsigned int long long)(_zzq_arg4); \
_zzq_args[5] = (unsigned int long long)(_zzq_arg5); \
_zzq_args[6] = (unsigned int long long)(_zzq_default); \
_zzq_ptr = _zzq_args; \
__asm__ volatile("mr 4,%1\n\t" \
"ld 3, 48(4)\n\t" \
__SPECIAL_INSTRUCTION_PREAMBLE \
/* %R3 = client_request ( %R4 ) */ \
"or 1,1,1\n\t" \
"mr %0,3" \
: "=b" (_zzq_result) \
: "b" (_zzq_ptr) \
: "r3", "r4", "cc", "memory"); \
_zzq_rlval = _zzq_result; \
}
#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
{ volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
register unsigned long long int __addr; \
__asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
/* %R3 = guest_NRADDR */ \
"or 2,2,2\n\t" \
"mr %0,3" \
: "=b" (__addr) \
: \
: "r3", "cc", "memory" \
); \
_zzq_orig->nraddr = __addr; \
__asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
/* %R3 = guest_NRADDR_GPR2 */ \
"or 4,4,4\n\t" \
"mr %0,3" \
: "=b" (__addr) \
: \
: "r3", "cc", "memory" \
); \
_zzq_orig->r2 = __addr; \
} }
OrigFn;
#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \ /* __SPECIAL_INSTRUCTION_PREAMBLE will be used to identify Valgrind specifi
__SPECIAL_INSTRUCTION_PREAMBLE \ c
/* branch-and-link-to-noredir *%R11 */ \ * code. This detection is implemented in platform specific toIR.c
"or 3,3,3\n\t" * (e.g. VEX/priv/guest_s390_decoder.c).
*/
#define __SPECIAL_INSTRUCTION_PREAMBLE \
"lr 15,15\n\t" \
"lr 1,1\n\t" \
"lr 2,2\n\t" \
"lr 3,3\n\t"
#define __CLIENT_REQUEST_CODE "lr 2,2\n\t"
#define __GET_NR_CONTEXT_CODE "lr 3,3\n\t"
#define __CALL_NO_REDIR_CODE "lr 4,4\n\t"
#define VALGRIND_DO_CLIENT_REQUEST_EXPR( \
_zzq_default, _zzq_request, \
_zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
__extension__ \
({volatile uint64_t _zzq_args[6]; \
volatile uint64_t _zzq_result; \
_zzq_args[0] = (uint64_t)(_zzq_request); \
_zzq_args[1] = (uint64_t)(_zzq_arg1); \
_zzq_args[2] = (uint64_t)(_zzq_arg2); \
_zzq_args[3] = (uint64_t)(_zzq_arg3); \
_zzq_args[4] = (uint64_t)(_zzq_arg4); \
_zzq_args[5] = (uint64_t)(_zzq_arg5); \
__asm__ volatile(/* r2 = args */ \
"lgr 2,%1\n\t" \
/* r3 = default */ \
"lgr 3,%2\n\t" \
__SPECIAL_INSTRUCTION_PREAMBLE \
__CLIENT_REQUEST_CODE \
/* results = r3 */ \
"lgr %0, 3\n\t" \
: "=d" (_zzq_result) \
: "a" (&_zzq_args[0]), "0" (_zzq_default) \
: "cc", "2", "3", "memory" \
); \
_zzq_result; \
})
#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval) \
{ volatile OrigFn* _zzq_orig = &(_zzq_rlval); \
volatile uint64_t __addr; \
__asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \
__GET_NR_CONTEXT_CODE \
"lgr %0, 3\n\t" \
: "=a" (__addr) \
: \
: "cc", "3", "memory" \
); \
_zzq_orig->nraddr = __addr; \
}
#define VALGRIND_CALL_NOREDIR_R1 \
__SPECIAL_INSTRUCTION_PREAMBLE \
__CALL_NO_REDIR_CODE
#endif /* PLAT_ppc64_aix5 */ #endif /* PLAT_s390x_linux */
/* Insert assembly code for other platforms here... */ /* Insert assembly code for other platforms here... */
#endif /* NVALGRIND */ #endif /* NVALGRIND */
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
/* PLATFORM SPECIFICS for FUNCTION WRAPPING. This is all very */ /* PLATFORM SPECIFICS for FUNCTION WRAPPING. This is all very */
/* ugly. It's the least-worst tradeoff I can think of. */ /* ugly. It's the least-worst tradeoff I can think of. */
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
skipping to change at line 580 skipping to change at line 679
'W' stands for "word" and 'v' for "void". Hence there are 'W' stands for "word" and 'v' for "void". Hence there are
different macros for calling arity 0, 1, 2, 3, 4, etc, functions, different macros for calling arity 0, 1, 2, 3, 4, etc, functions,
and for each, the possibility of returning a word-typed result, or and for each, the possibility of returning a word-typed result, or
no result. no result.
*/ */
/* Use these to write the name of your wrapper. NOTE: duplicates /* Use these to write the name of your wrapper. NOTE: duplicates
VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. */ VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. */
/* Use an extra level of macroisation so as to ensure the soname/fnname
args are fully macro-expanded before pasting them together. */
#define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd
#define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \ #define I_WRAP_SONAME_FNNAME_ZU(soname,fnname) \
_vgwZU_##soname##_##fnname VG_CONCAT4(_vgwZU_,soname,_,fnname)
#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \ #define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname) \
_vgwZZ_##soname##_##fnname VG_CONCAT4(_vgwZZ_,soname,_,fnname)
/* Use this macro from within a wrapper function to collect the /* Use this macro from within a wrapper function to collect the
context (address and possibly other info) of the original function. context (address and possibly other info) of the original function.
Once you have that you can then use it in one of the CALL_FN_ Once you have that you can then use it in one of the CALL_FN_
macros. The type of the argument _lval is OrigFn. */ macros. The type of the argument _lval is OrigFn. */
#define VALGRIND_GET_ORIG_FN(_lval) VALGRIND_GET_NR_CONTEXT(_lval) #define VALGRIND_GET_ORIG_FN(_lval) VALGRIND_GET_NR_CONTEXT(_lval)
/* Derivatives of the main macros below, for calling functions /* Derivatives of the main macros below, for calling functions
returning void. */ returning void. */
skipping to change at line 611 skipping to change at line 714
CALL_FN_W_W(_junk,fnptr,arg1); } while (0) CALL_FN_W_W(_junk,fnptr,arg1); } while (0)
#define CALL_FN_v_WW(fnptr, arg1,arg2) \ #define CALL_FN_v_WW(fnptr, arg1,arg2) \
do { volatile unsigned long _junk; \ do { volatile unsigned long _junk; \
CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0) CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0)
#define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3) \ #define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3) \
do { volatile unsigned long _junk; \ do { volatile unsigned long _junk; \
CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0) CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0)
/* ------------------------- x86-linux ------------------------- */ #define CALL_FN_v_WWWW(fnptr, arg1,arg2,arg3,arg4) \
do { volatile unsigned long _junk; \
CALL_FN_W_WWWW(_junk,fnptr,arg1,arg2,arg3,arg4); } while (0)
#define CALL_FN_v_5W(fnptr, arg1,arg2,arg3,arg4,arg5) \
do { volatile unsigned long _junk; \
CALL_FN_W_5W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5); } while (0)
#define CALL_FN_v_6W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6) \
do { volatile unsigned long _junk; \
CALL_FN_W_6W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6); } while (0
)
#define CALL_FN_v_7W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6,arg7) \
do { volatile unsigned long _junk; \
CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } whi
le (0)
/* ------------------------- x86-{linux,darwin} ---------------- */
#if defined(PLAT_x86_linux) #if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin)
/* These regs are trashed by the hidden call. No need to mention eax /* These regs are trashed by the hidden call. No need to mention eax
as gcc can already see that, plus causes gcc to bomb. */ as gcc can already see that, plus causes gcc to bomb. */
#define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx" #define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx"
/* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned /* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned
long) == 4. */ long) == 4. */
#define CALL_FN_W_v(lval, orig) \ #define CALL_FN_W_v(lval, orig) \
do { \ do { \
skipping to change at line 646 skipping to change at line 765
} while (0) } while (0)
#define CALL_FN_W_W(lval, orig, arg1) \ #define CALL_FN_W_W(lval, orig, arg1) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[2]; \ volatile unsigned long _argvec[2]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)(arg1); \ _argvec[1] = (unsigned long)(arg1); \
__asm__ volatile( \ __asm__ volatile( \
"subl $12, %%esp\n\t" \
"pushl 4(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \
"movl (%%eax), %%eax\n\t" /* target->%eax */ \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_CALL_NOREDIR_EAX \
"addl $4, %%esp\n" \ "addl $16, %%esp\n" \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ #define CALL_FN_W_WW(lval, orig, arg1,arg2) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3]; \ volatile unsigned long _argvec[3]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)(arg1); \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)(arg2); \ _argvec[2] = (unsigned long)(arg2); \
__asm__ volatile( \ __asm__ volatile( \
"subl $8, %%esp\n\t" \
"pushl 8(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \
"pushl 4(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \
"movl (%%eax), %%eax\n\t" /* target->%eax */ \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_CALL_NOREDIR_EAX \
"addl $8, %%esp\n" \ "addl $16, %%esp\n" \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[4]; \ volatile unsigned long _argvec[4]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)(arg1); \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)(arg2); \ _argvec[2] = (unsigned long)(arg2); \
_argvec[3] = (unsigned long)(arg3); \ _argvec[3] = (unsigned long)(arg3); \
__asm__ volatile( \ __asm__ volatile( \
"subl $4, %%esp\n\t" \
"pushl 12(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \
"pushl 8(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \
"pushl 4(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \
"movl (%%eax), %%eax\n\t" /* target->%eax */ \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_CALL_NOREDIR_EAX \
"addl $12, %%esp\n" \ "addl $16, %%esp\n" \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
skipping to change at line 738 skipping to change at line 860
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[6]; \ volatile unsigned long _argvec[6]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)(arg1); \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)(arg2); \ _argvec[2] = (unsigned long)(arg2); \
_argvec[3] = (unsigned long)(arg3); \ _argvec[3] = (unsigned long)(arg3); \
_argvec[4] = (unsigned long)(arg4); \ _argvec[4] = (unsigned long)(arg4); \
_argvec[5] = (unsigned long)(arg5); \ _argvec[5] = (unsigned long)(arg5); \
__asm__ volatile( \ __asm__ volatile( \
"subl $12, %%esp\n\t" \
"pushl 20(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \
"pushl 16(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \
"pushl 12(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \
"pushl 8(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \
"pushl 4(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \
"movl (%%eax), %%eax\n\t" /* target->%eax */ \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_CALL_NOREDIR_EAX \
"addl $20, %%esp\n" \ "addl $32, %%esp\n" \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[7]; \ volatile unsigned long _argvec[7]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)(arg1); \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)(arg2); \ _argvec[2] = (unsigned long)(arg2); \
_argvec[3] = (unsigned long)(arg3); \ _argvec[3] = (unsigned long)(arg3); \
_argvec[4] = (unsigned long)(arg4); \ _argvec[4] = (unsigned long)(arg4); \
_argvec[5] = (unsigned long)(arg5); \ _argvec[5] = (unsigned long)(arg5); \
_argvec[6] = (unsigned long)(arg6); \ _argvec[6] = (unsigned long)(arg6); \
__asm__ volatile( \ __asm__ volatile( \
"subl $8, %%esp\n\t" \
"pushl 24(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \
"pushl 20(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \
"pushl 16(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \
"pushl 12(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \
"pushl 8(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \
"pushl 4(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \
"movl (%%eax), %%eax\n\t" /* target->%eax */ \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_CALL_NOREDIR_EAX \
"addl $24, %%esp\n" \ "addl $32, %%esp\n" \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7) \ arg7) \
do { \ do { \
skipping to change at line 797 skipping to change at line 921
volatile unsigned long _res; \ volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)(arg1); \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)(arg2); \ _argvec[2] = (unsigned long)(arg2); \
_argvec[3] = (unsigned long)(arg3); \ _argvec[3] = (unsigned long)(arg3); \
_argvec[4] = (unsigned long)(arg4); \ _argvec[4] = (unsigned long)(arg4); \
_argvec[5] = (unsigned long)(arg5); \ _argvec[5] = (unsigned long)(arg5); \
_argvec[6] = (unsigned long)(arg6); \ _argvec[6] = (unsigned long)(arg6); \
_argvec[7] = (unsigned long)(arg7); \ _argvec[7] = (unsigned long)(arg7); \
__asm__ volatile( \ __asm__ volatile( \
"subl $4, %%esp\n\t" \
"pushl 28(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \
"pushl 24(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \
"pushl 20(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \
"pushl 16(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \
"pushl 12(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \
"pushl 8(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \
"pushl 4(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \
"movl (%%eax), %%eax\n\t" /* target->%eax */ \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_CALL_NOREDIR_EAX \
"addl $28, %%esp\n" \ "addl $32, %%esp\n" \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7,arg8) \ arg7,arg8) \
do { \ do { \
skipping to change at line 865 skipping to change at line 990
_argvec[1] = (unsigned long)(arg1); \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)(arg2); \ _argvec[2] = (unsigned long)(arg2); \
_argvec[3] = (unsigned long)(arg3); \ _argvec[3] = (unsigned long)(arg3); \
_argvec[4] = (unsigned long)(arg4); \ _argvec[4] = (unsigned long)(arg4); \
_argvec[5] = (unsigned long)(arg5); \ _argvec[5] = (unsigned long)(arg5); \
_argvec[6] = (unsigned long)(arg6); \ _argvec[6] = (unsigned long)(arg6); \
_argvec[7] = (unsigned long)(arg7); \ _argvec[7] = (unsigned long)(arg7); \
_argvec[8] = (unsigned long)(arg8); \ _argvec[8] = (unsigned long)(arg8); \
_argvec[9] = (unsigned long)(arg9); \ _argvec[9] = (unsigned long)(arg9); \
__asm__ volatile( \ __asm__ volatile( \
"subl $12, %%esp\n\t" \
"pushl 36(%%eax)\n\t" \ "pushl 36(%%eax)\n\t" \
"pushl 32(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \
"pushl 28(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \
"pushl 24(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \
"pushl 20(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \
"pushl 16(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \
"pushl 12(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \
"pushl 8(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \
"pushl 4(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \
"movl (%%eax), %%eax\n\t" /* target->%eax */ \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_CALL_NOREDIR_EAX \
"addl $36, %%esp\n" \ "addl $48, %%esp\n" \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7,arg8,arg9,arg10) \ arg7,arg8,arg9,arg10) \
do { \ do { \
skipping to change at line 902 skipping to change at line 1028
_argvec[2] = (unsigned long)(arg2); \ _argvec[2] = (unsigned long)(arg2); \
_argvec[3] = (unsigned long)(arg3); \ _argvec[3] = (unsigned long)(arg3); \
_argvec[4] = (unsigned long)(arg4); \ _argvec[4] = (unsigned long)(arg4); \
_argvec[5] = (unsigned long)(arg5); \ _argvec[5] = (unsigned long)(arg5); \
_argvec[6] = (unsigned long)(arg6); \ _argvec[6] = (unsigned long)(arg6); \
_argvec[7] = (unsigned long)(arg7); \ _argvec[7] = (unsigned long)(arg7); \
_argvec[8] = (unsigned long)(arg8); \ _argvec[8] = (unsigned long)(arg8); \
_argvec[9] = (unsigned long)(arg9); \ _argvec[9] = (unsigned long)(arg9); \
_argvec[10] = (unsigned long)(arg10); \ _argvec[10] = (unsigned long)(arg10); \
__asm__ volatile( \ __asm__ volatile( \
"subl $8, %%esp\n\t" \
"pushl 40(%%eax)\n\t" \ "pushl 40(%%eax)\n\t" \
"pushl 36(%%eax)\n\t" \ "pushl 36(%%eax)\n\t" \
"pushl 32(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \
"pushl 28(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \
"pushl 24(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \
"pushl 20(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \
"pushl 16(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \
"pushl 12(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \
"pushl 8(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \
"pushl 4(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \
"movl (%%eax), %%eax\n\t" /* target->%eax */ \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_CALL_NOREDIR_EAX \
"addl $40, %%esp\n" \ "addl $48, %%esp\n" \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
arg6,arg7,arg8,arg9,arg10, \ arg6,arg7,arg8,arg9,arg10, \
arg11) \ arg11) \
skipping to change at line 942 skipping to change at line 1069
_argvec[3] = (unsigned long)(arg3); \ _argvec[3] = (unsigned long)(arg3); \
_argvec[4] = (unsigned long)(arg4); \ _argvec[4] = (unsigned long)(arg4); \
_argvec[5] = (unsigned long)(arg5); \ _argvec[5] = (unsigned long)(arg5); \
_argvec[6] = (unsigned long)(arg6); \ _argvec[6] = (unsigned long)(arg6); \
_argvec[7] = (unsigned long)(arg7); \ _argvec[7] = (unsigned long)(arg7); \
_argvec[8] = (unsigned long)(arg8); \ _argvec[8] = (unsigned long)(arg8); \
_argvec[9] = (unsigned long)(arg9); \ _argvec[9] = (unsigned long)(arg9); \
_argvec[10] = (unsigned long)(arg10); \ _argvec[10] = (unsigned long)(arg10); \
_argvec[11] = (unsigned long)(arg11); \ _argvec[11] = (unsigned long)(arg11); \
__asm__ volatile( \ __asm__ volatile( \
"subl $4, %%esp\n\t" \
"pushl 44(%%eax)\n\t" \ "pushl 44(%%eax)\n\t" \
"pushl 40(%%eax)\n\t" \ "pushl 40(%%eax)\n\t" \
"pushl 36(%%eax)\n\t" \ "pushl 36(%%eax)\n\t" \
"pushl 32(%%eax)\n\t" \ "pushl 32(%%eax)\n\t" \
"pushl 28(%%eax)\n\t" \ "pushl 28(%%eax)\n\t" \
"pushl 24(%%eax)\n\t" \ "pushl 24(%%eax)\n\t" \
"pushl 20(%%eax)\n\t" \ "pushl 20(%%eax)\n\t" \
"pushl 16(%%eax)\n\t" \ "pushl 16(%%eax)\n\t" \
"pushl 12(%%eax)\n\t" \ "pushl 12(%%eax)\n\t" \
"pushl 8(%%eax)\n\t" \ "pushl 8(%%eax)\n\t" \
"pushl 4(%%eax)\n\t" \ "pushl 4(%%eax)\n\t" \
"movl (%%eax), %%eax\n\t" /* target->%eax */ \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_CALL_NOREDIR_EAX \
"addl $44, %%esp\n" \ "addl $48, %%esp\n" \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \ #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
arg6,arg7,arg8,arg9,arg10, \ arg6,arg7,arg8,arg9,arg10, \
arg11,arg12) \ arg11,arg12) \
skipping to change at line 1006 skipping to change at line 1134
"movl (%%eax), %%eax\n\t" /* target->%eax */ \ "movl (%%eax), %%eax\n\t" /* target->%eax */ \
VALGRIND_CALL_NOREDIR_EAX \ VALGRIND_CALL_NOREDIR_EAX \
"addl $48, %%esp\n" \ "addl $48, %%esp\n" \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#endif /* PLAT_x86_linux */ #endif /* PLAT_x86_linux || PLAT_x86_darwin */
/* ------------------------ amd64-linux ------------------------ */ /* ------------------------ amd64-{linux,darwin} --------------- */
#if defined(PLAT_amd64_linux) #if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin)
/* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */ /* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */
/* These regs are trashed by the hidden call. */ /* These regs are trashed by the hidden call. */
#define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi", \ #define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi", \
"rdi", "r8", "r9", "r10", "r11" "rdi", "r8", "r9", "r10", "r11"
/* This is all pretty complex. It's so as to make stack unwinding
work reliably. See bug 243270. The basic problem is the sub and
add of 128 of %rsp in all of the following macros. If gcc believes
the CFA is in %rsp, then unwinding may fail, because what's at the
CFA is not what gcc "expected" when it constructs the CFIs for the
places where the macros are instantiated.
But we can't just add a CFI annotation to increase the CFA offset
by 128, to match the sub of 128 from %rsp, because we don't know
whether gcc has chosen %rsp as the CFA at that point, or whether it
has chosen some other register (eg, %rbp). In the latter case,
adding a CFI annotation to change the CFA offset is simply wrong.
So the solution is to get hold of the CFA using
__builtin_dwarf_cfa(), put it in a known register, and add a
CFI annotation to say what the register is. We choose %rbp for
this (perhaps perversely), because:
(1) %rbp is already subject to unwinding. If a new register was
chosen then the unwinder would have to unwind it in all stack
traces, which is expensive, and
(2) %rbp is already subject to precise exception updates in the
JIT. If a new register was chosen, we'd have to have precise
exceptions for it too, which reduces performance of the
generated code.
However .. one extra complication. We can't just whack the result
of __builtin_dwarf_cfa() into %rbp and then add %rbp to the
list of trashed registers at the end of the inline assembly
fragments; gcc won't allow %rbp to appear in that list. Hence
instead we need to stash %rbp in %r15 for the duration of the asm,
and say that %r15 is trashed instead. gcc seems happy to go with
that.
Oh .. and this all needs to be conditionalised so that it is
unchanged from before this commit, when compiled with older gccs
that don't support __builtin_dwarf_cfa. Furthermore, since
this header file is freestanding, it has to be independent of
config.h, and so the following conditionalisation cannot depend on
configure time checks.
Although it's not clear from
'defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)',
this expression excludes Darwin.
.cfi directives in Darwin assembly appear to be completely
different and I haven't investigated how they work.
For even more entertainment value, note we have to use the
completely undocumented __builtin_dwarf_cfa(), which appears to
really compute the CFA, whereas __builtin_frame_address(0) claims
to but actually doesn't. See
https://bugs.kde.org/show_bug.cgi?id=243270#c47
*/
#if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)
# define __FRAME_POINTER \
,"r"(__builtin_dwarf_cfa())
# define VALGRIND_CFI_PROLOGUE \
"movq %%rbp, %%r15\n\t" \
"movq %2, %%rbp\n\t" \
".cfi_remember_state\n\t" \
".cfi_def_cfa rbp, 0\n\t"
# define VALGRIND_CFI_EPILOGUE \
"movq %%r15, %%rbp\n\t" \
".cfi_restore_state\n\t"
#else
# define __FRAME_POINTER
# define VALGRIND_CFI_PROLOGUE
# define VALGRIND_CFI_EPILOGUE
#endif
/* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned /* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned
long) == 8. */ long) == 8. */
/* NB 9 Sept 07. There is a nasty kludge here in all these CALL_FN_ /* NB 9 Sept 07. There is a nasty kludge here in all these CALL_FN_
macros. In order not to trash the stack redzone, we need to drop macros. In order not to trash the stack redzone, we need to drop
%rsp by 128 before the hidden call, and restore afterwards. The %rsp by 128 before the hidden call, and restore afterwards. The
nastyness is that it is only by luck that the stack still appears nastyness is that it is only by luck that the stack still appears
to be unwindable during the hidden call - since then the behaviour to be unwindable during the hidden call - since then the behaviour
of any routine using this macro does not match what the CFI data of any routine using this macro does not match what the CFI data
says. Sigh. says. Sigh.
Why is this important? Imagine that a wrapper has a stack Why is this important? Imagine that a wrapper has a stack
allocated local, and passes to the hidden call, a pointer to it. allocated local, and passes to the hidden call, a pointer to it.
Because gcc does not know about the hidden call, it may allocate Because gcc does not know about the hidden call, it may allocate
that local in the redzone. Unfortunately the hidden call may then that local in the redzone. Unfortunately the hidden call may then
trash it before it comes to use it. So we must step clear of the trash it before it comes to use it. So we must step clear of the
redzone, for the duration of the hidden call, to make it safe. redzone, for the duration of the hidden call, to make it safe.
Probably the same problem afflicts the other redzone-style ABIs too Probably the same problem afflicts the other redzone-style ABIs too
(ppc64-linux, ppc32-aix5, ppc64-aix5); but for those, the stack is (ppc64-linux); but for those, the stack is
self describing (none of this CFI nonsense) so at least messing self describing (none of this CFI nonsense) so at least messing
with the stack pointer doesn't give a danger of non-unwindable with the stack pointer doesn't give a danger of non-unwindable
stack. */ stack. */
#define CALL_FN_W_v(lval, orig) \ #define CALL_FN_W_v(lval, orig) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[1]; \ volatile unsigned long _argvec[1]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[0] = (unsigned long)_orig.nraddr; \
__asm__ volatile( \ __asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"subq $128,%%rsp\n\t" \ "subq $128,%%rsp\n\t" \
"movq (%%rax), %%rax\n\t" /* target->%rax */ \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_CALL_NOREDIR_RAX \
"addq $128,%%rsp\n\t" \ "addq $128,%%rsp\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_W(lval, orig, arg1) \ #define CALL_FN_W_W(lval, orig, arg1) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[2]; \ volatile unsigned long _argvec[2]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)(arg1); \ _argvec[1] = (unsigned long)(arg1); \
__asm__ volatile( \ __asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"subq $128,%%rsp\n\t" \ "subq $128,%%rsp\n\t" \
"movq 8(%%rax), %%rdi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \
"movq (%%rax), %%rax\n\t" /* target->%rax */ \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_CALL_NOREDIR_RAX \
"addq $128,%%rsp\n\t" \ "addq $128,%%rsp\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ #define CALL_FN_W_WW(lval, orig, arg1,arg2) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3]; \ volatile unsigned long _argvec[3]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)(arg1); \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)(arg2); \ _argvec[2] = (unsigned long)(arg2); \
__asm__ volatile( \ __asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"subq $128,%%rsp\n\t" \ "subq $128,%%rsp\n\t" \
"movq 16(%%rax), %%rsi\n\t" \ "movq 16(%%rax), %%rsi\n\t" \
"movq 8(%%rax), %%rdi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \
"movq (%%rax), %%rax\n\t" /* target->%rax */ \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_CALL_NOREDIR_RAX \
"addq $128,%%rsp\n\t" \ "addq $128,%%rsp\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[4]; \ volatile unsigned long _argvec[4]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)(arg1); \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)(arg2); \ _argvec[2] = (unsigned long)(arg2); \
_argvec[3] = (unsigned long)(arg3); \ _argvec[3] = (unsigned long)(arg3); \
__asm__ volatile( \ __asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"subq $128,%%rsp\n\t" \ "subq $128,%%rsp\n\t" \
"movq 24(%%rax), %%rdx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \
"movq 16(%%rax), %%rsi\n\t" \ "movq 16(%%rax), %%rsi\n\t" \
"movq 8(%%rax), %%rdi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \
"movq (%%rax), %%rax\n\t" /* target->%rax */ \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_CALL_NOREDIR_RAX \
"addq $128,%%rsp\n\t" \ "addq $128,%%rsp\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[5]; \ volatile unsigned long _argvec[5]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)(arg1); \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)(arg2); \ _argvec[2] = (unsigned long)(arg2); \
_argvec[3] = (unsigned long)(arg3); \ _argvec[3] = (unsigned long)(arg3); \
_argvec[4] = (unsigned long)(arg4); \ _argvec[4] = (unsigned long)(arg4); \
__asm__ volatile( \ __asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"subq $128,%%rsp\n\t" \ "subq $128,%%rsp\n\t" \
"movq 32(%%rax), %%rcx\n\t" \ "movq 32(%%rax), %%rcx\n\t" \
"movq 24(%%rax), %%rdx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \
"movq 16(%%rax), %%rsi\n\t" \ "movq 16(%%rax), %%rsi\n\t" \
"movq 8(%%rax), %%rdi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \
"movq (%%rax), %%rax\n\t" /* target->%rax */ \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_CALL_NOREDIR_RAX \
"addq $128,%%rsp\n\t" \ "addq $128,%%rsp\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[6]; \ volatile unsigned long _argvec[6]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)(arg1); \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)(arg2); \ _argvec[2] = (unsigned long)(arg2); \
_argvec[3] = (unsigned long)(arg3); \ _argvec[3] = (unsigned long)(arg3); \
_argvec[4] = (unsigned long)(arg4); \ _argvec[4] = (unsigned long)(arg4); \
_argvec[5] = (unsigned long)(arg5); \ _argvec[5] = (unsigned long)(arg5); \
__asm__ volatile( \ __asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"subq $128,%%rsp\n\t" \ "subq $128,%%rsp\n\t" \
"movq 40(%%rax), %%r8\n\t" \ "movq 40(%%rax), %%r8\n\t" \
"movq 32(%%rax), %%rcx\n\t" \ "movq 32(%%rax), %%rcx\n\t" \
"movq 24(%%rax), %%rdx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \
"movq 16(%%rax), %%rsi\n\t" \ "movq 16(%%rax), %%rsi\n\t" \
"movq 8(%%rax), %%rdi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \
"movq (%%rax), %%rax\n\t" /* target->%rax */ \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_CALL_NOREDIR_RAX \
"addq $128,%%rsp\n\t" \ "addq $128,%%rsp\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[7]; \ volatile unsigned long _argvec[7]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)(arg1); \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)(arg2); \ _argvec[2] = (unsigned long)(arg2); \
_argvec[3] = (unsigned long)(arg3); \ _argvec[3] = (unsigned long)(arg3); \
_argvec[4] = (unsigned long)(arg4); \ _argvec[4] = (unsigned long)(arg4); \
_argvec[5] = (unsigned long)(arg5); \ _argvec[5] = (unsigned long)(arg5); \
_argvec[6] = (unsigned long)(arg6); \ _argvec[6] = (unsigned long)(arg6); \
__asm__ volatile( \ __asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"subq $128,%%rsp\n\t" \ "subq $128,%%rsp\n\t" \
"movq 48(%%rax), %%r9\n\t" \ "movq 48(%%rax), %%r9\n\t" \
"movq 40(%%rax), %%r8\n\t" \ "movq 40(%%rax), %%r8\n\t" \
"movq 32(%%rax), %%rcx\n\t" \ "movq 32(%%rax), %%rcx\n\t" \
"movq 24(%%rax), %%rdx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \
"movq 16(%%rax), %%rsi\n\t" \ "movq 16(%%rax), %%rsi\n\t" \
"movq 8(%%rax), %%rdi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \
"movq (%%rax), %%rax\n\t" /* target->%rax */ \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
"addq $128,%%rsp\n\t" \
VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_CALL_NOREDIR_RAX \
"addq $128,%%rsp\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7) \ arg7) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[8]; \ volatile unsigned long _argvec[8]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)(arg1); \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)(arg2); \ _argvec[2] = (unsigned long)(arg2); \
_argvec[3] = (unsigned long)(arg3); \ _argvec[3] = (unsigned long)(arg3); \
_argvec[4] = (unsigned long)(arg4); \ _argvec[4] = (unsigned long)(arg4); \
_argvec[5] = (unsigned long)(arg5); \ _argvec[5] = (unsigned long)(arg5); \
_argvec[6] = (unsigned long)(arg6); \ _argvec[6] = (unsigned long)(arg6); \
_argvec[7] = (unsigned long)(arg7); \ _argvec[7] = (unsigned long)(arg7); \
__asm__ volatile( \ __asm__ volatile( \
"subq $128,%%rsp\n\t" \ VALGRIND_CFI_PROLOGUE \
"subq $136,%%rsp\n\t" \
"pushq 56(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \
"movq 48(%%rax), %%r9\n\t" \ "movq 48(%%rax), %%r9\n\t" \
"movq 40(%%rax), %%r8\n\t" \ "movq 40(%%rax), %%r8\n\t" \
"movq 32(%%rax), %%rcx\n\t" \ "movq 32(%%rax), %%rcx\n\t" \
"movq 24(%%rax), %%rdx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \
"movq 16(%%rax), %%rsi\n\t" \ "movq 16(%%rax), %%rsi\n\t" \
"movq 8(%%rax), %%rdi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \
"movq (%%rax), %%rax\n\t" /* target->%rax */ \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_CALL_NOREDIR_RAX \
"addq $8, %%rsp\n" \ "addq $8, %%rsp\n" \
"addq $128,%%rsp\n\t" \ "addq $136,%%rsp\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7,arg8) \ arg7,arg8) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[9]; \ volatile unsigned long _argvec[9]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)(arg1); \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)(arg2); \ _argvec[2] = (unsigned long)(arg2); \
_argvec[3] = (unsigned long)(arg3); \ _argvec[3] = (unsigned long)(arg3); \
_argvec[4] = (unsigned long)(arg4); \ _argvec[4] = (unsigned long)(arg4); \
_argvec[5] = (unsigned long)(arg5); \ _argvec[5] = (unsigned long)(arg5); \
_argvec[6] = (unsigned long)(arg6); \ _argvec[6] = (unsigned long)(arg6); \
_argvec[7] = (unsigned long)(arg7); \ _argvec[7] = (unsigned long)(arg7); \
_argvec[8] = (unsigned long)(arg8); \ _argvec[8] = (unsigned long)(arg8); \
__asm__ volatile( \ __asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"subq $128,%%rsp\n\t" \ "subq $128,%%rsp\n\t" \
"pushq 64(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \
"pushq 56(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \
"movq 48(%%rax), %%r9\n\t" \ "movq 48(%%rax), %%r9\n\t" \
"movq 40(%%rax), %%r8\n\t" \ "movq 40(%%rax), %%r8\n\t" \
"movq 32(%%rax), %%rcx\n\t" \ "movq 32(%%rax), %%rcx\n\t" \
"movq 24(%%rax), %%rdx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \
"movq 16(%%rax), %%rsi\n\t" \ "movq 16(%%rax), %%rsi\n\t" \
"movq 8(%%rax), %%rdi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \
"movq (%%rax), %%rax\n\t" /* target->%rax */ \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_CALL_NOREDIR_RAX \
"addq $16, %%rsp\n" \ "addq $16, %%rsp\n" \
"addq $128,%%rsp\n\t" \ "addq $128,%%rsp\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7,arg8,arg9) \ arg7,arg8,arg9) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[10]; \ volatile unsigned long _argvec[10]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
skipping to change at line 1297 skipping to change at line 1514
_argvec[1] = (unsigned long)(arg1); \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)(arg2); \ _argvec[2] = (unsigned long)(arg2); \
_argvec[3] = (unsigned long)(arg3); \ _argvec[3] = (unsigned long)(arg3); \
_argvec[4] = (unsigned long)(arg4); \ _argvec[4] = (unsigned long)(arg4); \
_argvec[5] = (unsigned long)(arg5); \ _argvec[5] = (unsigned long)(arg5); \
_argvec[6] = (unsigned long)(arg6); \ _argvec[6] = (unsigned long)(arg6); \
_argvec[7] = (unsigned long)(arg7); \ _argvec[7] = (unsigned long)(arg7); \
_argvec[8] = (unsigned long)(arg8); \ _argvec[8] = (unsigned long)(arg8); \
_argvec[9] = (unsigned long)(arg9); \ _argvec[9] = (unsigned long)(arg9); \
__asm__ volatile( \ __asm__ volatile( \
"subq $128,%%rsp\n\t" \ VALGRIND_CFI_PROLOGUE \
"subq $136,%%rsp\n\t" \
"pushq 72(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \
"pushq 64(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \
"pushq 56(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \
"movq 48(%%rax), %%r9\n\t" \ "movq 48(%%rax), %%r9\n\t" \
"movq 40(%%rax), %%r8\n\t" \ "movq 40(%%rax), %%r8\n\t" \
"movq 32(%%rax), %%rcx\n\t" \ "movq 32(%%rax), %%rcx\n\t" \
"movq 24(%%rax), %%rdx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \
"movq 16(%%rax), %%rsi\n\t" \ "movq 16(%%rax), %%rsi\n\t" \
"movq 8(%%rax), %%rdi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \
"movq (%%rax), %%rax\n\t" /* target->%rax */ \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_CALL_NOREDIR_RAX \
"addq $24, %%rsp\n" \ "addq $24, %%rsp\n" \
"addq $128,%%rsp\n\t" \ "addq $136,%%rsp\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7,arg8,arg9,arg10) \ arg7,arg8,arg9,arg10) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[11]; \ volatile unsigned long _argvec[11]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
skipping to change at line 1336 skipping to change at line 1555
_argvec[2] = (unsigned long)(arg2); \ _argvec[2] = (unsigned long)(arg2); \
_argvec[3] = (unsigned long)(arg3); \ _argvec[3] = (unsigned long)(arg3); \
_argvec[4] = (unsigned long)(arg4); \ _argvec[4] = (unsigned long)(arg4); \
_argvec[5] = (unsigned long)(arg5); \ _argvec[5] = (unsigned long)(arg5); \
_argvec[6] = (unsigned long)(arg6); \ _argvec[6] = (unsigned long)(arg6); \
_argvec[7] = (unsigned long)(arg7); \ _argvec[7] = (unsigned long)(arg7); \
_argvec[8] = (unsigned long)(arg8); \ _argvec[8] = (unsigned long)(arg8); \
_argvec[9] = (unsigned long)(arg9); \ _argvec[9] = (unsigned long)(arg9); \
_argvec[10] = (unsigned long)(arg10); \ _argvec[10] = (unsigned long)(arg10); \
__asm__ volatile( \ __asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"subq $128,%%rsp\n\t" \ "subq $128,%%rsp\n\t" \
"pushq 80(%%rax)\n\t" \ "pushq 80(%%rax)\n\t" \
"pushq 72(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \
"pushq 64(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \
"pushq 56(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \
"movq 48(%%rax), %%r9\n\t" \ "movq 48(%%rax), %%r9\n\t" \
"movq 40(%%rax), %%r8\n\t" \ "movq 40(%%rax), %%r8\n\t" \
"movq 32(%%rax), %%rcx\n\t" \ "movq 32(%%rax), %%rcx\n\t" \
"movq 24(%%rax), %%rdx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \
"movq 16(%%rax), %%rsi\n\t" \ "movq 16(%%rax), %%rsi\n\t" \
"movq 8(%%rax), %%rdi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \
"movq (%%rax), %%rax\n\t" /* target->%rax */ \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_CALL_NOREDIR_RAX \
"addq $32, %%rsp\n" \ "addq $32, %%rsp\n" \
"addq $128,%%rsp\n\t" \ "addq $128,%%rsp\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7,arg8,arg9,arg10,arg11) \ arg7,arg8,arg9,arg10,arg11) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[12]; \ volatile unsigned long _argvec[12]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
skipping to change at line 1377 skipping to change at line 1598
_argvec[3] = (unsigned long)(arg3); \ _argvec[3] = (unsigned long)(arg3); \
_argvec[4] = (unsigned long)(arg4); \ _argvec[4] = (unsigned long)(arg4); \
_argvec[5] = (unsigned long)(arg5); \ _argvec[5] = (unsigned long)(arg5); \
_argvec[6] = (unsigned long)(arg6); \ _argvec[6] = (unsigned long)(arg6); \
_argvec[7] = (unsigned long)(arg7); \ _argvec[7] = (unsigned long)(arg7); \
_argvec[8] = (unsigned long)(arg8); \ _argvec[8] = (unsigned long)(arg8); \
_argvec[9] = (unsigned long)(arg9); \ _argvec[9] = (unsigned long)(arg9); \
_argvec[10] = (unsigned long)(arg10); \ _argvec[10] = (unsigned long)(arg10); \
_argvec[11] = (unsigned long)(arg11); \ _argvec[11] = (unsigned long)(arg11); \
__asm__ volatile( \ __asm__ volatile( \
"subq $128,%%rsp\n\t" \ VALGRIND_CFI_PROLOGUE \
"subq $136,%%rsp\n\t" \
"pushq 88(%%rax)\n\t" \ "pushq 88(%%rax)\n\t" \
"pushq 80(%%rax)\n\t" \ "pushq 80(%%rax)\n\t" \
"pushq 72(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \
"pushq 64(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \
"pushq 56(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \
"movq 48(%%rax), %%r9\n\t" \ "movq 48(%%rax), %%r9\n\t" \
"movq 40(%%rax), %%r8\n\t" \ "movq 40(%%rax), %%r8\n\t" \
"movq 32(%%rax), %%rcx\n\t" \ "movq 32(%%rax), %%rcx\n\t" \
"movq 24(%%rax), %%rdx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \
"movq 16(%%rax), %%rsi\n\t" \ "movq 16(%%rax), %%rsi\n\t" \
"movq 8(%%rax), %%rdi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \
"movq (%%rax), %%rax\n\t" /* target->%rax */ \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_CALL_NOREDIR_RAX \
"addq $40, %%rsp\n" \ "addq $40, %%rsp\n" \
"addq $128,%%rsp\n\t" \ "addq $136,%%rsp\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7,arg8,arg9,arg10,arg11,arg12) \ arg7,arg8,arg9,arg10,arg11,arg12) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[13]; \ volatile unsigned long _argvec[13]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
skipping to change at line 1420 skipping to change at line 1643
_argvec[4] = (unsigned long)(arg4); \ _argvec[4] = (unsigned long)(arg4); \
_argvec[5] = (unsigned long)(arg5); \ _argvec[5] = (unsigned long)(arg5); \
_argvec[6] = (unsigned long)(arg6); \ _argvec[6] = (unsigned long)(arg6); \
_argvec[7] = (unsigned long)(arg7); \ _argvec[7] = (unsigned long)(arg7); \
_argvec[8] = (unsigned long)(arg8); \ _argvec[8] = (unsigned long)(arg8); \
_argvec[9] = (unsigned long)(arg9); \ _argvec[9] = (unsigned long)(arg9); \
_argvec[10] = (unsigned long)(arg10); \ _argvec[10] = (unsigned long)(arg10); \
_argvec[11] = (unsigned long)(arg11); \ _argvec[11] = (unsigned long)(arg11); \
_argvec[12] = (unsigned long)(arg12); \ _argvec[12] = (unsigned long)(arg12); \
__asm__ volatile( \ __asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"subq $128,%%rsp\n\t" \ "subq $128,%%rsp\n\t" \
"pushq 96(%%rax)\n\t" \ "pushq 96(%%rax)\n\t" \
"pushq 88(%%rax)\n\t" \ "pushq 88(%%rax)\n\t" \
"pushq 80(%%rax)\n\t" \ "pushq 80(%%rax)\n\t" \
"pushq 72(%%rax)\n\t" \ "pushq 72(%%rax)\n\t" \
"pushq 64(%%rax)\n\t" \ "pushq 64(%%rax)\n\t" \
"pushq 56(%%rax)\n\t" \ "pushq 56(%%rax)\n\t" \
"movq 48(%%rax), %%r9\n\t" \ "movq 48(%%rax), %%r9\n\t" \
"movq 40(%%rax), %%r8\n\t" \ "movq 40(%%rax), %%r8\n\t" \
"movq 32(%%rax), %%rcx\n\t" \ "movq 32(%%rax), %%rcx\n\t" \
"movq 24(%%rax), %%rdx\n\t" \ "movq 24(%%rax), %%rdx\n\t" \
"movq 16(%%rax), %%rsi\n\t" \ "movq 16(%%rax), %%rsi\n\t" \
"movq 8(%%rax), %%rdi\n\t" \ "movq 8(%%rax), %%rdi\n\t" \
"movq (%%rax), %%rax\n\t" /* target->%rax */ \ "movq (%%rax), %%rax\n\t" /* target->%rax */ \
VALGRIND_CALL_NOREDIR_RAX \ VALGRIND_CALL_NOREDIR_RAX \
"addq $48, %%rsp\n" \ "addq $48, %%rsp\n" \
"addq $128,%%rsp\n\t" \ "addq $128,%%rsp\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=a" (_res) \ : /*out*/ "=a" (_res) \
: /*in*/ "a" (&_argvec[0]) \ : /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15" \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#endif /* PLAT_amd64_linux */ #endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
/* ------------------------ ppc32-linux ------------------------ */ /* ------------------------ ppc32-linux ------------------------ */
#if defined(PLAT_ppc32_linux) #if defined(PLAT_ppc32_linux)
/* This is useful for finding out about the on-stack stuff: /* This is useful for finding out about the on-stack stuff:
extern int f9 ( int,int,int,int,int,int,int,int,int ); extern int f9 ( int,int,int,int,int,int,int,int,int );
extern int f10 ( int,int,int,int,int,int,int,int,int,int ); extern int f10 ( int,int,int,int,int,int,int,int,int,int );
extern int f11 ( int,int,int,int,int,int,int,int,int,int,int ); extern int f11 ( int,int,int,int,int,int,int,int,int,int,int );
skipping to change at line 2437 skipping to change at line 2662
"addi 1,1,144" /* restore frame */ \ "addi 1,1,144" /* restore frame */ \
: /*out*/ "=r" (_res) \ : /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \ : /*in*/ "r" (&_argvec[2]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#endif /* PLAT_ppc64_linux */ #endif /* PLAT_ppc64_linux */
/* ------------------------ ppc32-aix5 ------------------------- */ /* ------------------------- arm-linux ------------------------- */
#if defined(PLAT_ppc32_aix5) #if defined(PLAT_arm_linux)
/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
/* These regs are trashed by the hidden call. */ /* These regs are trashed by the hidden call. */
#define __CALLER_SAVED_REGS \ #define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3","r4","r14"
"lr", "ctr", "xer", \
"cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \
"r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \
"r11", "r12", "r13"
/* Expand the stack frame, copying enough info that unwinding
still works. Trashes r3. */
#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr) \ /* These CALL_FN_ macros assume that on arm-linux, sizeof(unsigned
"addi 1,1,-" #_n_fr "\n\t" \
"lwz 3," #_n_fr "(1)\n\t" \
"stw 3,0(1)\n\t"
#define VG_CONTRACT_FRAME_BY(_n_fr) \
"addi 1,1," #_n_fr "\n\t"
/* These CALL_FN_ macros assume that on ppc32-aix5, sizeof(unsigned
long) == 4. */ long) == 4. */
#define CALL_FN_W_v(lval, orig) \ #define CALL_FN_W_v(lval, orig) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+0]; \ volatile unsigned long _argvec[1]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)_orig.r2; \
_argvec[2] = (unsigned long)_orig.nraddr; \
__asm__ volatile( \ __asm__ volatile( \
"mr 11,%1\n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \
VG_EXPAND_FRAME_BY_trashes_r3(512) \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
"stw 2,-8(11)\n\t" /* save tocptr */ \ "mov %0, r0\n" \
"lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
"lwz 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"lwz 2,-8(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \ : /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \ : /*in*/ "0" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_W(lval, orig, arg1) \ #define CALL_FN_W_W(lval, orig, arg1) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+1]; \ volatile unsigned long _argvec[2]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)_orig.r2; \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)_orig.nraddr; \
_argvec[2+1] = (unsigned long)arg1; \
__asm__ volatile( \ __asm__ volatile( \
"mr 11,%1\n\t" \ "ldr r0, [%1, #4] \n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \ "ldr r4, [%1] \n\t" /* target->r4 */ \
"stw 2,-8(11)\n\t" /* save tocptr */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
"lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ "mov %0, r0\n" \
"lwz 3, 4(11)\n\t" /* arg1->r3 */ \
"lwz 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"lwz 2,-8(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \ : /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \ : /*in*/ "0" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_WW(lval, orig, arg1,arg2) \ #define CALL_FN_W_WW(lval, orig, arg1,arg2) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+2]; \ volatile unsigned long _argvec[3]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)_orig.r2; \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2] = (unsigned long)(arg2); \
_argvec[2+1] = (unsigned long)arg1; \
_argvec[2+2] = (unsigned long)arg2; \
__asm__ volatile( \ __asm__ volatile( \
"mr 11,%1\n\t" \ "ldr r0, [%1, #4] \n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \ "ldr r1, [%1, #8] \n\t" \
"stw 2,-8(11)\n\t" /* save tocptr */ \ "ldr r4, [%1] \n\t" /* target->r4 */ \
"lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
"lwz 3, 4(11)\n\t" /* arg1->r3 */ \ "mov %0, r0\n" \
"lwz 4, 8(11)\n\t" /* arg2->r4 */ \
"lwz 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"lwz 2,-8(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \ : /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \ : /*in*/ "0" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \ #define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+3]; \ volatile unsigned long _argvec[4]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)_orig.r2; \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2] = (unsigned long)(arg2); \
_argvec[2+1] = (unsigned long)arg1; \ _argvec[3] = (unsigned long)(arg3); \
_argvec[2+2] = (unsigned long)arg2; \
_argvec[2+3] = (unsigned long)arg3; \
__asm__ volatile( \ __asm__ volatile( \
"mr 11,%1\n\t" \ "ldr r0, [%1, #4] \n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \ "ldr r1, [%1, #8] \n\t" \
"stw 2,-8(11)\n\t" /* save tocptr */ \ "ldr r2, [%1, #12] \n\t" \
"lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ "ldr r4, [%1] \n\t" /* target->r4 */ \
"lwz 3, 4(11)\n\t" /* arg1->r3 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
"lwz 4, 8(11)\n\t" /* arg2->r4 */ \ "mov %0, r0\n" \
"lwz 5, 12(11)\n\t" /* arg3->r5 */ \
"lwz 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"lwz 2,-8(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \ : /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \ : /*in*/ "0" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \ #define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+4]; \ volatile unsigned long _argvec[5]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)_orig.r2; \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2] = (unsigned long)(arg2); \
_argvec[2+1] = (unsigned long)arg1; \ _argvec[3] = (unsigned long)(arg3); \
_argvec[2+2] = (unsigned long)arg2; \ _argvec[4] = (unsigned long)(arg4); \
_argvec[2+3] = (unsigned long)arg3; \
_argvec[2+4] = (unsigned long)arg4; \
__asm__ volatile( \ __asm__ volatile( \
"mr 11,%1\n\t" \ "ldr r0, [%1, #4] \n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \ "ldr r1, [%1, #8] \n\t" \
"stw 2,-8(11)\n\t" /* save tocptr */ \ "ldr r2, [%1, #12] \n\t" \
"lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \ "ldr r3, [%1, #16] \n\t" \
"lwz 3, 4(11)\n\t" /* arg1->r3 */ \ "ldr r4, [%1] \n\t" /* target->r4 */ \
"lwz 4, 8(11)\n\t" /* arg2->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
"lwz 5, 12(11)\n\t" /* arg3->r5 */ \ "mov %0, r0" \
"lwz 6, 16(11)\n\t" /* arg4->r6 */ \
"lwz 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"lwz 2,-8(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \ : /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \ : /*in*/ "0" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \ #define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+5]; \ volatile unsigned long _argvec[6]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)_orig.r2; \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2] = (unsigned long)(arg2); \
_argvec[2+1] = (unsigned long)arg1; \ _argvec[3] = (unsigned long)(arg3); \
_argvec[2+2] = (unsigned long)arg2; \ _argvec[4] = (unsigned long)(arg4); \
_argvec[2+3] = (unsigned long)arg3; \ _argvec[5] = (unsigned long)(arg5); \
_argvec[2+4] = (unsigned long)arg4; \
_argvec[2+5] = (unsigned long)arg5; \
__asm__ volatile( \
"mr 11,%1\n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \
"stw 2,-8(11)\n\t" /* save tocptr */ \
"lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
"lwz 3, 4(11)\n\t" /* arg1->r3 */ \
"lwz 4, 8(11)\n\t" /* arg2->r4 */ \
"lwz 5, 12(11)\n\t" /* arg3->r5 */ \
"lwz 6, 16(11)\n\t" /* arg4->r6 */ \
"lwz 7, 20(11)\n\t" /* arg5->r7 */ \
"lwz 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"lwz 2,-8(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+6]; \
volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \
_argvec[1] = (unsigned long)_orig.r2; \
_argvec[2] = (unsigned long)_orig.nraddr; \
_argvec[2+1] = (unsigned long)arg1; \
_argvec[2+2] = (unsigned long)arg2; \
_argvec[2+3] = (unsigned long)arg3; \
_argvec[2+4] = (unsigned long)arg4; \
_argvec[2+5] = (unsigned long)arg5; \
_argvec[2+6] = (unsigned long)arg6; \
__asm__ volatile( \
"mr 11,%1\n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \
"stw 2,-8(11)\n\t" /* save tocptr */ \
"lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
"lwz 3, 4(11)\n\t" /* arg1->r3 */ \
"lwz 4, 8(11)\n\t" /* arg2->r4 */ \
"lwz 5, 12(11)\n\t" /* arg3->r5 */ \
"lwz 6, 16(11)\n\t" /* arg4->r6 */ \
"lwz 7, 20(11)\n\t" /* arg5->r7 */ \
"lwz 8, 24(11)\n\t" /* arg6->r8 */ \
"lwz 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"lwz 2,-8(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+7]; \
volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \
_argvec[1] = (unsigned long)_orig.r2; \
_argvec[2] = (unsigned long)_orig.nraddr; \
_argvec[2+1] = (unsigned long)arg1; \
_argvec[2+2] = (unsigned long)arg2; \
_argvec[2+3] = (unsigned long)arg3; \
_argvec[2+4] = (unsigned long)arg4; \
_argvec[2+5] = (unsigned long)arg5; \
_argvec[2+6] = (unsigned long)arg6; \
_argvec[2+7] = (unsigned long)arg7; \
__asm__ volatile( \
"mr 11,%1\n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \
"stw 2,-8(11)\n\t" /* save tocptr */ \
"lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
"lwz 3, 4(11)\n\t" /* arg1->r3 */ \
"lwz 4, 8(11)\n\t" /* arg2->r4 */ \
"lwz 5, 12(11)\n\t" /* arg3->r5 */ \
"lwz 6, 16(11)\n\t" /* arg4->r6 */ \
"lwz 7, 20(11)\n\t" /* arg5->r7 */ \
"lwz 8, 24(11)\n\t" /* arg6->r8 */ \
"lwz 9, 28(11)\n\t" /* arg7->r9 */ \
"lwz 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"lwz 2,-8(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7,arg8) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+8]; \
volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \
_argvec[1] = (unsigned long)_orig.r2; \
_argvec[2] = (unsigned long)_orig.nraddr; \
_argvec[2+1] = (unsigned long)arg1; \
_argvec[2+2] = (unsigned long)arg2; \
_argvec[2+3] = (unsigned long)arg3; \
_argvec[2+4] = (unsigned long)arg4; \
_argvec[2+5] = (unsigned long)arg5; \
_argvec[2+6] = (unsigned long)arg6; \
_argvec[2+7] = (unsigned long)arg7; \
_argvec[2+8] = (unsigned long)arg8; \
__asm__ volatile( \
"mr 11,%1\n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \
"stw 2,-8(11)\n\t" /* save tocptr */ \
"lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
"lwz 3, 4(11)\n\t" /* arg1->r3 */ \
"lwz 4, 8(11)\n\t" /* arg2->r4 */ \
"lwz 5, 12(11)\n\t" /* arg3->r5 */ \
"lwz 6, 16(11)\n\t" /* arg4->r6 */ \
"lwz 7, 20(11)\n\t" /* arg5->r7 */ \
"lwz 8, 24(11)\n\t" /* arg6->r8 */ \
"lwz 9, 28(11)\n\t" /* arg7->r9 */ \
"lwz 10, 32(11)\n\t" /* arg8->r10 */ \
"lwz 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"lwz 2,-8(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7,arg8,arg9) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+9]; \
volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \
_argvec[1] = (unsigned long)_orig.r2; \
_argvec[2] = (unsigned long)_orig.nraddr; \
_argvec[2+1] = (unsigned long)arg1; \
_argvec[2+2] = (unsigned long)arg2; \
_argvec[2+3] = (unsigned long)arg3; \
_argvec[2+4] = (unsigned long)arg4; \
_argvec[2+5] = (unsigned long)arg5; \
_argvec[2+6] = (unsigned long)arg6; \
_argvec[2+7] = (unsigned long)arg7; \
_argvec[2+8] = (unsigned long)arg8; \
_argvec[2+9] = (unsigned long)arg9; \
__asm__ volatile( \
"mr 11,%1\n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \
"stw 2,-8(11)\n\t" /* save tocptr */ \
"lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
VG_EXPAND_FRAME_BY_trashes_r3(64) \
/* arg9 */ \
"lwz 3,36(11)\n\t" \
"stw 3,56(1)\n\t" \
/* args1-8 */ \
"lwz 3, 4(11)\n\t" /* arg1->r3 */ \
"lwz 4, 8(11)\n\t" /* arg2->r4 */ \
"lwz 5, 12(11)\n\t" /* arg3->r5 */ \
"lwz 6, 16(11)\n\t" /* arg4->r6 */ \
"lwz 7, 20(11)\n\t" /* arg5->r7 */ \
"lwz 8, 24(11)\n\t" /* arg6->r8 */ \
"lwz 9, 28(11)\n\t" /* arg7->r9 */ \
"lwz 10, 32(11)\n\t" /* arg8->r10 */ \
"lwz 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"lwz 2,-8(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(64) \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7,arg8,arg9,arg10) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+10]; \
volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \
_argvec[1] = (unsigned long)_orig.r2; \
_argvec[2] = (unsigned long)_orig.nraddr; \
_argvec[2+1] = (unsigned long)arg1; \
_argvec[2+2] = (unsigned long)arg2; \
_argvec[2+3] = (unsigned long)arg3; \
_argvec[2+4] = (unsigned long)arg4; \
_argvec[2+5] = (unsigned long)arg5; \
_argvec[2+6] = (unsigned long)arg6; \
_argvec[2+7] = (unsigned long)arg7; \
_argvec[2+8] = (unsigned long)arg8; \
_argvec[2+9] = (unsigned long)arg9; \
_argvec[2+10] = (unsigned long)arg10; \
__asm__ volatile( \
"mr 11,%1\n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \
"stw 2,-8(11)\n\t" /* save tocptr */ \
"lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
VG_EXPAND_FRAME_BY_trashes_r3(64) \
/* arg10 */ \
"lwz 3,40(11)\n\t" \
"stw 3,60(1)\n\t" \
/* arg9 */ \
"lwz 3,36(11)\n\t" \
"stw 3,56(1)\n\t" \
/* args1-8 */ \
"lwz 3, 4(11)\n\t" /* arg1->r3 */ \
"lwz 4, 8(11)\n\t" /* arg2->r4 */ \
"lwz 5, 12(11)\n\t" /* arg3->r5 */ \
"lwz 6, 16(11)\n\t" /* arg4->r6 */ \
"lwz 7, 20(11)\n\t" /* arg5->r7 */ \
"lwz 8, 24(11)\n\t" /* arg6->r8 */ \
"lwz 9, 28(11)\n\t" /* arg7->r9 */ \
"lwz 10, 32(11)\n\t" /* arg8->r10 */ \
"lwz 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"lwz 2,-8(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(64) \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7,arg8,arg9,arg10,arg11) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+11]; \
volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \
_argvec[1] = (unsigned long)_orig.r2; \
_argvec[2] = (unsigned long)_orig.nraddr; \
_argvec[2+1] = (unsigned long)arg1; \
_argvec[2+2] = (unsigned long)arg2; \
_argvec[2+3] = (unsigned long)arg3; \
_argvec[2+4] = (unsigned long)arg4; \
_argvec[2+5] = (unsigned long)arg5; \
_argvec[2+6] = (unsigned long)arg6; \
_argvec[2+7] = (unsigned long)arg7; \
_argvec[2+8] = (unsigned long)arg8; \
_argvec[2+9] = (unsigned long)arg9; \
_argvec[2+10] = (unsigned long)arg10; \
_argvec[2+11] = (unsigned long)arg11; \
__asm__ volatile( \
"mr 11,%1\n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \
"stw 2,-8(11)\n\t" /* save tocptr */ \
"lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
VG_EXPAND_FRAME_BY_trashes_r3(72) \
/* arg11 */ \
"lwz 3,44(11)\n\t" \
"stw 3,64(1)\n\t" \
/* arg10 */ \
"lwz 3,40(11)\n\t" \
"stw 3,60(1)\n\t" \
/* arg9 */ \
"lwz 3,36(11)\n\t" \
"stw 3,56(1)\n\t" \
/* args1-8 */ \
"lwz 3, 4(11)\n\t" /* arg1->r3 */ \
"lwz 4, 8(11)\n\t" /* arg2->r4 */ \
"lwz 5, 12(11)\n\t" /* arg3->r5 */ \
"lwz 6, 16(11)\n\t" /* arg4->r6 */ \
"lwz 7, 20(11)\n\t" /* arg5->r7 */ \
"lwz 8, 24(11)\n\t" /* arg6->r8 */ \
"lwz 9, 28(11)\n\t" /* arg7->r9 */ \
"lwz 10, 32(11)\n\t" /* arg8->r10 */ \
"lwz 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"lwz 2,-8(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(72) \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7,arg8,arg9,arg10,arg11,arg12) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+12]; \
volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \
_argvec[1] = (unsigned long)_orig.r2; \
_argvec[2] = (unsigned long)_orig.nraddr; \
_argvec[2+1] = (unsigned long)arg1; \
_argvec[2+2] = (unsigned long)arg2; \
_argvec[2+3] = (unsigned long)arg3; \
_argvec[2+4] = (unsigned long)arg4; \
_argvec[2+5] = (unsigned long)arg5; \
_argvec[2+6] = (unsigned long)arg6; \
_argvec[2+7] = (unsigned long)arg7; \
_argvec[2+8] = (unsigned long)arg8; \
_argvec[2+9] = (unsigned long)arg9; \
_argvec[2+10] = (unsigned long)arg10; \
_argvec[2+11] = (unsigned long)arg11; \
_argvec[2+12] = (unsigned long)arg12; \
__asm__ volatile( \
"mr 11,%1\n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \
"stw 2,-8(11)\n\t" /* save tocptr */ \
"lwz 2,-4(11)\n\t" /* use nraddr's tocptr */ \
VG_EXPAND_FRAME_BY_trashes_r3(72) \
/* arg12 */ \
"lwz 3,48(11)\n\t" \
"stw 3,68(1)\n\t" \
/* arg11 */ \
"lwz 3,44(11)\n\t" \
"stw 3,64(1)\n\t" \
/* arg10 */ \
"lwz 3,40(11)\n\t" \
"stw 3,60(1)\n\t" \
/* arg9 */ \
"lwz 3,36(11)\n\t" \
"stw 3,56(1)\n\t" \
/* args1-8 */ \
"lwz 3, 4(11)\n\t" /* arg1->r3 */ \
"lwz 4, 8(11)\n\t" /* arg2->r4 */ \
"lwz 5, 12(11)\n\t" /* arg3->r5 */ \
"lwz 6, 16(11)\n\t" /* arg4->r6 */ \
"lwz 7, 20(11)\n\t" /* arg5->r7 */ \
"lwz 8, 24(11)\n\t" /* arg6->r8 */ \
"lwz 9, 28(11)\n\t" /* arg7->r9 */ \
"lwz 10, 32(11)\n\t" /* arg8->r10 */ \
"lwz 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"lwz 2,-8(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(72) \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#endif /* PLAT_ppc32_aix5 */
/* ------------------------ ppc64-aix5 ------------------------- */
#if defined(PLAT_ppc64_aix5)
/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
/* These regs are trashed by the hidden call. */
#define __CALLER_SAVED_REGS \
"lr", "ctr", "xer", \
"cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", \
"r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", \
"r11", "r12", "r13"
/* Expand the stack frame, copying enough info that unwinding
still works. Trashes r3. */
#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr) \
"addi 1,1,-" #_n_fr "\n\t" \
"ld 3," #_n_fr "(1)\n\t" \
"std 3,0(1)\n\t"
#define VG_CONTRACT_FRAME_BY(_n_fr) \
"addi 1,1," #_n_fr "\n\t"
/* These CALL_FN_ macros assume that on ppc64-aix5, sizeof(unsigned
long) == 8. */
#define CALL_FN_W_v(lval, orig) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+0]; \
volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \
_argvec[1] = (unsigned long)_orig.r2; \
_argvec[2] = (unsigned long)_orig.nraddr; \
__asm__ volatile( \
"mr 11,%1\n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \
"std 2,-16(11)\n\t" /* save tocptr */ \
"ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
"ld 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"ld 2,-16(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_W(lval, orig, arg1) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+1]; \
volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \
_argvec[1] = (unsigned long)_orig.r2; \
_argvec[2] = (unsigned long)_orig.nraddr; \
_argvec[2+1] = (unsigned long)arg1; \
__asm__ volatile( \
"mr 11,%1\n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \
"std 2,-16(11)\n\t" /* save tocptr */ \
"ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
"ld 3, 8(11)\n\t" /* arg1->r3 */ \
"ld 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"ld 2,-16(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_WW(lval, orig, arg1,arg2) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+2]; \
volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \
_argvec[1] = (unsigned long)_orig.r2; \
_argvec[2] = (unsigned long)_orig.nraddr; \
_argvec[2+1] = (unsigned long)arg1; \
_argvec[2+2] = (unsigned long)arg2; \
__asm__ volatile( \
"mr 11,%1\n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \
"std 2,-16(11)\n\t" /* save tocptr */ \
"ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
"ld 3, 8(11)\n\t" /* arg1->r3 */ \
"ld 4, 16(11)\n\t" /* arg2->r4 */ \
"ld 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"ld 2,-16(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+3]; \
volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \
_argvec[1] = (unsigned long)_orig.r2; \
_argvec[2] = (unsigned long)_orig.nraddr; \
_argvec[2+1] = (unsigned long)arg1; \
_argvec[2+2] = (unsigned long)arg2; \
_argvec[2+3] = (unsigned long)arg3; \
__asm__ volatile( \
"mr 11,%1\n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \
"std 2,-16(11)\n\t" /* save tocptr */ \
"ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
"ld 3, 8(11)\n\t" /* arg1->r3 */ \
"ld 4, 16(11)\n\t" /* arg2->r4 */ \
"ld 5, 24(11)\n\t" /* arg3->r5 */ \
"ld 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"ld 2,-16(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+4]; \
volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \
_argvec[1] = (unsigned long)_orig.r2; \
_argvec[2] = (unsigned long)_orig.nraddr; \
_argvec[2+1] = (unsigned long)arg1; \
_argvec[2+2] = (unsigned long)arg2; \
_argvec[2+3] = (unsigned long)arg3; \
_argvec[2+4] = (unsigned long)arg4; \
__asm__ volatile( \
"mr 11,%1\n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \
"std 2,-16(11)\n\t" /* save tocptr */ \
"ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \
"ld 3, 8(11)\n\t" /* arg1->r3 */ \
"ld 4, 16(11)\n\t" /* arg2->r4 */ \
"ld 5, 24(11)\n\t" /* arg3->r5 */ \
"ld 6, 32(11)\n\t" /* arg4->r6 */ \
"ld 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"ld 2,-16(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+5]; \
volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \
_argvec[1] = (unsigned long)_orig.r2; \
_argvec[2] = (unsigned long)_orig.nraddr; \
_argvec[2+1] = (unsigned long)arg1; \
_argvec[2+2] = (unsigned long)arg2; \
_argvec[2+3] = (unsigned long)arg3; \
_argvec[2+4] = (unsigned long)arg4; \
_argvec[2+5] = (unsigned long)arg5; \
__asm__ volatile( \ __asm__ volatile( \
"mr 11,%1\n\t" \ "ldr r0, [%1, #20] \n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \ "push {r0} \n\t" \
"std 2,-16(11)\n\t" /* save tocptr */ \ "ldr r0, [%1, #4] \n\t" \
"ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ldr r1, [%1, #8] \n\t" \
"ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ldr r2, [%1, #12] \n\t" \
"ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ldr r3, [%1, #16] \n\t" \
"ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ldr r4, [%1] \n\t" /* target->r4 */ \
"ld 6, 32(11)\n\t" /* arg4->r6 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
"ld 7, 40(11)\n\t" /* arg5->r7 */ \ "add sp, sp, #4 \n\t" \
"ld 11, 0(11)\n\t" /* target->r11 */ \ "mov %0, r0" \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"ld 2,-16(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \ : /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \ : /*in*/ "0" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \ #define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+6]; \ volatile unsigned long _argvec[7]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)_orig.r2; \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2] = (unsigned long)(arg2); \
_argvec[2+1] = (unsigned long)arg1; \ _argvec[3] = (unsigned long)(arg3); \
_argvec[2+2] = (unsigned long)arg2; \ _argvec[4] = (unsigned long)(arg4); \
_argvec[2+3] = (unsigned long)arg3; \ _argvec[5] = (unsigned long)(arg5); \
_argvec[2+4] = (unsigned long)arg4; \ _argvec[6] = (unsigned long)(arg6); \
_argvec[2+5] = (unsigned long)arg5; \
_argvec[2+6] = (unsigned long)arg6; \
__asm__ volatile( \ __asm__ volatile( \
"mr 11,%1\n\t" \ "ldr r0, [%1, #20] \n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \ "ldr r1, [%1, #24] \n\t" \
"std 2,-16(11)\n\t" /* save tocptr */ \ "push {r0, r1} \n\t" \
"ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ldr r0, [%1, #4] \n\t" \
"ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ldr r1, [%1, #8] \n\t" \
"ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ldr r2, [%1, #12] \n\t" \
"ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ldr r3, [%1, #16] \n\t" \
"ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ldr r4, [%1] \n\t" /* target->r4 */ \
"ld 7, 40(11)\n\t" /* arg5->r7 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
"ld 8, 48(11)\n\t" /* arg6->r8 */ \ "add sp, sp, #8 \n\t" \
"ld 11, 0(11)\n\t" /* target->r11 */ \ "mov %0, r0" \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"ld 2,-16(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \ : /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \ : /*in*/ "0" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ #define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7) \ arg7) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+7]; \ volatile unsigned long _argvec[8]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)_orig.r2; \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2] = (unsigned long)(arg2); \
_argvec[2+1] = (unsigned long)arg1; \ _argvec[3] = (unsigned long)(arg3); \
_argvec[2+2] = (unsigned long)arg2; \ _argvec[4] = (unsigned long)(arg4); \
_argvec[2+3] = (unsigned long)arg3; \ _argvec[5] = (unsigned long)(arg5); \
_argvec[2+4] = (unsigned long)arg4; \ _argvec[6] = (unsigned long)(arg6); \
_argvec[2+5] = (unsigned long)arg5; \ _argvec[7] = (unsigned long)(arg7); \
_argvec[2+6] = (unsigned long)arg6; \
_argvec[2+7] = (unsigned long)arg7; \
__asm__ volatile( \ __asm__ volatile( \
"mr 11,%1\n\t" \ "ldr r0, [%1, #20] \n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \ "ldr r1, [%1, #24] \n\t" \
"std 2,-16(11)\n\t" /* save tocptr */ \ "ldr r2, [%1, #28] \n\t" \
"ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "push {r0, r1, r2} \n\t" \
"ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ldr r0, [%1, #4] \n\t" \
"ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ldr r1, [%1, #8] \n\t" \
"ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ldr r2, [%1, #12] \n\t" \
"ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ldr r3, [%1, #16] \n\t" \
"ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ldr r4, [%1] \n\t" /* target->r4 */ \
"ld 8, 48(11)\n\t" /* arg6->r8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
"ld 9, 56(11)\n\t" /* arg7->r9 */ \ "add sp, sp, #12 \n\t" \
"ld 11, 0(11)\n\t" /* target->r11 */ \ "mov %0, r0" \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"ld 2,-16(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \ : /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \ : /*in*/ "0" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ #define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7,arg8) \ arg7,arg8) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+8]; \ volatile unsigned long _argvec[9]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)_orig.r2; \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2] = (unsigned long)(arg2); \
_argvec[2+1] = (unsigned long)arg1; \ _argvec[3] = (unsigned long)(arg3); \
_argvec[2+2] = (unsigned long)arg2; \ _argvec[4] = (unsigned long)(arg4); \
_argvec[2+3] = (unsigned long)arg3; \ _argvec[5] = (unsigned long)(arg5); \
_argvec[2+4] = (unsigned long)arg4; \ _argvec[6] = (unsigned long)(arg6); \
_argvec[2+5] = (unsigned long)arg5; \ _argvec[7] = (unsigned long)(arg7); \
_argvec[2+6] = (unsigned long)arg6; \ _argvec[8] = (unsigned long)(arg8); \
_argvec[2+7] = (unsigned long)arg7; \
_argvec[2+8] = (unsigned long)arg8; \
__asm__ volatile( \ __asm__ volatile( \
"mr 11,%1\n\t" \ "ldr r0, [%1, #20] \n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \ "ldr r1, [%1, #24] \n\t" \
"std 2,-16(11)\n\t" /* save tocptr */ \ "ldr r2, [%1, #28] \n\t" \
"ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ldr r3, [%1, #32] \n\t" \
"ld 3, 8(11)\n\t" /* arg1->r3 */ \ "push {r0, r1, r2, r3} \n\t" \
"ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ldr r0, [%1, #4] \n\t" \
"ld 5, 24(11)\n\t" /* arg3->r5 */ \ "ldr r1, [%1, #8] \n\t" \
"ld 6, 32(11)\n\t" /* arg4->r6 */ \ "ldr r2, [%1, #12] \n\t" \
"ld 7, 40(11)\n\t" /* arg5->r7 */ \ "ldr r3, [%1, #16] \n\t" \
"ld 8, 48(11)\n\t" /* arg6->r8 */ \ "ldr r4, [%1] \n\t" /* target->r4 */ \
"ld 9, 56(11)\n\t" /* arg7->r9 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
"ld 10, 64(11)\n\t" /* arg8->r10 */ \ "add sp, sp, #16 \n\t" \
"ld 11, 0(11)\n\t" /* target->r11 */ \ "mov %0, r0" \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"ld 2,-16(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \ : /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \ : /*in*/ "0" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ #define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7,arg8,arg9) \ arg7,arg8,arg9) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+9]; \ volatile unsigned long _argvec[10]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)_orig.r2; \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2] = (unsigned long)(arg2); \
_argvec[2+1] = (unsigned long)arg1; \ _argvec[3] = (unsigned long)(arg3); \
_argvec[2+2] = (unsigned long)arg2; \ _argvec[4] = (unsigned long)(arg4); \
_argvec[2+3] = (unsigned long)arg3; \ _argvec[5] = (unsigned long)(arg5); \
_argvec[2+4] = (unsigned long)arg4; \ _argvec[6] = (unsigned long)(arg6); \
_argvec[2+5] = (unsigned long)arg5; \ _argvec[7] = (unsigned long)(arg7); \
_argvec[2+6] = (unsigned long)arg6; \ _argvec[8] = (unsigned long)(arg8); \
_argvec[2+7] = (unsigned long)arg7; \ _argvec[9] = (unsigned long)(arg9); \
_argvec[2+8] = (unsigned long)arg8; \
_argvec[2+9] = (unsigned long)arg9; \
__asm__ volatile( \ __asm__ volatile( \
"mr 11,%1\n\t" \ "ldr r0, [%1, #20] \n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \ "ldr r1, [%1, #24] \n\t" \
"std 2,-16(11)\n\t" /* save tocptr */ \ "ldr r2, [%1, #28] \n\t" \
"ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ldr r3, [%1, #32] \n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(128) \ "ldr r4, [%1, #36] \n\t" \
/* arg9 */ \ "push {r0, r1, r2, r3, r4} \n\t" \
"ld 3,72(11)\n\t" \ "ldr r0, [%1, #4] \n\t" \
"std 3,112(1)\n\t" \ "ldr r1, [%1, #8] \n\t" \
/* args1-8 */ \ "ldr r2, [%1, #12] \n\t" \
"ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ldr r3, [%1, #16] \n\t" \
"ld 4, 16(11)\n\t" /* arg2->r4 */ \ "ldr r4, [%1] \n\t" /* target->r4 */ \
"ld 5, 24(11)\n\t" /* arg3->r5 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
"ld 6, 32(11)\n\t" /* arg4->r6 */ \ "add sp, sp, #20 \n\t" \
"ld 7, 40(11)\n\t" /* arg5->r7 */ \ "mov %0, r0" \
"ld 8, 48(11)\n\t" /* arg6->r8 */ \
"ld 9, 56(11)\n\t" /* arg7->r9 */ \
"ld 10, 64(11)\n\t" /* arg8->r10 */ \
"ld 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"ld 2,-16(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(128) \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \ : /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \ : /*in*/ "0" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ #define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \
arg7,arg8,arg9,arg10) \ arg7,arg8,arg9,arg10) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+10]; \ volatile unsigned long _argvec[11]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)_orig.r2; \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2] = (unsigned long)(arg2); \
_argvec[2+1] = (unsigned long)arg1; \ _argvec[3] = (unsigned long)(arg3); \
_argvec[2+2] = (unsigned long)arg2; \ _argvec[4] = (unsigned long)(arg4); \
_argvec[2+3] = (unsigned long)arg3; \ _argvec[5] = (unsigned long)(arg5); \
_argvec[2+4] = (unsigned long)arg4; \ _argvec[6] = (unsigned long)(arg6); \
_argvec[2+5] = (unsigned long)arg5; \ _argvec[7] = (unsigned long)(arg7); \
_argvec[2+6] = (unsigned long)arg6; \ _argvec[8] = (unsigned long)(arg8); \
_argvec[2+7] = (unsigned long)arg7; \ _argvec[9] = (unsigned long)(arg9); \
_argvec[2+8] = (unsigned long)arg8; \ _argvec[10] = (unsigned long)(arg10); \
_argvec[2+9] = (unsigned long)arg9; \
_argvec[2+10] = (unsigned long)arg10; \
__asm__ volatile( \ __asm__ volatile( \
"mr 11,%1\n\t" \ "ldr r0, [%1, #40] \n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \ "push {r0} \n\t" \
"std 2,-16(11)\n\t" /* save tocptr */ \ "ldr r0, [%1, #20] \n\t" \
"ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ldr r1, [%1, #24] \n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(128) \ "ldr r2, [%1, #28] \n\t" \
/* arg10 */ \ "ldr r3, [%1, #32] \n\t" \
"ld 3,80(11)\n\t" \ "ldr r4, [%1, #36] \n\t" \
"std 3,120(1)\n\t" \ "push {r0, r1, r2, r3, r4} \n\t" \
/* arg9 */ \ "ldr r0, [%1, #4] \n\t" \
"ld 3,72(11)\n\t" \ "ldr r1, [%1, #8] \n\t" \
"std 3,112(1)\n\t" \ "ldr r2, [%1, #12] \n\t" \
/* args1-8 */ \ "ldr r3, [%1, #16] \n\t" \
"ld 3, 8(11)\n\t" /* arg1->r3 */ \ "ldr r4, [%1] \n\t" /* target->r4 */ \
"ld 4, 16(11)\n\t" /* arg2->r4 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
"ld 5, 24(11)\n\t" /* arg3->r5 */ \ "add sp, sp, #24 \n\t" \
"ld 6, 32(11)\n\t" /* arg4->r6 */ \ "mov %0, r0" \
"ld 7, 40(11)\n\t" /* arg5->r7 */ \
"ld 8, 48(11)\n\t" /* arg6->r8 */ \
"ld 9, 56(11)\n\t" /* arg7->r9 */ \
"ld 10, 64(11)\n\t" /* arg8->r10 */ \
"ld 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"ld 2,-16(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(128) \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \ : /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \ : /*in*/ "0" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ #define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
arg7,arg8,arg9,arg10,arg11) \ arg6,arg7,arg8,arg9,arg10, \
arg11) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+11]; \ volatile unsigned long _argvec[12]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)_orig.r2; \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2] = (unsigned long)(arg2); \
_argvec[2+1] = (unsigned long)arg1; \ _argvec[3] = (unsigned long)(arg3); \
_argvec[2+2] = (unsigned long)arg2; \ _argvec[4] = (unsigned long)(arg4); \
_argvec[2+3] = (unsigned long)arg3; \ _argvec[5] = (unsigned long)(arg5); \
_argvec[2+4] = (unsigned long)arg4; \ _argvec[6] = (unsigned long)(arg6); \
_argvec[2+5] = (unsigned long)arg5; \ _argvec[7] = (unsigned long)(arg7); \
_argvec[2+6] = (unsigned long)arg6; \ _argvec[8] = (unsigned long)(arg8); \
_argvec[2+7] = (unsigned long)arg7; \ _argvec[9] = (unsigned long)(arg9); \
_argvec[2+8] = (unsigned long)arg8; \ _argvec[10] = (unsigned long)(arg10); \
_argvec[2+9] = (unsigned long)arg9; \ _argvec[11] = (unsigned long)(arg11); \
_argvec[2+10] = (unsigned long)arg10; \
_argvec[2+11] = (unsigned long)arg11; \
__asm__ volatile( \ __asm__ volatile( \
"mr 11,%1\n\t" \ "ldr r0, [%1, #40] \n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \ "ldr r1, [%1, #44] \n\t" \
"std 2,-16(11)\n\t" /* save tocptr */ \ "push {r0, r1} \n\t" \
"ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "ldr r0, [%1, #20] \n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(144) \ "ldr r1, [%1, #24] \n\t" \
/* arg11 */ \ "ldr r2, [%1, #28] \n\t" \
"ld 3,88(11)\n\t" \ "ldr r3, [%1, #32] \n\t" \
"std 3,128(1)\n\t" \ "ldr r4, [%1, #36] \n\t" \
/* arg10 */ \ "push {r0, r1, r2, r3, r4} \n\t" \
"ld 3,80(11)\n\t" \ "ldr r0, [%1, #4] \n\t" \
"std 3,120(1)\n\t" \ "ldr r1, [%1, #8] \n\t" \
/* arg9 */ \ "ldr r2, [%1, #12] \n\t" \
"ld 3,72(11)\n\t" \ "ldr r3, [%1, #16] \n\t" \
"std 3,112(1)\n\t" \ "ldr r4, [%1] \n\t" /* target->r4 */ \
/* args1-8 */ \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
"ld 3, 8(11)\n\t" /* arg1->r3 */ \ "add sp, sp, #28 \n\t" \
"ld 4, 16(11)\n\t" /* arg2->r4 */ \ "mov %0, r0" \
"ld 5, 24(11)\n\t" /* arg3->r5 */ \
"ld 6, 32(11)\n\t" /* arg4->r6 */ \
"ld 7, 40(11)\n\t" /* arg5->r7 */ \
"ld 8, 48(11)\n\t" /* arg6->r8 */ \
"ld 9, 56(11)\n\t" /* arg7->r9 */ \
"ld 10, 64(11)\n\t" /* arg8->r10 */ \
"ld 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"ld 2,-16(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(144) \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \ : /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \ : /*in*/ "0" (&_argvec[0]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory",__CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6, \ #define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5, \
arg7,arg8,arg9,arg10,arg11,arg12) \ arg6,arg7,arg8,arg9,arg10, \
arg11,arg12) \
do { \ do { \
volatile OrigFn _orig = (orig); \ volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3+12]; \ volatile unsigned long _argvec[13]; \
volatile unsigned long _res; \ volatile unsigned long _res; \
/* _argvec[0] holds current r2 across the call */ \ _argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)_orig.r2; \ _argvec[1] = (unsigned long)(arg1); \
_argvec[2] = (unsigned long)_orig.nraddr; \ _argvec[2] = (unsigned long)(arg2); \
_argvec[2+1] = (unsigned long)arg1; \ _argvec[3] = (unsigned long)(arg3); \
_argvec[2+2] = (unsigned long)arg2; \ _argvec[4] = (unsigned long)(arg4); \
_argvec[2+3] = (unsigned long)arg3; \ _argvec[5] = (unsigned long)(arg5); \
_argvec[2+4] = (unsigned long)arg4; \ _argvec[6] = (unsigned long)(arg6); \
_argvec[2+5] = (unsigned long)arg5; \ _argvec[7] = (unsigned long)(arg7); \
_argvec[2+6] = (unsigned long)arg6; \ _argvec[8] = (unsigned long)(arg8); \
_argvec[2+7] = (unsigned long)arg7; \ _argvec[9] = (unsigned long)(arg9); \
_argvec[2+8] = (unsigned long)arg8; \ _argvec[10] = (unsigned long)(arg10); \
_argvec[2+9] = (unsigned long)arg9; \ _argvec[11] = (unsigned long)(arg11); \
_argvec[2+10] = (unsigned long)arg10; \ _argvec[12] = (unsigned long)(arg12); \
_argvec[2+11] = (unsigned long)arg11; \
_argvec[2+12] = (unsigned long)arg12; \
__asm__ volatile( \ __asm__ volatile( \
"mr 11,%1\n\t" \ "ldr r0, [%1, #40] \n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(512) \ "ldr r1, [%1, #44] \n\t" \
"std 2,-16(11)\n\t" /* save tocptr */ \ "ldr r2, [%1, #48] \n\t" \
"ld 2,-8(11)\n\t" /* use nraddr's tocptr */ \ "push {r0, r1, r2} \n\t" \
VG_EXPAND_FRAME_BY_trashes_r3(144) \ "ldr r0, [%1, #20] \n\t" \
/* arg12 */ \ "ldr r1, [%1, #24] \n\t" \
"ld 3,96(11)\n\t" \ "ldr r2, [%1, #28] \n\t" \
"std 3,136(1)\n\t" \ "ldr r3, [%1, #32] \n\t" \
/* arg11 */ \ "ldr r4, [%1, #36] \n\t" \
"ld 3,88(11)\n\t" \ "push {r0, r1, r2, r3, r4} \n\t" \
"std 3,128(1)\n\t" \ "ldr r0, [%1, #4] \n\t" \
/* arg10 */ \ "ldr r1, [%1, #8] \n\t" \
"ld 3,80(11)\n\t" \ "ldr r2, [%1, #12] \n\t" \
"std 3,120(1)\n\t" \ "ldr r3, [%1, #16] \n\t" \
/* arg9 */ \ "ldr r4, [%1] \n\t" /* target->r4 */ \
"ld 3,72(11)\n\t" \ VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4 \
"std 3,112(1)\n\t" \ "add sp, sp, #32 \n\t" \
/* args1-8 */ \ "mov %0, r0" \
"ld 3, 8(11)\n\t" /* arg1->r3 */ \ : /*out*/ "=r" (_res) \
"ld 4, 16(11)\n\t" /* arg2->r4 */ \ : /*in*/ "0" (&_argvec[0]) \
"ld 5, 24(11)\n\t" /* arg3->r5 */ \
"ld 6, 32(11)\n\t" /* arg4->r6 */ \
"ld 7, 40(11)\n\t" /* arg5->r7 */ \
"ld 8, 48(11)\n\t" /* arg6->r8 */ \
"ld 9, 56(11)\n\t" /* arg7->r9 */ \
"ld 10, 64(11)\n\t" /* arg8->r10 */ \
"ld 11, 0(11)\n\t" /* target->r11 */ \
VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11 \
"mr 11,%1\n\t" \
"mr %0,3\n\t" \
"ld 2,-16(11)\n\t" /* restore tocptr */ \
VG_CONTRACT_FRAME_BY(144) \
VG_CONTRACT_FRAME_BY(512) \
: /*out*/ "=r" (_res) \
: /*in*/ "r" (&_argvec[2]) \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \ : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS \
); \ ); \
lval = (__typeof__(lval)) _res; \ lval = (__typeof__(lval)) _res; \
} while (0) } while (0)
#endif /* PLAT_ppc64_aix5 */ #endif /* PLAT_arm_linux */
/* ------------------------- s390x-linux ------------------------- */
#if defined(PLAT_s390x_linux)
/* Similar workaround as amd64 (see above), but we use r11 as frame
pointer and save the old r11 in r7. r11 might be used for
argvec, therefore we copy argvec in r1 since r1 is clobbered
after the call anyway. */
#if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)
# define __FRAME_POINTER \
,"d"(__builtin_dwarf_cfa())
# define VALGRIND_CFI_PROLOGUE \
".cfi_remember_state\n\t" \
"lgr 1,%1\n\t" /* copy the argvec pointer in r1 */ \
"lgr 7,11\n\t" \
"lgr 11,%2\n\t" \
".cfi_def_cfa r11, 0\n\t"
# define VALGRIND_CFI_EPILOGUE \
"lgr 11, 7\n\t" \
".cfi_restore_state\n\t"
#else
# define __FRAME_POINTER
# define VALGRIND_CFI_PROLOGUE \
"lgr 1,%1\n\t"
# define VALGRIND_CFI_EPILOGUE
#endif
/* These regs are trashed by the hidden call. Note that we overwrite
r14 in s390_irgen_noredir (VEX/priv/guest_s390_irgen.c) to give the
function a proper return address. All others are ABI defined call
clobbers. */
#define __CALLER_SAVED_REGS "0","1","2","3","4","5","14", \
"f0","f1","f2","f3","f4","f5","f6","f7"
#define CALL_FN_W_v(lval, orig) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[1]; \
volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \
__asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"aghi 15,-160\n\t" \
"lg 1, 0(1)\n\t" /* target->r1 */ \
VALGRIND_CALL_NOREDIR_R1 \
"lgr %0, 2\n\t" \
"aghi 15,160\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=d" (_res) \
: /*in*/ "d" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
/* The call abi has the arguments in r2-r6 and stack */
#define CALL_FN_W_W(lval, orig, arg1) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[2]; \
volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)arg1; \
__asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"aghi 15,-160\n\t" \
"lg 2, 8(1)\n\t" \
"lg 1, 0(1)\n\t" \
VALGRIND_CALL_NOREDIR_R1 \
"lgr %0, 2\n\t" \
"aghi 15,160\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=d" (_res) \
: /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_WW(lval, orig, arg1, arg2) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[3]; \
volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)arg1; \
_argvec[2] = (unsigned long)arg2; \
__asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"aghi 15,-160\n\t" \
"lg 2, 8(1)\n\t" \
"lg 3,16(1)\n\t" \
"lg 1, 0(1)\n\t" \
VALGRIND_CALL_NOREDIR_R1 \
"lgr %0, 2\n\t" \
"aghi 15,160\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=d" (_res) \
: /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_WWW(lval, orig, arg1, arg2, arg3) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[4]; \
volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)arg1; \
_argvec[2] = (unsigned long)arg2; \
_argvec[3] = (unsigned long)arg3; \
__asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"aghi 15,-160\n\t" \
"lg 2, 8(1)\n\t" \
"lg 3,16(1)\n\t" \
"lg 4,24(1)\n\t" \
"lg 1, 0(1)\n\t" \
VALGRIND_CALL_NOREDIR_R1 \
"lgr %0, 2\n\t" \
"aghi 15,160\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=d" (_res) \
: /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_WWWW(lval, orig, arg1, arg2, arg3, arg4) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[5]; \
volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)arg1; \
_argvec[2] = (unsigned long)arg2; \
_argvec[3] = (unsigned long)arg3; \
_argvec[4] = (unsigned long)arg4; \
__asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"aghi 15,-160\n\t" \
"lg 2, 8(1)\n\t" \
"lg 3,16(1)\n\t" \
"lg 4,24(1)\n\t" \
"lg 5,32(1)\n\t" \
"lg 1, 0(1)\n\t" \
VALGRIND_CALL_NOREDIR_R1 \
"lgr %0, 2\n\t" \
"aghi 15,160\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=d" (_res) \
: /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"7" \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_5W(lval, orig, arg1, arg2, arg3, arg4, arg5) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[6]; \
volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)arg1; \
_argvec[2] = (unsigned long)arg2; \
_argvec[3] = (unsigned long)arg3; \
_argvec[4] = (unsigned long)arg4; \
_argvec[5] = (unsigned long)arg5; \
__asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"aghi 15,-160\n\t" \
"lg 2, 8(1)\n\t" \
"lg 3,16(1)\n\t" \
"lg 4,24(1)\n\t" \
"lg 5,32(1)\n\t" \
"lg 6,40(1)\n\t" \
"lg 1, 0(1)\n\t" \
VALGRIND_CALL_NOREDIR_R1 \
"lgr %0, 2\n\t" \
"aghi 15,160\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=d" (_res) \
: /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_6W(lval, orig, arg1, arg2, arg3, arg4, arg5, \
arg6) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[7]; \
volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)arg1; \
_argvec[2] = (unsigned long)arg2; \
_argvec[3] = (unsigned long)arg3; \
_argvec[4] = (unsigned long)arg4; \
_argvec[5] = (unsigned long)arg5; \
_argvec[6] = (unsigned long)arg6; \
__asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"aghi 15,-168\n\t" \
"lg 2, 8(1)\n\t" \
"lg 3,16(1)\n\t" \
"lg 4,24(1)\n\t" \
"lg 5,32(1)\n\t" \
"lg 6,40(1)\n\t" \
"mvc 160(8,15), 48(1)\n\t" \
"lg 1, 0(1)\n\t" \
VALGRIND_CALL_NOREDIR_R1 \
"lgr %0, 2\n\t" \
"aghi 15,168\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=d" (_res) \
: /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_7W(lval, orig, arg1, arg2, arg3, arg4, arg5, \
arg6, arg7) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[8]; \
volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)arg1; \
_argvec[2] = (unsigned long)arg2; \
_argvec[3] = (unsigned long)arg3; \
_argvec[4] = (unsigned long)arg4; \
_argvec[5] = (unsigned long)arg5; \
_argvec[6] = (unsigned long)arg6; \
_argvec[7] = (unsigned long)arg7; \
__asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"aghi 15,-176\n\t" \
"lg 2, 8(1)\n\t" \
"lg 3,16(1)\n\t" \
"lg 4,24(1)\n\t" \
"lg 5,32(1)\n\t" \
"lg 6,40(1)\n\t" \
"mvc 160(8,15), 48(1)\n\t" \
"mvc 168(8,15), 56(1)\n\t" \
"lg 1, 0(1)\n\t" \
VALGRIND_CALL_NOREDIR_R1 \
"lgr %0, 2\n\t" \
"aghi 15,176\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=d" (_res) \
: /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_8W(lval, orig, arg1, arg2, arg3, arg4, arg5, \
arg6, arg7 ,arg8) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[9]; \
volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)arg1; \
_argvec[2] = (unsigned long)arg2; \
_argvec[3] = (unsigned long)arg3; \
_argvec[4] = (unsigned long)arg4; \
_argvec[5] = (unsigned long)arg5; \
_argvec[6] = (unsigned long)arg6; \
_argvec[7] = (unsigned long)arg7; \
_argvec[8] = (unsigned long)arg8; \
__asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"aghi 15,-184\n\t" \
"lg 2, 8(1)\n\t" \
"lg 3,16(1)\n\t" \
"lg 4,24(1)\n\t" \
"lg 5,32(1)\n\t" \
"lg 6,40(1)\n\t" \
"mvc 160(8,15), 48(1)\n\t" \
"mvc 168(8,15), 56(1)\n\t" \
"mvc 176(8,15), 64(1)\n\t" \
"lg 1, 0(1)\n\t" \
VALGRIND_CALL_NOREDIR_R1 \
"lgr %0, 2\n\t" \
"aghi 15,184\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=d" (_res) \
: /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_9W(lval, orig, arg1, arg2, arg3, arg4, arg5, \
arg6, arg7 ,arg8, arg9) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[10]; \
volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)arg1; \
_argvec[2] = (unsigned long)arg2; \
_argvec[3] = (unsigned long)arg3; \
_argvec[4] = (unsigned long)arg4; \
_argvec[5] = (unsigned long)arg5; \
_argvec[6] = (unsigned long)arg6; \
_argvec[7] = (unsigned long)arg7; \
_argvec[8] = (unsigned long)arg8; \
_argvec[9] = (unsigned long)arg9; \
__asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"aghi 15,-192\n\t" \
"lg 2, 8(1)\n\t" \
"lg 3,16(1)\n\t" \
"lg 4,24(1)\n\t" \
"lg 5,32(1)\n\t" \
"lg 6,40(1)\n\t" \
"mvc 160(8,15), 48(1)\n\t" \
"mvc 168(8,15), 56(1)\n\t" \
"mvc 176(8,15), 64(1)\n\t" \
"mvc 184(8,15), 72(1)\n\t" \
"lg 1, 0(1)\n\t" \
VALGRIND_CALL_NOREDIR_R1 \
"lgr %0, 2\n\t" \
"aghi 15,192\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=d" (_res) \
: /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_10W(lval, orig, arg1, arg2, arg3, arg4, arg5, \
arg6, arg7 ,arg8, arg9, arg10) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[11]; \
volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)arg1; \
_argvec[2] = (unsigned long)arg2; \
_argvec[3] = (unsigned long)arg3; \
_argvec[4] = (unsigned long)arg4; \
_argvec[5] = (unsigned long)arg5; \
_argvec[6] = (unsigned long)arg6; \
_argvec[7] = (unsigned long)arg7; \
_argvec[8] = (unsigned long)arg8; \
_argvec[9] = (unsigned long)arg9; \
_argvec[10] = (unsigned long)arg10; \
__asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"aghi 15,-200\n\t" \
"lg 2, 8(1)\n\t" \
"lg 3,16(1)\n\t" \
"lg 4,24(1)\n\t" \
"lg 5,32(1)\n\t" \
"lg 6,40(1)\n\t" \
"mvc 160(8,15), 48(1)\n\t" \
"mvc 168(8,15), 56(1)\n\t" \
"mvc 176(8,15), 64(1)\n\t" \
"mvc 184(8,15), 72(1)\n\t" \
"mvc 192(8,15), 80(1)\n\t" \
"lg 1, 0(1)\n\t" \
VALGRIND_CALL_NOREDIR_R1 \
"lgr %0, 2\n\t" \
"aghi 15,200\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=d" (_res) \
: /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_11W(lval, orig, arg1, arg2, arg3, arg4, arg5, \
arg6, arg7 ,arg8, arg9, arg10, arg11) \
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[12]; \
volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)arg1; \
_argvec[2] = (unsigned long)arg2; \
_argvec[3] = (unsigned long)arg3; \
_argvec[4] = (unsigned long)arg4; \
_argvec[5] = (unsigned long)arg5; \
_argvec[6] = (unsigned long)arg6; \
_argvec[7] = (unsigned long)arg7; \
_argvec[8] = (unsigned long)arg8; \
_argvec[9] = (unsigned long)arg9; \
_argvec[10] = (unsigned long)arg10; \
_argvec[11] = (unsigned long)arg11; \
__asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"aghi 15,-208\n\t" \
"lg 2, 8(1)\n\t" \
"lg 3,16(1)\n\t" \
"lg 4,24(1)\n\t" \
"lg 5,32(1)\n\t" \
"lg 6,40(1)\n\t" \
"mvc 160(8,15), 48(1)\n\t" \
"mvc 168(8,15), 56(1)\n\t" \
"mvc 176(8,15), 64(1)\n\t" \
"mvc 184(8,15), 72(1)\n\t" \
"mvc 192(8,15), 80(1)\n\t" \
"mvc 200(8,15), 88(1)\n\t" \
"lg 1, 0(1)\n\t" \
VALGRIND_CALL_NOREDIR_R1 \
"lgr %0, 2\n\t" \
"aghi 15,208\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=d" (_res) \
: /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#define CALL_FN_W_12W(lval, orig, arg1, arg2, arg3, arg4, arg5, \
arg6, arg7 ,arg8, arg9, arg10, arg11, arg12)\
do { \
volatile OrigFn _orig = (orig); \
volatile unsigned long _argvec[13]; \
volatile unsigned long _res; \
_argvec[0] = (unsigned long)_orig.nraddr; \
_argvec[1] = (unsigned long)arg1; \
_argvec[2] = (unsigned long)arg2; \
_argvec[3] = (unsigned long)arg3; \
_argvec[4] = (unsigned long)arg4; \
_argvec[5] = (unsigned long)arg5; \
_argvec[6] = (unsigned long)arg6; \
_argvec[7] = (unsigned long)arg7; \
_argvec[8] = (unsigned long)arg8; \
_argvec[9] = (unsigned long)arg9; \
_argvec[10] = (unsigned long)arg10; \
_argvec[11] = (unsigned long)arg11; \
_argvec[12] = (unsigned long)arg12; \
__asm__ volatile( \
VALGRIND_CFI_PROLOGUE \
"aghi 15,-216\n\t" \
"lg 2, 8(1)\n\t" \
"lg 3,16(1)\n\t" \
"lg 4,24(1)\n\t" \
"lg 5,32(1)\n\t" \
"lg 6,40(1)\n\t" \
"mvc 160(8,15), 48(1)\n\t" \
"mvc 168(8,15), 56(1)\n\t" \
"mvc 176(8,15), 64(1)\n\t" \
"mvc 184(8,15), 72(1)\n\t" \
"mvc 192(8,15), 80(1)\n\t" \
"mvc 200(8,15), 88(1)\n\t" \
"mvc 208(8,15), 96(1)\n\t" \
"lg 1, 0(1)\n\t" \
VALGRIND_CALL_NOREDIR_R1 \
"lgr %0, 2\n\t" \
"aghi 15,216\n\t" \
VALGRIND_CFI_EPILOGUE \
: /*out*/ "=d" (_res) \
: /*in*/ "a" (&_argvec[0]) __FRAME_POINTER \
: /*trash*/ "cc", "memory", __CALLER_SAVED_REGS,"6","7" \
); \
lval = (__typeof__(lval)) _res; \
} while (0)
#endif /* PLAT_s390x_linux */
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
/* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS. */ /* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS. */
/* */ /* */
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
/* Some request codes. There are many more of these, but most are not /* Some request codes. There are many more of these, but most are not
exposed to end-user view. These are the public ones, all of the exposed to end-user view. These are the public ones, all of the
form 0x1000 + small_number. form 0x1000 + small_number.
skipping to change at line 3602 skipping to change at line 3594
VG_USERREQ__CLIENT_CALL0 = 0x1101, VG_USERREQ__CLIENT_CALL0 = 0x1101,
VG_USERREQ__CLIENT_CALL1 = 0x1102, VG_USERREQ__CLIENT_CALL1 = 0x1102,
VG_USERREQ__CLIENT_CALL2 = 0x1103, VG_USERREQ__CLIENT_CALL2 = 0x1103,
VG_USERREQ__CLIENT_CALL3 = 0x1104, VG_USERREQ__CLIENT_CALL3 = 0x1104,
/* Can be useful in regression testing suites -- eg. can /* Can be useful in regression testing suites -- eg. can
send Valgrind's output to /dev/null and still count send Valgrind's output to /dev/null and still count
errors. */ errors. */
VG_USERREQ__COUNT_ERRORS = 0x1201, VG_USERREQ__COUNT_ERRORS = 0x1201,
/* Allows a string (gdb monitor command) to be passed to the tool
Used for interaction with vgdb/gdb */
VG_USERREQ__GDB_MONITOR_COMMAND = 0x1202,
/* These are useful and can be interpreted by any tool that /* These are useful and can be interpreted by any tool that
tracks malloc() et al, by using vg_replace_malloc.c. */ tracks malloc() et al, by using vg_replace_malloc.c. */
VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301, VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301,
VG_USERREQ__RESIZEINPLACE_BLOCK = 0x130b,
VG_USERREQ__FREELIKE_BLOCK = 0x1302, VG_USERREQ__FREELIKE_BLOCK = 0x1302,
/* Memory pool support. */ /* Memory pool support. */
VG_USERREQ__CREATE_MEMPOOL = 0x1303, VG_USERREQ__CREATE_MEMPOOL = 0x1303,
VG_USERREQ__DESTROY_MEMPOOL = 0x1304, VG_USERREQ__DESTROY_MEMPOOL = 0x1304,
VG_USERREQ__MEMPOOL_ALLOC = 0x1305, VG_USERREQ__MEMPOOL_ALLOC = 0x1305,
VG_USERREQ__MEMPOOL_FREE = 0x1306, VG_USERREQ__MEMPOOL_FREE = 0x1306,
VG_USERREQ__MEMPOOL_TRIM = 0x1307, VG_USERREQ__MEMPOOL_TRIM = 0x1307,
VG_USERREQ__MOVE_MEMPOOL = 0x1308, VG_USERREQ__MOVE_MEMPOOL = 0x1308,
VG_USERREQ__MEMPOOL_CHANGE = 0x1309, VG_USERREQ__MEMPOOL_CHANGE = 0x1309,
VG_USERREQ__MEMPOOL_EXISTS = 0x130a, VG_USERREQ__MEMPOOL_EXISTS = 0x130a,
/* Allow printfs to valgrind log. */ /* Allow printfs to valgrind log. */
/* The first two pass the va_list argument by value, which
assumes it is the same size as or smaller than a UWord,
which generally isn't the case. Hence are deprecated.
The second two pass the vargs by reference and so are
immune to this problem. */
/* both :: char* fmt, va_list vargs (DEPRECATED) */
VG_USERREQ__PRINTF = 0x1401, VG_USERREQ__PRINTF = 0x1401,
VG_USERREQ__PRINTF_BACKTRACE = 0x1402, VG_USERREQ__PRINTF_BACKTRACE = 0x1402,
/* both :: char* fmt, va_list* vargs */
VG_USERREQ__PRINTF_VALIST_BY_REF = 0x1403,
VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF = 0x1404,
/* Stack support. */ /* Stack support. */
VG_USERREQ__STACK_REGISTER = 0x1501, VG_USERREQ__STACK_REGISTER = 0x1501,
VG_USERREQ__STACK_DEREGISTER = 0x1502, VG_USERREQ__STACK_DEREGISTER = 0x1502,
VG_USERREQ__STACK_CHANGE = 0x1503 VG_USERREQ__STACK_CHANGE = 0x1503,
/* Wine support */
VG_USERREQ__LOAD_PDB_DEBUGINFO = 0x1601,
/* Querying of debug info. */
VG_USERREQ__MAP_IP_TO_SRCLOC = 0x1701
} Vg_ClientRequest; } Vg_ClientRequest;
#if !defined(__GNUC__) #if !defined(__GNUC__)
# define __extension__ /* */ # define __extension__ /* */
#endif #endif
/* Returns the number of Valgrinds this code is running under. That /* Returns the number of Valgrinds this code is running under. That
is, 0 if running natively, 1 if running under Valgrind, 2 if is, 0 if running natively, 1 if running under Valgrind, 2 if
running under Valgrind which is running under another Valgrind, running under Valgrind which is running under another Valgrind,
etc. */ etc. */
#define RUNNING_ON_VALGRIND __extension__ \ #define RUNNING_ON_VALGRIND \
({unsigned int _qzz_res; \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* if not */, \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0 /* if not */, \ VG_USERREQ__RUNNING_ON_VALGRIND, \
VG_USERREQ__RUNNING_ON_VALGRIND, \ 0, 0, 0, 0, 0) \
0, 0, 0, 0, 0); \
_qzz_res; \
})
/* Discard translation of code in the range [_qzz_addr .. _qzz_addr + /* Discard translation of code in the range [_qzz_addr .. _qzz_addr +
_qzz_len - 1]. Useful if you are debugging a JITter or some such, _qzz_len - 1]. Useful if you are debugging a JITter or some such,
since it provides a way to make sure valgrind will retranslate the since it provides a way to make sure valgrind will retranslate the
invalidated area. Returns no value. */ invalidated area. Returns no value. */
#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \ #define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len) \
{unsigned int _qzz_res; \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__DISCARD_TRANSLATIONS, \ VG_USERREQ__DISCARD_TRANSLATIONS, \
_qzz_addr, _qzz_len, 0, 0, 0); \ _qzz_addr, _qzz_len, 0, 0, 0)
}
/* These requests are for getting Valgrind itself to print something. /* These requests are for getting Valgrind itself to print something.
Possibly with a backtrace. This is a really ugly hack. */ Possibly with a backtrace. This is a really ugly hack. The return valu
e
#if defined(NVALGRIND) is the number of characters printed, excluding the "**<pid>** " part at
the
# define VALGRIND_PRINTF(...) start and the backtrace (if present). */
# define VALGRIND_PRINTF_BACKTRACE(...)
#else /* NVALGRIND */
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
/* Modern GCC will optimize the static routine out if unused, /* Modern GCC will optimize the static routine out if unused,
and unused attribute will shut down warnings about it. */ and unused attribute will shut down warnings about it. */
static int VALGRIND_PRINTF(const char *format, ...) static int VALGRIND_PRINTF(const char *format, ...)
__attribute__((format(__printf__, 1, 2), __unused__)); __attribute__((format(__printf__, 1, 2), __unused__));
#endif
static int static int
#if defined(_MSC_VER)
__inline
#endif
VALGRIND_PRINTF(const char *format, ...) VALGRIND_PRINTF(const char *format, ...)
{ {
#if defined(NVALGRIND)
return 0;
#else /* NVALGRIND */
#if defined(_MSC_VER)
uintptr_t _qzz_res;
#else
unsigned long _qzz_res; unsigned long _qzz_res;
#endif
va_list vargs; va_list vargs;
va_start(vargs, format); va_start(vargs, format);
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, VG_USERREQ__PRINTF, #if defined(_MSC_VER)
(unsigned long)format, (unsigned long)vargs, _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0,
VG_USERREQ__PRINTF_VALIST_BY_REF,
(uintptr_t)format,
(uintptr_t)&vargs,
0, 0, 0);
#else
_qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0,
VG_USERREQ__PRINTF_VALIST_BY_REF,
(unsigned long)format,
(unsigned long)&vargs,
0, 0, 0); 0, 0, 0);
#endif
va_end(vargs); va_end(vargs);
return (int)_qzz_res; return (int)_qzz_res;
#endif /* NVALGRIND */
} }
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...) static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
__attribute__((format(__printf__, 1, 2), __unused__)); __attribute__((format(__printf__, 1, 2), __unused__));
#endif
static int static int
#if defined(_MSC_VER)
__inline
#endif
VALGRIND_PRINTF_BACKTRACE(const char *format, ...) VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
{ {
#if defined(NVALGRIND)
return 0;
#else /* NVALGRIND */
#if defined(_MSC_VER)
uintptr_t _qzz_res;
#else
unsigned long _qzz_res; unsigned long _qzz_res;
#endif
va_list vargs; va_list vargs;
va_start(vargs, format); va_start(vargs, format);
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, VG_USERREQ__PRINTF_BACKTRACE, #if defined(_MSC_VER)
(unsigned long)format, (unsigned long)vargs, _qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0,
VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF,
(uintptr_t)format,
(uintptr_t)&vargs,
0, 0, 0);
#else
_qzz_res = VALGRIND_DO_CLIENT_REQUEST_EXPR(0,
VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF,
(unsigned long)format,
(unsigned long)&vargs,
0, 0, 0); 0, 0, 0);
#endif
va_end(vargs); va_end(vargs);
return (int)_qzz_res; return (int)_qzz_res;
}
#endif /* NVALGRIND */ #endif /* NVALGRIND */
}
/* These requests allow control to move from the simulated CPU to the /* These requests allow control to move from the simulated CPU to the
real CPU, calling an arbitary function. real CPU, calling an arbitary function.
Note that the current ThreadId is inserted as the first argument. Note that the current ThreadId is inserted as the first argument.
So this call: So this call:
VALGRIND_NON_SIMD_CALL2(f, arg1, arg2) VALGRIND_NON_SIMD_CALL2(f, arg1, arg2)
requires f to have this signature: requires f to have this signature:
skipping to change at line 3721 skipping to change at line 3767
Note that these client requests are not entirely reliable. For example, Note that these client requests are not entirely reliable. For example,
if you call a function with them that subsequently calls printf(), if you call a function with them that subsequently calls printf(),
there's a high chance Valgrind will crash. Generally, your prospects of there's a high chance Valgrind will crash. Generally, your prospects of
these working are made higher if the called function does not refer to these working are made higher if the called function does not refer to
any global variables, and does not refer to any libc or other functions any global variables, and does not refer to any libc or other functions
(printf et al). Any kind of entanglement with libc or dynamic linking i s (printf et al). Any kind of entanglement with libc or dynamic linking i s
likely to have a bad outcome, for tricky reasons which we've grappled likely to have a bad outcome, for tricky reasons which we've grappled
with a lot in the past. with a lot in the past.
*/ */
#define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \ #define VALGRIND_NON_SIMD_CALL0(_qyy_fn) \
__extension__ \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
({unsigned long _qyy_res; \ VG_USERREQ__CLIENT_CALL0, \
VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ _qyy_fn, \
VG_USERREQ__CLIENT_CALL0, \ 0, 0, 0, 0)
_qyy_fn, \
0, 0, 0, 0); \ #define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \
_qyy_res; \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
}) VG_USERREQ__CLIENT_CALL1, \
_qyy_fn, \
#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1) \ _qyy_arg1, 0, 0, 0)
__extension__ \
({unsigned long _qyy_res; \ #define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \
VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
VG_USERREQ__CLIENT_CALL1, \ VG_USERREQ__CLIENT_CALL2, \
_qyy_fn, \ _qyy_fn, \
_qyy_arg1, 0, 0, 0); \ _qyy_arg1, _qyy_arg2, 0, 0)
_qyy_res; \
})
#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2) \
__extension__ \
({unsigned long _qyy_res; \
VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \
VG_USERREQ__CLIENT_CALL2, \
_qyy_fn, \
_qyy_arg1, _qyy_arg2, 0, 0); \
_qyy_res; \
})
#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \ #define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \
__extension__ \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */, \
({unsigned long _qyy_res; \ VG_USERREQ__CLIENT_CALL3, \
VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \ _qyy_fn, \
VG_USERREQ__CLIENT_CALL3, \ _qyy_arg1, _qyy_arg2, \
_qyy_fn, \ _qyy_arg3, 0)
_qyy_arg1, _qyy_arg2, \
_qyy_arg3, 0); \
_qyy_res; \
})
/* Counts the number of errors that have been recorded by a tool. Nb: /* Counts the number of errors that have been recorded by a tool. Nb:
the tool must record the errors with VG_(maybe_record_error)() or the tool must record the errors with VG_(maybe_record_error)() or
VG_(unique_error)() for them to be counted. */ VG_(unique_error)() for them to be counted. */
#define VALGRIND_COUNT_ERRORS \ #define VALGRIND_COUNT_ERRORS \
__extension__ \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR( \
({unsigned int _qyy_res; \ 0 /* default return */, \
VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */, \
VG_USERREQ__COUNT_ERRORS, \ VG_USERREQ__COUNT_ERRORS, \
0, 0, 0, 0, 0); \ 0, 0, 0, 0, 0)
_qyy_res; \
})
/* Mark a block of memory as having been allocated by a malloc()-like
function. `addr' is the start of the usable block (ie. after any
redzone) `rzB' is redzone size if the allocator can apply redzones;
use '0' if not. Adding redzones makes it more likely Valgrind will spot
block overruns. `is_zeroed' indicates if the memory is zeroed, as it is
for calloc(). Put it immediately after the point where a block is
allocated.
If you're using Memcheck: If you're allocating memory via superblocks,
and then handing out small chunks of each superblock, if you don't have
redzones on your small blocks, it's worth marking the superblock with
VALGRIND_MAKE_MEM_NOACCESS when it's created, so that block overruns are
detected. But if you can put redzones on, it's probably better to not d
o
this, so that messages for small overruns are described in terms of the
small block rather than the superblock (but if you have a big overrun
that skips over a redzone, you could miss an error this way). See
memcheck/tests/custom_alloc.c for an example.
WARNING: if your allocator uses malloc() or 'new' to allocate
superblocks, rather than mmap() or brk(), this will not work properly --
you'll likely get assertion failures during leak detection. This is
because Valgrind doesn't like seeing overlapping heap blocks. Sorry.
Nb: block must be freed via a free()-like function specified /* Several Valgrind tools (Memcheck, Massif, Helgrind, DRD) rely on knowing
with VALGRIND_FREELIKE_BLOCK or mismatch errors will occur. */ when heap blocks are allocated in order to give accurate results. This
happens automatically for the standard allocator functions such as
malloc(), calloc(), realloc(), memalign(), new, new[], free(), delete,
delete[], etc.
But if your program uses a custom allocator, this doesn't automatically
happen, and Valgrind will not do as well. For example, if you allocate
superblocks with mmap() and then allocates chunks of the superblocks, al
l
Valgrind's observations will be at the mmap() level and it won't know th
at
the chunks should be considered separate entities. In Memcheck's case,
that means you probably won't get heap block overrun detection (because
there won't be redzones marked as unaddressable) and you definitely won'
t
get any leak detection.
The following client requests allow a custom allocator to be annotated s
o
that it can be handled accurately by Valgrind.
VALGRIND_MALLOCLIKE_BLOCK marks a region of memory as having been alloca
ted
by a malloc()-like function. For Memcheck (an illustrative case), this
does two things:
- It records that the block has been allocated. This means any addresse
s
within the block mentioned in error messages will be
identified as belonging to the block. It also means that if the block
isn't freed it will be detected by the leak checker.
- It marks the block as being addressable and undefined (if 'is_zeroed'
is
not set), or addressable and defined (if 'is_zeroed' is set). This
controls how accesses to the block by the program are handled.
'addr' is the start of the usable block (ie. after any
redzone), 'sizeB' is its size. 'rzB' is the redzone size if the allocat
or
can apply redzones -- these are blocks of padding at the start and end o
f
each block. Adding redzones is recommended as it makes it much more lik
ely
Valgrind will spot block overruns. `is_zeroed' indicates if the memory
is
zeroed (or filled with another predictable value), as is the case for
calloc().
VALGRIND_MALLOCLIKE_BLOCK should be put immediately after the point wher
e a
heap block -- that will be used by the client program -- is allocated.
It's best to put it at the outermost level of the allocator if possible;
for example, if you have a function my_alloc() which calls
internal_alloc(), and the client request is put inside internal_alloc(),
stack traces relating to the heap block will contain entries for both
my_alloc() and internal_alloc(), which is probably not what you want.
For Memcheck users: if you use VALGRIND_MALLOCLIKE_BLOCK to carve out
custom blocks from within a heap block, B, that has been allocated with
malloc/calloc/new/etc, then block B will be *ignored* during leak-checki
ng
-- the custom blocks will take precedence.
VALGRIND_FREELIKE_BLOCK is the partner to VALGRIND_MALLOCLIKE_BLOCK. Fo
r
Memcheck, it does two things:
- It records that the block has been deallocated. This assumes that the
block was annotated as having been allocated via
VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued.
- It marks the block as being unaddressable.
VALGRIND_FREELIKE_BLOCK should be put immediately after the point where
a
heap block is deallocated.
VALGRIND_RESIZEINPLACE_BLOCK informs a tool about reallocation. For
Memcheck, it does four things:
- It records that the size of a block has been changed. This assumes th
at
the block was annotated as having been allocated via
VALGRIND_MALLOCLIKE_BLOCK. Otherwise, an error will be issued.
- If the block shrunk, it marks the freed memory as being unaddressable.
- If the block grew, it marks the new area as undefined and defines a re
d
zone past the end of the new block.
- The V-bits of the overlap between the old and the new block are preser
ved.
VALGRIND_RESIZEINPLACE_BLOCK should be put after allocation of the new b
lock
and before deallocation of the old block.
In many cases, these three client requests will not be enough to get you
r
allocator working well with Memcheck. More specifically, if your alloca
tor
writes to freed blocks in any way then a VALGRIND_MAKE_MEM_UNDEFINED cal
l
will be necessary to mark the memory as addressable just before the zero
ing
occurs, otherwise you'll get a lot of invalid write errors. For example
,
you'll need to do this if your allocator recycles freed blocks, but it
zeroes them before handing them back out (via VALGRIND_MALLOCLIKE_BLOCK)
.
Alternatively, if your allocator reuses freed blocks for allocator-inter
nal
data structures, VALGRIND_MAKE_MEM_UNDEFINED calls will also be necessar
y.
Really, what's happening is a blurring of the lines between the client
program and the allocator... after VALGRIND_FREELIKE_BLOCK is called, th
e
memory should be considered unaddressable to the client program, but the
allocator knows more than the rest of the client program and so may be a
ble
to safely access it. Extra client requests are necessary for Valgrind t
o
understand the distinction between the allocator and the rest of the
program.
Ignored if addr == 0.
*/
#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \ #define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed) \
{unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__MALLOCLIKE_BLOCK, \ VG_USERREQ__MALLOCLIKE_BLOCK, \
addr, sizeB, rzB, is_zeroed, 0); \ addr, sizeB, rzB, is_zeroed, 0)
}
/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details.
Ignored if addr == 0.
*/
#define VALGRIND_RESIZEINPLACE_BLOCK(addr, oldSizeB, newSizeB, rzB) \
VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
VG_USERREQ__RESIZEINPLACE_BLOCK, \
addr, oldSizeB, newSizeB, rzB, 0)
/* Mark a block of memory as having been freed by a free()-like function. /* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details.
`rzB' is redzone size; it must match that given to Ignored if addr == 0.
VALGRIND_MALLOCLIKE_BLOCK. Memory not freed will be detected by the lea */
k
checker. Put it immediately after the point where the block is freed. *
/
#define VALGRIND_FREELIKE_BLOCK(addr, rzB) \ #define VALGRIND_FREELIKE_BLOCK(addr, rzB) \
{unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__FREELIKE_BLOCK, \ VG_USERREQ__FREELIKE_BLOCK, \
addr, rzB, 0, 0, 0); \ addr, rzB, 0, 0, 0)
}
/* Create a memory pool. */ /* Create a memory pool. */
#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \ #define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed) \
{unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__CREATE_MEMPOOL, \ VG_USERREQ__CREATE_MEMPOOL, \
pool, rzB, is_zeroed, 0, 0); \ pool, rzB, is_zeroed, 0, 0)
}
/* Destroy a memory pool. */ /* Destroy a memory pool. */
#define VALGRIND_DESTROY_MEMPOOL(pool) \ #define VALGRIND_DESTROY_MEMPOOL(pool) \
{unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__DESTROY_MEMPOOL, \ VG_USERREQ__DESTROY_MEMPOOL, \
pool, 0, 0, 0, 0); \ pool, 0, 0, 0, 0)
}
/* Associate a piece of memory with a memory pool. */ /* Associate a piece of memory with a memory pool. */
#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \ #define VALGRIND_MEMPOOL_ALLOC(pool, addr, size) \
{unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__MEMPOOL_ALLOC, \ VG_USERREQ__MEMPOOL_ALLOC, \
pool, addr, size, 0, 0); \ pool, addr, size, 0, 0)
}
/* Disassociate a piece of memory from a memory pool. */ /* Disassociate a piece of memory from a memory pool. */
#define VALGRIND_MEMPOOL_FREE(pool, addr) \ #define VALGRIND_MEMPOOL_FREE(pool, addr) \
{unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__MEMPOOL_FREE, \ VG_USERREQ__MEMPOOL_FREE, \
pool, addr, 0, 0, 0); \ pool, addr, 0, 0, 0)
}
/* Disassociate any pieces outside a particular range. */ /* Disassociate any pieces outside a particular range. */
#define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \ #define VALGRIND_MEMPOOL_TRIM(pool, addr, size) \
{unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__MEMPOOL_TRIM, \ VG_USERREQ__MEMPOOL_TRIM, \
pool, addr, size, 0, 0); \ pool, addr, size, 0, 0)
}
/* Resize and/or move a piece associated with a memory pool. */ /* Resize and/or move a piece associated with a memory pool. */
#define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \ #define VALGRIND_MOVE_MEMPOOL(poolA, poolB) \
{unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__MOVE_MEMPOOL, \ VG_USERREQ__MOVE_MEMPOOL, \
poolA, poolB, 0, 0, 0); \ poolA, poolB, 0, 0, 0)
}
/* Resize and/or move a piece associated with a memory pool. */ /* Resize and/or move a piece associated with a memory pool. */
#define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \ #define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size) \
{unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__MEMPOOL_CHANGE, \ VG_USERREQ__MEMPOOL_CHANGE, \
pool, addrA, addrB, size, 0); \ pool, addrA, addrB, size, 0)
}
/* Return 1 if a mempool exists, else 0. */ /* Return 1 if a mempool exists, else 0. */
#define VALGRIND_MEMPOOL_EXISTS(pool) \ #define VALGRIND_MEMPOOL_EXISTS(pool) \
({unsigned int _qzz_res; \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__MEMPOOL_EXISTS, \ VG_USERREQ__MEMPOOL_EXISTS, \
pool, 0, 0, 0, 0); \ pool, 0, 0, 0, 0)
_qzz_res; \
})
/* Mark a piece of memory as being a stack. Returns a stack id. */ /* Mark a piece of memory as being a stack. Returns a stack id. */
#define VALGRIND_STACK_REGISTER(start, end) \ #define VALGRIND_STACK_REGISTER(start, end) \
({unsigned int _qzz_res; \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__STACK_REGISTER, \ VG_USERREQ__STACK_REGISTER, \
start, end, 0, 0, 0); \ start, end, 0, 0, 0)
_qzz_res; \
})
/* Unmark the piece of memory associated with a stack id as being a /* Unmark the piece of memory associated with a stack id as being a
stack. */ stack. */
#define VALGRIND_STACK_DEREGISTER(id) \ #define VALGRIND_STACK_DEREGISTER(id) \
{unsigned int _qzz_res; \ (unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__STACK_DEREGISTER, \ VG_USERREQ__STACK_DEREGISTER, \
id, 0, 0, 0, 0); \ id, 0, 0, 0, 0)
}
/* Change the start and end address of the stack id. */ /* Change the start and end address of the stack id. */
#define VALGRIND_STACK_CHANGE(id, start, end) \ #define VALGRIND_STACK_CHANGE(id, start, end) \
{unsigned int _qzz_res; \ VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0, \
VG_USERREQ__STACK_CHANGE, \ VG_USERREQ__STACK_CHANGE, \
id, start, end, 0, 0); \ id, start, end, 0, 0)
}
/* Load PDB debug info for Wine PE image_map. */
#define VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta) \
VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
VG_USERREQ__LOAD_PDB_DEBUGINFO, \
fd, ptr, total_size, delta, 0)
/* Map a code address to a source file name and line number. buf64
must point to a 64-byte buffer in the caller's address space. The
result will be dumped in there and is guaranteed to be zero
terminated. If no info is found, the first byte is set to zero. */
#define VALGRIND_MAP_IP_TO_SRCLOC(addr, buf64) \
(unsigned)VALGRIND_DO_CLIENT_REQUEST_EXPR(0, \
VG_USERREQ__MAP_IP_TO_SRCLOC, \
addr, buf64, 0, 0, 0)
#undef PLAT_x86_darwin
#undef PLAT_amd64_darwin
#undef PLAT_x86_win32
#undef PLAT_x86_linux #undef PLAT_x86_linux
#undef PLAT_amd64_linux #undef PLAT_amd64_linux
#undef PLAT_ppc32_linux #undef PLAT_ppc32_linux
#undef PLAT_ppc64_linux #undef PLAT_ppc64_linux
#undef PLAT_ppc32_aix5 #undef PLAT_arm_linux
#undef PLAT_ppc64_aix5 #undef PLAT_s390x_linux
#endif /* __VALGRIND_H */ #endif /* __VALGRIND_H */
 End of changes. 243 change blocks. 
1363 lines changed or deleted 1498 lines changed or added

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