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 ¤tP lan ); | const QueryPlan *nextClauseBestGuessPlan( const QueryPlan ¤tP 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 | |||