TripleDB has been completely rewritten. Now requires Sleepycat Berkeley DB.

This commit is contained in:
terry%mozilla.org 2000-06-22 23:11:37 +00:00
Родитель ac9b617117
Коммит 49892e9607
31 изменённых файлов: 5426 добавлений и 2472 удалений

Просмотреть файл

@ -18,6 +18,10 @@ database. Each member of a triple can be a string, integer, or date.
For more details, read the API, in tdbapi.h.
Note that TripleDB now depends on the Sleepycat Berkeley DB, version
3.1.11 or greater. For more information on that, see
http://www.sleepycat.com.
FAQ:
@ -26,7 +30,7 @@ A: Yeah, yeah, I know. This is developed as part of a project at
work, and our Makefiles are all messed up. If you have one that fits in well
with other stuff at mozilla.org, please feel free to contribute it.
Q: Um, so else here uses this?
Q: Um, so nobody else here uses this?
A: That's right. But this maps in pretty well to RDF, I believe. I wouldn't
be surprised if someone decides to use it to store a biggish RDF database,
and adds it to mozilla for that purpose.

Просмотреть файл

@ -1,554 +0,0 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network
* Systems. Portions created by Geocast are
* Copyright (C) 1999 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
/* Routines that add or remove things to the database. */
#include "tdbtypes.h"
#ifdef DEBUG
#include "tdbdebug.h"
#include "prprf.h"
static PRBool makedots = PR_FALSE; /* If true, print out dot-graphs of
every step of balancing, to help my
poor mind debug. */
static int dotcount = 0;
#endif
PRStatus TDBAdd(TDB* db, TDBNodePtr triple[3])
{
PRStatus status = PR_FAILURE;
TDBRecord* record;
TDBPtr position;
PRInt32 tree;
PRInt32 i;
PRInt64 cmp;
PR_ASSERT(db != NULL);
if (db == NULL) return PR_FAILURE;
PR_Lock(db->mutex);
/* First, see if we already have this triple around... */
tree = 0; /* Hard-coded knowledge that tree zero does
things in [0], [1], [2] order. ### */
position = db->roots[tree];
while (position) {
record = tdbLoadRecord(db, position);
PR_ASSERT(record);
if (!record) {
goto DONE;
}
PR_ASSERT(record->position == position);
if (record->position != position) {
goto DONE;
}
for (i=0 ; i<3 ; i++) {
cmp = tdbCompareNodes(triple[i], record->data[i]);
if (cmp < 0) {
position = record->entry[tree].child[0];
break;
} else if (cmp > 0) {
position = record->entry[tree].child[1];
break;
}
}
if (position == record->position) {
/* This means that our new entry exactly matches this one. So,
we're done. */
status = PR_SUCCESS;
goto DONE;
}
}
tdbThrowOutCursorCaches(db);
record = tdbAllocateRecord(db, triple);
if (record == NULL) {
goto DONE;
}
for (tree=0 ; tree<NUMTREES ; tree++) {
status = tdbAddToTree(db, record, tree);
if (status != PR_SUCCESS) goto DONE;
}
status = tdbQueueMatchingCallbacks(db, record, TDBACTION_ADDED);
DONE:
if (status == PR_SUCCESS) {
tdbFlush(db);
} else {
tdbThrowAwayUnflushedChanges(db);
}
PR_Unlock(db->mutex);
return status;
}
PRStatus TDBReplace(TDB* db, TDBNodePtr triple[3])
{
/* Write me correctly!!! This works, but is inefficient. ### */
PRStatus status;
TDBNodeRange range[3];
range[0].min = triple[0];
range[0].max = triple[0];
range[1].min = triple[1];
range[1].max = triple[1];
range[2].min = NULL;
range[2].max = NULL;
status = TDBRemove(db, range);
if (status == PR_SUCCESS) {
status = TDBAdd(db, triple);
}
return status;
}
PRStatus TDBRemove(TDB* db, TDBNodeRange range[3])
{
/* This could definitely be faster. We're querying the database for
a matching item, then we go search for it again when we delete it.
The two operations probably ought to be merged. ### */
PRStatus status;
TDBCursor* cursor;
TDBTriple* triple;
TDBPtr position;
TDBRecord* record;
PRInt32 tree;
PR_ASSERT(db != NULL);
if (db == NULL) return PR_FAILURE;
PR_Lock(db->mutex);
tdbThrowOutCursorCaches(db);
for (;;) {
cursor = tdbQueryNolock(db, range, NULL);
if (!cursor) goto FAIL;
triple = tdbGetResultNolock(cursor);
if (triple) {
/* Probably ought to play refcnt games with this to prevent it
from being removed from the cache. ### */
position = cursor->lasthit->position;
}
tdbFreeCursorNolock(cursor);
cursor = NULL;
if (!triple) {
/* No more hits; all done. */
break;
}
record = tdbLoadRecord(db, position);
if (!record) goto FAIL;
for (tree=0 ; tree<NUMTREES ; tree++) {
status = tdbRemoveFromTree(db, record, tree);
if (status != PR_SUCCESS) goto FAIL;
}
status = tdbAddToTree(db, record, -1);
if (status != PR_SUCCESS) goto FAIL;
status = tdbQueueMatchingCallbacks(db, record, TDBACTION_REMOVED);
if (status != PR_SUCCESS) goto FAIL;
tdbFlush(db);
}
PR_Unlock(db->mutex);
return PR_SUCCESS;
FAIL:
tdbThrowAwayUnflushedChanges(db);
PR_Unlock(db->mutex);
return PR_FAILURE;
}
#ifdef MIN
#undef MIN
#endif
#ifdef MAX
#undef MAX
#endif
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) > (b) ? (a) : (b))
static PRBool
rotateOnce(TDB* db, TDBPtr* rootptr, TDBRecord* oldroot, PRInt32 tree,
PRInt32 dir)
{
PRInt32 otherdir = 1 - dir;
PRBool heightChanged;
TDBPtr otherptr;
TDBRecord* other;
PRInt8 oldrootbal;
PRInt8 otherbal;
#ifdef DEBUG
if (makedots) {
char* filename;
filename = PR_smprintf("/tmp/balance%d-%d.dot", tree, dotcount++);
TDBMakeDotGraph(db, filename, tree);
PR_smprintf_free(filename);
}
#endif
PR_ASSERT(dir == 0 || dir == 1);
if (dir != 0 && dir != 1) return PR_FALSE;
otherptr = oldroot->entry[tree].child[otherdir];
if (otherptr == 0) {
tdbMarkCorrupted(db);
return PR_FALSE;
}
other = tdbLoadRecord(db, otherptr);
heightChanged = (other->entry[tree].balance != 0);
*rootptr = otherptr;
oldroot->entry[tree].child[otherdir] = other->entry[tree].child[dir];
other->entry[tree].child[dir] = oldroot->position;
/* update balances */
oldrootbal = oldroot->entry[tree].balance;
otherbal = other->entry[tree].balance;
if (dir == 0) {
oldrootbal -= 1 + MAX(otherbal, 0);
otherbal -= 1 - MIN(oldrootbal, 0);
} else {
oldrootbal += 1 - MIN(otherbal, 0);
otherbal += 1 + MAX(oldrootbal, 0);
}
oldroot->entry[tree].balance = oldrootbal;
other->entry[tree].balance = otherbal;
oldroot->dirty = PR_TRUE;
other->dirty = PR_TRUE;
return heightChanged;
}
static void
rotateTwice(TDB* db, TDBPtr* rootptr, TDBRecord* oldroot, PRInt32 tree,
PRInt32 dir)
{
PRInt32 otherdir = 1 - dir;
TDBRecord* child;
PR_ASSERT(dir == 0 || dir == 1);
if (dir != 0 && dir != 1) return;
child = tdbLoadRecord(db, oldroot->entry[tree].child[otherdir]);
PR_ASSERT(child);
if (child == NULL) return;
rotateOnce(db, &(oldroot->entry[tree].child[otherdir]), child, tree,
otherdir);
oldroot->dirty = PR_TRUE;
rotateOnce(db, rootptr, oldroot, tree, dir);
}
static PRStatus
balance(TDB* db, TDBPtr* rootptr, TDBRecord* oldroot, PRInt32 tree,
PRBool* heightchange)
{
PRInt8 oldbalance;
TDBRecord* child;
*heightchange = PR_FALSE;
oldbalance = oldroot->entry[tree].balance;
if (oldbalance < -1) { /* need a right rotation */
child = tdbLoadRecord(db, oldroot->entry[tree].child[0]);
PR_ASSERT(child);
if (child == NULL) return PR_FAILURE;
if (child->entry[tree].balance == 1) {
rotateTwice(db, rootptr, oldroot, tree, 1); /* double RL rotation
needed */
*heightchange = PR_TRUE;
} else { /* single RR rotation needed */
*heightchange = rotateOnce(db, rootptr, oldroot, tree, 1);
}
} else if (oldbalance > 1) { /* need a left rotation */
child = tdbLoadRecord(db, oldroot->entry[tree].child[1]);
PR_ASSERT(child);
if (child == NULL) return PR_FAILURE;
if (child->entry[tree].balance == -1) {
rotateTwice(db, rootptr, oldroot, tree, 0); /* double LR rotation
needed */
*heightchange = PR_TRUE;
} else { /* single LL rotation needed */
*heightchange = rotateOnce(db, rootptr, oldroot, tree, 0);
}
}
return PR_SUCCESS;
}
static PRStatus doAdd(TDB* db, TDBRecord* record, PRInt32 tree,
PRInt32 comparerule, TDBPtr* rootptr,
PRBool* heightchange)
{
PRBool increase = PR_FALSE;
PRInt64 cmp;
PRInt32 kid;
PRStatus status;
TDBRecord* cur;
TDBPtr origptr;
if (*rootptr == 0) {
*rootptr = record->position;
*heightchange = PR_TRUE;
return PR_SUCCESS;
}
cur = tdbLoadRecord(db, *rootptr);
if (!cur) return PR_FAILURE;
cmp = tdbCompareRecords(record, cur, comparerule);
PR_ASSERT(cmp != 0); /* We carefully should never insert a
record that we already have. */
if (cmp == 0) return PR_FAILURE;
kid = (cmp < 0) ? 0 : 1;
origptr = cur->entry[tree].child[kid];
status = doAdd(db, record, tree, comparerule,
&(cur->entry[tree].child[kid]), &increase);
if (origptr != cur->entry[tree].child[kid]) {
cur->dirty = PR_TRUE;
}
if (increase) {
cur->entry[tree].balance += (kid == 0 ? -1 : 1);
cur->dirty = PR_TRUE;
}
if (status != PR_SUCCESS) return status;
if (increase && cur->entry[tree].balance != 0) {
status = balance(db, rootptr, cur, tree, &increase);
*heightchange = ! increase; /* If we did a rotate that absorbed
the height change, then we don't want
to propagate it on up. */
}
return PR_SUCCESS;
}
PRStatus tdbAddToTree(TDB* db, TDBRecord* record, PRInt32 tree)
{
TDBTreeEntry* entry;
PRBool checklinks;
PRBool ignore;
PRStatus status = PR_SUCCESS;
TDBPtr* rootptr;
TDBPtr origroot;
PRInt32 comparerule = tree;
PR_ASSERT(record != NULL);
if (record == NULL) return PR_FAILURE;
if (tree == -1) {
tree = 0;
rootptr = &(db->freeroot);
} else {
PR_ASSERT(tree >= 0 && tree < NUMTREES);
if (tree < 0 || tree >= NUMTREES) {
return PR_FAILURE;
}
rootptr = &(db->roots[tree]);
}
/* Check that this record does not seem to be already in this tree. */
entry = record->entry + tree;
checklinks = (entry->child[0] == 0 &&
entry->child[1] == 0 &&
entry->balance == 0);
PR_ASSERT(checklinks);
if (!checklinks) return PR_FAILURE;
origroot = *rootptr;
if (origroot == 0) {
*rootptr = record->position;
} else {
status = doAdd(db, record, tree, comparerule, rootptr, &ignore);
}
if (origroot != *rootptr) {
db->rootdirty = PR_TRUE;
}
db->dirty = PR_TRUE;
return status;
}
static PRStatus doRemove(TDB* db, TDBRecord* record, PRInt32 tree,
PRInt32 comparerule, TDBPtr* rootptr,
TDBPtr** foundleafptr, TDBRecord** foundleaf,
PRBool* heightchange)
{
PRStatus status;
TDBRecord* cur;
TDBPtr* leafptr;
TDBRecord* leaf;
PRInt32 kid;
TDBPtr origptr;
TDBPtr kid0;
TDBPtr kid1;
PRInt64 cmp;
PRBool decrease = PR_FALSE;
PRInt32 tmp;
PRInt8 tmpbal;
PRInt32 i;
PR_ASSERT(*rootptr != 0);
if (*rootptr == 0) return PR_FAILURE;
cur = tdbLoadRecord(db, *rootptr);
if (!cur) return PR_FAILURE;
if (record == NULL) {
cur->dirty = PR_TRUE; /* Oh, what a bad, bad hack. Need a better
way to make sure not to miss a parent
pointer that we've changed. ### */
}
kid0 = cur->entry[tree].child[0];
kid1 = cur->entry[tree].child[1];
if (record == NULL) {
/* We're looking for the smallest possible leaf node. */
PR_ASSERT(foundleafptr != NULL && foundleaf != NULL);
if (kid0) cmp = -1;
else {
cmp = 0;
*foundleafptr = rootptr;
*foundleaf = cur;
}
} else {
PR_ASSERT(foundleafptr == NULL && foundleaf == NULL);
cmp = tdbCompareRecords(record, cur, comparerule);
}
if (cmp == 0) {
PR_ASSERT(record == cur || record == NULL);
if (record != cur && record != NULL) return PR_FAILURE;
if (kid0 == 0 && kid1 == 0) {
/* We're a leaf node. */
*rootptr = 0;
*heightchange = PR_TRUE;
return PR_SUCCESS;
} else if (kid0 == 0 || kid1 == 0) {
/* Replace us with our single child. */
*rootptr = kid0 != 0 ? kid0 : kid1;
cur->entry[tree].child[0] = 0;
cur->entry[tree].child[1] = 0;
cur->entry[tree].balance = 0;
cur->dirty = PR_TRUE;
*heightchange = PR_TRUE;
return PR_SUCCESS;
} else {
/* Ick. We're a node in the middle of the tree. Find who to
replace us with. */
kid = 1; /* Informs balancing code later that we are
taking things from the right subtree. */
status = doRemove(db, NULL, tree, comparerule,
&(cur->entry[tree].child[1]),
&leafptr, &leaf, &decrease);
/* Swap us in the tree with leaf. Don't use the kid0/kid1
variables any more, as they may no longer be valid. */
if (record != NULL) {
leaf->entry[tree].child[0] = cur->entry[tree].child[0];
leaf->entry[tree].child[1] = cur->entry[tree].child[1];
leaf->entry[tree].balance = cur->entry[tree].balance;
cur->entry[tree].child[0] = 0;
cur->entry[tree].child[1] = 0;
cur->entry[tree].balance = 0;
cur->dirty = PR_TRUE;
*rootptr = leaf->position;
cur = leaf;
cur->dirty = PR_TRUE;
} else {
*foundleaf = cur;
*foundleafptr = leafptr;
PR_ASSERT(**foundleafptr == leaf->position);
*leafptr = cur->position;
*rootptr = leaf->position;
for (i=0 ; i<2 ; i++) {
tmp = leaf->entry[tree].child[i];
leaf->entry[tree].child[i] = cur->entry[tree].child[i];
cur->entry[tree].child[i] = tmp;
}
tmpbal = leaf->entry[tree].balance;
leaf->entry[tree].balance = cur->entry[tree].balance;
cur->entry[tree].balance = tmpbal;
cur->dirty = PR_TRUE;
leaf->dirty = PR_TRUE;
}
}
} else {
kid = (cmp < 0) ? 0 : 1;
origptr = cur->entry[tree].child[kid];
status = doRemove(db, record, tree, comparerule,
&(cur->entry[tree].child[kid]), foundleafptr,
foundleaf, &decrease);
if (origptr != cur->entry[tree].child[kid]) {
cur->dirty = PR_TRUE;
}
}
if (decrease) {
cur->entry[tree].balance += (kid == 0 ? 1 : -1);
cur->dirty = PR_TRUE;
}
if (status != PR_SUCCESS) return status;
if (decrease) {
if (cur->entry[tree].balance != 0) {
status = balance(db, rootptr, cur, tree, &decrease);
*heightchange = decrease;
} else {
*heightchange = PR_TRUE;
}
}
return PR_SUCCESS;
}
PRStatus tdbRemoveFromTree(TDB* db, TDBRecord* record, PRInt32 tree)
{
PRStatus status;
PRInt32 comparerule = tree;
TDBPtr* rootptr;
TDBPtr origroot;
PRBool ignore;
PR_ASSERT(record != NULL);
if (record == NULL) return PR_FAILURE;
if (tree == -1) {
tree = 0;
rootptr = &(db->freeroot);
} else {
PR_ASSERT(tree >= 0 && tree < NUMTREES);
if (tree < 0 || tree >= NUMTREES) {
return PR_FAILURE;
}
rootptr = &(db->roots[tree]);
}
origroot = *rootptr;
PR_ASSERT(origroot != 0);
if (origroot == 0) return PR_FAILURE;
status = doRemove(db, record, tree, comparerule, rootptr, NULL, NULL,
&ignore);
if (origroot != *rootptr) {
db->rootdirty = PR_TRUE;
}
db->dirty = PR_TRUE;
record->dirty = PR_TRUE;
return status;
}

263
db/tripledb/src/bg.c Normal file
Просмотреть файл

@ -0,0 +1,263 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#include "tdbapi.h"
#include "tdbbg.h"
#ifdef TDB_USE_NSPR
#include "tdbtypes.h"
#include "prtypes.h"
#include "prcvar.h"
#include "prlock.h"
#include "prmem.h"
#include "prinrval.h"
#include "prthread.h"
#include "plstr.h"
typedef struct _TDBBGFunc {
struct _TDBBGFunc* next;
char* name;
TDBBG_Function func;
void* closure;
TDBInt32 priority;
PRIntervalTime when;
} TDBBGFunc;
struct _TDBBG {
PRThread* bgthread; /* Background, low-priority thread. */
PRLock* mutex;
PRCondVar* cvar; /* Condition variable to wake up the
background thread. */
TDBBool killbgthread; /* If TRUE, then we are waiting for the
background thread to die. */
TDBBool bgthreadidle;
TDBBGFunc* firstfunc;
};
static void
backgroundThread(void* closure)
{
TDBBG* bg = (TDBBG*) closure;
TDBBGFunc* func;
TDBBGFunc** ptr;
TDBBGFunc** which;
PRIntervalTime now;
PRIntervalTime delay;
PR_Lock(bg->mutex);
while (1) {
if (bg->killbgthread) break;
if (bg->firstfunc) {
now = PR_IntervalNow();
delay = (bg->firstfunc->when > now) ?
(bg->firstfunc->when - now) : 0;
} else {
delay = PR_INTERVAL_NO_TIMEOUT;
}
if (delay > 0) {
bg->bgthreadidle = TDB_TRUE;
PR_NotifyAllCondVar(bg->cvar);
PR_WaitCondVar(bg->cvar, delay);
bg->bgthreadidle = TDB_FALSE;
}
if (bg->killbgthread) break;
now = PR_IntervalNow();
if (bg->firstfunc == NULL || bg->firstfunc->when > now) continue;
/* Search through anything whose time has come, and find the one with
the highest priority. */
which = &(bg->firstfunc);
for (ptr = which ; *ptr ; ptr = &((*ptr)->next)) {
if ((*ptr)->when > now) break;
if ((*ptr)->priority > (*which)->priority) {
which = ptr;
}
}
func = *which;
*which = func->next;
PR_Unlock(bg->mutex);
(*func->func)(func->closure);
if (func->name) PR_Free(func->name);
PR_Free(func);
PR_Lock(bg->mutex);
}
PR_Unlock(bg->mutex);
}
TDBBG*
TDBBG_Open()
{
TDBBG* bg;
bg = PR_NEWZAP(TDBBG);
if (!bg) return NULL;
bg->mutex = PR_NewLock();
if (!bg->mutex) goto FAIL;
bg->cvar = PR_NewCondVar(bg->mutex);
if (!bg->cvar) goto FAIL;
bg->bgthread =
PR_CreateThread(PR_SYSTEM_THREAD, backgroundThread, bg,
PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
PR_JOINABLE_THREAD, 0);
if (bg->bgthread == NULL) goto FAIL;
PR_Lock(bg->mutex);
while (!bg->bgthreadidle) {
PR_WaitCondVar(bg->cvar, PR_INTERVAL_NO_TIMEOUT);
}
PR_Unlock(bg->mutex);
return bg;
FAIL:
TDBBG_Close(bg);
return NULL;
}
TDBStatus
TDBBG_Close(TDBBG* bg)
{
TDBBGFunc* func;
tdb_ASSERT(bg != NULL);
if (!bg) return TDB_FAILURE;
if (bg->bgthread) {
PR_Lock(bg->mutex);
bg->killbgthread = TDB_TRUE;
PR_NotifyAllCondVar(bg->cvar);
PR_Unlock(bg->mutex);
PR_JoinThread(bg->bgthread);
}
if (bg->cvar) PR_DestroyCondVar(bg->cvar);
if (bg->mutex) PR_DestroyLock(bg->mutex);
while (bg->firstfunc) {
func = bg->firstfunc;
bg->firstfunc = func->next;
PR_Free(func->name);
PR_Free(func);
}
PR_Free(bg);
return TDB_SUCCESS;
}
TDBStatus
TDBBG_AddFunction(TDBBG* bg, const char* name,
TDBInt32 secondsToWait, TDBInt32 priority,
TDBBG_Function f, void* closure)
{
TDBBGFunc** ptr;
TDBBGFunc* func;
if (bg == NULL|| name == NULL || f == NULL) {
tdb_ASSERT(0);
return PR_FAILURE;
}
func = PR_NEWZAP(TDBBGFunc);
if (!func) return PR_FAILURE;
func->name = PL_strdup(name);
if (!func->name) {
PR_Free(func->name);
PR_Free(func);
return PR_FAILURE;
}
func->func = f;
func->closure = closure;
func->priority = priority;
func->when = PR_IntervalNow() + PR_SecondsToInterval(secondsToWait);
PR_Lock(bg->mutex);
for (ptr = &(bg->firstfunc) ; *ptr ; ptr = &((*ptr)->next)) {
if (func->when <= (*ptr)->when) break;
}
func->next = *ptr;
*ptr = func;
if (bg->firstfunc == func) {
/* We have a new head function, which probably means that the
background thread has to sleep less long than it was before,
so wake it up. */
PR_NotifyAllCondVar(bg->cvar);
}
PR_Unlock(bg->mutex);
return PR_SUCCESS;
}
PRStatus
TDBBG_RescheduleFunction(TDBBG* bg, const char* name,
PRInt32 secondsToWait,
PRInt32 priority,
TDBBG_Function func, void* closure)
{
TDBBG_RemoveFunction(bg, name, func, closure);
return TDBBG_AddFunction(bg, name, secondsToWait, priority, func, closure);
}
PRStatus
TDBBG_RemoveFunction(TDBBG* bg, const char* name, TDBBG_Function f, void* closure)
{
PRStatus status = PR_FAILURE;
TDBBGFunc** ptr;
TDBBGFunc* func;
if (bg == NULL|| name == NULL || f == NULL) {
tdb_ASSERT(0);
return PR_FAILURE;
}
PR_Lock(bg->mutex);
ptr = &(bg->firstfunc);
while (*ptr) {
if ((*ptr)->func == f && (*ptr)->closure == closure &&
strcmp((*ptr)->name, name) == 0) {
func = *ptr;
*ptr = func->next;
PR_Free(func->name);
PR_Free(func);
status = PR_SUCCESS;
} else {
ptr = &((*ptr)->next);
}
}
PR_Unlock(bg->mutex);
return status;
}
PRStatus
TDBBG_WaitUntilIdle(TDBBG* bg)
{
if (bg == NULL) {
tdb_ASSERT(0);
return PR_FAILURE;
}
PR_Lock(bg->mutex);
while (!bg->bgthreadidle) {
PR_WaitCondVar(bg->cvar, PR_INTERVAL_NO_TIMEOUT);
}
PR_Unlock(bg->mutex);
return PR_SUCCESS;
}
#endif /* TDB_USE_NSPR */

