0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-11-30 17:10:48 +01:00
mongodb/db/pdfile.cpp

666 lines
18 KiB
C++
Raw Normal View History

2007-10-20 01:35:48 +02:00
// pdfile.cpp
2007-10-30 10:50:14 +01:00
/*
todo:
_ manage deleted records. bucket?
_ use deleted on inserts!
_ quantize allocations
2007-10-30 16:35:17 +01:00
_ table scans must be sequential, not next/prev pointers
2007-10-31 02:16:35 +01:00
_ regex support
2007-10-30 10:50:14 +01:00
*/
2007-10-20 01:35:48 +02:00
#include "stdafx.h"
#include "pdfile.h"
#include "db.h"
#include "../util/mmap.h"
#include "../util/hashtab.h"
2007-11-09 03:42:50 +01:00
#include "objwrappers.h"
#include "btree.h"
2007-11-22 03:44:57 +01:00
#include <algorithm>
2007-10-20 01:35:48 +02:00
2007-11-27 21:30:51 +01:00
const char *dbpath = "/data/db/";
2007-10-20 01:35:48 +02:00
DataFileMgr theDataFileMgr;
2007-11-02 03:34:44 +01:00
JSObj::JSObj(Record *r) {
_objdata = r->data;
_objsize = *((int*) _objdata);
assert( _objsize <= r->netLength() );
2007-11-05 04:34:37 +01:00
iFree = false;
2007-11-02 03:34:44 +01:00
}
2007-10-20 01:35:48 +02:00
/*---------------------------------------------------------------------*/
2007-10-30 10:50:14 +01:00
int bucketSizes[] = {
32, 64, 128, 256, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000,
0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000, 0x200000,
0x400000, 0x800000
};
2007-11-10 22:46:30 +01:00
NamespaceIndex namespaceIndex;
2007-11-10 22:46:30 +01:00
void NamespaceDetails::addDeletedRec(DeletedRecord *d, DiskLoc dloc) {
int b = bucket(d->lengthWithHeaders);
DiskLoc& list = deletedList[b];
DiskLoc oldHead = list;
list = dloc;
d->nextDeleted = oldHead;
}
2007-10-30 10:50:14 +01:00
2007-11-13 22:44:01 +01:00
/* lenToAlloc is WITH header */
2007-10-30 16:35:17 +01:00
DiskLoc NamespaceDetails::alloc(int lenToAlloc, DiskLoc& extentLoc) {
lenToAlloc = (lenToAlloc + 3) & 0xfffffffc;
DiskLoc loc = _alloc(lenToAlloc);
if( loc.isNull() )
return loc;
DeletedRecord *r = loc.drec();
/* note we want to grab from the front so our next pointers on disk tend
to go in a forward direction which is important for performance. */
int regionlen = r->lengthWithHeaders;
extentLoc.set(loc.a(), r->extentOfs);
int left = regionlen - lenToAlloc;
if( left < 24 ) {
// you get the whole thing.
return loc;
}
/* split off some for further use. */
r->lengthWithHeaders = lenToAlloc;
DiskLoc newDelLoc = loc;
newDelLoc.inc(lenToAlloc);
DeletedRecord *newDel = newDelLoc.drec();
newDel->extentOfs = r->extentOfs;
newDel->lengthWithHeaders = left;
newDel->nextDeleted.Null();
addDeletedRec(newDel, newDelLoc);
return loc;
}
/* returned item is out of the deleted list upon return */
DiskLoc NamespaceDetails::_alloc(int len) {
DiskLoc *prev;
DiskLoc *bestprev = 0;
DiskLoc bestmatch;
int bestmatchlen = 0x7fffffff;
int b = bucket(len);
DiskLoc cur = deletedList[b]; prev = &deletedList[b];
int extra = 5; // look for a better fit, a little.
int chain = 0;
while( 1 ) {
if( cur.isNull() ) {
// move to next bucket. if we were doing "extra", just break
if( bestmatchlen < 0x7fffffff )
break;
b++;
if( b > MaxBucket ) {
// out of space. alloc a new extent.
return DiskLoc();
}
cur = deletedList[b]; prev = &deletedList[b];
continue;
}
DeletedRecord *r = cur.drec();
if( r->lengthWithHeaders >= len &&
r->lengthWithHeaders < bestmatchlen ) {
bestmatchlen = r->lengthWithHeaders;
bestmatch = cur;
bestprev = prev;
}
if( bestmatchlen < 0x7fffffff && --extra <= 0 )
break;
if( ++chain > 30 && b < MaxBucket ) {
// too slow, force move to next bucket to grab a big chunk
b++;
chain = 0;
cur.Null();
}
else {
cur = r->nextDeleted; prev = &r->nextDeleted;
}
}
/* unlink ourself from the deleted list */
*bestprev = bestmatch.drec()->nextDeleted;
return bestmatch;
}
2007-10-20 01:35:48 +02:00
2007-11-02 03:34:44 +01:00
class NamespaceCursor : public Cursor {
public:
virtual bool ok() { return i >= 0; }
virtual Record* _current() { assert(false); return 0; }
virtual DiskLoc currLoc() { assert(false); return DiskLoc(); }
virtual JSObj current() {
NamespaceDetails &d = namespaceIndex.ht->nodes[i].value;
JSObjBuilder b;
b.append("name", namespaceIndex.ht->nodes[i].k.buf);
return b.done();
}
virtual bool advance() {
while( 1 ) {
i++;
if( i >= namespaceIndex.ht->n )
break;
if( namespaceIndex.ht->nodes[i].inUse() )
return true;
}
i = -1000000;
return false;
}
NamespaceCursor() {
i = -1;
advance();
}
private:
int i;
};
auto_ptr<Cursor> makeNamespaceCursor() {
return auto_ptr<Cursor>(new NamespaceCursor());
}
2007-11-03 02:30:40 +01:00
void newNamespace(const char *ns) {
cout << "New namespace: " << ns << endl;
if( strcmp(ns, "system.namespaces") != 0 ) {
JSObjBuilder b;
b.append("name", ns);
JSObj j = b.done();
theDataFileMgr.insert("system.namespaces", j.objdata(), j.objsize(), true);
}
}
2007-10-20 01:35:48 +02:00
/*---------------------------------------------------------------------*/
void PhysicalDataFile::open(const char *filename, int length) {
header = (PDFHeader *) mmf.map(filename, length);
assert(header);
header->init(length);
}
2007-10-30 10:50:14 +01:00
/* prev - previous extent for this namespace. null=this is the first one. */
2007-11-06 03:43:49 +01:00
Extent* PhysicalDataFile::newExtent(const char *ns, int approxSize) {
int ExtentSize = approxSize <= header->unusedLength ? approxSize : header->unusedLength;
2007-10-30 16:35:17 +01:00
DiskLoc loc;
2007-11-06 03:43:49 +01:00
if( ExtentSize <= 0 ) {
2007-10-20 01:35:48 +02:00
cout << "ERROR: newExtent: no more room for extents. write more code" << endl;
assert(false);
exit(2);
}
int offset = header->unused.getOfs();
header->unused.setOfs( offset + ExtentSize );
header->unusedLength -= ExtentSize;
loc.setOfs(offset);
Extent *e = _getExtent(loc);
2007-10-30 16:35:17 +01:00
DiskLoc emptyLoc = e->init(ns, ExtentSize, offset);
DiskLoc oldExtentLoc;
2007-11-13 22:44:01 +01:00
NamespaceDetails *details = namespaceIndex.details(ns);
if( details ) {
assert( !details->firstExtent.isNull() );
e->xprev = details->lastExtent;
details->lastExtent.ext()->xnext = loc;
details->lastExtent = loc;
2007-10-30 10:50:14 +01:00
}
2007-10-30 16:35:17 +01:00
else {
namespaceIndex.add(ns, loc);
2007-11-13 22:44:01 +01:00
details = namespaceIndex.details(ns);
2007-10-30 16:35:17 +01:00
}
2007-11-13 22:44:01 +01:00
details->lastExtentSize = approxSize;
details->addDeletedRec(emptyLoc.drec(), emptyLoc);
2007-10-30 16:35:17 +01:00
2007-11-20 04:24:17 +01:00
cout << "*** new extent size: 0x" << hex << ExtentSize << " loc: 0x" << hex << offset << dec << endl;
2007-11-18 03:10:00 +01:00
cout << " emptyLoc:" << hex << emptyLoc.getOfs() << dec << endl;
2007-11-13 22:44:01 +01:00
cout << " " << ns << endl;
2007-10-20 01:35:48 +02:00
return e;
}
/*---------------------------------------------------------------------*/
/* assumes already zeroed -- insufficient for block 'reuse' perhaps */
2007-10-30 16:35:17 +01:00
DiskLoc Extent::init(const char *nsname, int _length, int _offset) {
2007-10-20 01:35:48 +02:00
magic = 0x41424344;
myLoc.setOfs(_offset);
2007-10-30 10:50:14 +01:00
xnext.Null(); xprev.Null();
2007-10-20 01:35:48 +02:00
ns = nsname;
length = _length;
firstRecord.Null(); lastRecord.Null();
2007-10-30 16:35:17 +01:00
DiskLoc emptyLoc = myLoc;
emptyLoc.inc( (extentData-(char*)this) );
2007-10-20 01:35:48 +02:00
2007-10-30 16:35:17 +01:00
DeletedRecord *empty1 = (DeletedRecord *) extentData;
DeletedRecord *empty = (DeletedRecord *) getRecord(emptyLoc);
2007-10-20 01:35:48 +02:00
assert( empty == empty1 );
empty->lengthWithHeaders = _length - (extentData - (char *) this);
2007-10-30 16:35:17 +01:00
empty->extentOfs = myLoc.getOfs();
return emptyLoc;
2007-10-20 01:35:48 +02:00
}
2007-10-30 16:35:17 +01:00
/*
2007-10-20 01:35:48 +02:00
Record* Extent::newRecord(int len) {
if( firstEmptyRegion.isNull() )
return 0;
assert(len > 0);
int newRecSize = len + Record::HeaderSize;
DiskLoc newRecordLoc = firstEmptyRegion;
Record *r = getRecord(newRecordLoc);
int left = r->netLength() - len;
if( left < 0 ) {
2007-10-30 16:35:17 +01:00
//
2007-10-20 01:35:48 +02:00
firstEmptyRegion.Null();
return 0;
}
2007-10-30 10:50:14 +01:00
DiskLoc nextEmpty = r->next.getNextEmpty(firstEmptyRegion);
2007-10-20 01:35:48 +02:00
r->lengthWithHeaders = newRecSize;
2007-10-30 10:50:14 +01:00
r->next.markAsFirstOrLastInExtent(this); // we're now last in the extent
2007-10-20 01:35:48 +02:00
if( !lastRecord.isNull() ) {
2007-10-30 10:50:14 +01:00
assert(getRecord(lastRecord)->next.lastInExtent()); // it was the last one
getRecord(lastRecord)->next.set(newRecordLoc); // until now
r->prev.set(lastRecord);
2007-10-20 01:35:48 +02:00
}
2007-10-30 10:50:14 +01:00
else {
r->prev.markAsFirstOrLastInExtent(this); // we are the first in the extent
assert( firstRecord.isNull() );
2007-10-20 01:35:48 +02:00
firstRecord = newRecordLoc;
2007-10-30 10:50:14 +01:00
}
lastRecord = newRecordLoc;
2007-10-20 01:35:48 +02:00
if( left < Record::HeaderSize + 32 ) {
firstEmptyRegion.Null();
}
else {
firstEmptyRegion.inc(newRecSize);
Record *empty = getRecord(firstEmptyRegion);
2007-10-30 10:50:14 +01:00
empty->next.set(nextEmpty); // not for empty records, unless in-use records, next and prev can be null.
empty->prev.Null();
2007-10-20 01:35:48 +02:00
empty->lengthWithHeaders = left;
}
return r;
}
2007-10-30 16:35:17 +01:00
*/
2007-10-20 01:35:48 +02:00
/*---------------------------------------------------------------------*/
2007-11-02 03:34:44 +01:00
auto_ptr<Cursor> DataFileMgr::findAll(const char *ns) {
2007-10-20 01:35:48 +02:00
DiskLoc loc;
bool found = namespaceIndex.find(ns, loc);
if( !found ) {
cout << "info: findAll() namespace does not exist: " << ns << endl;
2007-11-02 03:34:44 +01:00
return auto_ptr<Cursor>(new BasicCursor(DiskLoc()));
2007-10-20 01:35:48 +02:00
}
Extent *e = temp.getExtent(loc);
2007-11-02 03:34:44 +01:00
return auto_ptr<Cursor>(new BasicCursor( e->firstRecord ));
2007-10-20 01:35:48 +02:00
}
2007-11-05 01:17:42 +01:00
void aboutToDelete(const DiskLoc& dl);
2007-11-22 03:44:57 +01:00
void IndexDetails::getKeysFromObject(JSObj& obj, set<JSObj>& keys) {
JSObj keyPattern = info.obj().getObjectField("key");
JSObjBuilder b;
JSObj key = obj.extractFields(keyPattern, b);
if( key.isEmpty() )
return;
Element f = key.firstElement();
if( f.type() != Array ) {
b.decouple();
key.iWillFree();
keys.insert(key);
return;
}
JSObj arr = f.embeddedObject();
// cout << arr.toString() << endl;
2007-11-22 03:44:57 +01:00
JSElemIter i(arr);
while( i.more() ) {
Element e = i.next();
if( e.eoo() ) break;
JSObjBuilder b;
b.appendAs(e, f.fieldName());
JSObj o = b.doneAndDecouple();
// cout << "TEMP: got key " << o.toString() << endl;
2007-11-22 03:44:57 +01:00
keys.insert(o);
}
}
2007-11-11 20:21:02 +01:00
void _unindexRecord(IndexDetails& id, JSObj& obj) {
2007-11-22 03:44:57 +01:00
set<JSObj> keys;
id.getKeysFromObject(obj, keys);
for( set<JSObj>::iterator i=keys.begin(); i != keys.end(); i++ ) {
JSObj j = *i;
id.head.btree()->unindex(j);
}
/*
2007-11-11 20:21:02 +01:00
JSObj idxInfo = id.info.obj();
JSObjBuilder b;
JSObj key = obj.extractFields(idxInfo.getObjectField("key"), b);
if( !key.isEmpty() )
id.head.btree()->unindex(key);
2007-11-22 03:44:57 +01:00
*/
2007-11-11 20:21:02 +01:00
}
void unindexRecord(NamespaceDetails *d, Record *todelete) {
if( d->nIndexes == 0 ) return;
JSObj obj(todelete);
for( int i = 0; i < d->nIndexes; i++ ) {
_unindexRecord(d->indexes[i], obj);
}
}
2007-10-30 16:35:17 +01:00
void DataFileMgr::deleteRecord(const char *ns, Record *todelete, const DiskLoc& dl)
{
2007-11-05 01:17:42 +01:00
/* check if any cursors point to us. if so, advance them. */
aboutToDelete(dl);
2007-11-11 20:21:02 +01:00
NamespaceDetails* d = namespaceIndex.details(ns);
unindexRecord(d, todelete);
2007-10-30 10:50:14 +01:00
/* remove ourself from the record next/prev chain */
2007-10-30 16:35:17 +01:00
{
if( todelete->prevOfs != DiskLoc::NullOfs )
todelete->getPrev(dl).rec()->nextOfs = todelete->nextOfs;
if( todelete->nextOfs != DiskLoc::NullOfs )
todelete->getNext(dl).rec()->prevOfs = todelete->prevOfs;
}
2007-10-30 10:50:14 +01:00
/* remove ourself from extent pointers */
2007-10-30 16:35:17 +01:00
{
Extent *e = todelete->myExtent(dl);
if( e->firstRecord == dl )
e->firstRecord.setOfs(todelete->nextOfs);
if( e->lastRecord == dl )
e->lastRecord.setOfs(todelete->prevOfs);
2007-10-30 10:50:14 +01:00
}
2007-11-05 01:17:42 +01:00
/* add to the free list */
2007-10-30 16:35:17 +01:00
{
2007-11-06 03:43:49 +01:00
d->nrecords--;
d->datasize -= todelete->netLength();
2007-10-30 16:35:17 +01:00
d->addDeletedRec((DeletedRecord*)todelete, dl);
}
2007-10-30 10:50:14 +01:00
}
2007-11-22 03:44:57 +01:00
void setDifference(set<JSObj>& l, set<JSObj>& r, vector<JSObj*> &diff) {
set<JSObj>::iterator i = l.begin();
set<JSObj>::iterator j = r.begin();
while( 1 ) {
if( i == l.end() )
break;
// cout << i->toString() << endl;
2007-11-22 03:44:57 +01:00
while( j != r.end() && *j < *i )
j++;
if( !i->woEqual(*j) ) {
// cout << "INDIFF:" << i->toString() << " j:" << j->toString() << endl;
2007-11-22 03:44:57 +01:00
const JSObj *j = &*i;
diff.push_back( (JSObj *) j );
}
i++;
}
}
2007-10-30 10:50:14 +01:00
/** Note: as written so far, if the object shrinks a lot, we don't free up space. */
void DataFileMgr::update(
const char *ns,
Record *toupdate, const DiskLoc& dl,
const char *buf, int len)
{
2007-11-12 00:28:33 +01:00
if( toupdate->netLength() < len ) {
2007-10-30 10:50:14 +01:00
// doesn't fit.
deleteRecord(ns, toupdate, dl);
insert(ns, buf, len);
return;
}
2007-11-12 00:28:33 +01:00
/* has any index keys changed? */
{
NamespaceDetails *d = namespaceIndex.details(ns);
if( d->nIndexes ) {
JSObj newObj(buf);
JSObj oldObj = dl.obj();
for( int i = 0; i < d->nIndexes; i++ ) {
IndexDetails& idx = d->indexes[i];
JSObj idxKey = idx.info.obj().getObjectField("key");
2007-11-22 03:44:57 +01:00
set<JSObj> oldkeys;
set<JSObj> newkeys;
idx.getKeysFromObject(oldObj, oldkeys);
idx.getKeysFromObject(newObj, newkeys);
vector<JSObj*> removed;
setDifference(oldkeys, newkeys, removed);
for( unsigned i = 0; i < removed.size(); i++ ) {
idx.head.btree()->unindex(*removed[i]);
}
vector<JSObj*> added;
setDifference(newkeys, oldkeys, added);
string idxns = idx.indexNamespace();
for( unsigned i = 0; i < added.size(); i++ ) {
idx.head.btree()->insert(
idx.head, idxns.c_str(),
dl, *added[i], false, idx);
}
/*
2007-11-12 00:28:33 +01:00
JSObjBuilder b1,b2;
JSObj kNew = newObj.extractFields(idxKey, b1);
JSObj kOld = oldObj.extractFields(idxKey, b2);
if( !kNew.woEqual(kOld) ) {
cout << " updating index, key changed " << idx.indexNamespace() << endl;
// delete old key
if( !kOld.isEmpty() )
idx.head.btree()->unindex(kOld);
// add new key
if( !kNew.isEmpty() ) {
idx.head.btree()->insert(
idx.head,
idx.indexNamespace().c_str(),
dl, kNew, false, idx);
2007-11-12 00:28:33 +01:00
}
2007-11-22 03:44:57 +01:00
}
*/
2007-11-12 00:28:33 +01:00
}
}
}
// cout << "doing update in place" << endl;
2007-10-30 10:50:14 +01:00
memcpy(toupdate->data, buf, len);
}
2007-11-06 03:43:49 +01:00
int initialExtentSize(int len) {
2007-11-13 22:44:01 +01:00
// if( 1 )
// return 4000000;
2007-11-06 03:43:49 +01:00
long long sz = len * 16;
if( len < 1000 ) sz = len * 64;
if( sz > 1000000000 )
sz = 1000000000;
int z = ((int)sz) & 0xffffff00;
assert( z > len );
2007-11-20 04:24:17 +01:00
cout << "initialExtentSize(" << len << ") returns " << z << endl;
2007-11-06 03:43:49 +01:00
return z;
}
int followupExtentSize(int len, int lastExtentLen) {
int x = initialExtentSize(len);
int y = (int) (lastExtentLen < 4000000 ? lastExtentLen * 4.0 : lastExtentLen * 1.2);
int sz = y > x ? y : x;
sz = ((int)sz) & 0xffffff00;
assert( sz > len );
return sz;
}
/* add keys to indexes for a new record */
void _indexRecord(IndexDetails& idx, JSObj& obj, DiskLoc newRecordLoc) {
// cout << "temp: " << obj.toString() << endl;
2007-11-22 03:44:57 +01:00
set<JSObj> keys;
idx.getKeysFromObject(obj, keys);
for( set<JSObj>::iterator i=keys.begin(); i != keys.end(); i++ ) {
// cout << "_indexRecord " << i->toString() << endl;
2007-11-22 03:44:57 +01:00
idx.head.btree()->insert(idx.head, idx.indexNamespace().c_str(), newRecordLoc,
(JSObj&) *i, false, idx);
}
/*
JSObj idxInfo = idx.info.obj();
JSObjBuilder b;
JSObj key = obj.extractFields(idxInfo.getObjectField("key"), b);
if( !key.isEmpty() ) {
2007-11-20 04:24:17 +01:00
cout << "_indexRecord " << key.toString() << endl;
idx.head.btree()->insert(
idx.head,
2007-11-11 20:21:02 +01:00
idx.indexNamespace().c_str(),
newRecordLoc, key, false, idx);
}
2007-11-22 03:44:57 +01:00
*/
}
/* note there are faster ways to build an index in bulk, that can be
done eventually */
void addExistingToIndex(const char *ns, IndexDetails& idx) {
cout << "Adding all existing records for " << ns << " to new index" << endl;
int n = 0;
auto_ptr<Cursor> c = theDataFileMgr.findAll(ns);
while( c->ok() ) {
JSObj js = c->current();
_indexRecord(idx, js, c->currLoc());
c->advance();
n++;
};
cout << " indexing complete for " << n << " records" << endl;
}
/* add keys to indexes for a new record */
void indexRecord(NamespaceDetails *d, const void *buf, int len, DiskLoc newRecordLoc) {
JSObj obj((const char *)buf);
for( int i = 0; i < d->nIndexes; i++ ) {
_indexRecord(d->indexes[i], obj, newRecordLoc);
}
}
2007-11-09 03:42:50 +01:00
DiskLoc DataFileMgr::insert(const char *ns, const void *buf, int len, bool god) {
2007-11-13 22:44:01 +01:00
{
JSObj obj((const char *) buf);
OID *oid = obj.getOID();
// cout << "insert() " << ns << " oid:";
// if( oid )
// cout << hex << oid->a << ':' << hex << oid->b << dec;
// cout << endl;
2007-11-13 22:44:01 +01:00
}
2007-11-09 03:42:50 +01:00
bool addIndex = false;
if( strncmp(ns, "system.", 7) == 0 ) {
if( strcmp(ns, "system.indexes") == 0 )
addIndex = true;
else if( !god ) {
cout << "ERROR: attempt to insert in system namespace " << ns << endl;
return DiskLoc();
}
2007-11-03 02:30:40 +01:00
}
2007-10-30 16:35:17 +01:00
NamespaceDetails *d = namespaceIndex.details(ns);
if( d == 0 ) {
2007-11-03 02:30:40 +01:00
newNamespace(ns);
2007-11-06 03:43:49 +01:00
temp.newExtent(ns, initialExtentSize(len));
2007-10-30 16:35:17 +01:00
d = namespaceIndex.details(ns);
2007-10-20 01:35:48 +02:00
}
2007-10-30 16:35:17 +01:00
NamespaceDetails *tableToIndex = 0;
2007-11-09 03:42:50 +01:00
string indexFullNS;
const char *tabletoidxns = 0;
2007-11-09 03:42:50 +01:00
if( addIndex ) {
JSObj io((const char *) buf);
const char *name = io.getStringField("name"); // name of the index
tabletoidxns = io.getStringField("ns"); // table it indexes
2007-11-09 03:42:50 +01:00
JSObj key = io.getObjectField("key");
if( name == 0 || *name == 0 || tabletoidxns == 0 || key.isEmpty() || key.objsize() > 2048 ) {
2007-11-20 04:24:17 +01:00
cout << "user warning: bad add index attempt name:" << (name?name:"") << " ns:" <<
(tabletoidxns?tabletoidxns:"") << endl;
return DiskLoc();
}
tableToIndex = namespaceIndex.details(tabletoidxns);
if( tableToIndex == 0 ) {
cout << "ERROR: bad add index attempt, no such table(ns):" << tabletoidxns << endl;
2007-11-09 03:42:50 +01:00
return DiskLoc();
}
if( tableToIndex->nIndexes >= MaxIndexes ) {
cout << "ERROR: bad add index attempt, too many indexes for:" << tabletoidxns << endl;
2007-11-09 03:42:50 +01:00
return DiskLoc();
}
if( tableToIndex->findIndexByName(name) >= 0 ) {
2007-11-18 03:10:00 +01:00
cout << "WARNING: bad add index attempt, index:" << name << " already exists for:" << tabletoidxns << endl;
2007-11-09 03:42:50 +01:00
return DiskLoc();
}
indexFullNS = tabletoidxns;
2007-11-09 03:42:50 +01:00
indexFullNS += ".$";
indexFullNS += name; // client.table.$index -- note this doesn't contain jsobjs, it contains BtreeBuckets.
}
2007-10-30 16:35:17 +01:00
DiskLoc extentLoc;
int lenWHdr = len + Record::HeaderSize;
DiskLoc loc = d->alloc(lenWHdr, extentLoc);
if( loc.isNull() ) {
// out of space
cout << "allocating new extent for " << ns << endl;
2007-11-06 03:43:49 +01:00
temp.newExtent(ns, followupExtentSize(len, d->lastExtentSize));
2007-10-30 16:35:17 +01:00
loc = d->alloc(lenWHdr, extentLoc);
if( loc.isNull() ) {
2007-11-13 22:44:01 +01:00
cout << "****** ERROR: out of space in datafile. write more code." << endl;
2007-10-30 16:35:17 +01:00
assert(false);
2007-11-09 03:42:50 +01:00
return DiskLoc();
2007-10-30 16:35:17 +01:00
}
}
Record *r = loc.rec();
assert( r->lengthWithHeaders >= lenWHdr );
2007-10-20 01:35:48 +02:00
memcpy(r->data, buf, len);
2007-10-30 16:35:17 +01:00
Extent *e = r->myExtent(loc);
if( e->lastRecord.isNull() ) {
e->firstRecord = e->lastRecord = loc;
r->prevOfs = r->nextOfs = DiskLoc::NullOfs;
}
else {
Record *oldlast = e->lastRecord.rec();
r->prevOfs = e->lastRecord.getOfs();
r->nextOfs = DiskLoc::NullOfs;
2007-10-30 18:43:44 +01:00
oldlast->nextOfs = loc.getOfs();
2007-10-30 16:35:17 +01:00
e->lastRecord = loc;
}
2007-11-06 03:43:49 +01:00
d->nrecords++;
d->datasize += r->netLength();
2007-11-09 03:42:50 +01:00
if( tableToIndex ) {
IndexDetails& idxinfo = tableToIndex->indexes[tableToIndex->nIndexes];
idxinfo.info = loc;
idxinfo.head = BtreeBucket::addHead(indexFullNS.c_str());
tableToIndex->nIndexes++;
2007-11-09 03:42:50 +01:00
/* todo: index existing records here */
addExistingToIndex(tabletoidxns, idxinfo);
2007-11-09 03:42:50 +01:00
}
/* add this record to our indexes */
if( d->nIndexes )
indexRecord(d, buf, len, loc);
// cout << " inserted at loc:" << hex << loc.getOfs() << " lenwhdr:" << hex << lenWHdr << dec << endl;
2007-11-09 03:42:50 +01:00
return loc;
2007-10-20 01:35:48 +02:00
}
2007-11-27 21:30:51 +01:00
void DataFileMgr::init(const char *dir) {
string path = dir;
path += "temp.dat";
temp.open(path.c_str(), 64 * 1024 * 1024);
2007-10-20 01:35:48 +02:00
}
void pdfileInit() {
2007-11-27 21:30:51 +01:00
namespaceIndex.init(dbpath);
theDataFileMgr.init(dbpath);
2007-10-20 01:35:48 +02:00
}