2008-08-13 18:17:18 +02:00
|
|
|
/**
|
|
|
|
* Copyright (C) 2008 10gen Inc.
|
2008-12-29 02:28:49 +01:00
|
|
|
*
|
2008-08-13 18:17:18 +02:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License, version 3,
|
|
|
|
* as published by the Free Software Foundation.
|
2008-12-29 02:28:49 +01:00
|
|
|
*
|
2008-08-13 18:17:18 +02:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Affero General Public License for more details.
|
2008-12-29 02:28:49 +01:00
|
|
|
*
|
2008-08-13 18:17:18 +02:00
|
|
|
* 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/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "../stdafx.h"
|
|
|
|
|
2009-02-17 21:53:19 +01:00
|
|
|
#include "jsobj.h"
|
|
|
|
#include "storage.h"
|
|
|
|
|
2009-01-14 23:09:51 +01:00
|
|
|
namespace mongo {
|
2009-02-17 21:53:19 +01:00
|
|
|
|
|
|
|
class Record;
|
2009-01-14 23:09:51 +01:00
|
|
|
|
2009-01-29 00:08:02 +01:00
|
|
|
/* 0 = ok
|
|
|
|
1 = kill current operation and reset this to 0
|
|
|
|
future: maybe use this as a "going away" thing on process termination with a higher flag value
|
|
|
|
*/
|
2009-02-17 21:53:19 +01:00
|
|
|
extern int killCurrentOp;
|
|
|
|
|
2009-01-29 00:08:02 +01:00
|
|
|
inline void checkForInterrupt() {
|
|
|
|
if( killCurrentOp ) {
|
|
|
|
killCurrentOp = 0;
|
|
|
|
uasserted("interrupted");
|
|
|
|
}
|
2009-02-17 21:53:19 +01:00
|
|
|
}
|
2009-01-29 00:08:02 +01:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
/* Query cursors, base class. This is for our internal cursors. "ClientCursor" is a separate
|
|
|
|
concept and is for the user's cursor.
|
|
|
|
*/
|
|
|
|
class Cursor {
|
|
|
|
public:
|
2009-02-18 00:39:52 +01:00
|
|
|
virtual ~Cursor() {}
|
2009-01-15 16:17:11 +01:00
|
|
|
virtual bool ok() = 0;
|
|
|
|
bool eof() {
|
|
|
|
return !ok();
|
|
|
|
}
|
|
|
|
virtual Record* _current() = 0;
|
|
|
|
virtual BSONObj current() = 0;
|
|
|
|
virtual DiskLoc currLoc() = 0;
|
|
|
|
virtual bool advance() = 0; /*true=ok*/
|
2009-03-19 21:23:04 +01:00
|
|
|
virtual BSONObj currKey() const { return BSONObj(); }
|
2009-03-11 22:05:50 +01:00
|
|
|
// DiskLoc the cursor requires for continued operation. Before this
|
|
|
|
// DiskLoc is deleted, the cursor must be incremented or destroyed.
|
|
|
|
virtual DiskLoc refLoc() = 0;
|
2009-01-15 16:17:11 +01:00
|
|
|
|
|
|
|
/* Implement these if you want the cursor to be "tailable" */
|
2009-03-11 22:05:50 +01:00
|
|
|
|
|
|
|
/* Request that the cursor starts tailing after advancing past last record. */
|
|
|
|
/* The implementation may or may not honor this request. */
|
|
|
|
virtual void setTailable() {}
|
|
|
|
/* indicates if tailing is enabled. */
|
2009-01-15 16:17:11 +01:00
|
|
|
virtual bool tailable() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void aboutToDeleteBucket(const DiskLoc& b) { }
|
|
|
|
|
|
|
|
/* optional to implement. if implemented, means 'this' is a prototype */
|
|
|
|
virtual Cursor* clone() {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual BSONObj indexKeyPattern() {
|
|
|
|
return BSONObj();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* called after every query block is iterated -- i.e. between getMore() blocks
|
|
|
|
so you can note where we are, if necessary.
|
|
|
|
*/
|
|
|
|
virtual void noteLocation() { }
|
|
|
|
|
|
|
|
/* called before query getmore block is iterated */
|
|
|
|
virtual void checkLocation() { }
|
|
|
|
|
|
|
|
virtual string toString() {
|
|
|
|
return "abstract?";
|
|
|
|
}
|
|
|
|
|
2009-07-07 19:17:53 +02:00
|
|
|
/* used for multikey index traversal to avoid sending back dups. see JSMatcher::matches().
|
|
|
|
if a multikey index traversal:
|
|
|
|
if loc has already been sent, returns true.
|
|
|
|
otherwise, marks loc as sent.
|
|
|
|
@param deep - match was against an array, so we know it is multikey. this is legacy and kept
|
|
|
|
for backwards datafile compatibility. 'deep' can be eliminated next time we
|
|
|
|
force a data file conversion. 7Jul09
|
|
|
|
*/
|
|
|
|
virtual bool getsetdup(bool deep, DiskLoc loc) = 0;
|
|
|
|
/*
|
2009-01-15 16:17:11 +01:00
|
|
|
set<DiskLoc> dups;
|
|
|
|
bool getsetdup(DiskLoc loc) {
|
|
|
|
if ( dups.count(loc) > 0 )
|
|
|
|
return true;
|
|
|
|
dups.insert(loc);
|
2008-12-29 02:28:49 +01:00
|
|
|
return false;
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
2009-07-07 19:17:53 +02:00
|
|
|
*/
|
2009-01-15 19:04:25 +01:00
|
|
|
|
2009-03-19 21:23:04 +01:00
|
|
|
virtual BSONObj prettyStartKey() const { return BSONObj(); }
|
|
|
|
virtual BSONObj prettyEndKey() const { return BSONObj(); }
|
2009-03-11 22:05:50 +01:00
|
|
|
|
2009-05-14 17:30:13 +02:00
|
|
|
virtual bool capped() const { return false; }
|
2009-01-15 16:17:11 +01:00
|
|
|
};
|
|
|
|
|
2009-05-28 21:22:24 +02:00
|
|
|
// strategy object implementing direction of traversal.
|
2009-01-15 16:17:11 +01:00
|
|
|
class AdvanceStrategy {
|
|
|
|
public:
|
2009-02-18 19:42:32 +01:00
|
|
|
virtual ~AdvanceStrategy() {}
|
2009-01-15 16:17:11 +01:00
|
|
|
virtual DiskLoc next( const DiskLoc &prev ) const = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
AdvanceStrategy *forward();
|
|
|
|
AdvanceStrategy *reverse();
|
|
|
|
|
|
|
|
/* table-scan style cursor */
|
|
|
|
class BasicCursor : public Cursor {
|
|
|
|
protected:
|
|
|
|
DiskLoc curr, last;
|
|
|
|
AdvanceStrategy *s;
|
|
|
|
|
|
|
|
private:
|
2009-03-11 22:05:50 +01:00
|
|
|
bool tailable_;
|
2009-01-15 16:17:11 +01:00
|
|
|
void init() {
|
2009-03-11 22:05:50 +01:00
|
|
|
tailable_ = false;
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
public:
|
|
|
|
bool ok() {
|
|
|
|
return !curr.isNull();
|
|
|
|
}
|
|
|
|
Record* _current() {
|
|
|
|
assert( ok() );
|
|
|
|
return curr.rec();
|
|
|
|
}
|
|
|
|
BSONObj current() {
|
|
|
|
Record *r = _current();
|
|
|
|
BSONObj j(r);
|
|
|
|
return j;
|
|
|
|
}
|
|
|
|
virtual DiskLoc currLoc() {
|
|
|
|
return curr;
|
|
|
|
}
|
2009-03-11 22:05:50 +01:00
|
|
|
virtual DiskLoc refLoc() {
|
|
|
|
return curr.isNull() ? last : curr;
|
|
|
|
}
|
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
bool advance() {
|
2009-01-29 00:08:02 +01:00
|
|
|
checkForInterrupt();
|
2009-03-11 22:05:50 +01:00
|
|
|
if ( eof() ) {
|
|
|
|
if ( tailable_ && !last.isNull() ) {
|
|
|
|
curr = s->next( last );
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
last = curr;
|
|
|
|
curr = s->next( curr );
|
|
|
|
}
|
2009-01-15 16:17:11 +01:00
|
|
|
return ok();
|
|
|
|
}
|
|
|
|
|
|
|
|
BasicCursor(DiskLoc dl, AdvanceStrategy *_s = forward()) : curr(dl), s( _s ) {
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
BasicCursor(AdvanceStrategy *_s = forward()) : s( _s ) {
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
virtual string toString() {
|
|
|
|
return "BasicCursor";
|
|
|
|
}
|
2009-03-11 22:05:50 +01:00
|
|
|
virtual void setTailable() {
|
|
|
|
if ( !curr.isNull() || !last.isNull() )
|
|
|
|
tailable_ = true;
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
virtual bool tailable() {
|
2009-03-11 22:05:50 +01:00
|
|
|
return tailable_;
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
2009-07-07 19:17:53 +02:00
|
|
|
virtual bool getsetdup(bool deep, DiskLoc loc) { return false; }
|
2009-01-15 16:17:11 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/* used for order { $natural: -1 } */
|
|
|
|
class ReverseCursor : public BasicCursor {
|
|
|
|
public:
|
|
|
|
ReverseCursor(DiskLoc dl) : BasicCursor( dl, reverse() ) { }
|
|
|
|
ReverseCursor() : BasicCursor( reverse() ) { }
|
|
|
|
virtual string toString() {
|
|
|
|
return "ReverseCursor";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class NamespaceDetails;
|
|
|
|
|
|
|
|
class ForwardCappedCursor : public BasicCursor, public AdvanceStrategy {
|
|
|
|
public:
|
2009-03-18 22:24:10 +01:00
|
|
|
ForwardCappedCursor( NamespaceDetails *nsd = 0, const DiskLoc &startLoc = DiskLoc() );
|
2009-01-15 16:17:11 +01:00
|
|
|
virtual string toString() {
|
|
|
|
return "ForwardCappedCursor";
|
|
|
|
}
|
|
|
|
virtual DiskLoc next( const DiskLoc &prev ) const;
|
2009-05-14 17:30:13 +02:00
|
|
|
virtual bool capped() const { return true; }
|
2009-01-15 16:17:11 +01:00
|
|
|
private:
|
|
|
|
NamespaceDetails *nsd;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ReverseCappedCursor : public BasicCursor, public AdvanceStrategy {
|
|
|
|
public:
|
2009-03-18 22:24:10 +01:00
|
|
|
ReverseCappedCursor( NamespaceDetails *nsd = 0, const DiskLoc &startLoc = DiskLoc() );
|
2009-01-15 16:17:11 +01:00
|
|
|
virtual string toString() {
|
|
|
|
return "ReverseCappedCursor";
|
|
|
|
}
|
|
|
|
virtual DiskLoc next( const DiskLoc &prev ) const;
|
2009-05-14 17:30:13 +02:00
|
|
|
virtual bool capped() const { return true; }
|
2009-01-15 16:17:11 +01:00
|
|
|
private:
|
|
|
|
NamespaceDetails *nsd;
|
|
|
|
};
|
2009-01-14 23:09:51 +01:00
|
|
|
|
|
|
|
} // namespace mongo
|