Просмотреть файл

@ -1,213 +0,0 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network
* Systems. Portions created by Geocast are
* Copyright (C) 1999 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
/* Routines that query things from the database. */
#include "tdbtypes.h"
static void
tdbFreeCallbackInfo(TDBCallbackInfo* info)
{
PRInt32 i;
for (i=0 ; i<3 ; i++) {
if (info->range[i].min != NULL) TDBFreeNode(info->range[i].min);
if (info->range[i].max != NULL) TDBFreeNode(info->range[i].max);
}
PR_Free(info);
}
static void
tdbFreePendingCall(TDBPendingCall* call)
{
PRInt32 i;
for (i=0 ; i<3 ; i++) {
if (call->triple.data[i] != NULL) {
TDBFreeNode(call->triple.data[i]);
}
}
PR_Free(call);
}
void
tdbCallbackThread(void* closure)
{
PRStatus status;
TDB* db = (TDB*) closure;
PRLock* mutex = db->mutex;
PRCondVar* cvar = db->callbackcvargo;
TDBPendingCall* call;
TDBPendingCall* tmp;
PR_Lock(mutex);
while (1) {
while (db->firstpendingcall == NULL) {
db->callbackidle = PR_TRUE;
PR_NotifyAllCondVar(db->callbackcvaridle); /* Inform anyone who
cares that we are
idle. */
if (db->killcallbackthread) {
/* This db is being closed; go away now. */
PR_Unlock(db->mutex);
return;
}
status = PR_WaitCondVar(cvar, PR_INTERVAL_NO_TIMEOUT);
db->callbackidle = PR_FALSE;
}
call = db->firstpendingcall;
db->firstpendingcall = NULL;
db->lastpendingcall = NULL;
PR_Unlock(db->mutex);
while (call) {
(*call->func)(db, call->closure, &(call->triple), call->action);
tmp = call;
call = call->next;
tdbFreePendingCall(tmp);
}
PR_Lock(db->mutex);
}
}
PRStatus tdbQueueMatchingCallbacks(TDB* db, TDBRecord* record,
PRInt32 action)
{
TDBCallbackInfo* info;
TDBPendingCall* call;
PRInt32 i;
for (info = db->firstcallback ; info ; info = info->nextcallback) {
if (tdbMatchesRange(record, info->range)) {
call = PR_NEWZAP(TDBPendingCall);
if (!call) return PR_FAILURE;
call->func = info->func;
call->closure = info->closure;
call->action = action;
for (i=0 ; i<3 ; i++) {
call->triple.data[i] = tdbNodeDup(record->data[i]);
if (call->triple.data[i] == NULL) {
tdbFreePendingCall(call);
return PR_FAILURE;
}
}
if (db->lastpendingcall) {
db->lastpendingcall->next = call;
}
db->lastpendingcall = call;
if (db->firstpendingcall == NULL) {
db->firstpendingcall = call;
}
}
}
if (db->firstpendingcall != NULL) {
/* Kick the background thread. */
PR_NotifyAllCondVar(db->callbackcvargo);
}
return PR_SUCCESS;
}
PRStatus TDBAddCallback(TDB* db, TDBNodeRange range[3],
TDBCallbackFunction func, void* closure)
{
TDBCallbackInfo* info;
PRInt32 i;
PR_ASSERT(db != NULL);
if (db == NULL) return PR_FAILURE;
info = PR_NEWZAP(TDBCallbackInfo);
if (!info) return PR_FAILURE;
for (i=0 ; i<3 ; i++) {
if (range[i].min) {
info->range[i].min = tdbNodeDup(range[i].min);
if (info->range[i].min == NULL) goto FAIL;
}
if (range[i].max) {
info->range[i].max = tdbNodeDup(range[i].max);
if (info->range[i].max == NULL) goto FAIL;
}
}
info->func = func;
info->closure = closure;
info->nextcallback = db->firstcallback;
PR_Lock(db->mutex);
db->firstcallback = info;
PR_Unlock(db->mutex);
return PR_SUCCESS;
FAIL:
tdbFreeCallbackInfo(info);
return PR_FAILURE;
}
PRStatus TDBRemoveCallback(TDB* db, TDBNodeRange range[3],
TDBCallbackFunction func, void* closure)
{
PRStatus status = PR_FAILURE;
TDBCallbackInfo** ptr;
TDBCallbackInfo* info;
PRInt32 i;
PRBool match;
PR_ASSERT(db != NULL);
if (db == NULL) return PR_FAILURE;
PR_Lock(db->mutex);
for (ptr = &(db->firstcallback) ; *ptr ; ptr = &((*ptr)->nextcallback)) {
info = *ptr;
if (info->func == func && info->closure == closure) {
match = PR_TRUE;
for (i=0 ; i<3 ; i++) {
if (range[i].min != info->range[i].min &&
(range[i].min == NULL || info->range[i].min == NULL ||
tdbCompareNodes(range[i].min, info->range[i].min) != 0)) {
match = PR_FALSE;
break;
}
if (range[i].max != info->range[i].max &&
(range[i].max == NULL || info->range[i].max == NULL ||
tdbCompareNodes(range[i].max, info->range[i].max) != 0)) {
match = PR_FALSE;
break;
}
}
if (match) {
*ptr = info->nextcallback;
tdbFreeCallbackInfo(info);
status = PR_SUCCESS;
/* We now make sure that we have no outstanding callbacks
queued up to the callback we just removed. It would be
real bad to call that callback after we return. So, we
make sure to call it now. */
while (db->firstpendingcall) {
PR_NotifyAllCondVar(db->callbackcvargo);
PR_WaitCondVar(db->callbackcvaridle,
PR_INTERVAL_NO_TIMEOUT);
}
break;
}
}
}
PR_Unlock(db->mutex);
return status;
}

417
db/tripledb/src/cursor.c Normal file
Просмотреть файл

@ -0,0 +1,417 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#include "tdbtypes.h"
#include "cursor.h"
#include "intern.h"
#include "node.h"
#include "rtype.h"
#include "tdb.h"
#include "vector.h"
#include "windex.h"
struct _TDBCursor {
TDB* tdb;
TDBBase* base;
void* implcursor;
TDBCursor* next;
TDBNodePtr* range;
TDBVector* vector; /* The last vector returned from this cursor */
TDBVector* curvector; /* The current position being considered by
the cursor. */
TDBVector* candidate; /* The next candidate to be returned as a
match. */
TDBWindexCursor* wcursor;
DBC* dbcurs;
TDBInt32 curentry;
TDBRType* indextype;
TDBInt32 numfields; /* Cached from indextype. */
TDBBool reverse;
TDBBool includefalse;
TDBBool alldone;
TDBTriple triple;
TDBInt32 hits;
TDBInt32 misses;
};
TDBCursor*
tdbCursorNew(TDB* tdb, TDBRType* indextype, TDBNodePtr* range,
TDBBool includefalse, TDBBool reverse)
{
TDBInt32 i;
TDBCursor* cursor;
if (indextype == NULL || range == NULL) {
tdb_ASSERT(0);
return NULL;
}
cursor = tdb_NEWZAP(TDBCursor);
if (!cursor) return NULL;
cursor->tdb = tdb;
cursor->base = tdbGetBase(tdb);
cursor->numfields = tdbRTypeGetNumFields(indextype);
cursor->range = tdb_Calloc(cursor->numfields, sizeof(TDBNodePtr));
if (!cursor->range) {
tdb_Free(cursor);
return NULL;
}
for (i=0 ; i<cursor->numfields ; i++) {
if (range[i]) {
if (i == 1 && range[i]->type != TDBTYPE_INTERNED) {
cursor->range[i] = tdbIntern(cursor->base, range[i]);
} else {
cursor->range[i] = TDBNodeDup(range[i]);
}
if (!cursor->range[i]) {
tdbCursorFree(cursor);
return NULL;
}
}
}
cursor->indextype = indextype;
cursor->includefalse = includefalse;
cursor->reverse = reverse;
cursor->next = tdbGetFirstCursor(cursor->tdb);
tdbSetFirstCursor(cursor->tdb, cursor);
return cursor;
}
TDBCursor*
tdbCursorNewWordSubstring(TDB* tdb, const char* string)
{
TDBWindex* windex;
TDBCursor* cursor;
TDBBase* base;
base = tdbGetBase(tdb);
windex = tdbGetWindex(base);
cursor = tdb_NEWZAP(TDBCursor);
if (!cursor) return NULL;
cursor->base = base;
cursor->tdb = tdb;
cursor->wcursor = tdbWindexGetCursor(windex, string);
if (!cursor->wcursor) {
tdb_Free(cursor);
return NULL;
}
return cursor;
}
TDBCursor*
tdbCursorNewImpl(TDB* tdb, void* implcursor)
{
TDBCursor* cursor;
if (tdb == NULL || implcursor == NULL) {
tdb_ASSERT(0);
return NULL;
}
cursor = tdb_NEWZAP(TDBCursor);
if (!cursor) return NULL;
cursor->tdb = tdb;
cursor->base = tdbGetBase(tdb);
cursor->implcursor = implcursor;
return cursor;
}
static void
freeCurVector(TDBCursor* cursor)
{
if (cursor->curvector) {
if (cursor->curvector != cursor->candidate &&
cursor->curvector != cursor->vector) {
tdbVectorFree(cursor->curvector);
}
cursor->curvector = NULL;
}
}
void
tdbCursorFree(TDBCursor* cursor)
{
TDBInt32 i;
TDBCursor* first;
if (cursor == NULL) {
tdb_ASSERT(0);
return;
}
if (cursor->wcursor) tdbWindexCursorFree(cursor->wcursor);
freeCurVector(cursor);
if (cursor->vector) tdbVectorFree(cursor->vector);
if (cursor->candidate) tdbVectorFree(cursor->candidate);
if (cursor->range) {
for (i=0 ; i<cursor->numfields ; i++) {
if (cursor->range[i]) TDBFreeNode(cursor->range[i]);
}
tdb_Free(cursor->range);
}
if (cursor->dbcurs) cursor->dbcurs->c_close(cursor->dbcurs);
first = tdbGetFirstCursor(cursor->tdb);
if (first == cursor) {
tdbSetFirstCursor(cursor->tdb, first->next);
} else {
for (; first ; first = first->next) {
if (first->next == cursor) {
first->next = cursor->next;
break;
}
}
}
tdb_Free(cursor);
}
TDB*
tdbCursorGetTDB(TDBCursor* cursor)
{
if (cursor == NULL) {
tdb_ASSERT(0);
return NULL;
}
return cursor->tdb;
}
TDBBase*
tdbCursorGetBase(TDBCursor* cursor)
{
if (cursor == NULL) {
tdb_ASSERT(0);
return NULL;
}
return cursor->base;
}
void*
tdbCursorGetImplcursor(TDBCursor* cursor)
{
if (cursor == NULL) {
tdb_ASSERT(0);
return NULL;
}
return cursor->implcursor;
}
static TDBVector*
getNextCandidate(TDBCursor* cursor)
{
TDBInt32 i;
TDBNode minmaxnode;
TDBNodePtr nodes[3];
TDBBool bumpcursor = TDB_FALSE;
TDBVector* vector;
TDBBool inrange;
if (cursor->curvector == NULL) {
/* First time. */
for (i=0 ; i<cursor->numfields ; i++) {
if (cursor->range[i]) {
nodes[i] = cursor->range[i];
} else {
minmaxnode.type =
cursor->reverse ? TDBTYPE_MAXNODE : TDBTYPE_MINNODE;
nodes[i] = &minmaxnode;
/* The below should be restored if we ever restore the rule
that the first member of a triple must be an ID. */
/* if (i == 0) { */
/* minmaxid.type = TDBTYPE_ID; */
/* minmaxid.d.i = cursor->reverse ? 0xffffffffffffffff : 0; */
/* nodes[i] = &minmaxid; */
/* } */
}
}
cursor->curvector = tdbVectorNewFromNodes(cursor->base, nodes, 0, 0, 0);
if (!cursor->curvector) return NULL;
}
while (1) {
vector = NULL;
if (cursor->dbcurs == NULL) {
cursor->dbcurs = tdbRTypeGetCursor(cursor->indextype,
cursor->curvector);
if (!cursor->dbcurs) return NULL;
} else {
bumpcursor = TDB_TRUE;
}
vector = tdbRTypeGetCursorValue(cursor->indextype, cursor->dbcurs,
bumpcursor ?
(cursor->reverse ? DB_PREV :
DB_NEXT) : DB_CURRENT);
freeCurVector(cursor);
cursor->curvector = vector;
if (vector == NULL) {
break;
}
inrange = TDB_TRUE;
for (i=0 ; i<cursor->numfields ; i++) {
if (cursor->range[i] &&
TDBCompareNodes(cursor->range[i],
tdbVectorGetInternedNode(vector, i)) != 0) {
inrange = TDB_FALSE;
break;
}
}
if (inrange) {
if (cursor->includefalse ||
(tdbVectorGetFlags(cursor->curvector) & TDBFLAG_ISASSERT)) {
return cursor->curvector;
}
}
if (!inrange) break;
/* So, this one missed, but there might be more. */
cursor->misses++;
}
freeCurVector(cursor);
if (cursor->dbcurs) {
cursor->dbcurs->c_close(cursor->dbcurs);
cursor->dbcurs = NULL;
}
return NULL;
}
TDBVector*
tdbCursorGetNext(TDBCursor* cursor)
{
TDBInt32 i;
TDBVector* next;
TDBInt32 l;
TDBInt32 l1;
TDBInt32 l2;
TDBInt32 numlayers;
if (cursor == NULL) {
tdb_ASSERT(0);
return NULL;
}
if (cursor->wcursor) {
while (1) {
if (cursor->vector) tdbVectorFree(cursor->vector);
cursor->vector = tdbWindexGetCursorValue(cursor->wcursor);
if (!cursor->vector) return NULL;
if (tdbVectorLayerMatches(cursor->vector, cursor->tdb)) {
cursor->hits++;
return cursor->vector;
}
cursor->misses++;
}
}
if (cursor->alldone) return NULL;
while (1) {
next = getNextCandidate(cursor);
if (next == NULL) {
cursor->alldone = TDB_TRUE;
if (cursor->vector) tdbVectorFree(cursor->vector);
cursor->vector = cursor->candidate;
cursor->candidate = NULL;
if (cursor->vector) cursor->hits++;
return cursor->vector;
}
if (!tdbVectorLayerMatches(next, cursor->tdb)) {
cursor->misses++;
continue;
}
if (cursor->candidate == NULL) {
cursor->candidate = next;
continue;
}
if (!tdbVectorEqual(cursor->candidate, next)) {
if (cursor->vector) tdbVectorFree(cursor->vector);
cursor->vector = cursor->candidate;
cursor->candidate = next;
cursor->hits++;
return cursor->vector;
}
cursor->misses++;
l1 = tdbVectorGetLayer(cursor->candidate);
l2 = tdbVectorGetLayer(next);
if (l1 != l2) {
numlayers = tdbGetNumLayers(cursor->tdb);
for (i=0 ; i<numlayers ; i++) {
l = tdbGetLayer(cursor->tdb, i);
if (l == l1) {
break; /* Our existing candidate wins. */
}
if (l == l2) {
tdbVectorFree(cursor->candidate);
cursor->candidate = next;
next = NULL;
}
}
}
}
}
TDBTriple*
tdbCursorGetLastResultAsTriple(TDBCursor* cursor)
{
TDBInt32 i;
if (cursor == NULL) {
tdb_ASSERT(0);
return NULL;
}
if (cursor->vector == NULL) return NULL;
for (i=0 ; i<3 ; i++) {
cursor->triple.data[i] =
tdbVectorGetNonInternedNode(cursor->vector, i);
}
cursor->triple.asserted =
((tdbVectorGetFlags(cursor->vector) & TDBFLAG_ISASSERT) != 0);
return &(cursor->triple);
}
extern void
TDBGetCursorStats(TDBCursor* cursor,
TDBInt32* hits,
TDBInt32* misses)
{
if (cursor == NULL || hits == NULL || misses == NULL) {
tdb_ASSERT(0);
return;
}
*hits = cursor->hits;
*misses = cursor->misses;
}
TDBStatus
tdbCursorInvalidateCache(TDB* tdb)
{
TDBCursor* cursor;
for (cursor = tdbGetFirstCursor(tdb) ; cursor ; cursor = cursor->next) {
if (cursor->dbcurs) {
cursor->dbcurs->c_close(cursor->dbcurs);
cursor->dbcurs = NULL;
}
}
return TDB_SUCCESS;
}

63
db/tripledb/src/cursor.h Normal file
Просмотреть файл

@ -0,0 +1,63 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#ifndef _cursor_h_
#define _cursor_h_ 1
extern TDBCursor* tdbCursorNew(TDB* tdb, TDBRType* indextype,
TDBNodePtr* triple,
TDBBool includefalse, TDBBool reverse);
extern TDBCursor* tdbCursorNewWordSubstring(TDB* tdb, const char* string);
extern TDBCursor* tdbCursorNewImpl(TDB* tdb, void* implcursor);
extern void tdbCursorFree(TDBCursor* cursor);
extern TDB* tdbCursorGetTDB(TDBCursor* cursor);
extern TDBBase* tdbCursorGetBase(TDBCursor* cursor);
extern void* tdbCursorGetImplcursor(TDBCursor* cursor);
/* tdbCursorGetNext() returns the next matching item for this cursor. The
returned vector is owned by the cursor object, and must not be freed or
modified. */
extern TDBVector* tdbCursorGetNext(TDBCursor* cursor);
/* tdbCursorGetLastResultAsTriple() is a hack that returns the
last result as a TDBTriple*, to help us implement our published API
(which has drifted a bit from our internal implementation.) */
extern TDBTriple* tdbCursorGetLastResultAsTriple(TDBCursor* cursor);
/* tdbCursorInvalidateCache() causes all cursors to invalidate any
information about the tree that they may have cached. This is called when
a change is going to be made to the tree structure. */
extern TDBStatus tdbCursorInvalidateCache(TDB* tdb);
#endif /* _cursor_h_ */

246
db/tripledb/src/dbnspr.c Normal file
Просмотреть файл

