0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 09:32:32 +01:00

Merge branch 'master' of github.com:mongodb/mongo

This commit is contained in:
Aaron 2010-01-20 16:39:24 -08:00
commit d26dff949e
24 changed files with 306 additions and 92 deletions

View File

@ -7,7 +7,7 @@
namespace mongo {
SyncCluterConnection::SyncCluterConnection( string commaSeperated ){
SyncClusterConnection::SyncClusterConnection( string commaSeperated ){
string::size_type idx;
while ( ( idx = commaSeperated.find( ',' ) ) != string::npos ){
string h = commaSeperated.substr( 0 , idx );
@ -15,27 +15,27 @@ namespace mongo {
_connect( h );
}
_connect( commaSeperated );
uassert( 8004 , "SyncCluterConnection needs 3 servers" , _conns.size() == 3 );
uassert( 8004 , "SyncClusterConnection needs 3 servers" , _conns.size() == 3 );
}
SyncCluterConnection::SyncCluterConnection( string a , string b , string c ){
SyncClusterConnection::SyncClusterConnection( string a , string b , string c ){
// connect to all even if not working
_connect( a );
_connect( b );
_connect( c );
}
SyncCluterConnection::~SyncCluterConnection(){
SyncClusterConnection::~SyncClusterConnection(){
for ( size_t i=0; i<_conns.size(); i++ )
delete _conns[i];
_conns.clear();
}
bool SyncCluterConnection::prepare( string& errmsg ){
bool SyncClusterConnection::prepare( string& errmsg ){
return fsync( errmsg );
}
bool SyncCluterConnection::fsync( string& errmsg ){
bool SyncClusterConnection::fsync( string& errmsg ){
bool ok = true;
errmsg = "";
for ( size_t i=0; i<_conns.size(); i++ ){
@ -55,7 +55,7 @@ namespace mongo {
return ok;
}
void SyncCluterConnection::_checkLast(){
void SyncClusterConnection::_checkLast(){
vector<BSONObj> all;
vector<string> errors;
@ -91,22 +91,22 @@ namespace mongo {
if ( ok )
return;
throw UserException( 8001 , (string)"SyncCluterConnection write op failed: " + err.str() );
throw UserException( 8001 , (string)"SyncClusterConnection write op failed: " + err.str() );
}
void SyncCluterConnection::_connect( string host ){
log() << "SyncCluterConnection connecting to: " << host << endl;
void SyncClusterConnection::_connect( string host ){
log() << "SyncClusterConnection connecting to: " << host << endl;
DBClientConnection * c = new DBClientConnection( true );
string errmsg;
if ( ! c->connect( host , errmsg ) )
log() << "SyncCluterConnection connect fail to: " << host << " errmsg: " << errmsg << endl;
log() << "SyncClusterConnection connect fail to: " << host << " errmsg: " << errmsg << endl;
_conns.push_back( c );
}
auto_ptr<DBClientCursor> SyncCluterConnection::query(const string &ns, Query query, int nToReturn, int nToSkip,
auto_ptr<DBClientCursor> SyncClusterConnection::query(const string &ns, Query query, int nToReturn, int nToSkip,
const BSONObj *fieldsToReturn, int queryOptions){
uassert( 10021 , "$cmd not support yet in SyncCluterConnection::query" , ns.find( "$cmd" ) == string::npos );
uassert( 10021 , "$cmd not support yet in SyncClusterConnection::query" , ns.find( "$cmd" ) == string::npos );
for ( size_t i=0; i<_conns.size(); i++ ){
try {
@ -123,16 +123,16 @@ namespace mongo {
throw UserException( 8002 , "all servers down!" );
}
auto_ptr<DBClientCursor> SyncCluterConnection::getMore( const string &ns, long long cursorId, int nToReturn, int options ){
uassert( 10022 , "SyncCluterConnection::getMore not supported yet" , 0);
auto_ptr<DBClientCursor> SyncClusterConnection::getMore( const string &ns, long long cursorId, int nToReturn, int options ){
uassert( 10022 , "SyncClusterConnection::getMore not supported yet" , 0);
auto_ptr<DBClientCursor> c;
return c;
}
void SyncCluterConnection::insert( const string &ns, BSONObj obj ){
void SyncClusterConnection::insert( const string &ns, BSONObj obj ){
string errmsg;
if ( ! prepare( errmsg ) )
throw UserException( 8003 , (string)"SyncCluterConnection::insert prepare failed: " + errmsg );
throw UserException( 8003 , (string)"SyncClusterConnection::insert prepare failed: " + errmsg );
for ( size_t i=0; i<_conns.size(); i++ ){
_conns[i]->insert( ns , obj );
@ -141,17 +141,17 @@ namespace mongo {
_checkLast();
}
void SyncCluterConnection::insert( const string &ns, const vector< BSONObj >& v ){
uassert( 10023 , "SyncCluterConnection bulk insert not implemented" , 0);
void SyncClusterConnection::insert( const string &ns, const vector< BSONObj >& v ){
uassert( 10023 , "SyncClusterConnection bulk insert not implemented" , 0);
}
void SyncCluterConnection::remove( const string &ns , Query query, bool justOne ){ assert(0); }
void SyncClusterConnection::remove( const string &ns , Query query, bool justOne ){ assert(0); }
void SyncCluterConnection::update( const string &ns , Query query , BSONObj obj , bool upsert , bool multi ){ assert(0); }
void SyncClusterConnection::update( const string &ns , Query query , BSONObj obj , bool upsert , bool multi ){ assert(0); }
string SyncCluterConnection::toString(){
string SyncClusterConnection::toString(){
stringstream ss;
ss << "SyncCluterConnection [";
ss << "SyncClusterConnection [";
for ( size_t i=0; i<_conns.size(); i++ ){
if ( i > 0 )
ss << ",";

View File

@ -9,14 +9,14 @@ namespace mongo {
* this is a connection to a cluster of servers that operate as one
* for super high durability
*/
class SyncCluterConnection : public DBClientWithCommands {
class SyncClusterConnection : public DBClientWithCommands {
public:
/**
* @param commaSeperated should be 3 hosts comma seperated
*/
SyncCluterConnection( string commaSeperated );
SyncCluterConnection( string a , string b , string c );
~SyncCluterConnection();
SyncClusterConnection( string commaSeperated );
SyncClusterConnection( string a , string b , string c );
~SyncClusterConnection();
/**

View File

@ -926,12 +926,11 @@ namespace mongo {
b->k(1).setUnused();
b->dumpTree(id.head, order);
cout << "---\n";
b->bt_insert(id.head, A, key, order, false, id);
b->dumpTree(id.head, order);
cout << "---\n";*/
*/
// this should assert. does it? (it might "accidentally" though, not asserting proves a problem, asserting proves nothing)
b->bt_insert(id.head, C, key, order, false, id);

View File

@ -217,7 +217,7 @@ namespace mongo {
static bool inEmpty = false;
if( test && !inEmpty ) {
inEmpty = true;
log() << "TEST: manipulate collection during remove" << endl;
log() << "TEST: manipulate collection during cc:yield" << endl;
if( test == 1 )
Helpers::emptyCollection(ns.c_str());
else if( test == 2 ) {

View File

@ -105,7 +105,12 @@ namespace mongo {
int pos; // # objects into the cursor so far
BSONObj query;
ClientCursor() : _idleAgeMillis(0), _pinValue(0), _doingDeletes(false), pos(0) {
ClientCursor(auto_ptr<Cursor>& _c, const char *_ns) :
_idleAgeMillis(0), _pinValue(0),
_doingDeletes(false),
ns(_ns), c(_c),
pos(0)
{
recursive_boostlock lock(ccmutex);
cursorid = allocCursorId_inlock();
clientCursorsById.insert( make_pair(cursorid, this) );

View File

@ -206,6 +206,11 @@ namespace mongo {
break;
}
if ( inShutdown() ) {
log() << "got request after shutdown()" << endl;
break;
}
lastError.startRequest( m , le );
DbResponse dbresponse;

View File

@ -1342,7 +1342,7 @@
>
</File>
<File
RelativePath="..\client\quorum.cpp"
RelativePath="..\client\syncclusterconnection.cpp"
>
</File>
<Filter

View File

@ -1012,9 +1012,7 @@ namespace mongo {
CursorId id;
{
auto_ptr< Cursor > c = theDataFileMgr.findAll( fromNs.c_str(), startLoc );
ClientCursor *cc = new ClientCursor();
cc->c = c;
cc->ns = fromNs;
ClientCursor *cc = new ClientCursor(c, fromNs.c_str());
cc->matcher.reset( new CoveredIndexMatcher( BSONObj(), fromjson( "{$natural:1}" ) ) );
id = cc->cursorid;
}

View File

@ -84,12 +84,6 @@ namespace mongo {
}
}
ElementMatcher::~ElementMatcher(){
}
} // namespace mongo
#include "pdfile.h"
@ -307,8 +301,9 @@ namespace mongo {
inline int Matcher::valuesMatch(const BSONElement& l, const BSONElement& r, int op, const ElementMatcher& bm) {
assert( op != BSONObj::NE && op != BSONObj::NIN );
if ( op == BSONObj::Equality )
if ( op == BSONObj::Equality ) {
return l.valuesEqual(r);
}
if ( op == BSONObj::opIN ) {
// { $in : [1,2,3] }
@ -383,16 +378,15 @@ namespace mongo {
0 missing element
1 match
*/
int Matcher::matchesDotted(const char *fieldName, const BSONElement& toMatch, const BSONObj& obj, int compareOp, const ElementMatcher& bm , bool isArr) {
int Matcher::matchesDotted(const char *fieldName, const BSONElement& toMatch, const BSONObj& obj, int compareOp, const ElementMatcher& em , bool isArr) {
if ( compareOp == BSONObj::opALL ) {
if ( bm.myset->size() == 0 )
if ( em.myset->size() == 0 )
return -1; // is this desired?
BSONObjSetDefaultOrder actualKeys;
IndexSpec( BSON( fieldName << 1 ) ).getKeys( obj, actualKeys );
if ( actualKeys.size() == 0 )
return 0;
for( set< BSONElement, element_lt >::const_iterator i = bm.myset->begin(); i != bm.myset->end(); ++i ) {
for( set< BSONElement, element_lt >::const_iterator i = em.myset->begin(); i != em.myset->end(); ++i ) {
// ignore nulls
if ( i->type() == jstNULL )
continue;
@ -406,10 +400,10 @@ namespace mongo {
}
if ( compareOp == BSONObj::NE )
return matchesNe( fieldName, toMatch, obj, bm );
return matchesNe( fieldName, toMatch, obj, em );
if ( compareOp == BSONObj::NIN ) {
for( set<BSONElement,element_lt>::const_iterator i = bm.myset->begin(); i != bm.myset->end(); ++i ) {
int ret = matchesNe( fieldName, *i, obj, bm );
for( set<BSONElement,element_lt>::const_iterator i = em.myset->begin(); i != em.myset->end(); ++i ) {
int ret = matchesNe( fieldName, *i, obj, em );
if ( ret != 1 )
return ret;
}
@ -422,14 +416,37 @@ namespace mongo {
e = obj.getFieldUsingIndexNames(fieldName, constrainIndexKey_);
assert( !e.eoo() );
} else {
const char *p = strchr(fieldName, '.');
if ( p ) {
string left(fieldName, p-fieldName);
BSONElement se = obj.getField(left.c_str());
if ( se.eoo() )
;
else if ( se.type() != Object && se.type() != Array )
;
else {
BSONObj eo = se.embeddedObject();
return matchesDotted(p+1, toMatch, eo, compareOp, em, se.type() == Array);
}
}
if ( isArr ) {
BSONObjIterator ai(obj);
bool found = false;
while ( ai.moreWithEOO() ) {
BSONElement z = ai.next();
if( strcmp(z.fieldName(),fieldName) == 0 && valuesMatch(z, toMatch, compareOp, em) ) {
// "field.<n>" array notation was used
return 1;
}
if ( z.type() == Object ) {
BSONObj eo = z.embeddedObject();
int cmp = matchesDotted(fieldName, toMatch, eo, compareOp, bm, false);
int cmp = matchesDotted(fieldName, toMatch, eo, compareOp, em, false);
if ( cmp > 0 ) {
return 1;
} else if ( cmp < 0 ) {
@ -437,21 +454,13 @@ namespace mongo {
}
}
}
return found ? -1 : retMissing( bm );
return found ? -1 : retMissing( em );
}
const char *p = strchr(fieldName, '.');
if ( p ) {
string left(fieldName, p-fieldName);
BSONElement se = obj.getField(left.c_str());
if ( se.eoo() )
return retMissing( bm );
if ( se.type() != Object && se.type() != Array )
return retMissing( bm );
BSONObj eo = se.embeddedObject();
return matchesDotted(p+1, toMatch, eo, compareOp, bm, se.type() == Array);
} else {
if( p ) {
return retMissing( em );
}
else {
e = obj.getField(fieldName);
}
}
@ -459,7 +468,7 @@ namespace mongo {
if ( compareOp == BSONObj::opEXISTS ) {
return ( e.eoo() ^ toMatch.boolean() ) ? 1 : -1;
} else if ( ( e.type() != Array || indexed || compareOp == BSONObj::opSIZE ) &&
valuesMatch(e, toMatch, compareOp, bm ) ) {
valuesMatch(e, toMatch, compareOp, em ) ) {
return 1;
} else if ( e.type() == Array && compareOp != BSONObj::opSIZE ) {
@ -470,11 +479,11 @@ namespace mongo {
if ( compareOp == BSONObj::opELEM_MATCH ){
// SERVER-377
if ( z.type() == Object && bm.subMatcher->matches( z.embeddedObject() ) )
if ( z.type() == Object && em.subMatcher->matches( z.embeddedObject() ) )
return 1;
}
else {
if ( valuesMatch( z, toMatch, compareOp, bm) ) {
if ( valuesMatch( z, toMatch, compareOp, em) ) {
return 1;
}
}

View File

@ -71,7 +71,7 @@ namespace mongo {
}
}
~ElementMatcher();
~ElementMatcher() { }
BSONElement toMatch;
int compareOp;
@ -85,8 +85,7 @@ namespace mongo {
shared_ptr<Matcher> subMatcher;
};
// SQL where clause equivalent
class Where;
class Where; // used for $where javascript eval
class DiskLoc;
/* Match BSON objects against a query pattern.
@ -145,7 +144,6 @@ namespace mongo {
BSONObj jsobj; // the query pattern. e.g., { name: "joe" }
BSONObj constrainIndexKey_;
vector<ElementMatcher> basics;
// int n; // # of basicmatcher items
bool haveSize;
bool all;
bool hasArray;

View File

@ -968,7 +968,6 @@ namespace mongo {
RARELY killCurrentOp.checkForInterrupt();
BSONObjExternalSorter::Data d = i->next();
//cout<<"TEMP SORTER next " << d.first.toString() << endl;
try {
btBuilder.addKey(d.first, d.second);
}

View File

@ -136,10 +136,7 @@ namespace mongo {
CoveredIndexMatcher matcher(pattern, creal->indexKeyPattern());
auto_ptr<ClientCursor> cc;
cc.reset( new ClientCursor() );
cc->c = creal;
cc->ns = ns;
auto_ptr<ClientCursor> cc( new ClientCursor(creal,ns) );
cc->noTimeout();
cc->setDoingDeletes( true );
@ -514,10 +511,9 @@ namespace mongo {
if ( findingStart_ ) {
// Use a ClientCursor here so we can release db mutex while scanning
// oplog (can take quite a while with large oplogs).
findingStartCursor_ = new ClientCursor();
auto_ptr<Cursor> c = qp().newReverseCursor();
findingStartCursor_ = new ClientCursor(c, qp().ns());
findingStartCursor_->noTimeout();
findingStartCursor_->c = qp().newReverseCursor();
findingStartCursor_->ns = qp().ns();
} else {
c_ = qp().newCursor();
}
@ -855,15 +851,13 @@ namespace mongo {
auto_ptr< Cursor > c = dqo.cursor();
log( 5 ) << " used cursor: " << c.get() << endl;
if ( dqo.saveClientCursor() ) {
ClientCursor *cc = new ClientCursor();
ClientCursor *cc = new ClientCursor(c, ns); // the clientcursor now owns the Cursor* and 'c' is released.
if ( queryOptions & QueryOption_NoCursorTimeout )
cc->noTimeout();
cc->c = c;
cursorid = cc->cursorid;
cc->query = jsobj.getOwned();
DEV out() << " query has more, cursorid: " << cursorid << endl;
cc->matcher = dqo.matcher();
cc->ns = ns;
cc->pos = n;
cc->filter = filter;
cc->originalMessage = m;

View File

@ -515,6 +515,37 @@ namespace JSTests {
};
class NumberLong {
public:
void run() {
Scope * s = globalScriptEngine->newScope();
s->localConnect( "blah" );
BSONObjBuilder b;
long long val = (long long)( 0xbabadeadbeefbaddULL );
b.append( "a", val );
BSONObj in = b.obj();
s->setObject( "a", in );
BSONObj out = s->getObject( "a" );
ASSERT_EQUALS( mongo::NumberLong, out.firstElement().type() );
ASSERT( s->exec( "b = {b:a.a}", "foo", false, true, false ) );
out = s->getObject( "b" );
ASSERT_EQUALS( mongo::NumberLong, out.firstElement().type() );
ASSERT_EQUALS( val, out.firstElement().numberLong() );
ASSERT( s->exec( "c = {c:a.a.toString()}", "foo", false, true, false ) );
out = s->getObject( "c" );
stringstream ss;
ss << val;
ASSERT_EQUALS( ss.str(), out.firstElement().valuestr() );
ASSERT( s->exec( "d = {d:a.a.toNumber()}", "foo", false, true, false ) );
out = s->getObject( "d" );
ASSERT_EQUALS( NumberDouble, out.firstElement().type() );
ASSERT_EQUALS( double( val ), out.firstElement().number() );
}
};
class WeirdObjects {
public:
@ -752,6 +783,7 @@ namespace JSTests {
add< OtherJSTypes >();
add< SpecialDBTypes >();
add< TypeConservation >();
add< NumberLong >();
add< WeirdObjects >();
add< Utf8Check >();

View File

@ -1330,7 +1330,7 @@
>
</File>
<File
RelativePath="..\client\quorum.cpp"
RelativePath="..\client\syncclusterconnection.cpp"
>
</File>
<Filter

View File

@ -6,7 +6,7 @@ before = db._adminCommand( "serverStatus" )
if ( before.mem.supported ){
db._adminCommand( "closeAllDatabases" );
after = db._adminCommand( "serverStatus" );
assert( before.mem.mapped > after.mem.mapped , "closeAllDatabases does something before:" + tojson( before ) + " after:" + tojson( after ) );
assert( before.mem.mapped.toNumber() > after.mem.mapped.toNumber() , "closeAllDatabases does something before:" + tojson( before ) + " after:" + tojson( after ) );
}
else {
print( "can't test serverStatus on this machine" );

View File

@ -9,3 +9,33 @@ assert.eq( 2 , t.find().count() , "A" );
assert.eq( 1 , t.find( { b : null } ).count() , "B" );
assert.eq( 1 , t.find( "function() { return this.b == null; }" ).itcount() , "C" );
assert.eq( 1 , t.find( "function() { return this.b == null; }" ).count() , "D" );
/* test some stuff with dot array notation */
q = db.find6a;
q.drop();
q.insert( { "a" : [ { "0" : 1 } ] } );
q.insert( { "a" : [ { "0" : 2 } ] } );
q.insert( { "a" : [ 1 ] } );
q.insert( { "a" : [ 9, 1 ] } );
function f() {
assert.eq( 2, q.find( { 'a.0' : 1 } ).count(), "da1");
assert.eq( 2, q.find( { 'a.0' : 1 } ).count(), "da2");
assert.eq( 1, q.find( { 'a.0' : { $gt : 8 } } ).count(), "da3");
assert.eq( 0, q.find( { 'a.0' : { $lt : 0 } } ).count(), "da4");
}
for( var pass = 0; pass <= 1 ; pass++ ) {
f();
q.ensureIndex({a:1});
}
t = db.multidim;
t.drop();
t.insert({"a" : [ [ ], 1, [ 3, 4 ] ] });
assert.eq(1, t.find({"a.2":[3,4]}).count(), "md1");
assert.eq(1, t.find({"a.2.1":4}).count(), "md2");
assert.eq(0, t.find({"a.2.1":3}).count(), "md3");

View File

@ -4,6 +4,6 @@ t.drop();
t.save( { a : 1 } );
assert.lt( 0 , t.dataSize() , "A" );
assert.lt( t.dataSize() , t.storageSize() , "B" );
assert.lt( 0 , t.dataSize().toNumber() , "A" );
assert.lt( t.dataSize() , t.storageSize().toNumber() , "B" );
assert.lt( 0 , t.totalIndexSize() , "C" );

View File

@ -158,6 +158,14 @@ namespace mongo {
return toString( JS_ValueToString( _context , v ) );
}
// NOTE No validation of passed in object
long long toNumberLongUnsafe( JSObject *o ) {
unsigned long long val =
( (unsigned long long)( getNumber( o , "top" ) ) << 32 ) +
( unsigned )( getNumber( o , "bottom" ) );
return val;
}
double toNumber( jsval v ){
double d;
uassert( 10214 , "not a number" , JS_ValueToNumber( _context , v , &d ) );
@ -469,7 +477,6 @@ namespace mongo {
return JSVAL_NULL;
case NumberDouble:
case NumberInt:
case NumberLong:
return toval( e.number() );
case Symbol: // TODO: should we make a special class for this
case String:
@ -557,7 +564,15 @@ namespace mongo {
setProperty( o , "i" , toval( (double)(e.timestampInc()) ) );
return OBJECT_TO_JSVAL( o );
}
case NumberLong: {
unsigned long long val = (unsigned long long)e.numberLong();
JSObject * o = JS_NewObject( _context , &numberlong_class , 0 , 0 );
// using 2 doubles here instead of a single double because certain double
// bit patterns represent undefined values and sm might trash them
setProperty( o , "top" , toval( (double)( val >> 32 ) ) );
setProperty( o , "bottom" , toval( (double)( val & 0x00000000ffffffff ) ) );
return OBJECT_TO_JSVAL( o );
}
case DBRef: {
JSObject * o = JS_NewObject( _context , &dbpointer_class , 0 , 0 );
setProperty( o , "ns" , toval( e.dbrefNS() ) );

View File

@ -93,6 +93,7 @@ namespace mongo {
extern JSClass dbref_class;
extern JSClass bindata_class;
extern JSClass timestamp_class;
extern JSClass numberlong_class;
extern JSClass minkey_class;
extern JSClass maxkey_class;

View File

@ -101,7 +101,6 @@ namespace mongo {
*rval = c.toval( &n );
return JS_TRUE;
}
JSFunctionSpec internal_cursor_functions[] = {
{ "hasNext" , internal_cursor_hasNext , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
@ -173,7 +172,7 @@ namespace mongo {
}
}
else if ( numCommas == 2 ){
conn.reset( new SyncCluterConnection( host ) );
conn.reset( new SyncClusterConnection( host ) );
}
else {
JS_ReportError( cx , "1 (paired) or 2(quorum) commas are allowed" );
@ -526,6 +525,7 @@ namespace mongo {
{ 0 }
};
// dbpointer
JSBool dbpointer_constructor( JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval ){
@ -656,7 +656,33 @@ namespace mongo {
JS_EnumerateStub, JS_ResolveStub , JS_ConvertStub, JS_FinalizeStub,
JSCLASS_NO_OPTIONAL_MEMBERS
};
JSClass numberlong_class = {
"NumberLong" , JSCLASS_HAS_PRIVATE ,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub , JS_ConvertStub, JS_FinalizeStub,
JSCLASS_NO_OPTIONAL_MEMBERS
};
JSBool numberlong_tostring(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){
Convertor c(cx);
stringstream ss;
ss << c.toNumberLongUnsafe( obj );
string ret = ss.str();
return *rval = c.toval( ret.c_str() );
}
JSBool numberlong_tonumber(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){
Convertor c(cx);
return *rval = c.toval( double( c.toNumberLongUnsafe( obj ) ) );
}
JSFunctionSpec numberlong_functions[] = {
{ "toString" , numberlong_tostring , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
{ "toNumber" , numberlong_tonumber , 0 , JSPROP_READONLY | JSPROP_PERMANENT, 0 } ,
{ 0 }
};
JSClass minkey_class = {
"MinKey" , JSCLASS_HAS_PRIVATE ,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
@ -748,6 +774,7 @@ namespace mongo {
assert( JS_InitClass( cx , global , 0 , &bindata_class , bindata_constructor , 0 , 0 , bindata_functions , 0 , 0 ) );
assert( JS_InitClass( cx , global , 0 , &timestamp_class , 0 , 0 , 0 , 0 , 0 , 0 ) );
assert( JS_InitClass( cx , global , 0 , &numberlong_class , 0 , 0 , 0 , numberlong_functions , 0 , 0 ) );
assert( JS_InitClass( cx , global , 0 , &minkey_class , 0 , 0 , 0 , 0 , 0 , 0 ) );
assert( JS_InitClass( cx , global , 0 , &maxkey_class , 0 , 0 , 0 , 0 , 0 , 0 ) );
@ -783,6 +810,11 @@ namespace mongo {
return true;
}
if ( JS_InstanceOf( c->_context , o , &numberlong_class , 0 ) ){
b.append( name.c_str() , c->toNumberLongUnsafe( o ) );
return true;
}
if ( JS_InstanceOf( c->_context , o , &dbpointer_class , 0 ) ){
b.appendDBRef( name.c_str() , c->getString( o , "ns" ).c_str() , c->toOID( c->getProperty( o , "id" ) ) );
return true;

View File

@ -49,6 +49,17 @@ namespace mongo {
return mongo;
}
v8::Handle<v8::FunctionTemplate> getNumberLongFunctionTemplate() {
v8::Local<v8::FunctionTemplate> numberLong = FunctionTemplate::New( numberLongInit );
v8::Local<v8::Template> proto = numberLong->PrototypeTemplate();
proto->Set( v8::String::New( "toString" ) , FunctionTemplate::New( numberLongToString ) );
proto->Set( v8::String::New( "toNumber" ) , FunctionTemplate::New( numberLongToNumber ) );
return numberLong;
}
void installDBTypes( Handle<ObjectTemplate>& global ){
v8::Local<v8::FunctionTemplate> db = FunctionTemplate::New( dbInit );
db->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback );
@ -71,6 +82,8 @@ namespace mongo {
global->Set( v8::String::New("BinData") , FunctionTemplate::New( binDataInit ) );
global->Set( v8::String::New("NumberLong") , getNumberLongFunctionTemplate() );
}
void installDBTypes( Handle<v8::Object>& global ){
@ -95,6 +108,8 @@ namespace mongo {
global->Set( v8::String::New("BinData") , FunctionTemplate::New( binDataInit )->GetFunction() );
global->Set( v8::String::New("NumberLong") , getNumberLongFunctionTemplate()->GetFunction() );
BSONObjBuilder b;
b.appendMaxKey( "" );
b.appendMinKey( "" );
@ -531,6 +546,59 @@ namespace mongo {
return it;
}
v8::Handle<v8::Value> numberLongInit( const v8::Arguments& args ) {
if (args.Length() != 2) {
return v8::ThrowException( v8::String::New( "NumberLong needs 2 arguments" ) );
}
v8::Handle<v8::Object> it = args.This();
if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ){
v8::Function* f = getNamedCons( "NumberLong" );
it = f->NewInstance();
}
it->Set( v8::String::New( "top" ) , args[0] );
it->Set( v8::String::New( "bottom" ) , args[1] );
it->SetHiddenValue( v8::String::New( "__NumberLong" ), v8::Number::New( 1 ) );
return it;
}
v8::Handle<v8::Value> numberLongToString( const v8::Arguments& args ) {
if (args.Length() != 0) {
return v8::ThrowException( v8::String::New( "toString needs 0 arguments" ) );
}
v8::Handle<v8::Object> it = args.This();
unsigned long long val =
( (unsigned long long)( it->Get( v8::String::New( "top" ) )->ToInt32()->Value() ) << 32 ) +
(unsigned)( it->Get( v8::String::New( "bottom" ) )->ToInt32()->Value() );
stringstream ss;
ss << (long long)val;
string ret = ss.str();
return v8::String::New( ret.c_str() );
}
v8::Handle<v8::Value> numberLongToNumber( const v8::Arguments& args ) {
if (args.Length() != 0) {
return v8::ThrowException( v8::String::New( "toNumber needs 0 arguments" ) );
}
v8::Handle<v8::Object> it = args.This();
unsigned long long val =
( (unsigned long long)( it->Get( v8::String::New( "top" ) )->ToInt32()->Value() ) << 32 ) +
(unsigned)( it->Get( v8::String::New( "bottom" ) )->ToInt32()->Value() );
return v8::Number::New( double( (long long)val ) );
}
v8::Handle<v8::Value> bsonsize( const v8::Arguments& args ) {
if (args.Length() != 1 || !args[ 0 ]->IsObject()) {

View File

@ -60,6 +60,9 @@ namespace mongo {
v8::Handle<v8::Value> dbPointerInit( const v8::Arguments& args );
v8::Handle<v8::Value> binDataInit( const v8::Arguments& args );
v8::Handle<v8::Value> numberLongInit( const v8::Arguments& args );
v8::Handle<v8::Value> numberLongToString(const v8::Arguments& args);
v8::Handle<v8::Value> numberLongToNumber(const v8::Arguments& args);
v8::Handle<v8::Value> dbQueryInit( const v8::Arguments& args );
v8::Handle<v8::Value> dbQueryIndexAccess( uint32_t index , const v8::AccessorInfo& info );

View File

@ -149,7 +149,6 @@ namespace mongo {
case mongo::NumberDouble:
case mongo::NumberInt:
case mongo::NumberLong: // may lose information here - just copying sm engine behavior
o->Set( v8::String::New( f.fieldName() ) , v8::Number::New( f.number() ) );
break;
@ -208,6 +207,17 @@ namespace mongo {
break;
}
case mongo::NumberLong: {
Local<v8::Object> sub = readOnly ? readOnlyObjects->NewInstance() : internalFieldObjects->NewInstance();
unsigned long long val = f.numberLong();
v8::Function* numberLong = getNamedCons( "NumberLong" );
v8::Handle<v8::Value> argv[2];
argv[0] = v8::Integer::New( val >> 32 );
argv[1] = v8::Integer::New( (unsigned long)(val & 0x00000000ffffffff) );
o->Set( v8::String::New( f.fieldName() ), numberLong->NewInstance(2, argv) );
break;
}
case mongo::MinKey: {
Local<v8::Object> sub = readOnly ? readOnlyObjects->NewInstance() : internalFieldObjects->NewInstance();
sub->Set( v8::String::New( "$MinKey" ), v8::Boolean::New( true ) );
@ -325,6 +335,16 @@ namespace mongo {
return sub;
}
case mongo::NumberLong: {
Local<v8::Object> sub = internalFieldObjects->NewInstance();
unsigned long long val = f.numberLong();
v8::Function* numberLong = getNamedCons( "NumberLong" );
v8::Handle<v8::Value> argv[2];
argv[0] = v8::Integer::New( val >> 32 );
argv[1] = v8::Integer::New( (unsigned long)(val & 0x00000000ffffffff) );
return numberLong->NewInstance( 2, argv );
}
case mongo::MinKey: {
Local<v8::Object> sub = internalFieldObjects->NewInstance();
@ -431,10 +451,16 @@ namespace mongo {
oid.init( toSTLString( value ) );
b.appendOID( sname.c_str() , &oid );
}
else if ( !value->ToObject()->GetHiddenValue( v8::String::New( "__DBPointer" ) ).IsEmpty() ) {
else if ( !value->ToObject()->GetHiddenValue( v8::String::New( "__NumberLong" ) ).IsEmpty() ) {
// TODO might be nice to potentially speed this up with an indexed internal
// field, but I don't yet know how to use an ObjectTemplate with a
// constructor.
unsigned long long val =
( (unsigned long long)( value->ToObject()->Get( v8::String::New( "top" ) )->ToInt32()->Value() ) << 32 ) +
(unsigned)( value->ToObject()->Get( v8::String::New( "bottom" ) )->ToInt32()->Value() );
b.append( sname.c_str(), (long long)val );
}
else if ( !value->ToObject()->GetHiddenValue( v8::String::New( "__DBPointer" ) ).IsEmpty() ) {
OID oid;
oid.init( toSTLString( value->ToObject()->Get( v8::String::New( "id" ) ) ) );
string ns = toSTLString( value->ToObject()->Get( v8::String::New( "ns" ) ) );

View File

@ -32,6 +32,6 @@
namespace mongo {
const char versionString[] = "1.3.1";
const char versionString[] = "1.3.2-";
} // namespace mongo