@ -0,0 +1,246 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
/* #include "db/db_int.h" */
#define MEGABYTE 1048576
#include "tdbtypes.h"
#ifdef TDB_USE_NSPR
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "db/db.h"
#include "plstr.h"
#include "prerror.h"
#include "prinrval.h"
#include "prio.h"
#include "prmem.h"
#include "prthread.h"
static int
func_close(int fd)
{
if (fd == 0) return -1;
if (PR_Close((PRFileDesc*) fd) == PR_SUCCESS) return 0;
return PR_GetError();
}
static void
func_dirfree(char** names, int count)
{
int i;
for (i=0 ; i<count ; i++) {
PR_Free(names[i]);
}
PR_Free(names);
}
static int
func_dirlist(const char* dirname, char*** names, int* cnt)
{
int max = 0;
int count = 0;
char** result = NULL;
PRDir* dir;
PRDirEntry* entry;
dir = PR_OpenDir(dirname);
if (dir == NULL) return PR_GetError();
while (NULL != (entry = PR_ReadDir(dir, PR_SKIP_NONE))) {
if (count >= max) {
max += 100;
result = result ? PR_Realloc(result, max * sizeof(char*)) :
PR_Malloc(max * sizeof(char*));
if (!result) return PR_GetError();
}
result[count] = PL_strdup(entry->name);
if (result[count] == NULL) {
func_dirfree(result, count);
return PR_GetError();
}
count++;
}
*names = result;
*cnt = count;
return 0;
}
static int
func_exists(const char *path, int *isdirp)
{
PRFileInfo info;
if (PR_GetFileInfo(path, &info) != PR_SUCCESS) {
return PR_GetError();
}
if (isdirp) {
*isdirp = (info.type == PR_FILE_DIRECTORY);
}
return 0;
}
static int
func_fsync(int fd)
{
return PR_Sync((PRFileDesc*) fd) == PR_SUCCESS ? 0 : PR_GetError();
}
static int
func_ioinfo(const char *path, int fd, u_int32_t *mbytesp, u_int32_t *bytesp,
u_int32_t *iosizep)
{
PRFileInfo64 info;
if (PR_GetFileInfo64(path, &info) != PR_SUCCESS) {
return PR_GetError();
}
if (mbytesp) *mbytesp = info.size / MEGABYTE;
if (bytesp) *bytesp = info.size % MEGABYTE;
if (iosizep) *iosizep = (8 * 1024); /* ### Ack! Fix! *** */
return 0;
}
static int
func_open(const char* path, int flags, int mode)
{
PRIntn f = 0;
PRFileDesc* fid;
if (flags & O_RDONLY) {
f |= PR_RDONLY;
}
if (flags & O_WRONLY) {
f |= PR_WRONLY;
}
if (flags & O_RDWR) {
f |= PR_RDWR;
}
if (flags & O_CREAT) {
f |= PR_CREATE_FILE;
}
if (flags & O_TRUNC) {
f |= PR_TRUNCATE;
}
if (flags & O_SYNC) {
f |= PR_SYNC;
}
fid = PR_Open(path, f, mode);
if (fid == NULL) return -1;
return (int) fid;
}
static ssize_t
func_read(int fd, void* buf, size_t nbytes)
{
return PR_Read((PRFileDesc*) fd, buf, nbytes);
}
static int
func_seek(int fd, size_t pgsize,
db_pgno_t pageno, u_int32_t relative, int rewind, int db_whence)
{
PRSeekWhence whence;
PRInt64 offset;
switch (db_whence) {
case SEEK_CUR:
whence = PR_SEEK_CUR;
break;
case SEEK_END:
whence = PR_SEEK_END;
break;
case SEEK_SET:
whence = PR_SEEK_SET;
break;
default:
return -1;
}
offset = ((PRInt64) pgsize) * ((PRInt64) pageno) + relative;
if (rewind) offset = -offset;
if (PR_Seek64((PRFileDesc*) fd, offset, whence) < 0) return PR_GetError();
return 0;
}
static int
func_sleep(u_long seconds, u_long microseconds)
{
if (PR_Sleep(PR_SecondsToInterval(seconds) +
PR_MicrosecondsToInterval(microseconds)) == PR_SUCCESS) {
return 0;
}
return PR_GetError();
}
static int
func_unlink(const char* path)
{
return PR_Delete(path) == PR_SUCCESS ? 0 : PR_GetError();
}
static ssize_t
func_write(int fd, const void* buffer, size_t nbytes)
{
return PR_Write((PRFileDesc*) fd, buffer, nbytes);
}
TDBStatus
tdbMakeDBCompatableWithNSPR(DB_ENV* env)
{
if (env->set_func_close(env, func_close) != DB_OK) return TDB_FAILURE;
if (env->set_func_dirfree(env, func_dirfree) != DB_OK) return TDB_FAILURE;
if (env->set_func_dirlist(env, func_dirlist) != DB_OK) return TDB_FAILURE;
if (env->set_func_exists(env, func_exists) != DB_OK) return TDB_FAILURE;
if (env->set_func_free(env, PR_Free) != DB_OK) return TDB_FAILURE;
if (env->set_func_fsync(env, func_fsync) != DB_OK) return TDB_FAILURE;
if (env->set_func_ioinfo(env, func_ioinfo) != DB_OK) return TDB_FAILURE;
if (env->set_func_malloc(env, PR_Malloc) != DB_OK) return TDB_FAILURE;
/* if (env->set_func_map(env, func_map) != DB_OK) return TDB_FAILURE; */
if (env->set_func_open(env, (int (*)(const char *, int, ...)) func_open)
!= DB_OK) return TDB_FAILURE;
if (env->set_func_read(env, func_read) != DB_OK) return TDB_FAILURE;
if (env->set_func_realloc(env, PR_Realloc) != DB_OK) return TDB_FAILURE;
if (env->set_func_seek(env, func_seek) != DB_OK) return TDB_FAILURE;
if (env->set_func_sleep(env, func_sleep) != DB_OK) return TDB_FAILURE;
if (env->set_func_unlink(env, func_unlink) != DB_OK) return TDB_FAILURE;
/* if (env->set_func_unmap(env, func_unmap) != DB_OK) return TDB_FAILURE;*/
if (env->set_func_write(env, func_write) != DB_OK) return TDB_FAILURE;
/* if (env->set_func_yield(env, func_yield) != DB_OK) return TDB_FAILURE;*/
return TDB_SUCCESS;
}
#endif /* TDB_USE_NSPR */

28
db/tripledb/src/dbnspr.h Normal file
Просмотреть файл

@ -0,0 +1,28 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#ifndef _dbnspr_h_
#define _dbnspr_h_ 1
extern TDBStatus tdbMakeDBCompatableWithNSPR(DB_ENV* env);
#endif /* _dbnspr_h_ */

Просмотреть файл

@ -14,288 +14,113 @@
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 1999 Geocast Network Systems. All
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
/* Various debugging routines. */
#include "tdbtypes.h"
#include "tdbdebug.h"
#include "prprf.h"
void TDBDumpNode(PRFileDesc* fid, TDBNode* node)
#include "tdb.h"
#include "rtype.h"
#include "vector.h"
#ifdef TDB_USE_NSPR
#include "prprf.h"
#define tdb_fprintf PR_fprintf
#else
#define tdb_fprintf fprintf
#endif
void TDBDumpNode(TDBFileDesc* fid, TDBNode* node)
{
#ifdef TDB_USE_NSPR
PRExplodedTime expl;
#endif
switch(node->type) {
case TDBTYPE_STRING:
PR_fprintf(fid, "%s", node->d.str.string);
tdb_fprintf(fid, "%s", node->d.str.string);
break;
#ifdef TDB_USE_NSPR
case TDBTYPE_TIME:
PR_ExplodeTime(node->d.time, PR_LocalTimeParameters, &expl);
tdb_fprintf(fid, "%02d/%02d/%04d %02d:%02d:%02d",
expl.tm_month+1, expl.tm_mday, expl.tm_year,
expl.tm_hour, expl.tm_min, expl.tm_sec);
break;
#endif
default:
PR_fprintf(fid, "%ld", node->d.i);
tdb_fprintf(fid, "%lld", node->d.i);
}
}
void TDBDumpRecord(PRFileDesc* fid, TDB* db, TDBPtr ptr, PRInt32 tree, int indent, const char* kidname)
void
TDBDumpTree(TDBFileDesc* fid, TDB* db, TDBInt32 tree)
{
TDBRecord* record;
/* Write me! (or not...) */
}
TDBStatus TDBSanityCheck(TDBBase* base, TDBFileDesc* fid)
{
TDBNode minnode;
DBC* cursor;
TDBVector* vector;
int m;
int i;
TDBPtr kid0;
TDBPtr kid1;
if (ptr == 0) return;
record = tdbLoadRecord(db, ptr);
for (i=0 ; i<indent ; i++) {
PR_fprintf(fid, " ");
}
PR_fprintf(fid, "[%s] pos=%d, len=%d, bal=%d ", kidname, record->position,
record->length, record->entry[tree].balance);
TDBDumpNode(fid, record->data[0]);
PR_fprintf(fid, ",");
TDBDumpNode(fid, record->data[1]);
PR_fprintf(fid, ",");
TDBDumpNode(fid, record->data[2]);
PR_fprintf(fid, "\n");
kid0 = record->entry[tree].child[0];
kid1 = record->entry[tree].child[1];
tdbFlush(db);
TDBDumpRecord(fid, db, kid0, tree, indent + 1, "0");
TDBDumpRecord(fid, db, kid1, tree, indent + 1, "1");
}
void TDBDumpTree(PRFileDesc* fid, TDB* db, PRInt32 tree)
{
TDBPtr root;
if (tree < 0) {
root = db->freeroot;
tree = 0;
} else {
root = db->roots[tree];
}
TDBDumpRecord(fid, db, root, tree, 0, "root");
}
typedef struct _TDBRangeSet {
PRInt32 position;
PRInt32 length;
struct _TDBRangeSet* next;
struct _TDBRangeSet* prev;
} TDBRangeSet;
static PRStatus checkMerges(TDBRangeSet* set, TDBRangeSet* tmp)
{
while (tmp->next != set &&
tmp->position + tmp->length == tmp->next->position) {
TDBRangeSet* t = tmp->next;
tmp->next = t->next;
tmp->next->prev = tmp;
tmp->length += t->length;
PR_Free(t);
}
while (tmp->prev != set &&
tmp->position == tmp->prev->position + tmp->prev->length) {
TDBRangeSet* t = tmp->prev;
tmp->prev = t->prev;
tmp->prev->next = tmp;
tmp->position = t->position;
t->length += t->length;
PR_Free(t);
}
return PR_SUCCESS;
}
static PRStatus addRange(TDBRangeSet* set, PRInt32 position, PRInt32 length)
{
TDBRangeSet* tmp;
TDBRangeSet* this;
for (tmp = set->next ; tmp != set ; tmp = tmp->next) {
if ((position >= tmp->position &&
position < tmp->position + tmp->length) ||
(tmp->position >= position &&
tmp->position < position + length)) {
PR_ASSERT(0); /* Collision! */
return PR_FAILURE;
}
if (position + length == tmp->position) {
tmp->position = position;
tmp->length += length;
return checkMerges(set, tmp);
} else if (tmp->position + tmp->length == position) {
tmp->length += length;
return checkMerges(set, tmp);
}
if (tmp->position > position + length) {
break;
}
}
this = PR_NEWZAP(TDBRangeSet);
if (!this) return PR_FAILURE;
this->next = tmp;
this->prev = tmp->prev;
this->next->prev = this;
this->prev->next = this;
this->position = position;
this->length = length;
return PR_SUCCESS;
}
typedef struct _TDBTreeInfo {
TDB* db;
PRInt32 tree; /* Which tree we're analyzing */
PRInt32 comparerule;
PRInt32 count; /* Number of nodes in tree. */
TDBRangeSet set; /* Range of bytes used by tree. */
PRInt32 maxdepth; /* Maximum depth of tree. */
} TDBTreeInfo;
static PRStatus checkTree(TDBTreeInfo* info, TDBPtr ptr, int depth,
int* maxdepth, TDBRecord* parent, int kid)
{
TDBRecord* record;
PRStatus status;
TDBPtr kid0;
TDBPtr kid1;
int d0 = depth;
int d1 = depth;
PRInt8 bal;
TDBRecord keep;
PRInt64 cmp;
int i;
if (ptr == 0) return PR_SUCCESS;
info->count++;
if (*maxdepth < depth) {
*maxdepth = depth;
}
record = tdbLoadRecord(info->db, ptr);
if (parent) {
cmp = tdbCompareRecords(record, parent, info->comparerule);
PR_ASSERT((kid == 0 && cmp < 0) || (kid == 1 && cmp > 0));
if (! ((kid == 0 && cmp < 0) || (kid == 1 && cmp > 0))) {
return PR_FAILURE;
}
}
status = addRange(&(info->set), record->position, record->length);
if (status != PR_SUCCESS) return status;
bal = record->entry[info->tree].balance;
if (bal < -1 || bal > 1) {
PR_ASSERT(0);
return PR_FAILURE;
}
kid0 = record->entry[info->tree].child[0];
kid1 = record->entry[info->tree].child[1];
memcpy(&keep, record, sizeof(TDBRecord));
int flag;
int count;
int numindices;
TDBNodePtr nodes[3];
TDBRType* rtype;
tdbBeginExclusiveOp(base);
minnode.type = TDBTYPE_MINNODE;
for (i=0 ; i<3 ; i++) {
keep.data[i] = tdbNodeDup(keep.data[i]);
nodes[i] = &minnode;
}
tdbFlush(info->db);
status = checkTree(info, kid0, depth + 1, &d0, &keep, 0);
if (status != PR_SUCCESS) return status;
status = checkTree(info, kid1, depth + 1, &d1, &keep, 1);
if (status != PR_SUCCESS) return status;
for (i=0 ; i<3 ; i++) {
TDBFreeNode(keep.data[i]);
}
if (d1 - d0 != bal) {
PR_ASSERT(0);
return PR_FAILURE;
}
if (*maxdepth < d0) {
*maxdepth = d0;
}
if (*maxdepth < d1) {
*maxdepth = d1;
}
return PR_SUCCESS;
}
PRStatus TDBSanityCheck(TDB* db, PRFileDesc* fid)
{
TDBTreeInfo info;
TDBRangeSet* tmp;
int i;
for (i=-1 ; i<4 ; i++) {
info.set.next = &(info.set);
info.set.prev = &(info.set);
info.db = db;
info.tree = (i < 0 ? 0 : i);
info.comparerule = i;
info.maxdepth = 0;
info.count = 0;
PR_fprintf(fid, "Checking tree %d...\n", i);
if (checkTree(&info, i < 0 ? db->freeroot : db->roots[i], 0,
&(info.maxdepth), NULL, 0) != PR_SUCCESS) {
PR_fprintf(fid, "Problem found!\n");
return PR_FAILURE;
numindices = tdbGetNumIndices(base);
for (m = 0 ; m<numindices ; m++) {
if (fid) tdb_fprintf(fid, "Checking index %d ...", m);
rtype = tdbGetIndex(base, m);
vector = tdbVectorNewFromNodes(base, nodes, 0, 0, 0);
cursor = tdbRTypeGetCursor(rtype, vector);
tdbVectorFree(vector);
if (!cursor) continue;
count = 0;
flag = DB_CURRENT;
while (NULL != (vector = tdbRTypeGetCursorValue(rtype,
cursor, flag))) {
flag = DB_NEXT;
count++;
for (i=0 ; i<numindices ; i++) {
tdb_ASSERT(i == m || tdbRTypeProbe(tdbGetIndex(base, i),
vector));
}
tdbVectorFree(vector);
}
for (tmp = info.set.next; tmp != &(info.set) ; tmp = tmp->next) {
PR_fprintf(fid, " %d - %d (%d)\n",
tmp->position, tmp->position + tmp->length,
tmp->length);
}
PR_fprintf(fid, " maxdepth: %d count %d\n", info.maxdepth,
info.count);
cursor->c_close(cursor);
if (fid) tdb_fprintf(fid, " done (%d triples found)\n", count);
}
return PR_SUCCESS;
tdbEndExclusiveOp(base);
return TDB_SUCCESS;
}
extern void TDBGetCursorStats(TDBCursor* cursor,
PRInt32* hits,
PRInt32* misses)
void TDBMakeDotGraph(TDB* db, const char* filename, TDBInt32 tree)
{
*hits = cursor->hits;
*misses = cursor->misses;
}
void makeDotEntry(TDB* db, PRFileDesc* fid, TDBPtr ptr, PRInt32 tree)
{
TDBRecord* record;
TDBPtr kid[2];
int i;
record = tdbLoadRecord(db, ptr);
PR_fprintf(fid, "%d [label=\"%d\\n", record->position, record->position);
for (i=0 ; i<3 ; i++) {
TDBDumpNode(fid, record->data[i]);
if (i<2) PR_fprintf(fid, ",");
}
PR_fprintf(fid, "\\nbal=%d\"]\n", record->entry[tree].balance);
kid[0] = record->entry[tree].child[0];
kid[1] = record->entry[tree].child[1];
/* tdbFlush(db); */
for (i=0 ; i<2 ; i++) {
if (kid[i] != 0) {
makeDotEntry(db, fid, kid[i], tree);
PR_fprintf(fid, "%d -> %d [label=\"%d\"]\n", ptr, kid[i], i);
}
}
}
void TDBMakeDotGraph(TDB* db, const char* filename, PRInt32 tree)
{
TDBPtr root;
PRFileDesc* fid;
fid = PR_Open(filename, PR_WRONLY | PR_CREATE_FILE, 0666);
if (tree == -1) {
root = db->freeroot;
tree = 0;
} else {
root = db->roots[tree];
}
PR_fprintf(fid, "digraph G {\n");
makeDotEntry(db, fid, root, tree);
PR_fprintf(fid, "}\n");
PR_Close(fid);
/* Write me! (or not...) */
}

237
db/tripledb/src/intern.c Normal file
Просмотреть файл

@ -0,0 +1,237 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#include "tdbtypes.h"
#include "intern.h"
#include "node.h"
#include "tdb.h"
#include "util.h"
struct _TDBIntern {
DB* nodetoatomdb;
DB* atomtonodedb;
char* tmpbuf;
TDBInt32 tmpbufsize;
};
TDBIntern*
tdbInternInit(TDBBase* base)
{
TDBIntern* intern;
if (base == NULL) {
tdb_ASSERT(0);
return NULL;
}
intern = tdb_NEWZAP(TDBIntern);
if (!intern) return NULL;
if (db_create(&(intern->nodetoatomdb), tdbGetDBEnv(base), 0) != DB_OK) {
goto FAIL;
}
if (intern->nodetoatomdb->open(intern->nodetoatomdb, "nodetoatomdb",
NULL, DB_HASH,
DB_CREATE, 0666) != DB_OK) goto FAIL;
if (db_create(&(intern->atomtonodedb), tdbGetDBEnv(base), 0) != DB_OK) {
goto FAIL;
}
if (intern->atomtonodedb->open(intern->atomtonodedb, "atomtonodedb",
NULL, DB_RECNO,
DB_CREATE, 0666) != DB_OK) goto FAIL;
intern->tmpbufsize = 512;
intern->tmpbuf = tdb_Malloc(intern->tmpbufsize);
if (!intern->tmpbuf) goto FAIL;
return intern;
FAIL:
tdbInternFree(intern);
return NULL;
}
void
tdbInternFree(TDBIntern* intern)
{
if (intern == NULL) {
tdb_ASSERT(0);
return;
}
if (intern->nodetoatomdb) {
intern->nodetoatomdb->close(intern->nodetoatomdb, 0);
}
if (intern->atomtonodedb) {
intern->atomtonodedb->close(intern->atomtonodedb, 0);
}
if (intern->tmpbuf) tdb_Free(intern->tmpbuf);
tdb_Free(intern);
}
TDBNodePtr
tdbIntern(TDBBase* base, TDBNodePtr node)
{
TDBIntern* intern;
char* ptr;
char* endptr;
DBT key;
DBT data;
int dbstatus;
TDBUint32 atom;
TDBUint32 atom2;
if (base == NULL || node == NULL) {
tdb_ASSERT(0);
return NULL;
}
intern = tdbGetIntern(base);
if (intern == NULL || intern->tmpbuf == NULL) {
tdb_ASSERT(0);
return NULL;
}
if (node->type == TDBTYPE_MINNODE) {
return TDBCreateIntNode(0, TDBTYPE_INTERNED);
}
if (node->type == TDBTYPE_MAXNODE) {
return TDBCreateIntNode(0xffffffff, TDBTYPE_INTERNED);
}
if (node->type == TDBTYPE_INTERNED) {
tdb_ASSERT(0);
return NULL;
}
if (intern->tmpbuf) {
ptr = intern->tmpbuf;
endptr = ptr + intern->tmpbufsize;
tdbPutNode(&ptr, node, endptr);
} else {
ptr = NULL;
}
if (ptr == NULL || ptr >= endptr) {
intern->tmpbufsize = tdbNodeSize(node) + 10;
intern->tmpbuf = tdb_Realloc(intern->tmpbuf, intern->tmpbufsize);
if (!intern->tmpbuf) return NULL;
ptr = intern->tmpbuf;
endptr = ptr + intern->tmpbufsize;
tdbPutNode(&ptr, node, endptr);
if (ptr >= endptr) {
tdb_ASSERT(0);
return NULL;
}
}
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
key.data = intern->tmpbuf;
key.size = ptr - intern->tmpbuf;
dbstatus = intern->nodetoatomdb->get(intern->nodetoatomdb,
tdbGetTransaction(base),
&key, &data, 0);
if (dbstatus == DB_NOTFOUND) {
do {
data.data = &atom;
data.ulen = sizeof(atom);
data.flags = DB_DBT_USERMEM;
dbstatus = intern->atomtonodedb->put(intern->atomtonodedb,
tdbGetTransaction(base),
&data, &key, DB_APPEND);
if (dbstatus != DB_OK) return NULL;
tdb_ASSERT(data.size == sizeof(TDBUint32));
} while (atom == 0); /* First time, we may get an atom of zero,
which I don't want, since I reserve atom
of zero to mean something special. */
data.data = &atom2;
ptr = data.data;
endptr = ptr + data.size;
tdbPutUInt32(&ptr, atom, endptr);
dbstatus = intern->nodetoatomdb->put(intern->nodetoatomdb,
tdbGetTransaction(base),
&key, &data, 0);
if (dbstatus != DB_OK) return NULL;
} else {
if (dbstatus != DB_OK) return NULL;
if (data.size != sizeof(TDBUint32)) {
tdb_ASSERT(0);
return NULL;
}
ptr = data.data;
endptr = ptr + data.size;
atom = tdbGetUInt32(&ptr, endptr);
}
return TDBCreateIntNode(atom, TDBTYPE_INTERNED);
}
TDBNodePtr
tdbUnintern(TDBBase* base, TDBNodePtr node)
{
char* ptr;
char* endptr;
DBT key;
DBT data;
TDBIntern* intern;
TDBUint32 atom;
int dbstatus;
if (base == NULL || node == NULL || node->type != TDBTYPE_INTERNED ||
node->d.i == 0 || node->d.i == 0xffffffff) {
tdb_ASSERT(0);
return NULL;
}
intern = tdbGetIntern(base);
if (intern == NULL) {
tdb_ASSERT(0);
return NULL;
}
atom = node->d.i;
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
key.data = &atom;
key.size = sizeof(atom);
dbstatus = intern->atomtonodedb->get(intern->atomtonodedb,
tdbGetTransaction(base),
&key, &data, 0);
if (dbstatus != DB_OK) return NULL;
ptr = (char*) data.data;
endptr = ptr + data.size;
return tdbGetNode(&ptr, endptr);
}
TDBStatus
tdbInternSync(TDBBase* base)
{
TDBIntern* intern;
if (base == NULL) {
tdb_ASSERT(0);
return TDB_FAILURE;
}
intern = tdbGetIntern(base);
if (intern->atomtonodedb->sync(intern->atomtonodedb, 0) != DB_OK) {
return TDB_FAILURE;
}
if (intern->nodetoatomdb->sync(intern->nodetoatomdb, 0) != DB_OK) {
return TDB_FAILURE;
}
return TDB_SUCCESS;
}

48
db/tripledb/src/intern.h Normal file
Просмотреть файл

@ -0,0 +1,48 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#ifndef _intern_h_
#define _intern_h_ 1
extern TDBIntern* tdbInternInit(TDBBase* base);
extern void tdbInternFree(TDBIntern* intern);
/* tdbIntern() takes a non-interned node and returns an atom representing it.
The returned node should be free'd with TDBFreeNode(). */
extern TDBNodePtr tdbIntern(TDBBase* base, TDBNodePtr node);
/* tdbUnintern() takes an atom and allocates a new node representing it. The
returned node should be free'd with TDBFreeNode(). */
extern TDBNodePtr tdbUnintern(TDBBase* base, TDBNodePtr node);
/* tdbRTypeSync() causes any changes made to intern tables to be written out
to disk. */
extern TDBStatus tdbInternSync(TDBBase* base);
#endif /* _intern_h_ */

Просмотреть файл

@ -14,24 +14,29 @@
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 1999 Geocast Network Systems. All
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
/* Operations that do things on nodes. */
#include "tdbtypes.h"
#include "node.h"
#include "util.h"
TDBNodePtr TDBCreateStringNode(const char* string)
{
TDBNode* result;
PRInt32 length;
PR_ASSERT(string != NULL);
TDBInt32 length;
tdb_ASSERT(string != NULL);
if (string == NULL) return NULL;
length = strlen(string);
result = (TDBNode*) PR_Malloc(sizeof(TDBNode) + length + 1);
if (length > 65535) {
tdb_ASSERT(0); /* Don't call us with huge strings! */
return NULL;
}
result = (TDBNode*) tdb_Malloc(sizeof(TDBNode) + length + 1);
if (result == NULL) return NULL;
result->type = TDBTYPE_STRING;
@ -41,34 +46,46 @@ TDBNodePtr TDBCreateStringNode(const char* string)
}
TDBNodePtr TDBCreateIntNode(PRInt64 value, PRInt8 type)
TDBNodePtr TDBCreateIntNode(TDBInt64 value, TDBInt8 type)
{
TDBNode* result;
PR_ASSERT(type >= TDBTYPE_INT8 && type <= TDBTYPE_TIME);
if (type < TDBTYPE_INT8 || type > TDBTYPE_TIME) {
if ((type < TDBTYPE_INT32 || type >= TDBTYPE_STRING) && type !=
TDBTYPE_INTERNED) {
tdb_ASSERT(0);
return NULL;
}
result = PR_NEW(TDBNode);
result = tdb_NEWZAP(TDBNode);
if (result == NULL) return NULL;
result->type = type;
result->d.i = value;
return result;
}
void TDBFreeNode(TDBNode* node)
TDBNodePtr tdbCreateSpecialNode(TDBInt8 type)
{
PR_Free(node);
TDBNodePtr result;
tdb_ASSERT(type == TDBTYPE_MINNODE || type == TDBTYPE_MAXNODE);
result = tdb_NEWZAP(TDBNode);
if (result == NULL) return NULL;
result->type = type;
return result;
}
TDBNode* tdbNodeDup(TDBNode* node)
void TDBFreeNode(TDBNode* node)
{
tdb_Free(node);
}
TDBNode* TDBNodeDup(TDBNode* node)
{
TDBNode* result;
PRInt32 length;
PR_ASSERT(node != NULL);
TDBInt32 length;
tdb_ASSERT(node != NULL);
if (node == NULL) return NULL;
if (node->type == TDBTYPE_STRING) {
length = node->d.str.length;
result = PR_Malloc(sizeof(TDBNode) + length + 1);
result = tdb_Malloc(sizeof(TDBNode) + length + 1);
if (result == NULL) return NULL;
result->type = TDBTYPE_STRING;
result->d.str.length = length;
@ -76,54 +93,106 @@ TDBNode* tdbNodeDup(TDBNode* node)
result->d.str.string[length] = '\0';
return result;
}
if (node->type == TDBTYPE_MINNODE || node->type == TDBTYPE_MAXNODE) {
return tdbCreateSpecialNode(node->type);
}
return TDBCreateIntNode(node->d.i, node->type);
}
PRInt32 tdbNodeSize(TDBNode* node)
TDBInt32 tdbNodeSize(TDBNode* node)
{
PR_ASSERT(node != NULL);
tdb_ASSERT(node != NULL);
if (node == NULL) return 0;
switch (node->type) {
case TDBTYPE_INT8:
return 1 + sizeof(PRInt8);
case TDBTYPE_INT16:
return 1 + sizeof(PRInt16);
case TDBTYPE_INT32:
return 1 + sizeof(PRInt32);
return 1 + sizeof(TDBInt32);
case TDBTYPE_INT64:
return 1 + sizeof(PRInt64);
return 1 + sizeof(TDBInt64);
case TDBTYPE_ID:
return 1 + sizeof(TDBUint64);
case TDBTYPE_TIME:
return 1 + sizeof(PRTime);
return 1 + sizeof(TDBTime);
case TDBTYPE_STRING:
return 1 + sizeof(PRUint16) + node->d.str.length;
return 1 + node->d.str.length + 1;
case TDBTYPE_BLOB:
return 1 + sizeof(TDBUint16) + node->d.str.length;
case TDBTYPE_INTERNED:
return 1 + sizeof(TDBUint32);
default:
PR_ASSERT(0);
tdb_ASSERT(0);
return 0;
}
}
PRInt64 tdbCompareNodes(TDBNode* n1, TDBNode* n2)
TDBStatus tdbPutNode(char** ptr, TDBNode* node, char* endptr)
{
if (n1->type == TDBTYPE_STRING && n2->type == TDBTYPE_STRING) {
return strcmp(n1->d.str.string, n2->d.str.string);
} else if (n1->type != TDBTYPE_STRING && n2->type != TDBTYPE_STRING) {
return n1->d.i - n2->d.i;
} else {
return n1->type - n2->type;
if (tdbPutInt8(ptr, node->type, endptr) != TDB_SUCCESS) {
return TDB_FAILURE;
}
switch (node->type) {
case TDBTYPE_STRING:
if (endptr - *ptr <= node->d.str.length) return TDB_FAILURE;
memcpy(*ptr, node->d.str.string, node->d.str.length);
*ptr += node->d.str.length;
*(*ptr)++ = '\0';
return TDB_SUCCESS;
case TDBTYPE_BLOB:
tdbPutUInt16(ptr, node->d.str.length, endptr);
if (endptr - *ptr < node->d.str.length) {
return TDB_FAILURE;
}
memcpy(*ptr, node->d.str.string, node->d.str.length);
*ptr += node->d.str.length;
return TDB_SUCCESS;
case TDBTYPE_INT32:
return tdbPutInt32(ptr, (TDBInt32) node->d.i, endptr);
case TDBTYPE_INT64:
case TDBTYPE_TIME:
return tdbPutInt64(ptr, node->d.i, endptr);
case TDBTYPE_ID:
return tdbPutUInt64(ptr, node->d.i, endptr);
case TDBTYPE_INTERNED:
return tdbPutUInt32(ptr, node->d.i, endptr);
case TDBTYPE_MINNODE:
case TDBTYPE_MAXNODE:
return TDB_SUCCESS;
default:
tdb_ASSERT(0);
return TDB_FAILURE;
}
}
TDBNode* tdbGetNode(TDB* db, char** ptr)
TDBNode* tdbGetNode(char** ptr, char* endptr)
{
TDBNode* result;
PRInt8 type = tdbGetInt8(ptr);
PRInt64 i;
if (type == TDBTYPE_STRING) {
PRUint16 length = tdbGetUInt16(ptr);
result = (TDBNode*) PR_Malloc(sizeof(TDBNode) + length + 1);
TDBInt8 type;
TDBInt64 i;
TDBUint16 length;
char* p;
type = tdbGetInt8(ptr, endptr);
if (*ptr >= endptr) return NULL;
switch (type) {
case TDBTYPE_STRING:
for (p = *ptr ; p <= endptr && *p ; p++) {}
if (p > endptr) return NULL;
length = p - *ptr;
result = (TDBNode*) tdb_Malloc(sizeof(TDBNode) + length + 1);
if (result == NULL) {
return NULL;
}
result->type = type;
result->d.str.length = length;
memcpy(result->d.str.string, *ptr, length + 1);
*ptr = p + 1;
return result;
case TDBTYPE_BLOB:
length = tdbGetUInt16(ptr, endptr);
if (*ptr > endptr) return NULL;
if (*ptr + length > endptr) return NULL;
result = (TDBNode*) tdb_Malloc(sizeof(TDBNode) + length + 1);
if (result == NULL) {
return NULL;
}
@ -132,55 +201,39 @@ TDBNode* tdbGetNode(TDB* db, char** ptr)
memcpy(result->d.str.string, *ptr, length);
result->d.str.string[length] = '\0';
(*ptr) += length;
} else {
switch(type) {
case TDBTYPE_INT8:
i = tdbGetInt8(ptr);
break;
case TDBTYPE_INT16:
i = tdbGetInt16(ptr);
break;
case TDBTYPE_INT32:
i = tdbGetInt32(ptr);
break;
case TDBTYPE_INT64:
case TDBTYPE_TIME:
i = tdbGetInt64(ptr);
break;
default:
tdbMarkCorrupted(db);
return NULL;
}
result = TDBCreateIntNode(i, type);
return result;
case TDBTYPE_INT32:
i = tdbGetInt32(ptr, endptr);
break;
case TDBTYPE_INT64:
case TDBTYPE_TIME:
i = tdbGetInt64(ptr, endptr);
break;
case TDBTYPE_ID:
i = tdbGetUInt64(ptr, endptr);
break;
case TDBTYPE_INTERNED:
i = tdbGetUInt32(ptr, endptr);
break;
default:
return NULL;
}
return result;
return TDBCreateIntNode(i, type);
}
void tdbPutNode(TDB* db, char** ptr, TDBNode* node)
TDBInt64 TDBCompareNodes(TDBNode* n1, TDBNode* n2)
{
tdbPutInt8(ptr, node->type);
switch (node->type) {
case TDBTYPE_STRING:
tdbPutUInt16(ptr, node->d.str.length);
memcpy(*ptr, node->d.str.string, node->d.str.length);
*ptr += node->d.str.length;
break;
case TDBTYPE_INT8:
tdbPutInt8(ptr, (PRInt8) node->d.i);
break;
case TDBTYPE_INT16:
tdbPutInt16(ptr, (PRInt16) node->d.i);
break;
case TDBTYPE_INT32:
tdbPutInt32(ptr, (PRInt32) node->d.i);
break;
case TDBTYPE_INT64:
case TDBTYPE_TIME:
tdbPutInt64(ptr, node->d.i);
break;
default:
tdbMarkCorrupted(db);
break;
TDBInt64 result;
if (n1->type != n2->type) {
return n1->type - n2->type;
} else if (n1->type == TDBTYPE_STRING || n1->type == TDBTYPE_BLOB) {
result = memcmp(n1->d.str.string, n2->d.str.string,
n1->d.str.length < n2->d.str.length ?
n1->d.str.length : n2->d.str.length);
if (result != 0) return result;
return ((TDBInt64) n1->d.str.length) - ((TDBInt64) n2->d.str.length);
} else {
return n1->d.i - n2->d.i;
}
}

39
db/tripledb/src/node.h Normal file
Просмотреть файл

@ -0,0 +1,39 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#ifndef _node_h_
#define _node_h_ 1
extern TDBNode* tdbNodeDup(TDBNode* node);
extern TDBInt32 tdbNodeSize(TDBNode* node);
extern TDBNode* tdbGetNode(char** ptr, char* endptr);
extern TDBStatus tdbPutNode(char** ptr, TDBNode* node, char* endptr);
extern TDBNode* tdbGetNodeFromKey(char** ptr, char* endptr);
extern TDBStatus tdbPutNodeToKey(char** ptr, TDBNode* node, char* endptr,
TDBUint8 *flags);
#endif /* _node_h_ */

Просмотреть файл

@ -1,504 +0,0 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 1999 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
/* Routines that query things from the database. */
#include "tdbtypes.h"
/* Argh, this same static array appears in record.c. Don't do that. ### */
static int key[NUMTREES][3] = {
{0, 1, 2},
{1, 0, 2},
{2, 1, 0},
{1, 2, 0}
};
static void
freeParentChain(TDBCursor* cursor)
{
TDBParentChain* tmp;
while (cursor->parent) {
tmp = cursor->parent->next;
cursor->parent->record->refcnt--;
PR_ASSERT(cursor->parent->record->refcnt >= 0);
PR_Free(cursor->parent);
cursor->parent = tmp;
}
}
static PRStatus
moveCursorForward(TDBCursor* cursor)
{
TDBRecord* cur;
PRBool found;
PRInt32 fwd;
PRInt32 rev;
TDBPtr ptr;
PRInt32 tree = cursor->tree;
TDBParentChain* parent;
TDBParentChain* tmp;
cur = cursor->cur;
PR_ASSERT(cur != NULL);
if (cur == NULL) {
return PR_FAILURE;
}
cur->refcnt--;
PR_ASSERT(cur->refcnt >= 0);
cursor->cur = NULL;
fwd = cursor->reverse ? 0 : 1;
rev = cursor->reverse ? 1 : 0;
ptr = cur->entry[tree].child[fwd];
if (ptr != 0) {
do {
cur->refcnt++;
parent = PR_NEWZAP(TDBParentChain);
parent->record = cur;
parent->next = cursor->parent;
cursor->parent = parent;
cur = tdbLoadRecord(cursor->db, ptr);
PR_ASSERT(cur);
if (!cur) {
return PR_FAILURE;
}
ptr = cur->entry[tree].child[rev];
} while (ptr != 0);
} else {
found = PR_FALSE;
while (cursor->parent) {
ptr = cur->position;
cur = cursor->parent->record;
cur->refcnt--;
PR_ASSERT(cur->refcnt >= 0);
tmp = cursor->parent->next;
PR_Free(cursor->parent);
cursor->parent = tmp;
if (cur->entry[tree].child[rev] == ptr) {
found = PR_TRUE;
break;
}
if (cur->entry[tree].child[fwd] != ptr) {
tdbMarkCorrupted(cursor->db);
return PR_FAILURE;
}
}
if (!found) cur = NULL;
}
if (cur) cur->refcnt++;
cursor->cur = cur;
return PR_SUCCESS;
}
static PRStatus findFirstNode(TDBCursor* cursor, TDBNodeRange range[3])
{
PRInt32 fwd;
PRInt32 rev;
PRBool reverse;
PRInt32 tree;
TDBParentChain* parent;
TDBPtr curptr;
TDBRecord* cur;
PRInt64 cmp;
reverse = cursor->reverse;
fwd = reverse ? 0 : 1;
rev = reverse ? 1 : 0;
tree = cursor->tree;
freeParentChain(cursor);
curptr = cursor->db->roots[tree];
cur = NULL;
while (curptr) {
if (cur) {
cur->refcnt++;
parent = PR_NEWZAP(TDBParentChain);
parent->record = cur;
parent->next = cursor->parent;
cursor->parent = parent;
}
cur = tdbLoadRecord(cursor->db, curptr);
PR_ASSERT(cur);
if (!cur) return PR_FAILURE;
cmp = tdbCompareToRange(cur, range, tree);
if (reverse) cmp = -cmp;
if (cmp >= 0) {
curptr = cur->entry[tree].child[rev];
} else {
curptr = cur->entry[tree].child[fwd];
}
}
if (cursor->cur) {
cursor->cur->refcnt--;
PR_ASSERT(cursor->cur->refcnt >= 0);
}
cursor->cur = cur;
if (cursor->cur) {
cursor->cur->refcnt++;
}
while (cursor->cur != NULL &&
tdbCompareToRange(cursor->cur, range, tree) < 0) {
moveCursorForward(cursor);
}
return PR_SUCCESS;
}
TDBCursor* tdbQueryNolock(TDB* db, TDBNodeRange range[3],
TDBSortSpecification* sortspec)
{
PRInt32 rangescore[3];
PRInt32 tree;
PRInt32 curscore;
PRInt32 bestscore = -1;
PRInt32 i;
TDBCursor* result;
PRBool reverse;
PRStatus status;
result = PR_NEWZAP(TDBCursor);
if (!result) return NULL;
for (i=0 ; i<3 ; i++) {
if (range[i].min) {
result->range[i].min = tdbNodeDup(range[i].min);
if (result->range[i].min == NULL) goto FAIL;
}
if (range[i].max) {
result->range[i].max = tdbNodeDup(range[i].max);
if (result->range[i].max == NULL) goto FAIL;
}
}
for (tree = 0 ; tree < NUMTREES ; tree++) {
if (key[tree][0] == sortspec->keyorder[0] &&
key[tree][1] == sortspec->keyorder[1] &&
key[tree][2] == sortspec->keyorder[2]) {
break;
}
}
if (tree >= NUMTREES) {
/* The passed in keyorder was not valid (which, in fact, is the usual
case). Go find the best tree to use. */
for (i=0 ; i<3 ; i++) {
rangescore[i] = 0;
if (range[i].min != NULL || range[i].max != NULL) {
/* Hey, some limitations were specified, we like this key
some. */
rangescore[i]++;
if (range[i].min != NULL && range[i].max != NULL) {
/* Ooh, we were given both minimum and maximum, that's
better than only getting one.*/
rangescore[i]++;
if (tdbCompareNodes(range[i].min, range[i].max) == 0) {
/* Say! This key was exactly specified. We like it
best. */
rangescore[i]++;
}
}
}
}
for (i=0 ; i<NUMTREES ; i++) {
curscore = rangescore[key[i][0]] * 100 +
rangescore[key[i][1]] * 10 +
rangescore[key[i][2]];
if (bestscore < curscore) {
bestscore = curscore;
tree = i;
}
}
}
reverse = sortspec != NULL && sortspec->reverse;
result->reverse = reverse;
result->db = db;
result->tree = tree;
status = findFirstNode(result, range);
if (status != PR_SUCCESS) goto FAIL;
result->nextcursor = db->firstcursor;
if (result->nextcursor) {
result->nextcursor->prevcursor = result;
}
db->firstcursor = result;
tdbFlush(db);
return result;
FAIL:
tdbFreeCursorNolock(result);
return NULL;
}
TDBCursor* TDBQuery(TDB* db, TDBNodeRange range[3],
TDBSortSpecification* sortspec)
{
TDBCursor* result;
PR_Lock(db->mutex);
result = tdbQueryNolock(db, range, sortspec);
PR_Unlock(db->mutex);
return result;
}
PRStatus tdbFreeCursorNolock(TDBCursor* cursor)
{
PRInt32 i;
TDB* db;
PR_ASSERT(cursor);
if (!cursor) return PR_FAILURE;
db = cursor->db;
if (cursor->cur) {
cursor->cur->refcnt--;
PR_ASSERT(cursor->cur->refcnt >= 0);
}
if (cursor->lasthit) {
cursor->lasthit->refcnt--;
PR_ASSERT(cursor->lasthit->refcnt >= 0);
}
freeParentChain(cursor);
if (db) tdbFlush(db);
for (i=0 ; i<3 ; i++) {
PR_FREEIF(cursor->range[i].min);
PR_FREEIF(cursor->range[i].max);
}
if (cursor->prevcursor) {
cursor->prevcursor->nextcursor = cursor->nextcursor;
} else {
if (db) db->firstcursor = cursor->nextcursor;
}
if (cursor->nextcursor) {
cursor->nextcursor->prevcursor = cursor->prevcursor;
}
PR_Free(cursor);
return PR_SUCCESS;
}
PRStatus TDBFreeCursor(TDBCursor* cursor)
{
PRStatus status;
TDB* db;
PR_ASSERT(cursor);
if (!cursor) return PR_FAILURE;
db = cursor->db;
PR_Lock(db->mutex);
status = tdbFreeCursorNolock(cursor);
#ifdef DEBUG
if (db->firstcursor == 0) {
/* There are no more cursors. No other thread can be in the middle of
writing stuff, because we have the mutex. And so, there shouldn't
be anything left in our cache of records; they should all be
flushed out. So... */
PR_ASSERT(db->firstrecord == NULL);
}
#endif
PR_Unlock(db->mutex);
return status;
}
TDBTriple* tdbGetResultNolock(TDBCursor* cursor)
{
PRStatus status;
PRInt32 i;
PRInt64 cmp;
TDBNodeRange range[3];
PR_ASSERT(cursor);
if (!cursor) return NULL;
if (cursor->cur == NULL && cursor->lasthit == NULL &&
cursor->triple.data[0] != NULL) {
/* Looks like someone did a write to the database since we last were
here, and therefore threw away all our cached information about
where we were. Go find our place again. */
for (i=0 ; i<3 ; i++) {
range[i].min = cursor->triple.data[i];
range[i].max = NULL;
if (cursor->reverse) {
range[i].max = range[i].min;
range[i].min = NULL;
}
}
status = findFirstNode(cursor, range);
if (status != PR_SUCCESS) return NULL;
if (cursor->cur) {
PRBool match = PR_TRUE;
for (i=0 ; i<3 ; i++) {
if (tdbCompareNodes(cursor->cur->data[i],
cursor->triple.data[i]) != 0) {
match = PR_FALSE;
break;
}
}
if (match) {
/* OK, this node we found was exactly the one we were at
last time. Bump it up one. */
moveCursorForward(cursor);
}
}
}
for (i=0 ; i<3 ; i++) {
PR_FREEIF(cursor->triple.data[i]);
}
if (cursor->lasthit) {
cursor->lasthit->refcnt--;
cursor->lasthit = NULL;
}
if (cursor->cur == NULL) return NULL;
while (cursor->cur != NULL) {
if (tdbMatchesRange(cursor->cur, cursor->range)) {
break;
}
cmp = tdbCompareToRange(cursor->cur, cursor->range, cursor->tree);
if (cursor->reverse ? (cmp < 0) : (cmp > 0)) {
/* We're off the end of the range, all done. */
cursor->cur->refcnt--;
PR_ASSERT(cursor->cur->refcnt >= 0);
cursor->cur = NULL;
break;
}
cursor->misses++;
moveCursorForward(cursor);
}
if (cursor->cur == NULL) {
tdbFlush(cursor->db);
return NULL;
}
for (i=0 ; i<3 ; i++) {
cursor->triple.data[i] = tdbNodeDup(cursor->cur->data[i]);
}
cursor->lasthit = cursor->cur;
cursor->lasthit->refcnt++;
moveCursorForward(cursor);
cursor->hits++;
#ifdef DEBUG
{
TDBParentChain* tmp;
PR_ASSERT(cursor->cur == NULL || cursor->cur->refcnt > 0);
for (tmp = cursor->parent ; tmp ; tmp = tmp->next) {
PR_ASSERT(tmp->record->refcnt > 0);
}
}
#endif
tdbFlush(cursor->db);
return &(cursor->triple);
}
TDBTriple* TDBGetResult(TDBCursor* cursor)
{
TDBTriple* result;
PR_ASSERT(cursor && cursor->db);
if (!cursor || !cursor->db) return NULL;
PR_Lock(cursor->db->mutex);
result = tdbGetResultNolock(cursor);
PR_Unlock(cursor->db->mutex);
return result;
}
/* Determines where this item falls within the range of items defined.
Negative means this item is too early, and positive means too late.
Zero means that it seems to fall within the range, but you need to do
a call to tdbMatchesRange() to really make sure. The idea here is that
as you slowly walk along the appropriate tree in the DB, this routine
will always return a nondecreasing result. */
PRInt64 tdbCompareToRange(TDBRecord* record, TDBNodeRange* range,
PRInt32 comparerule)
{
int i;
int k;
PR_ASSERT(record != NULL && range != NULL);
if (record == NULL || range == NULL) return PR_FALSE;
PR_ASSERT(comparerule >= 0 && comparerule < NUMTREES);
if (comparerule < 0 || comparerule >= NUMTREES) {
return 0;
}
for (i=0 ; i<3 ; i++) {
k = key[comparerule][i];
if (range[k].min != NULL &&
tdbCompareNodes(record->data[k], range[k].min) < 0) {
return -1;
}
if (range[k].max != NULL &&
tdbCompareNodes(record->data[k], range[k].max) > 0) {
return 1;
}
if (range[k].min == NULL || range[k].max == NULL ||
tdbCompareNodes(range[k].min, range[k].max) != 0) {
return 0;
}
}
return 0;
}
PRBool tdbMatchesRange(TDBRecord* record, TDBNodeRange* range)
{
PRInt32 i;
PR_ASSERT(record != NULL && range != NULL);
if (record == NULL || range == NULL) return PR_FALSE;
for (i=0 ; i<3 ; i++) {
if (range[i].min != NULL &&
tdbCompareNodes(record->data[i], range[i].min) < 0) {
return PR_FALSE;
}
if (range[i].max != NULL &&
tdbCompareNodes(record->data[i], range[i].max) > 0) {
return PR_FALSE;
}
}
return PR_TRUE;
}
void tdbThrowOutCursorCaches(TDB* db)
{
TDBCursor* cursor;
for (cursor = db->firstcursor ; cursor ; cursor = cursor->nextcursor) {
freeParentChain(cursor);
if (cursor->cur) {
cursor->cur->refcnt--;
PR_ASSERT(cursor->cur->refcnt >= 0);
cursor->cur = NULL;
}
if (cursor->lasthit) {
cursor->lasthit->refcnt--;
PR_ASSERT(cursor->lasthit->refcnt >= 0);
cursor->lasthit = NULL;
}
}
}

Просмотреть файл

@ -1,242 +0,0 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 1999 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
/* Operations that do things on file record. */
#include "tdbtypes.h"
TDBRecord* tdbLoadRecord(TDB* db, TDBPtr position)
{
TDBRecord* result;
char buf[sizeof(PRUint32)];
char* ptr;
PRInt32 i;
PRInt32 num;
PRInt32 numtoread;
for (result = db->firstrecord ; result ; result = result->next) {
if (result->position == position) {
goto DONE;
}
}
if (PR_Seek(db->fid, position, PR_SEEK_SET) < 0) {
goto DONE;
}
num = PR_Read(db->fid, buf, sizeof(buf));
if (num != sizeof(buf)) {
goto DONE;
}
result = PR_NEWZAP(TDBRecord);
if (result == NULL) goto DONE;
result->position = position;
ptr = buf;
result->length = tdbGetInt32(&ptr);
if (result->length < MINRECORDSIZE || result->length > MAXRECORDSIZE) {
tdbMarkCorrupted(db);
PR_Free(result);
result = NULL;
goto DONE;
}
if (tdbGrowIobuf(db, result->length) != PR_SUCCESS) {
PR_Free(result);
result = NULL;
goto DONE;
}
numtoread = result->length - sizeof(PRInt32);
num = PR_Read(db->fid, db->iobuf, numtoread);
if (num < numtoread) {
PR_Free(result);
result = NULL;
goto DONE;
}
ptr = db->iobuf;
for (i=0 ; i<NUMTREES ; i++) {
result->entry[i].child[0] = tdbGetInt32(&ptr);
result->entry[i].child[1] = tdbGetInt32(&ptr);
result->entry[i].balance = tdbGetInt8(&ptr);
}
for (i=0 ; i<3 ; i++) {
result->data[i] = tdbGetNode(db, &ptr);
if (result->data[i] == NULL) {
while (--i >= 0) {
PR_Free(result->data[i]);
}
PR_Free(result);
result = NULL;
goto DONE;
}
}
if (ptr - db->iobuf != numtoread) {
tdbMarkCorrupted(db);
for (i=0 ; i<3 ; i++) {
PR_Free(result->data[i]);
}
PR_Free(result);
result = NULL;
goto DONE;
}
PR_ASSERT(db->firstrecord != result);
result->next = db->firstrecord;
db->firstrecord = result;
DONE:
return result;
}
PRStatus tdbSaveRecord(TDB* db, TDBRecord* record)
{
PRStatus status;
PRInt32 i;
char* ptr;
if (PR_Seek(db->fid, record->position, PR_SEEK_SET) < 0) {
return PR_FAILURE;
}
status = tdbGrowIobuf(db, record->length);
if (status != PR_SUCCESS) return status;
ptr = db->iobuf;
tdbPutInt32(&ptr, record->length);
for (i=0 ; i<NUMTREES ; i++) {
tdbPutInt32(&ptr, record->entry[i].child[0]);
tdbPutInt32(&ptr, record->entry[i].child[1]);
tdbPutInt8(&ptr, record->entry[i].balance);
}
for (i=0 ; i<3 ; i++) {
tdbPutNode(db, &ptr, record->data[i]);
}
PR_ASSERT(ptr - db->iobuf == record->length);
if (PR_Write(db->fid, db->iobuf, record->length) != record->length) {
return PR_FAILURE;
}
return PR_SUCCESS;
}
PRStatus tdbFreeRecord(TDBRecord* record)
{
PRInt32 i;
for (i=0 ; i<3 ; i++) {
PR_Free(record->data[i]);
}
PR_Free(record);
return PR_SUCCESS;
}
TDBRecord* tdbAllocateRecord(TDB* db, TDBNodePtr triple[3])
{
PRInt32 i;
PRInt32 size;
TDBRecord* result = NULL;
TDBRecord* tmp;
TDBPtr position;
size = sizeof(PRInt32) +
NUMTREES * (sizeof(PRInt32) + sizeof(PRInt32) + sizeof(PRInt8)) +
tdbNodeSize(triple[0]) +
tdbNodeSize(triple[1]) +
tdbNodeSize(triple[2]);
position = db->freeroot;
if (position > 0) {
do {
result = tdbLoadRecord(db, position);
if (result->length > size) {
position = result->entry[0].child[0];
} else if (result->length < size) {
position = result->entry[0].child[1];
} else {
/* Hey, we found one! */
if (tdbRemoveFromTree(db, result, -1) != PR_SUCCESS) {
tdbMarkCorrupted(db);
return NULL;
}
break;
}
} while (position != 0);
}
if (position == 0) {
result = PR_NEWZAP(TDBRecord);
if (!result) return NULL;
position = db->filelength;
db->filelength += size;
PR_ASSERT(db->firstrecord != result);
result->next = db->firstrecord;
db->firstrecord = result;
} else {
for (i=0 ; i<3 ; i++) {
PR_Free(result->data[i]);
}
tmp = result->next;
memset(result, 0, sizeof(TDBRecord));
result->next = tmp;
}
result->position = position;
result->length = size;
for (i=0 ; i<3 ; i++) {
result->data[i] = tdbNodeDup(triple[i]);
if (result->data[i] == NULL) {
while (--i >= 0) {
PR_Free(result->data[i]);
}
PR_Free(result);
return NULL;
}
}
result->dirty = PR_TRUE;
return result;
}
/* Argh, this same static array appears in query.c. Don't do that. ### */
static int key[4][3] = {
{0, 1, 2},
{1, 0, 2},
{2, 1, 0},
{1, 2, 0}
};
PRInt64 tdbCompareRecords(TDBRecord* r1, TDBRecord* r2, PRInt32 comparerule)
{
int i, k;
PRInt64 cmp;
if (comparerule == -1) {
cmp = r1->length - r2->length;
if (cmp != 0) return cmp;
return r1->position - r2->position;
}
PR_ASSERT(comparerule >= 0 && comparerule < NUMTREES);
for (i=0 ; i<3 ; i++) {
k = key[comparerule][i];
cmp = tdbCompareNodes(r1->data[k], r2->data[k]);
if (cmp != 0) return cmp;
}
return 0;
}

431
db/tripledb/src/rtype.c Normal file
Просмотреть файл

@ -0,0 +1,431 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#include "tdbtypes.h"
#include "node.h"
#include "rtype.h"
#include "tdb.h"
#include "util.h"
#include "vector.h"
struct _TDBRType {
TDBBase* base;
TDBRType* next;
char* name;
TDBUint8 code;
TDBInt32 numfields;
TDBInt32 fieldnum[TDB_MAXTYPES];
DB* db;
};
TDBRType*
tdbRTypeNew(TDBBase* base, const char* name, TDBUint8 code,
TDBInt32 numfields, TDBInt32* fieldnum)
{
TDBInt32 i;
TDBRType* result;
TDBRType* first;
int dbstatus;
first = tdbGetFirstRType(base);
if (numfields <= 0 || numfields > TDB_MAXTYPES || fieldnum == NULL) {
tdb_ASSERT(0);
return NULL;
}
for (result = first ; result ; result = result->next) {
if (result->code == code) {
tdb_ASSERT(0);
return NULL;
}
}
result = tdb_NEWZAP(TDBRType);
if (!result) return NULL;
result->base = base;
result->name = tdb_strdup(name);
if (!result->name) {
tdb_Free(result);
return NULL;
}
result->code = code;
result->numfields = numfields;
result->next = first;
tdbSetFirstRType(base, result);
for (i=0 ; i<numfields ; i++) {
result->fieldnum[i] = fieldnum[i];
}
dbstatus = db_create(&(result->db), tdbGetDBEnv(base), 0);
if (dbstatus != DB_OK) goto FAIL;
dbstatus = result->db->open(result->db, name, NULL, DB_BTREE,
DB_CREATE, 0666);
if (dbstatus != DB_OK) goto FAIL;
return result;
FAIL:
tdbRTypeFree(result);
return NULL;
}
void tdbRTypeFree(TDBRType* rtype)
{
TDBRType* first;
if (!rtype) {
tdb_ASSERT(0);
return;
}
first = tdbGetFirstRType(rtype->base);
if (first == rtype) {
tdbSetFirstRType(rtype->base, first->next);
} else {
for (; first ; first = first->next) {
if (first->next == rtype) {
first->next = rtype->next;
break;
}
}
}
if (rtype->name) tdb_Free(rtype->name);
if (rtype->db) {
rtype->db->close(rtype->db, 0);
}
tdb_Free(rtype);
}
TDBBase*
tdbRTypeGetBase(TDBRType* rtype)
{
if (!rtype) {
tdb_ASSERT(0);
return NULL;
}
return rtype->base;
}
TDBUint8
tdbRTypeGetCode(TDBRType* rtype)
{
if (!rtype) {
tdb_ASSERT(0);
return 0;
}
return rtype->code;
}
const char*
tdbRTypeGetName(TDBRType* rtype)
{
if (!rtype) {
tdb_ASSERT(0);
return 0;
}
return rtype->name;
}
TDBInt32
tdbRTypeGetNumFields(TDBRType* rtype)
{
if (!rtype) {
tdb_ASSERT(0);
return 0;
}
return rtype->numfields;
}
TDBStatus
tdbRTypeIndexGetField(TDBRType* rtype, TDBInt32 which, TDBInt32* fieldnum)
{
if (!rtype || which < 0 || which >= rtype->numfields) {
tdb_ASSERT(0);
return TDB_FAILURE;
}
if (fieldnum) *fieldnum = rtype->fieldnum[which];
return TDB_SUCCESS;
}
TDBRType*
tdbRTypeFromCode(TDBBase* base, TDBUint8 code)
{
TDBRType* result;
tdb_ASSERT((code & TDB_FREERECORD) == 0);
for (result = tdbGetFirstRType(base); result ; result = result->next) {
if (result->code == code) break;
}
return result;
}
TDBRType* tdbRTypeGetNextRType(TDBRType* rtype)
{
if (rtype == NULL) {
tdb_ASSERT(0);
return NULL;
}
return rtype->next;
}
#define FIELDTYPE(i) ((i)==0 ? TDBTYPE_INT64 : ((i)==1 ? TDBTYPE_INTERNED : 0))
static TDBStatus
loadKeyData(TDBRType* rtype, DBT* key, TDBVector* vector)
{
char* keydata;
TDBNodePtr node;
TDBInt32 i;
TDBInt32 w;
char* ptr;
char* endptr;
if (rtype == NULL || vector == NULL ||
tdbVectorGetNumFields(vector) != rtype->numfields) {
tdb_ASSERT(0);
return TDB_FAILURE;
}
keydata = tdbGrowTmpBuf(rtype->base, 512);
if (keydata == NULL) {
tdb_ASSERT(0);
return TDB_FAILURE;
}
ptr = keydata;
endptr = ptr + tdbGetTmpBufSize(rtype->base);
for (i=0 ; i<rtype->numfields ; i++) {
w = rtype->fieldnum[i];
node = tdbVectorGetInternedNode(vector, w);
switch (w) {
case 1:
if (node->type != TDBTYPE_INTERNED) {
tdb_ASSERT(0);
return TDB_FAILURE;
}
tdbPutUInt32(&ptr, node->d.i, endptr);
break;
default:
tdb_ASSERT(w == 0 || w == 2);
if (tdbPutNode(&ptr, node, endptr) != TDB_SUCCESS) {
ptr = endptr;
}
break;
}
}
tdbPutUInt8(&ptr, tdbVectorGetLayer(vector), endptr);
tdbPutUInt8(&ptr, tdbVectorGetFlags(vector), endptr);
if (ptr >= endptr) {
if (tdbGrowTmpBuf(rtype->base, sizeof(TDBUint64) + sizeof(TDBUint32) +
tdbNodeSize(tdbVectorGetInternedNode(vector, 2))
+ 10) != TDB_SUCCESS) return TDB_FAILURE;
return loadKeyData(rtype, key, vector);
}
key->data = keydata;
key->size = ptr - keydata;
return TDB_SUCCESS;
}
TDBStatus
tdbRTypeAdd(TDBRType* rtype, TDBVector* vector)
{
DBT key;
DBT data;
int dbstatus;
TDBUint32 recordnum;
char buf[10];
char* ptr;
char* endptr;
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
if (loadKeyData(rtype, &key, vector) != TDB_SUCCESS) {
return TDB_FAILURE;
}
recordnum = tdbVectorGetRecordNumber(vector);
tdb_ASSERT(recordnum > 0);
ptr = buf;
endptr = buf + sizeof(buf);
tdbPutUInt32(&ptr, recordnum, endptr);
data.data = buf;
data.size = ptr - buf;
/* tdb_ASSERT(rtype->tdb->transaction != NULL); */
dbstatus = rtype->db->put(rtype->db, tdbGetTransaction(rtype->base),
&key, &data, 0);
if (dbstatus != DB_OK) return TDB_FAILURE;
return TDB_SUCCESS;
}
TDBStatus
tdbRTypeRemove(TDBRType* rtype, TDBVector* vector)
{
DBT key;
int dbstatus;
memset(&key, 0, sizeof(key));
if (loadKeyData(rtype, &key, vector) != TDB_SUCCESS) {
return TDB_FAILURE;
}
dbstatus = rtype->db->del(rtype->db, tdbGetTransaction(rtype->base),
&key, 0);
if (dbstatus != DB_OK) return TDB_FAILURE;
return TDB_SUCCESS;
}
DBC*
tdbRTypeGetCursor(TDBRType* rtype, TDBVector* vector)
{
DBT key;
DBT data;
int dbstatus;
DBC* cursor;
if (rtype == NULL || vector == NULL) {
tdb_ASSERT(0);
return NULL;
}
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
if (loadKeyData(rtype, &key, vector) != TDB_SUCCESS) {
return NULL;
}
dbstatus = rtype->db->cursor(rtype->db, NULL,
&cursor, 0);
if (dbstatus != DB_OK) return NULL;
dbstatus = cursor->c_get(cursor, &key, &data, DB_SET_RANGE);
if (dbstatus != DB_OK) {
cursor->c_close(cursor);
return NULL;
}
return cursor;
}
TDBVector*
tdbRTypeGetCursorValue(TDBRType* rtype, DBC* cursor, int dbflags)
{
DBT key;
DBT data;
TDBNodePtr nodes[20];
int dbstatus;
TDBInt32 i;
TDBInt32 w;
char* ptr;
char* endptr;
TDBUint8 layer;
TDBUint8 flags;
TDBUint32 recordnum;
TDBVector* result;
if (rtype == NULL || cursor == NULL ||
rtype->numfields > sizeof(nodes) / sizeof(nodes[0])) {
tdb_ASSERT(0);
return NULL;
}
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
dbstatus = cursor->c_get(cursor, &key, &data, dbflags);
if (dbstatus == DB_NOTFOUND) return NULL;
if (dbstatus != DB_OK) return NULL;
ptr = key.data;
endptr = ptr + key.size;
for (i=0 ; i<rtype->numfields ; i++) {
w = rtype->fieldnum[i];
switch (w) {
case 1:
nodes[w] = TDBCreateIntNode(tdbGetUInt32(&ptr, endptr),
TDBTYPE_INTERNED);
break;
default:
nodes[w] = tdbGetNode(&ptr, endptr);
break;
}
if (nodes[w] == NULL) {
for (i-- ; i>=0 ; i--) {
w = rtype->fieldnum[i];
TDBFreeNode(nodes[w]);
}
return NULL;
}
}
layer = tdbGetUInt8(&ptr, endptr);
flags = tdbGetUInt8(&ptr, endptr);
tdb_ASSERT(ptr == endptr);
ptr = data.data;
endptr = ptr + data.size;
recordnum = tdbGetUInt32(&ptr, endptr);
result = tdbVectorNewFromNodes(rtype->base, nodes, layer, flags,
recordnum);
for (i=0 ; i<rtype->numfields ; i++) {
w = rtype->fieldnum[i];
TDBFreeNode(nodes[w]);
}
return result;
}
TDBStatus
tdbRTypeSync(TDBRType* rtype)
{
if (rtype == NULL) {
tdb_ASSERT(0);
return TDB_FAILURE;
}
if (rtype->db->sync(rtype->db, 0) != DB_OK) return TDB_FAILURE;
return TDB_SUCCESS;
}
extern TDBBool
tdbRTypeProbe(TDBRType* rtype, TDBVector* vector)
{
TDBBool result = TDB_FALSE;
DBC* cursor;
TDBVector* v;
cursor = tdbRTypeGetCursor(rtype, vector);
if (!cursor) {
return TDB_FALSE;
}
v = tdbRTypeGetCursorValue(rtype, cursor, DB_CURRENT);
cursor->c_close(cursor);
if (v) {
if (tdbVectorEqual(vector, v)) {
result = TDB_TRUE;
}
tdbVectorFree(v);
}
return result;
}

111
db/tripledb/src/rtype.h Normal file
Просмотреть файл

@ -0,0 +1,111 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#ifndef _rtype_h_
#define _rtype_h_ 1
extern TDBRType* tdbRTypeNew(TDBBase* base, const char* name, TDBUint8 code,
TDBInt32 numfields, TDBInt32* fieldnums);
/* tdbRTypeFree() frees the given rtype. */
extern void tdbRTypeFree(TDBRType* rtype);
/* tdbRTypeGetBase() gets the TDB associated with this rtype. */
extern TDBBase* tdbRTypeGetBase(TDBRType* rtype);
/* tdbRTypeGetCode() returns the code associated with the given rtype. */
extern TDBUint8 tdbRTypeGetCode(TDBRType* rtype);
/* tdbRTypeGetName() returns the name associated with the given rtype. */
extern const char* tdbRTypeGetName(TDBRType* rtype);
/* tdbRTypeGetNumFields() returns how many fields this type has. If it is
an index, this is the number of fields it indexes; if it is a base type,
this is the number of different values we are storing in this type; if it
is an extension type, this is zero. */
extern TDBInt32 tdbRTypeGetNumFields(TDBRType* rtype);
/* tdbRTypeIndexGetField() returns information about one field that this type
indexes. */
extern TDBStatus tdbRTypeIndexGetField(TDBRType* rtype, TDBInt32 which,
TDBInt32* fieldnum);
/* tdbRTypeFromCode() returns the rtype entry given the code number. */
extern TDBRType* tdbRTypeFromCode(TDBBase* base, TDBUint8 code);
/* tdbRTypeGetNextRType() gets the next rtype from the master list of all
rtypes. */
extern TDBRType* tdbRTypeGetNextRType(TDBRType* rtype);
extern TDBStatus tdbRTypeAdd(TDBRType* rtype, TDBVector* vector);
extern TDBStatus tdbRTypeRemove(TDBRType* rtype, TDBVector* vector);
/* tdbRTypeGetCursor() gets a DB cursor into this index, and starts it pointing
at the first node greater than or equal to the given vector. */
extern DBC* tdbRTypeGetCursor(TDBRType* rtype, TDBVector* vector);
/* tdbRTypeGetCursorValue() passes the given flags to the cursor, and retrieves
the value of the resulting position of the cursor, translating it to
a TDBVector. */
extern TDBVector* tdbRTypeGetCursorValue(TDBRType* rtype, DBC* cursor,
int flags);
/* tdbRTypeSync() causes any changes made to this object to be written out
to disk. */
extern TDBStatus tdbRTypeSync(TDBRType* rtype);
/* tdbRTypeProbe() determines whether the given vector seems to be included
as part of this index. */
extern TDBBool tdbRTypeProbe(TDBRType* rtype, TDBVector* vector);
#endif /* _rtype_h_ */

Разница между файлами не показана из-за своего большого размера Загрузить разницу

117
db/tripledb/src/tdb.h Normal file
Просмотреть файл

@ -0,0 +1,117 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#ifndef _tdb_h_
#define _tdb_h_ 1
/* tdbGetFID() gets the file descripter for the database file. */
extern TDBFileDesc* tdbGetFID(TDBBase* base);
/* tdbMarkCorrupted() marks the tdb as being corrupted. */
extern void tdbMarkCorrupted(TDBBase* base);
/* tdbMarkTooBustedToRecover() marks the tdb as being so corrupted that we
shouldn't try to recover from it. */
extern void tdbMarkTooBustedToRecover(TDBBase* base);
/* tdbGetFileLength() gets the current length of the file. */
extern TDBPtr tdbGetFileLength(TDBBase* base);
/* tdbSetFileLength() sets in memory a new idea as to the current
length of the file. Should only be used by the page.c module, when
it adds a new page to the file. */
extern TDBStatus tdbSetFileLength(TDBBase* base, TDBPtr length);
/* tdbGetFirstRType() returns the first rtype. This should only be used by
the rtype.c module. */
extern TDBRType* tdbGetFirstRType(TDBBase* base);
/* tdbSetFirstRType() sets the first rtype. This should only be used by
the rtype.c module. */
extern TDBStatus tdbSetFirstRType(TDBBase* base, TDBRType* rtype);
/* tdbGetFirstCursor() returns the first cursor. This should only be used by
the cursor.c module. */
extern TDBCursor* tdbGetFirstCursor(TDB* tdb);
/* tdbSetFirstCursor() sets the first cursor. This should only be used by
the cursor.c module. */
extern TDBStatus tdbSetFirstCursor(TDB* tdb, TDBCursor* cursor);
extern void tdbBeginExclusiveOp(TDBBase* base);
extern void tdbEndExclusiveOp(TDBBase* base);
extern char* tdbGrowTmpBuf(TDBBase* base, TDBInt32 newsize);
extern TDBInt32 tdbGetTmpBufSize(TDBBase* base);
extern DB* tdbGetRecordDB(TDBBase* base);
extern TDBBase* tdbGetBase(TDB* base);
extern TDBStatus tdbRecover(TDBBase* base);
extern TDBWindex* tdbGetWindex(TDBBase* base);
extern TDBPendingCall* tdbGetFirstPendingCall(TDBBase* base);
extern void tdbSetFirstPendingCall(TDBBase* base, TDBPendingCall* call);
extern TDBPendingCall* tdbGetLastPendingCall(TDBBase* base);
extern void tdbSetLastPendingCall(TDBBase* base, TDBPendingCall* call);
extern DB_ENV* tdbGetDBEnv(TDBBase* base);
extern TDBIntern* tdbGetIntern(TDBBase* base);
extern DB_TXN* tdbGetTransaction(TDBBase* base);
extern TDBInt32 tdbGetNumIndices(TDBBase* base);
extern TDBRType* tdbGetIndex(TDBBase* base, TDBInt32 which);
extern TDBInt32 tdbGetNumLayers(TDB* tdb);
extern TDBInt32 tdbGetLayer(TDB* tdb, TDBInt32 which);
extern TDBInt32 tdbGetOutLayer(TDB* tdb);
#endif /* _tdb_h_ */

Просмотреть файл

@ -14,7 +14,7 @@
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 1999 Geocast Network Systems. All
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
@ -24,7 +24,83 @@
#define _TDBapi_h_ 1
/* All things are prefixed with TDB, which stands for "Triples
DataBase". Suggestions for better names are always welcome. */
DataBase". */
/* TDB can be built with or without NSPR. If built with NSPR, then it can be
built with thread support. If you want to built it with some non-NSPR
threading package, you'll have to do some hacking. */
#define TDB_USE_NSPR 1
#define TDB_USE_THREADS 1
#ifdef TDB_USE_NSPR
#include "prtypes.h"
#include "prtime.h"
#include "prmem.h"
typedef PRInt16 TDBInt16;
typedef PRInt32 TDBInt32;
typedef PRInt64 TDBInt64;
typedef PRInt8 TDBInt8;
typedef PRTime TDBTime;
typedef PRUint8 TDBUint8;
typedef PRUint16 TDBUint16;
typedef PRUint32 TDBUint32;
typedef PRUint64 TDBUint64;
typedef PRBool TDBBool;
#define TDB_TRUE PR_TRUE
#define TDB_FALSE PR_FALSE
#define TDB_BEGIN_EXTERN_C PR_BEGIN_EXTERN_C
#define TDB_END_EXTERN_C PR_END_EXTERN_C
#define TDB_EXTERN(t) PR_EXTERN(t)
typedef struct PRFileDesc TDBFileDesc;
#define tdb_NEWZAP(x) PR_NEWZAP(x)
#define tdb_Malloc PR_Malloc
#define tdb_Calloc(x,y) PR_Calloc(x,y)
#define tdb_Realloc(x,y) PR_Realloc(x,y)
#define tdb_Free(x) PR_Free(x)
#else
#include <stdio.h>
typedef short TDBInt16;
typedef int TDBInt32;
typedef long long TDBInt64;
typedef signed char TDBInt8;
typedef TDBInt64 TDBTime;
typedef unsigned char TDBUint8;
typedef unsigned short TDBUint16;
typedef unsigned long TDBUint32;
typedef unsigned long long TDBUint64;
typedef int TDBBool;
#define TDB_TRUE 1
#define TDB_FALSE 0
#define TDB_BEGIN_EXTERN_C
#define TDB_END_EXTERN_C
#define TDB_EXTERN(t) extern t
#define TDBFileDesc FILE
#define tdb_NEWZAP(x) ((x*)calloc(1, sizeof(x)))
#define tdb_Malloc malloc
#define tdb_Calloc(x,y) calloc(x,y)
#define tdb_Realloc(x,y) realloc(x,y)
#define tdb_Free(x) free(x)
#endif /* TDB_USE_NSPR */
typedef enum { TDB_FAILURE = -1, TDB_SUCCESS = 0 } TDBStatus;
/* A TDBNode contains one of the three items in a triple. This is a
structure that defines a very basic type, strings or ints or dates.
@ -32,29 +108,35 @@
then this is where we muck things.
It is important that all nodes be strictly ordered. All the integer values
sort together in the obvious way. PRTimes get sorted with them by treating
them as if they were PRInt64's. All strings are considered to be greater
sort together in the obvious way. TDBTimes get sorted with them by treating
them as if they were TDBInt64's. All strings are considered to be greater
than all integers. */
#define TDBTYPE_INT8 1 /* 8-bit signed integer */
#define TDBTYPE_INT16 2 /* 16-bit signed integer */
#define TDBTYPE_INT32 3 /* 32-bit signed integer */
#define TDBTYPE_INT64 4 /* 64-bit signed integer */
#define TDBTYPE_TIME 5 /* NSPR date&time stamp (PRTime) */
#define TDBTYPE_STRING 6 /* A string (up to 65535 chars long) */
#define TDBTYPE_INT32 1 /* 32-bit signed integer */
#define TDBTYPE_INT64 2 /* 64-bit signed integer */
#define TDBTYPE_ID 3 /* A 64-bit unsigned identifier, generally used
to represent an RDF resource. */
#define TDBTYPE_TIME 4 /* NSPR-style date&time stamp -- number of
microseconds since midnight,
1/1/1970, GMT. */
#define TDBTYPE_STRING 5 /* A string (up to 65535 chars long) */
#define TDBTYPE_BLOB 6 /* A blob, which is just like a string, except
it is not considered to have searchable text
in it.) */
typedef struct {
PRInt8 type;
TDBInt8 type;
union {
PRInt64 i; /* All the int types are stored here, as an
Int64. The type just indicates how it is to be
stored in the database. */
TDBInt64 i; /* All the int types are stored here, as an
Int64. The type just indicates how it is to be
stored in the database. */
TDBUint64 id; /* Unsigned 64-bit identifier. */
struct {
PRUint16 length;
TDBUint16 length;
char string[1];
} str;
PRTime time;
} str; /* Used for both blobs and strings. */
TDBTime time;
} d;
} TDBNode, *TDBNodePtr;
@ -65,36 +147,30 @@ typedef struct {
typedef struct {
TDBNodePtr data[3];
TDBBool asserted; /* If TRUE, then this is a normal triple.
If FALSE, then this is a triple that we
have explicitely turned off using
TDBAddFalse(). The only way to get such
triples from a query is to turn on the
includefalse member of the
TDBSortSpecification passed to
TDBQuery(). */
} TDBTriple;
/* A TDBNodeRange specifies a range of values for a node. If min is
not NULL, then this matches only nodes that are greater than or
equal to min. If max is not NULL, then this matches only nodes
that are less than or equal to max. Therefore, if both min and
max are NULL, then this specifies the range of all possible nodes.
If min and max are not NULL, and are the same value, then it specifies
exactly that value. */
typedef struct {
TDBNodePtr min;
TDBNodePtr max;
} TDBNodeRange;
/* A TDBSortSpecification specifies what order results from a request should
come in. I suspect that there will someday be much more to it than this. */
typedef struct {
PRBool reverse; /* If true, then return biggest results
TDBBool reverse; /* If true, then return biggest results
first. Otherwise, the smallest
stuff comes first. */
PRInt16 keyorder[3]; /* Specify which keys to sort in. If you use
TDBInt16 keyorder[3]; /* Specify which keys to sort in. If you use
this, then each of the three entries must
be a unique number between 0 and 2. For
example, if:
keyorder[0] == 1
keyorder[0] == 1
keyorder[1] == 2
keyorder[2] == 0
then results will be returned sorted
@ -115,19 +191,22 @@ typedef struct {
pick the order it can do most
efficiently.)
Practically speaking, the only reason to
ever set the keyorder is if your request
only gives values for one of the ranges,
and you want to specify which order the
other fields should be sorted in. And
keyorder[0] had better specify which
entry is the non-NULL one, or things will
be very slow.
Practically speaking, there is currently
no reason to ever set this stuff.
*/
TDBBool includefalse; /* Whether this query should include entries
that were added using TDBAddFalse(). If
so, such entries will have the asserted
field the TDBTriple structure turned off. */
} TDBSortSpecification;
/* A TDB* is an opaque pointer that represents an entire database. */
/* A TDBBase* is an opaque pointer that represents an entire database. */
typedef struct _TDBBase TDBBase;
/* A TDB* is an opaque pointer that represents a view on a database. */
typedef struct _TDB TDB;
@ -139,109 +218,162 @@ typedef struct _TDB TDB;
typedef struct _TDBCursor TDBCursor;
/* TDBCallbackFunction is for callbacks notifying of certain database
changes. */
typedef void (*TDBCallbackFunction)(TDB* database, void* closure,
TDBTriple* triple,
PRInt32 action); /* One of the below
TDBACTION_* values. */
#define TDBACTION_ADDED 1 /* The given triple has been added to the
database. */
#define TDBACTION_REMOVED 2 /* The given triple has been removed from the
database. */
PR_BEGIN_EXTERN_C
TDB_BEGIN_EXTERN_C
/* Open a database (creating it if non-existant). Returns NULL on failure. */
/* TDBOpenBase() opens a database from a file (creating it if non-existant).
Returns NULL on failure. */
PR_EXTERN(TDB*) TDBOpen(const char* filename);
TDB_EXTERN(TDBBase*) TDBOpenBase(const char* filename);
/* Close an opened database. Frees the storage for TDB; you may not use
that pointer after that call. Will flush out any changes that have
been made. This call will fail if you have not freed up all of the
cursors that were created with TDBQuery. */
/* TDBOpenLayers() opens a database, looking at the given layers. The layers
are given in priority order (earlier listed layers override later ones).
The first layer is the one that is to be changed by any calls that
add or remove triples.
PR_EXTERN(PRStatus) TDBClose(TDB* database);
### Need to add here or somewhere a lecture on what 'layers' are all
about. */
TDB_EXTERN(TDB*) TDBOpenLayers(TDBBase* base, TDBInt32 numlayers,
TDBInt32* layers);
/* TDBBlowAwayDatabaseFiles() blows away all database files associated with
the given pathname. This very much is throwing away real data; use this
call with care! */
TDB_EXTERN(TDBStatus) TDBBlowAwayDatabaseFiles(const char* filename);
/* TDBGetFilename() returns the filename associated with the database. The
returned string should not be modified in any way. */
const char* TDBGetFilename(TDB* database);
/* TDBClose() closes an opened database. Frees the storage for TDB; you may
not use that pointer after that call. Will flush out any changes that have
been made. This call will fail if you have not freed up all of the cursors
that were created with TDBQuery. */
TDB_EXTERN(TDBStatus) TDBClose(TDB* database);
/* TDBCloseBase() closes the base database file. This call will fail if you
have not freed up all of the database views that were created with
TDBOpenLayers(). */
TDB_EXTERN(TDBStatus) TDBCloseBase(TDBBase* base);
/* TDBSync() makes sure that any changes made to the database have been written
out to disk. It effectively gets called by TDBClose(), and may also be
implicitely called from time to time. */
TDB_EXTERN(TDBStatus) TDBSync(TDB* database);
/* TDBQuery() returns a cursor that you can use with TDBNextResult() to get
#ifdef TDB_USE_THREADS
/* TDBGetBG() returns the TDBBG* object (see tdbbg.h) that represents the
thread tripledb uses for its background operations. If you would like
that thread to do some other background operations, you can queue them
up. That can interfere with the performance of tripledb, so you may
want to create your own TDBBG* object instead. */
TDB_EXTERN(struct _TDBBG*) TDBGetBG(TDB* database);
#endif
/* TDBQuery() returns a cursor that you can use with TDBGetResult() to get
the results of a query. It will return NULL on failure. If the query
is legal, but there are no matching results, this will *not* return
NULL; it will return a cursor that will have no results.
If a single value is specified for both range[0] and range[1], then the
results are guaranteed to be sorted by range[2]. If a single value is
specified for both range[1] and range[2], then the results are guaranteed
to be sorted by range[0]. No other sorting rules are promised (at least,
not yet.)
If a member of a the given triple is not NULL, then only triples with the
identical value in that position will be returned. If it is NULL, then
all possible triples are returned.
A NULL TDBSortSpecification can be provided, which will sort in the
default manner. */
PR_EXTERN(TDBCursor*) TDBQuery(TDB* database, TDBNodeRange range[3],
TDBSortSpecification* sortspec);
If the only variation in triples are values that are of type
TDBTYPE_INT24, then the triples will be sorted by those values.
If a non-NULL sortspec is passed in, and it has the "reverse" field set,
then these int24's will be sorted in descending order; otherwise, they
will be ascending.
/* TDBGetResult returns the next result that matches the cursor, and
A NULL TDBSortSpecification can be provided, which will make the query
behave in the default manner. */
TDB_EXTERN(TDBCursor*) TDBQuery(TDB* database, TDBNodePtr triple[3],
TDBSortSpecification* sortspec);
/* TDBQueryWordSubstring() returns a cursor of all triples whose last element
is a string and matches the given string. It will only match by full words;
that is, if you provide a partial word, it will not match strings that
contain that word inside another one. It will only return strings which
contain the given string as a substring, ignoring case. */
TDB_EXTERN(TDBCursor*) TDBQueryWordSubstring(TDB* database,
const char* string);
/* TDBGetResult() returns the next result that matches the cursor, and
advances the cursor to the next matching entry. It will return NULL
when there are no more matching entries. The returned triple must
not be modified in any way by the caller, and is valid only until
the next call to TDBGetResult(), or until the cursor is freed. */
PR_EXTERN(TDBTriple*) TDBGetResult(TDBCursor* cursor);
TDB_EXTERN(TDBTriple*) TDBGetResult(TDBCursor* cursor);
/* TDBCursorGetTDB() returns the base TDB* object that the given cursor is
working on. */
TDB_EXTERN(TDB*) TDBCursorGetTDB(TDBCursor* cursor);
/* TDBFreeCursor frees the cursor. */
PR_EXTERN(PRStatus) TDBFreeCursor(TDBCursor* cursor);
/* TDBAddCallback calls the given function whenever a change to the database
is made that matches the given range. Note that no guarantees are made
about which thread this call will be done in. It is also possible (though
not very likely) that by the time the callback gets called, further changes
may have been made to the database, and the action being notified here has
already been undone. (If that happens, though, you will get another
callback soon.)
It is legal for the receiver of the callback to make any queries or
modifications it wishes to the database. It is probably not a good idea
to undo the action being notified about; this kind of policy leads to
infinite loops.
The receiver should not take unduly long before returning from the callback;
until the callback returns, no other callbacks will occur.
*/
PR_EXTERN(PRStatus) TDBAddCallback(TDB* database, TDBNodeRange range[3],
TDBCallbackFunction func, void* closure);
/* TDBRemoveCallback will remove a callback that was earlier registered with a
call to TDBAddCallback. */
PR_EXTERN(PRStatus) TDBRemoveCallback(TDB* database, TDBNodeRange range[3],
TDBCallbackFunction func, void* closure);
TDB_EXTERN(TDBStatus) TDBFreeCursor(TDBCursor* cursor);
/* TDBRemove() removes all entries matching the given parameters from
the database. */
PR_EXTERN(PRStatus) TDBRemove(TDB* database, TDBNodeRange range[3]);
TDB_EXTERN(TDBStatus) TDBRemove(TDB* database, TDBNodePtr triple[3]);
/* TDBAdd() adds a triple into the database. */
/* TDBAdd() adds a triple into the database. The "owner" of each triple
is recorded, so that we can later remove all things owned by a given
owner. */
PR_EXTERN(PRStatus) TDBAdd(TDB* database, TDBNodePtr triple[3]);
TDB_EXTERN(TDBStatus) TDBAdd(TDB* database, TDBNodePtr triple[3],
TDBUint64 owner);
/* TDBAddFalse() adds a triple into the database that explicitely asserts that
this triple is *not* to be considered part of the database. It is useful
when this database gets merged into a bigger database (using
TDBOpenMergedDatabase()). In that case, this triple will not be returned
by queries, even if it appears in an earlier database on the merge list. */
TDB_EXTERN(TDBStatus) TDBAddFalse(TDB* database, TDBNodePtr triple[3],
TDBUint64 owner);
/* TDBReplace() looks for an existing entry that matches triple[0] and
@ -251,7 +383,8 @@ PR_EXTERN(PRStatus) TDBAdd(TDB* database, TDBNodePtr triple[3]);
sense if you know up-front that there is no more than one existing
triple with the given "subject" and "verb". */
PR_EXTERN(PRStatus) TDBReplace(TDB* database, TDBNodePtr triple[3]);
TDB_EXTERN(TDBStatus) TDBReplace(TDB* database, TDBNodePtr triple[3],
TDBUint64 owner);
@ -259,7 +392,7 @@ PR_EXTERN(PRStatus) TDBReplace(TDB* database, TDBNodePtr triple[3]);
allocates a new TDBNode that represents the given string. The
TDBNode can be free'd using TDBFreeNode(). */
PR_EXTERN(TDBNodePtr) TDBCreateStringNode(const char* string);
TDB_EXTERN(TDBNodePtr) TDBCreateStringNode(const char* string);
/* TDBCreateIntNode() is just a utility routine that correctly
@ -267,13 +400,28 @@ PR_EXTERN(TDBNodePtr) TDBCreateStringNode(const char* string);
TDBNode can be free'd using TDBFreeNode(). You must specify
the correct TDBTYPE_* value for it. */
PR_EXTERN(TDBNodePtr) TDBCreateIntNode(PRInt64 value, PRInt8 type);
TDB_EXTERN(TDBNodePtr) TDBCreateIntNode(TDBInt64 value, TDBInt8 type);
/* Free up a node created with TDBCreateStringNode or TDBCreateIntNode. */
PR_EXTERN(void) TDBFreeNode(TDBNodePtr node);
TDB_EXTERN(void) TDBFreeNode(TDBNodePtr node);
PR_END_EXTERN_C
/* TDBCompareNodes() compares two nodes. Returns negative if the first is less
than the second, zero if they are equal, positive if the first is greater.
Note That this returns a 64-bit int; be careful! */
TDB_EXTERN(TDBInt64) TDBCompareNodes(TDBNode* n1, TDBNode* n2);
/* TDBNodeDup allocates a new node object, and initializes it to have the
same value as the given object. Returns NULL on failure. */
TDB_EXTERN(TDBNodePtr) TDBNodeDup(TDBNodePtr node);
TDB_END_EXTERN_C
#endif /* _TDBapi_h_ */

72
db/tripledb/src/tdbbg.h Normal file
Просмотреть файл

@ -0,0 +1,72 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#ifndef _tdbbg_h_
#define _tdbbg_h_ 1
typedef struct _TDBBG TDBBG;
typedef void (*TDBBG_Function)(void* closure);
TDB_BEGIN_EXTERN_C
#define TDBBG_PRIORITY_HIGH 100
#define TDBBG_PRIORITY_NORMAL 50
#define TDBBG_PRIORITY_LOW 0
TDB_EXTERN(TDBBG*) TDBBG_Open();
TDB_EXTERN(TDBStatus) TDBBG_Close(TDBBG* tdbbg);
TDB_EXTERN(TDBStatus) TDBBG_AddFunction(TDBBG* tdbbg, const char* name,
TDBInt32 secondsToWait,
TDBInt32 priority,
TDBBG_Function func, void* closure);
TDB_EXTERN(TDBStatus) TDBBG_RescheduleFunction(TDBBG* tdbbg, const char* name,
TDBInt32 secondsToWait,
TDBInt32 priority,
TDBBG_Function func,
void* closure);
TDB_EXTERN(TDBStatus) TDBBG_RemoveFunction(TDBBG* tdbbg, const char* name,
TDBBG_Function func, void* closure);
/* TDBBG_WaitUntilIdle() waits until the background thread is idle doing
nothing. This is occasionally useful, when you want to make sure any
immediate background tasks you may have had are not doing anything. Note
that this will *not* wait for any things that are scheduled off into the
future; it only looks for immediately scheduled tasks. */
TDB_EXTERN(TDBStatus) TDBBG_WaitUntilIdle(TDBBG* tdbbg);
TDB_END_EXTERN_C
#endif /* _tdbbg_h_ */

Просмотреть файл

@ -14,7 +14,7 @@
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 1999 Geocast Network Systems. All
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
@ -23,18 +23,18 @@
/* These are debugging routines for the TDB. Don't use any of these calls
in production code! */
extern void TDBDumpNode(PRFileDesc* fid, TDBNode* node);
extern void TDBDumpTree(PRFileDesc* fid, TDB* db, PRInt32 tree);
extern void TDBDumpNode(TDBFileDesc* fid, TDBNode* node);
extern void TDBDumpTree(TDBFileDesc* fid, TDB* db, TDBInt32 tree);
extern PRStatus TDBSanityCheck(TDB* db, PRFileDesc* fid);
extern TDBStatus TDBSanityCheck(TDBBase* base, TDBFileDesc* fid);
extern void TDBGetCursorStats(TDBCursor* cursor,
PRInt32* hits,
PRInt32* misses);
TDBInt32* hits,
TDBInt32* misses);
/* Create a "dot" graph file. To view these, and learn more about them,
see http://www.research.att.com/~north/cgi-bin/webdot.cgi */
extern void TDBMakeDotGraph(TDB* db, const char* filename, PRInt32 tree);
extern void TDBMakeDotGraph(TDB* db, const char* filename, TDBInt32 tree);

Просмотреть файл

@ -0,0 +1,61 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#ifndef _TDBexperimental_h_
#define _TDBexperimental_h_ 1
/* These are experimental APIs. You should not use them in real code; you
should only use them if you fully understand the fragility of the APIs,
etc., etc.*/
/* TDBGetTripleID() gets a unique identifier that represents a triple in the
database. You can later call TDBFindTripleFromID() to get back the
same triple. This will return TDB_FAILURE if the given triple is not
actually stored in the database.
The top four bits of the returned ID is guaranteed to be zero. */
TDB_EXTERN(TDBStatus) TDBGetTripleID(TDB* database, TDBNodePtr triple[3],
TDBInt64* id);
/* TDBFindTripleFromID() returns the triple that corresponds to the given ID.
It is potentially fatal to call this with an illegal ID (though we try real
hard to detect that case and return NULL instead). The returned triple
must be free'd with TDBFreeTriple().
*/
TDB_EXTERN(TDBTriple*) TDBFindTripleFromID(TDB* database, TDBInt64 id);
/* TDBFreeTriple() is used to free a triple returned from
TDBFindTripleFromID(). It must *not* be used on a triple returned from
TDBGetResult(); the TDB code is responsible for freeing those. */
TDB_EXTERN(void) TDBFreeTriple(TDBTriple* triple);
#endif /* _TDBexperimental_h_ */

94
db/tripledb/src/tdbimpl.h Normal file
Просмотреть файл

@ -0,0 +1,94 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#ifndef _TDBimpl_h_
#define _TDBimpl_h_ 1
typedef struct {
TDBStatus (*close)(TDB* database);
void* (*query)(TDB* database, TDBNodePtr triple[3],
TDBSortSpecification* sortspec);
TDBTriple* (*getresult)(void* cursor);
TDBStatus (*freecursor)(void* cursor);
TDBStatus (*remove)(TDB* database, TDBNodePtr triple[3]);
TDBStatus (*add)(TDB* database, TDBNodePtr triple[3], TDBUint64 owner);
TDBStatus (*addfalse)(TDB* database, TDBNodePtr triple[3],
TDBUint64 owner);
TDBStatus (*replace)(TDB* database, TDBNodePtr triple[3], TDBUint64 owner);
TDBStatus (*gettripleid)(TDB* db, TDBNodePtr triple[3], TDBInt64* id);
TDBTriple* (*findtriplefromid)(TDB* db, TDBInt64 id);
} TDBImplement;
TDB_BEGIN_EXTERN_C
/* TDBOpenImplementation() opens a database object which supports the calls
listed in tdbapi.h, but whose implentation is provided by some other module.
The implementation is provided as a bunch of function pointers. Each of
the TDB* routines that correspond to the pointers know to implement
themselves entirely by calling the appropriate routine.
NONE OF THESE FUNCTION POINTERS MAY BE NULL! We don't allow inheritence
from the base routines. Sorry!
The void* that are passed to and from the query(), getresult() and
freecursor() routines are implementation-specific instances of the
cursor object. It is up to the implementation how they are done,
although they will almost certainly need to include a pointer back to the
database object, or to the impldata.
The query() routine returns a pointer to a TDBImplCursor object.
The db field in that object should be a pointer back to the
database itself (the same pointer that was passed to query), and should
never be modified. The data field is implementation-specific, and is where
the implementation should hang all state relating to the cursor.
*/
TDB_EXTERN(TDB*) TDBOpenImplementation(TDBImplement* impl);
/* TDBSetImplData() sets implementation-specific data associated with the
database. */
TDB_EXTERN(TDBStatus) TDBSetImplData(TDB* database, void* impldata);
/* TDBGetImplData() gets any implementation-specific data associated with the
database. */
TDB_EXTERN(void*) TDBGetImplData(TDB* database);
/* TDBValidateSortOrder takes a sortspec and range, and makes sure the
keyorder field in the sortspec is correctly filled out.
*/
TDB_EXTERN(void) TDBValidateSortOrder(TDB* tdb, TDBSortSpecification* sortspec,
TDBNodePtr triple[3]);
TDB_END_EXTERN_C
#endif /* _TDBimpl_h_ */

Просмотреть файл

@ -14,7 +14,7 @@
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 1999 Geocast Network Systems. All
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
@ -26,6 +26,11 @@
/* These are private, internal type definitions, */
#include <string.h>
#include "tdbapi.h"
#include "db/db.h"
#ifdef TDB_USE_NSPR
#include "pratom.h"
#include "prcvar.h"
#include "prio.h"
@ -33,28 +38,100 @@
#include "prlog.h"
#include "prmem.h"
#include "prthread.h"
#include "prtime.h"
#include "prtypes.h"
#include "plstr.h"
#include "geoassert/geoassert.h" /* This line can be safely removed if you
are building this in a non-Geocast
environment. */
typedef PRLock TDBLock;
typedef PRThread TDBThread;
typedef PRCondVar TDBCondVar;
#define tdb_Lock(l) PR_Lock(l)
#define tdb_Unlock(l) PR_Unlock(l)
#ifdef GeoAssert
#define tdb_ASSERT(x) GeoAssert(x)
#else
#define tdb_ASSERT(x) PR_ASSERT(x)
#endif
#define tdb_OpenFileRW(filename) PR_Open(filename, PR_RDWR | PR_CREATE_FILE, 0666)
#define tdb_OpenFileReadOnly(filename) PR_Open(filename, PR_RDONLY, 0666)
#define tdb_Close PR_Close
#define tdb_Seek(fid, l) (PR_Seek(fid, l, PR_SEEK_SET) == l ? TDB_SUCCESS : TDB_FAILURE)
#define tdb_Read PR_Read
#define tdb_Write PR_Write
#define tdb_Delete PR_Delete
#define tdb_Rename PR_Rename
#define tdb_MkDir PR_MkDir
#define tdb_strdup PL_strdup
#define tdb_strcasestr PL_strcasestr
#else
#ifdef TDB_USE_THREADS
#undef TDB_USE_THREADS
#endif
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
typedef void* TDBLock;
typedef void* TDBThread;
typedef void* TDBCondVar;
#define tdb_Lock(l) ((void) 0)
#define tdb_Unlock(l) ((void) 0)
#define tdb_ASSERT assert
#define tdb_OpenFileRW(filename) fopen(filename, "r+")
#define tdb_OpenFileReadOnly(filename) fopen(filename, "r")
#define tdb_Close fclose
#define tdb_Seek(fid, l) (fseek(fid, l, SEEK_SET) == l ? TDB_SUCCESS : TDB_FAILURE)
#define tdb_Read(fid, buf, length) fread(buf, 1, length, fid)
#define tdb_Write(fid, buf, length) fwrite(buf, 1, length, fid)
#define tdb_Delete unlink
#define tdb_Rename rename
#define tdb_MkDir mkdir
#define tdb_strdup strdup
#define tdb_strcasestr strstr /* WRONG! Should be a case-independent one!
XXX ### */
#endif /* TDB_USE_NSPR */
/* Special node types that are used internally only. */
#define TDBTYPE_MINNODE 0 /* A node that is less than all other nodes. */
#define TDBTYPE_INTERNED 126 /* An interned string. */
#define TDBTYPE_MAXNODE 127 /* A node that is bigger than all others. */
#include "tdbapi.h"
/* Magic number that appears as first four bytes of db files. */
#define TDB_MAGIC "TDB\n"
/* Total number of bytes we reserve at the beginning of the db file for
special stuff. */
#define TDB_FILEHEADER_SIZE 1024
/* Current version number for db files. */
#define TDB_VERSION 1
#define TDB_MAJOR_VERSION 11
#define TDB_MINOR_VERSION 0
#define NUMTREES 4 /* How many binary trees we're keeping,
indexing the data. */
/* Maximum number of different record types we are prepared to handle. */
#define TDB_MAXTYPES 20
/* The trees index things in the following orders:
0: 0, 1, 2
@ -65,164 +142,56 @@
/* MINRECORDSIZE and MAXRECORDSIZE are the minimum and maximum possible record
size. They're useful for sanity checking. */
#define BASERECORDSIZE (sizeof(PRInt32) + NUMTREES * (2*sizeof(TDBPtr)+sizeof(PRInt8)))
#define BASERECORDSIZE (sizeof(TDBInt32) + NUMTREES * (2*sizeof(TDBPtr)+sizeof(TDBInt8)))
#define MINRECORDSIZE (BASERECORDSIZE + 3 * 2)
#define MAXRECORDSIZE (BASERECORDSIZE + 3 * 65540)
typedef PRInt32 TDBPtr;
/* The meaning of the various flag bits in a record entry. */
typedef struct {
TDBPtr child[2];
PRInt8 balance;
} TDBTreeEntry;
#define TDBFLAG_ISASSERT 0x1 /* On if this entry is an assertion, off
if this entry is a false assertion. */
#define TDBFLAG_ISEXTENDED 0x2 /* On if this entry is incomplete, and the
last four bytes of it is actually a
pointer to an extension record.. */
#define TDBFLAG_KEYINSUFFICIENT 0x4 /* Even though the data in the key may
look like it has enough to regenerate
the entire record content, in fact
it doesn't. This gets set in key
records when string data contains
embedded nulls, since the technique
for getting strings to and from
keys relies on using NULL characters
to mark end-of-string. */
typedef struct _TDBRecord {
TDBPtr position;
PRInt32 length;
PRInt32 refcnt;
PRBool dirty;
struct _TDBRecord* next;
PRUint8 flags;
TDBTreeEntry entry[NUMTREES];
TDBNode* data[3];
} TDBRecord;
/* The meaning of various flag bits in a record-type byte. */
#define TDB_FREERECORD 0x80 /* If set, then this record is in the
free list. */
typedef struct _TDBParentChain {
TDBRecord* record;
struct _TDBParentChain* next;
} TDBParentChain;
/* The meaning of various flag bits in a index record. */
#define TDB_LEAFFLAG 0x1
struct _TDBCursor {
TDB* db;
TDBNodeRange range[3];
TDBRecord* cur;
TDBRecord* lasthit;
TDBParentChain* parent;
PRInt32 tree;
PRBool reverse;
TDBTriple triple;
PRInt32 hits;
PRInt32 misses;
struct _TDBCursor* nextcursor;
struct _TDBCursor* prevcursor;
};
#define DB_OK 0
typedef struct _TDBCallbackInfo {
struct _TDBCallbackInfo* nextcallback;
TDBNodeRange range[3];
TDBCallbackFunction func;
void* closure;
} TDBCallbackInfo;
typedef struct _TDBPendingCall {
struct _TDBPendingCall* next;
TDBCallbackFunction func;
void* closure;
TDBTriple triple;
PRInt32 action;
} TDBPendingCall;
struct _TDB {
char* filename;
PRInt32 filelength;
PRFileDesc* fid;
TDBPtr roots[NUMTREES];
TDBPtr freeroot;
PRBool dirty;
PRBool rootdirty;
PRLock* mutex; /* Used to prevent more than one thread
from doing anything in DB code at the
same time. */
PRThread* callbackthread; /* Thread ID of the background
callback-calling thread. */
PRCondVar* callbackcvargo; /* Used to wake up the callback-calling
thread. */
PRCondVar* callbackcvaridle; /* Used by the callback-calling to indicate
that it is now idle. */
PRBool killcallbackthread;
PRBool callbackidle;
char* iobuf;
PRInt32 iobuflength;
TDBRecord* firstrecord;
TDBCursor* firstcursor;
TDBCallbackInfo* firstcallback;
TDBPendingCall* firstpendingcall;
TDBPendingCall* lastpendingcall;
};
/* ----------------------------- From add.c: ----------------------------- */
extern PRStatus tdbAddToTree(TDB* db, TDBRecord* record, PRInt32 tree);
extern PRStatus tdbRemoveFromTree(TDB* db, TDBRecord* record, PRInt32 tree);
/* ----------------------------- From callback.c: ------------------------- */
extern void tdbCallbackThread(void* closure);
extern PRStatus tdbQueueMatchingCallbacks(TDB* db, TDBRecord* record,
PRInt32 action);
/* ----------------------------- From node.c: ----------------------------- */
extern TDBNode* tdbNodeDup(TDBNode* node);
extern PRInt32 tdbNodeSize(TDBNode* node);
extern PRInt64 tdbCompareNodes(TDBNode* n1, TDBNode* n2);
extern TDBNode* tdbGetNode(TDB* db, char** ptr);
extern void tdbPutNode(TDB* db, char** ptr, TDBNode* node);
/* ----------------------------- From query.c: ----------------------------- */
extern TDBCursor* tdbQueryNolock(TDB* db, TDBNodeRange range[3],
TDBSortSpecification* sortspec);
extern PRStatus tdbFreeCursorNolock(TDBCursor* cursor);
extern TDBTriple* tdbGetResultNolock(TDBCursor* cursor);
extern PRInt64 tdbCompareToRange(TDBRecord* record, TDBNodeRange* range,
PRInt32 comparerule);
extern PRBool tdbMatchesRange(TDBRecord* record, TDBNodeRange* range);
extern void tdbThrowOutCursorCaches(TDB* db);
typedef TDBInt32 TDBPtr;
/* ----------------------------- From record.c: ---------------------------- */
extern TDBRecord* tdbLoadRecord(TDB* db, TDBPtr position);
extern PRStatus tdbSaveRecord(TDB* db, TDBRecord* record);
extern PRStatus tdbFreeRecord(TDBRecord* record);
extern TDBRecord* tdbAllocateRecord(TDB* db, TDBNodePtr triple[3]);
extern PRInt64 tdbCompareRecords(TDBRecord* r1, TDBRecord* r2,
PRInt32 comparerule);
typedef struct _TDBCallbackInfo TDBCallbackInfo;
typedef struct _TDBIntern TDBIntern;
typedef struct _TDBPendingCall TDBPendingCall;
typedef struct _TDBRType TDBRType;
typedef struct _TDBVector TDBVector;
typedef struct _TDBWindex TDBWindex;
typedef struct _TDBWindexCursor TDBWindexCursor;
/* ----------------------------- From tdb.c: ----------------------------- */
extern PRStatus tdbFlush(TDB* db);
extern PRStatus tdbThrowAwayUnflushedChanges(TDB* db);
extern PRStatus tdbGrowIobuf(TDB* db, PRInt32 length);
extern PRStatus tdbLoadRoots(TDB* db);
extern void tdbMarkCorrupted(TDB* db);
extern PRInt32 tdbGetInt32(char** ptr);
extern PRInt32 tdbGetInt16(char** ptr);
extern PRInt8 tdbGetInt8(char** ptr);
extern PRInt64 tdbGetInt64(char** ptr);
extern PRUint16 tdbGetUInt16(char** ptr);
extern void tdbPutInt32(char** ptr, PRInt32 value);
extern void tdbPutInt16(char** ptr, PRInt16 value) ;
extern void tdbPutUInt16(char** ptr, PRUint16 value) ;
extern void tdbPutInt8(char** ptr, PRInt8 value);
extern void tdbPutInt64(char** ptr, PRInt64 value);
#endif /* _TDBtypes_h_ */

237
db/tripledb/src/util.c Normal file
Просмотреть файл

@ -0,0 +1,237 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#include "tdbtypes.h"
#include "util.h"
#ifdef TDB_USE_NSPR
/* Don't attempt to use NSPR's "ll" routines; they don't do what we want. */
#include "prnetdb.h"
#define tdb_ntohs PR_ntohs
#define tdb_ntohl PR_ntohl
#define tdb_htons PR_htons
#define tdb_htonl PR_htonl
#else
#include <sys/types.h>
#include <netinet/in.h>
#define tdb_ntohs ntohs
#define tdb_ntohl ntohl
#define tdb_htons htons
#define tdb_htonl htonl
#endif
TDBPtr
tdbGetPtr(char** ptr, char* endptr)
{
TDBPtr result;
if (*ptr + sizeof(result) > endptr) return -1;
memcpy(&result, *ptr, sizeof(result));
*ptr += sizeof(result);
result = tdb_ntohl(result);
return result;
}
TDBInt32
tdbGetInt32(char** ptr, char* endptr)
{
TDBInt32 result;
if (*ptr + sizeof(TDBInt32) > endptr) return 0;
memcpy(&result, *ptr, sizeof(TDBInt32));
*ptr += sizeof(TDBInt32);
result = tdb_ntohl(result);
return result;
}
TDBInt32
tdbGetInt16(char** ptr, char* endptr)
{
TDBInt16 result;
if (*ptr + sizeof(TDBInt16) > endptr) return 0;
memcpy(&result, *ptr, sizeof(TDBInt16));
*ptr += sizeof(TDBInt16);
result = tdb_ntohs(result);
return result;
}
TDBInt8
tdbGetInt8(char** ptr, char* endptr)
{
TDBInt8 result;
if (*ptr + sizeof(TDBInt8) > endptr) return 0;
memcpy(&result, *ptr, sizeof(TDBInt8));
*ptr += sizeof(TDBInt8);
return result;
}
TDBUint8
tdbGetUInt8(char** ptr, char* endptr)
{
TDBUint8 result;
if (*ptr + sizeof(TDBUint8) > endptr) return 0;
memcpy(&result, *ptr, sizeof(TDBUint8));
*ptr += sizeof(TDBUint8);
return result;
}
TDBInt64
tdbGetInt64(char** ptr, char* endptr)
{
return (TDBInt64) tdbGetUInt64(ptr, endptr);
}
TDBUint16
tdbGetUInt16(char** ptr, char* endptr)
{
TDBUint16 result;
if (*ptr + sizeof(TDBUint16) > endptr) return 0;
memcpy(&result, *ptr, sizeof(TDBUint16));
*ptr += sizeof(TDBUint16);
result = tdb_ntohs(result);
return result;
}
TDBUint64
tdbGetUInt64(char** ptr, char* endptr)
{
TDBUint32 hi, low;
TDBUint64 result;
if (*ptr + sizeof(TDBUint64) > endptr) return 0;
hi = tdbGetUInt32(ptr, endptr);
low = tdbGetUInt32(ptr, endptr);
result = ((TDBUint64) hi) << 32 | low;
return result;
}
TDBUint32
tdbGetUInt32(char** ptr, char* endptr)
{
TDBUint32 result;
if (*ptr + sizeof(TDBUint32) > endptr) return 0;
memcpy(&result, *ptr, sizeof(TDBUint32));
*ptr += sizeof(TDBUint32);
result = tdb_ntohl(result);
return result;
}
TDBStatus
tdbPutPtr(char** ptr, TDBPtr value, char* endptr)
{
if (*ptr + sizeof(value) > endptr) return TDB_FAILURE;
value = tdb_htonl(value);
memcpy(*ptr, &value, sizeof(TDBPtr));
*ptr += sizeof(TDBPtr);
return TDB_SUCCESS;
}
TDBStatus
tdbPutInt32(char** ptr, TDBInt32 value, char* endptr)
{
if (*ptr + sizeof(value) > endptr) return TDB_FAILURE;
value = tdb_htonl(value);
memcpy(*ptr, &value, sizeof(TDBInt32));
*ptr += sizeof(TDBInt32);
return TDB_SUCCESS;
}
TDBStatus
tdbPutInt16(char** ptr, TDBInt16 value, char* endptr)
{
if (*ptr + sizeof(value) > endptr) return TDB_FAILURE;
value = tdb_htons(value);
memcpy(*ptr, &value, sizeof(TDBInt16));
*ptr += sizeof(TDBInt16);
return TDB_SUCCESS;
}
TDBStatus
tdbPutUInt16(char** ptr, TDBUint16 value, char* endptr)
{
if (*ptr + sizeof(value) > endptr) return TDB_FAILURE;
value = tdb_htons(value);
memcpy(*ptr, &value, sizeof(TDBUint16));
*ptr += sizeof(TDBUint16);
return TDB_SUCCESS;
}
TDBStatus
tdbPutInt8(char** ptr, TDBInt8 value, char* endptr)
{
if (*ptr + sizeof(value) > endptr) return TDB_FAILURE;
memcpy(*ptr, &value, sizeof(TDBInt8));
*ptr += sizeof(TDBInt8);
return TDB_SUCCESS;
}
TDBStatus
tdbPutUInt8(char** ptr, TDBUint8 value, char* endptr)
{
if (*ptr + sizeof(value) > endptr) return TDB_FAILURE;
memcpy(*ptr, &value, sizeof(TDBUint8));
*ptr += sizeof(TDBUint8);
return TDB_SUCCESS;
}
TDBStatus
tdbPutInt64(char** ptr, TDBInt64 value, char* endptr)
{
return tdbPutUInt64(ptr, (TDBUint64) value, endptr);
}
TDBStatus
tdbPutUInt64(char** ptr, TDBUint64 value, char* endptr)
{
TDBUint32 hi, low;
if (*ptr + sizeof(value) > endptr) return TDB_FAILURE;
hi = (TDBUint32) (value >> 32);
low = (TDBUint32) value;
if (tdbPutUInt32(ptr, hi, endptr) != TDB_SUCCESS) return TDB_FAILURE;
return tdbPutUInt32(ptr, low, endptr);
}
TDBStatus
tdbPutUInt32(char** ptr, TDBUint32 value, char* endptr)
{
if (*ptr + sizeof(value) > endptr) return TDB_FAILURE;
value = tdb_htonl(value);
memcpy(*ptr, &value, sizeof(TDBInt32));
*ptr += sizeof(TDBUint32);
return TDB_SUCCESS;
}
TDBStatus
tdbPutString(char** ptr, const char* str, char* endptr)
{
while (*str) {
if (*ptr >= endptr) return TDB_FAILURE;
*(*ptr)++ = *str++;
}
if (*ptr >= endptr) return TDB_FAILURE;
*(*ptr)++ = '\0';
return TDB_SUCCESS;
}

50
db/tripledb/src/util.h Normal file
Просмотреть файл

@ -0,0 +1,50 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#ifndef _util_h_
#define _util_h_ 1
extern TDBInt32 tdbGetInt16(char** ptr, char* endptr);
extern TDBInt32 tdbGetInt32(char** ptr, char* endptr);
extern TDBInt64 tdbGetInt64(char** ptr, char* endptr);
extern TDBInt8 tdbGetInt8(char** ptr, char* endptr);
extern TDBPtr tdbGetPtr(char** ptr, char* endptr);
extern TDBUint16 tdbGetUInt16(char** ptr, char* endptr);
extern TDBUint32 tdbGetUInt32(char** ptr, char* endptr);
extern TDBUint64 tdbGetUInt64(char** ptr, char* endptr);
extern TDBUint8 tdbGetUInt8(char** ptr, char* endptr);
extern TDBStatus tdbPutInt16(char** ptr, TDBInt16 value, char* endptr);
extern TDBStatus tdbPutInt32(char** ptr, TDBInt32 value, char* endptr);
extern TDBStatus tdbPutInt64(char** ptr, TDBInt64 value, char* endptr);
extern TDBStatus tdbPutInt8(char** ptr, TDBInt8 value, char* endptr);
extern TDBStatus tdbPutPtr(char** ptr, TDBPtr value, char* endptr);
extern TDBStatus tdbPutUInt16(char** ptr, TDBUint16 value, char* endptr);
extern TDBStatus tdbPutUInt32(char** ptr, TDBUint32 value, char* endptr);
extern TDBStatus tdbPutUInt64(char** ptr, TDBUint64 value, char* endptr);
extern TDBStatus tdbPutUInt8(char** ptr, TDBUint8 value, char* endptr);
/* tdbPutString() puts the string and its trailing NULL into the given
buffer. */
extern TDBStatus tdbPutString(char** ptr, const char* str, char* endptr);
#endif /* _util_h_ */

360
db/tripledb/src/vector.c Normal file
Просмотреть файл

@ -0,0 +1,360 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#include "tdbtypes.h"
#include "intern.h"
#include "node.h"
#include "tdb.h"
#include "util.h"
#include "vector.h"
struct _TDBVector {
TDBBase* base;
TDBInt32 numfields;
TDBNodePtr* nodes;
TDBNodePtr* interned;
TDBUint8 layer;
TDBUint8 flags;
TDBUint32 recordnum;
TDBUint64 owner;
};
TDBVector*
tdbVectorNewFromNodes(TDBBase* base, TDBNodePtr* nodes, TDBUint8 layer,
TDBUint8 flags, TDBUint32 recordnum)
{
TDBVector* vector;
TDBInt32 numfields = 3; /* Sigh... */
TDBInt32 i;
if (base == NULL || nodes == NULL) {
tdb_ASSERT(0);
return NULL;
}
vector = tdb_NEWZAP(TDBVector);
if (!vector) return NULL;
vector->base = base;
vector->numfields = numfields;
vector->nodes = tdb_Calloc(numfields, sizeof(TDBNodePtr));
vector->interned = tdb_Calloc(numfields, sizeof(TDBNodePtr));
if (!vector->nodes || !vector->interned) {
tdb_Free(vector);
return NULL;
}
for (i=0 ; i<numfields ; i++) {
if (!nodes[i]) {
tdb_ASSERT(0);
tdbVectorFree(vector);
return NULL;
}
vector->nodes[i] = TDBNodeDup(nodes[i]);
if (!vector->nodes[i]) {
tdbVectorFree(vector);
return NULL;
}
if (vector->nodes[i]->type == TDBTYPE_INTERNED) {
vector->interned[i] = vector->nodes[i];
vector->nodes[i] = NULL;
}
}
vector->layer = layer;
vector->flags = flags;
vector->recordnum = recordnum;
return vector;
}
extern
TDBVector* tdbVectorNewFromRecord(TDBBase* base, TDBUint32 recordnum)
{
TDBVector* vector;
TDBInt32 numfields = 3; /* Sigh... */
TDBNodePtr nodes[3];
DBT key;
DBT data;
DB* db;
int dbstatus;
char* ptr;
char* endptr;
TDBInt32 i;
TDBUint8 layer;
TDBUint8 flags;
TDBUint64 owner;
if (base == NULL || recordnum == 0) {
tdb_ASSERT(0);
return NULL;
}
db = tdbGetRecordDB(base);
if (db == NULL) {
tdb_ASSERT(0);
return NULL;
}
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
key.data = &recordnum;
key.size = sizeof(recordnum);
dbstatus = db->get(db, tdbGetTransaction(base), &key, &data, 0);
if (dbstatus != DB_OK) {
tdbMarkCorrupted(base);
return NULL;
}
ptr = data.data;
endptr = ptr + data.size;
for (i=0 ; i<numfields ; i++) {
nodes[i] = tdbGetNode(&ptr, endptr);
if (nodes[i] == NULL) {
tdbMarkCorrupted(base);
for (i-- ; i>=0 ; i--) TDBFreeNode(nodes[i]);
return NULL;
}
}
layer = tdbGetUInt8(&ptr, endptr);
flags = tdbGetUInt8(&ptr, endptr);
owner = tdbGetUInt64(&ptr, endptr);
vector = tdbVectorNewFromNodes(base, nodes, layer, flags, recordnum);
for (i=0 ; i<numfields ; i++) TDBFreeNode(nodes[i]);
if (vector == NULL) return NULL;
vector->owner = owner;
return vector;
}
extern TDBStatus
tdbVectorPutInNewRecord(TDBVector* vector, TDBUint64 owner)
{
DBT key;
DBT data;
DB* db;
TDBInt32 length;
TDBInt32 i;
char* tmpbuf;
char* ptr;
char* endptr;
int dbstatus;
if (vector == NULL || vector->recordnum != 0) {
tdb_ASSERT(0);
return TDB_FAILURE;
}
db = tdbGetRecordDB(vector->base);
if (db == NULL) {
tdb_ASSERT(0);
return TDB_FAILURE;
}
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
length = sizeof(TDBUint64) + sizeof(TDBUint8) + sizeof(TDBUint8);
for (i=0 ; i<vector->numfields ; i++) {
length += tdbNodeSize(tdbVectorGetInternedNode(vector, i));
}
length += 20; /* Just for general slop. */
tmpbuf = tdbGrowTmpBuf(vector->base, length);
if (tmpbuf == NULL) return TDB_FAILURE;
data.data = tmpbuf;
ptr = data.data;
endptr = ptr + length;
for (i=0 ; i<vector->numfields ; i++) {
if (tdbPutNode(&ptr, tdbVectorGetInternedNode(vector, i),
endptr) != TDB_SUCCESS) return TDB_FAILURE;
}
tdbPutUInt8(&ptr, vector->layer, endptr);
tdbPutUInt8(&ptr, vector->flags, endptr);
tdbPutUInt64(&ptr, vector->owner, endptr);
data.size = ptr - tmpbuf;
if (data.size != length - 20) {
tdb_ASSERT(0);
return TDB_FAILURE;
}
key.data = &(vector->recordnum);
key.ulen = sizeof(vector->recordnum);
key.flags = DB_DBT_USERMEM;
dbstatus = db->put(db, tdbGetTransaction(vector->base),
&key, &data, DB_APPEND);
if (dbstatus != DB_OK) return TDB_FAILURE;
tdb_ASSERT(vector->recordnum > 0);
return TDB_SUCCESS;
}
TDBUint32
tdbVectorGetRecordNumber(TDBVector* vector)
{
if (vector == NULL) {
tdb_ASSERT(0);
return 0;
}
return vector->recordnum;
}
TDBUint64
tdbVectorGetOwner(TDBVector* vector)
{
if (vector == NULL) {
tdb_ASSERT(0);
return 0;
}
return vector->owner;
}
void
tdbVectorFree(TDBVector* vector)
{
TDBInt32 i;
if (vector == NULL) {
tdb_ASSERT(0);
return;
}
if (vector->nodes) {
for (i=0 ; i<vector->numfields ; i++) {
if (vector->nodes[i]) TDBFreeNode(vector->nodes[i]);
}
tdb_Free(vector->nodes);
}
if (vector->interned) {
for (i=0 ; i<vector->numfields ; i++) {
if (vector->interned[i]) TDBFreeNode(vector->interned[i]);
}
tdb_Free(vector->interned);
}
tdb_Free(vector);
}
TDBNodePtr
tdbVectorGetNonInternedNode(TDBVector* vector, TDBInt32 i)
{
if (vector == NULL || i < 0 || i >= vector->numfields) {
tdb_ASSERT(0);
return NULL;
}
if (i != 1) {
tdb_ASSERT(vector->nodes[i] != NULL && vector->interned[i] == NULL);
return vector->nodes[i];
}
if (vector->nodes[i] == NULL) {
if (vector->interned[i] == NULL) {
tdb_ASSERT(0);
return NULL;
}
vector->nodes[i] = tdbUnintern(vector->base, vector->interned[i]);
}
return vector->nodes[i];
}
TDBNodePtr
tdbVectorGetInternedNode(TDBVector* vector, TDBInt32 i)
{
if (vector == NULL || i < 0 || i >= vector->numfields) {
tdb_ASSERT(0);
return NULL;
}
if (i != 1) {
tdb_ASSERT(vector->nodes[i] != NULL && vector->interned[i] == NULL);
return vector->nodes[i];
}
if (vector->interned[i] == NULL) {
if (vector->nodes[i] == NULL) {
tdb_ASSERT(0);
return NULL;
}
vector->interned[i] = tdbIntern(vector->base, vector->nodes[i]);
}
return vector->interned[i];
}
TDBUint8
tdbVectorGetLayer(TDBVector* vector)
{
if (vector == NULL) {
tdb_ASSERT(0);
return 0;
}
return vector->layer;
}
TDBUint8
tdbVectorGetFlags(TDBVector* vector)
{
if (vector == NULL) {
tdb_ASSERT(0);
return 0;
}
return vector->flags;
}
TDBInt32
tdbVectorGetNumFields(TDBVector* vector)
{
if (vector == NULL) {
tdb_ASSERT(0);
return -1;
}
return vector->numfields;
}
TDBBool
tdbVectorEqual(TDBVector* v1, TDBVector* v2)
{
TDBInt32 i;
TDBInt64 cmp;
if (v1 == NULL || v2 == NULL || v1->numfields != v2->numfields) {
tdb_ASSERT(0);
return TDB_FALSE;
}
for (i=0 ; i<v1->numfields ; i++) {
if (v1->interned[i] != NULL && v2->interned[i] != NULL) {
cmp = TDBCompareNodes(v1->interned[i], v2->interned[i]);
} else {
cmp = TDBCompareNodes(tdbVectorGetNonInternedNode(v1, i),
tdbVectorGetNonInternedNode(v2, i));
}
if (cmp != 0) return TDB_FALSE;
}
return TDB_TRUE;
}
TDBBool
tdbVectorLayerMatches(TDBVector* vector, TDB* tdb)
{
TDBInt32 i;
if (vector == NULL || tdb == NULL) {
tdb_ASSERT(0);
return TDB_FALSE;
}
for (i=tdbGetNumLayers(tdb) - 1 ; i >= 0 ; i--) {
if (vector->layer == tdbGetLayer(tdb, i)) {
return TDB_TRUE;
}
}
return TDB_FALSE;
}

61
db/tripledb/src/vector.h Normal file
Просмотреть файл

@ -0,0 +1,61 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#ifndef _vector_h_
#define _vector_h_ 1
extern TDBVector* tdbVectorNewFromNodes(TDBBase* base, TDBNodePtr* nodes,
TDBUint8 layer, TDBUint8 flags,
TDBUint32 recordnum);
extern TDBVector* tdbVectorNewFromRecord(TDBBase* base, TDBUint32 recordnum);
extern TDBStatus tdbVectorPutInNewRecord(TDBVector* vector, TDBUint64 owner);
extern TDBUint32 tdbVectorGetRecordNumber(TDBVector* vector);
extern TDBUint64 tdbVectorGetOwner(TDBVector* vector);
extern void tdbVectorFree(TDBVector* vector);
extern TDBNodePtr tdbVectorGetNonInternedNode(TDBVector* vector,
TDBInt32 which);
extern TDBNodePtr tdbVectorGetInternedNode(TDBVector* vector, TDBInt32 which);
extern TDBUint8 tdbVectorGetFlags(TDBVector* vector);
extern TDBUint8 tdbVectorGetLayer(TDBVector* vector);
extern TDBInt32 tdbVectorGetNumFields(TDBVector* vector);
extern TDBBool tdbVectorEqual(TDBVector* v1, TDBVector* v2);
/* tdbVectorLayerMatches() returns TRUE if the given vector is in one of the
layers specified by the given TDB. */
extern TDBBool tdbVectorLayerMatches(TDBVector* vector, TDB* tdb);
#endif /* _vector_h_ */

402
db/tripledb/src/windex.c Normal file
Просмотреть файл

@ -0,0 +1,402 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#include <ctype.h>
#include "tdbtypes.h"
#include "tdb.h"
#include "util.h"
#include "vector.h"
#include "windex.h"
#define MAXWORDLEN 10
typedef struct {
char word[MAXWORDLEN + 1];
TDBInt32 length;
TDBUint16 position;
} WordInfo;
struct _TDBWindex {
TDBBase* base;
DB* db;
};
struct _TDBWindexCursor {
TDBWindex* windex;
char* string;
DBC* cursor;
WordInfo* winfo;
TDBInt32 numwinfo;
TDBInt32 main;
int cmdflag;
};
TDBWindex*
tdbWindexNew(TDBBase* base)
{
TDBWindex* windex;
int dbstatus;
windex = tdb_NEWZAP(TDBWindex);
if (!windex) return NULL;
windex->base = base;
dbstatus = db_create(&(windex->db), tdbGetDBEnv(base), 0);
if (dbstatus != DB_OK) goto FAIL;
dbstatus = windex->db->open(windex->db, "windex", NULL, DB_BTREE,
DB_CREATE, 0666);
if (dbstatus != DB_OK) goto FAIL;
return windex;
FAIL:
tdbWindexFree(windex);
return NULL;
}
void
tdbWindexFree(TDBWindex* windex)
{
if (windex == NULL) {
tdb_ASSERT(0);
return;
}
if (windex->db) {
windex->db->close(windex->db, 0);
}
tdb_Free(windex);
}
TDBStatus
tdbWindexSync(TDBWindex* windex)
{
if (windex == NULL) {
tdb_ASSERT(0);
return TDB_FAILURE;
}
if (windex->db->sync(windex->db, 0) != DB_OK) return TDB_FAILURE;
return TDB_SUCCESS;
}
static WordInfo*
splitIntoWords(char* str, WordInfo* winfobuf, TDBInt32 winfobuflen)
{
WordInfo* winfo;
WordInfo* tmp;
TDBInt32 cur;
TDBInt32 max;
char* ptr;
char* ptr1;
char* ptr2;
TDBInt32 i;
TDBInt32 length;
winfo = winfobuf;
max = winfobuflen - 1;
cur = 0;
for (ptr1 = str ; *ptr1 ; ptr1++) {
if (!isalnum(*ptr1)) continue;
for (ptr2 = ptr1 + 1 ; *ptr2 && isalnum(*ptr2) ; ptr2++) { }
if (ptr2 - ptr1 > 2) {
/* Should check for stopwords here. XXX */
if (cur >= max) {
max = cur + 20;
tmp = tdb_Calloc(max + 1, sizeof(WordInfo));
for (i=0 ; i<cur ; i++) {
tmp[i] = winfo[i];
}
if (winfo != winfobuf) tdb_Free(winfo);
winfo = tmp;
}
length = ptr2 - ptr1;
if (length > MAXWORDLEN) length = MAXWORDLEN;
winfo[cur].length = length;
winfo[cur].position = ptr1 - str;
for (ptr = winfo[cur].word ; length > 0 ; length--) {
*ptr++ = tolower(*ptr1++);
}
*ptr = '\0';
cur++;
}
ptr1 = ptr2;
if (!*ptr1) break;
}
if (winfo) winfo[cur].length = 0;
return winfo;
}
TDBStatus
tdbWindexAdd(TDBWindex* windex, TDBVector* vector)
{
TDBNodePtr node;
WordInfo winfobuf[20];
WordInfo* winfo;
WordInfo* wptr;
char buf[100];
DBT key;
DBT data;
char* ptr;
char* endptr;
int dbstatus;
if (windex == NULL || vector == NULL) {
tdb_ASSERT(0);
return TDB_FAILURE;
}
node = tdbVectorGetNonInternedNode(vector, 2 /* XXX Stupid hardcoding */);
if (node == NULL) return TDB_FAILURE;
if (node->type != TDBTYPE_STRING) {
return TDB_SUCCESS; /* Quietly do nothing if it's not a string. */
}
winfo = splitIntoWords(node->d.str.string, winfobuf,
sizeof(winfobuf) / sizeof(winfobuf[0]));
if (!winfo) return TDB_FAILURE;
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
for (wptr = winfo ; wptr->length > 0 ; wptr++) {
ptr = buf;
endptr = buf + sizeof(buf);
tdbPutString(&ptr, wptr->word, endptr);
tdbPutPtr(&ptr, tdbVectorGetRecordNumber(vector), endptr);
tdbPutUInt16(&ptr, (TDBUint16) wptr->position, endptr);
if (ptr >= endptr) {
tdb_ASSERT(0);
} else {
key.size = ptr - buf;
key.data = buf;
dbstatus = windex->db->put(windex->db,
tdbGetTransaction(windex->base),
&key, &data, 0);
if (dbstatus != DB_OK) return TDB_FAILURE;
}
}
if (winfo != winfobuf) {
tdb_Free(winfo);
}
return TDB_SUCCESS;
}
TDBStatus
tdbWindexRemove(TDBWindex* windex, TDBVector* vector)
{
TDBNodePtr node;
WordInfo winfobuf[20];
WordInfo* winfo;
WordInfo* wptr;
DBT key;
DBT data;
char* ptr;
char* endptr;
char buf[100];
int dbstatus;
if (windex == NULL || vector == NULL) {
tdb_ASSERT(0);
return TDB_FAILURE;
}
node = tdbVectorGetNonInternedNode(vector, 2 /* XXX Stupid hardcoding */);
if (node == NULL) return TDB_FAILURE;
if (node->type != TDBTYPE_STRING) {
return TDB_SUCCESS; /* Quietly do nothing if it's not a string. */
}
winfo = splitIntoWords(node->d.str.string, winfobuf,
sizeof(winfobuf) / sizeof(winfobuf[0]));
if (!winfo) return TDB_FAILURE;
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
for (wptr = winfo ; wptr->length > 0 ; wptr++) {
ptr = buf;
endptr = buf + sizeof(buf);
tdbPutString(&ptr, wptr->word, endptr);
tdbPutPtr(&ptr, tdbVectorGetRecordNumber(vector), endptr);
tdbPutUInt16(&ptr, (TDBUint16) wptr->position, endptr);
if (ptr >= endptr) {
tdb_ASSERT(0);
} else {
key.size = ptr - buf;
key.data = buf;
dbstatus = windex->db->del(windex->db,
tdbGetTransaction(windex->base),
&key, 0);
if (dbstatus != DB_OK) return TDB_FAILURE;
}
}
if (winfo != winfobuf) {
tdb_Free(winfo);
}
return TDB_SUCCESS;
}
TDBWindexCursor*
tdbWindexGetCursor(TDBWindex* windex, const char* string)
{
DBT key;
DBT data;
int dbstatus;
TDBWindexCursor* cursor;
TDBInt32 i;
TDBInt32 l;
if (windex == NULL || string == NULL) {
tdb_ASSERT(0);
return NULL;
}
cursor = tdb_NEWZAP(TDBWindexCursor);
if (!cursor) return NULL;
cursor->windex = windex;
cursor->string = tdb_strdup(string);
if (!cursor->string) goto FAIL;
cursor->winfo = splitIntoWords(cursor->string, NULL, 0);
if (cursor->winfo == NULL) goto FAIL;
cursor->main = 0;
cursor->cmdflag = DB_CURRENT;
for (i=0 ; cursor->winfo[i].length > 0 ; i++) {
l = cursor->winfo[i].length;
if (l > cursor->winfo[cursor->main].length) {
cursor->main = i;
}
cursor->numwinfo = i + 1;
}
if (cursor->numwinfo == 0) goto FAIL;
dbstatus = windex->db->cursor(windex->db, NULL,
&(cursor->cursor), 0);
if (dbstatus != DB_OK) goto FAIL;
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
key.data = cursor->winfo[cursor->main].word;
key.size = cursor->winfo[cursor->main].length + 1;
dbstatus = cursor->cursor->c_get(cursor->cursor, &key, &data,
DB_SET_RANGE);
if (dbstatus != DB_OK && dbstatus != DB_NOTFOUND) goto FAIL;
return cursor;
FAIL:
tdbWindexCursorFree(cursor);
return NULL;
}
TDBStatus
tdbWindexCursorFree(TDBWindexCursor* cursor)
{
if (!cursor) {
tdb_ASSERT(0);
return TDB_FAILURE;
}
if (cursor->string) tdb_Free(cursor->string);
if (cursor->cursor) cursor->cursor->c_close(cursor->cursor);
if (cursor->winfo) tdb_Free(cursor->winfo);
tdb_Free(cursor);
return TDB_SUCCESS;
}
TDBVector*
tdbWindexGetCursorValue(TDBWindexCursor* cursor)
{
TDBInt32 l;
DBT key;
DBT data;
TDBBool match;
TDBPtr recordnum;
TDBInt32 position;
TDBInt32 p;
char* ptr;
char* endptr;
TDBInt32 i;
char buf[MAXWORDLEN + 20];
int dbstatus;
TDBWindex* windex;
TDBVector* vector;
TDBNodePtr node;
if (cursor == NULL) {
tdb_ASSERT(0);
return NULL;
}
windex = cursor->windex;
while (1) {
memset(&key, 0, sizeof(key));
memset(&data, 0, sizeof(data));
dbstatus = cursor->cursor->c_get(cursor->cursor, &key, &data,
cursor->cmdflag);
cursor->cmdflag = DB_NEXT;
if (dbstatus != DB_OK) return NULL;
l = cursor->winfo[cursor->main].length;
if (key.size <= l ||
memcmp(key.data, cursor->winfo[cursor->main].word, l + 1) != 0) {
/* We're past the end of matching things. */
return NULL;
}
ptr = key.data + l + 1;
endptr = key.data + key.size;
recordnum = tdbGetPtr(&ptr, endptr);
position = tdbGetUInt16(&ptr, endptr);
position -= cursor->winfo[cursor->main].position;
match = TDB_TRUE;
for (i=0 ; i<cursor->numwinfo ; i++) {
if (i == cursor->main) continue;
p = position + cursor->winfo[i].position;
if (p < 0) {
match = TDB_FALSE;
break;
}
ptr = buf;
endptr = buf + sizeof(buf);
tdbPutString(&ptr, cursor->winfo[i].word, endptr);
tdbPutPtr(&ptr, recordnum, endptr);
tdbPutUInt16(&ptr, p, endptr);
key.data = buf;
key.size = ptr - buf;
memset(&data, 0, sizeof(data));
dbstatus = windex->db->get(windex->db,
tdbGetTransaction(windex->base),
&key, &data, 0);
if (dbstatus != DB_OK) {
match = TDB_FALSE;
break;
}
}
if (match) {
vector = tdbVectorNewFromRecord(windex->base, recordnum);
node = tdbVectorGetNonInternedNode(vector, 2);
if (node && node->type == TDBTYPE_STRING &&
tdb_strcasestr(node->d.str.string, cursor->string) != NULL) {
return vector;
}
tdbVectorFree(vector);
}
}
}

44
db/tripledb/src/windex.h Normal file
Просмотреть файл

@ -0,0 +1,44 @@
/* -*- Mode: C; indent-tabs-mode: nil; -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the TripleDB database library.
*
* The Initial Developer of the Original Code is Geocast Network Systems.
* Portions created by Geocast are
* Copyright (C) 2000 Geocast Network Systems. All
* Rights Reserved.
*
* Contributor(s): Terry Weissman <terry@mozilla.org>
*/
#ifndef _windex_h_
#define _windex_h_ 1
extern TDBWindex* tdbWindexNew(TDBBase* base);
extern void tdbWindexFree(TDBWindex* windex);
extern TDBStatus tdbWindexSync(TDBWindex* windex);
extern TDBStatus tdbWindexAdd(TDBWindex* windex, TDBVector* vector);
extern TDBStatus tdbWindexRemove(TDBWindex* windex, TDBVector* vector);
extern TDBWindexCursor* tdbWindexGetCursor(TDBWindex* windex,
const char* string);
extern TDBStatus tdbWindexCursorFree(TDBWindexCursor* cursor);
extern TDBVector* tdbWindexGetCursorValue(TDBWindexCursor* cursor);
#endif /* _windex_h_ */