00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <eyedbconfig.h>
00026
00027 #include <stdlib.h>
00028
00029 #include <eyedbsm/eyedbsm.h>
00030 #include <BIdxBTree.h>
00031 #include <assert.h>
00032
00033 namespace eyedbsm {
00034 extern Boolean backend_interrupt;
00035
00036 class BIdxChain
00037 {
00038 BIdxChain * _next;
00039 BIdx * const idx;
00040 BIdxChain(BIdxChain const &);
00041 BIdxChain & operator=(BIdxChain const &);
00042 public:
00043 BIdxChain * const prev;
00044 unsigned i;
00045 BIdx::InCore blk;
00046
00047 BIdxChain(BIdx * b, BIdxChain * p) : blk(b), idx(b), prev(p), _next(0) { }
00048 ~BIdxChain() { if (_next) delete _next; }
00049
00050 BIdxChain * next() { return (_next) ? _next : (_next = new BIdxChain(idx, this));}
00051 };
00052
00053
00054 static Status
00055 findFirst(Oid oid, BIdxChain * chain, BIdxChain * * last)
00056 {
00057 Status s;
00058 while ((s = chain->blk.read(&oid)) == 0 && !chain->blk.node->leaf) {
00059 chain->i = 0;
00060 oid = chain->blk.node->c[0];
00061 chain = chain->next();
00062 }
00063 chain->i = 0;
00064 if (chain->blk.node->n == 0)
00065 *last = 0;
00066 else
00067 *last = chain;
00068 return s;
00069 }
00070
00071 static Status
00072 bTreeSearchAny(void const * key, Oid oid, BIdx::InCore * x, unsigned * ip, unsigned int *found_cnt, Boolean found_any)
00073 {
00074 *found_cnt = 0;
00075 for (;;) {
00076 if (backend_interrupt)
00077 return statusMake(BACKEND_INTERRUPTED, "");
00078 Status s;
00079 unsigned i;
00080 if (s = x->read(&oid))
00081 return s;
00082 for (i = 0; i < x->node->n && x->cmp(i, key, OP1_SWAP) < 0; i++)
00083 ;
00084 if ((i < x->node->n && x->cmp(i, key, OP1_SWAP) == 0)) {
00085 *ip = i;
00086 (*found_cnt)++;
00087 if (found_any)
00088 return Success;
00089 }
00090 if (x->node->leaf) {
00091 return Success;
00092 }
00093 oid = x->node->c[i];
00094 }
00095
00096 return eyedbsm::Success;
00097 }
00098
00099 Status
00100 BIdx::search(void const * key, unsigned int *found_cnt)
00101 {
00102 return searchPerform(key, found_cnt, eyedbsm::False, 0);
00103 }
00104
00105 Status
00106 BIdx::searchAny(void const * key, Boolean * found, void * data)
00107 {
00108 unsigned int found_cnt;
00109 Status s = searchPerform(key, &found_cnt, eyedbsm::True, data);
00110 if (s)
00111 return s;
00112 *found = (found_cnt != 0) ? eyedbsm::True : eyedbsm::False;
00113 return eyedbsm::Success;
00114 }
00115
00116 Status
00117 BIdx::searchPerform(void const * key, unsigned int * found_cnt, Boolean found_any, void * data)
00118 {
00119 #if 1
00120 BIdxCursor curs(this, key, key, False, False);
00121
00122 *found_cnt = 0;
00123 for (;;) {
00124 eyedbsm::Boolean found;
00125 eyedbsm::Status s = curs.next(&found, data);
00126 if (s)
00127 return s;
00128
00129 if (!found)
00130 break;
00131
00132 (*found_cnt)++;
00133
00134 if (found_any)
00135 return eyedbsm::Success;
00136 }
00137
00138 return eyedbsm::Success;
00139 #else
00140 BTree tree;
00141 if (stat = readBTree(tree))
00142 return fatal();
00143 BIdx::InCore x(this);
00144 unsigned i;
00145 Status s;
00146 #if 0
00147 if (!(s = bTreeSearchAny(key, tree.root, &x, &i, found_cnt, found_any))) {
00148 if (i < x.node->n && cmp(key, x.k(i), OP2_SWAP) == 0) {
00149 *found = True;
00150 if (data)
00151 memcpy(data, x.d(i), dataSize);
00152 }
00153 else
00154 *found = False;
00155 }
00156 #else
00157 if (!(s = bTreeSearchAny(key, tree.root, &x, &i, found_cnt, found_any))) {
00158 if (*found_cnt && data) {
00159 memcpy(data, x.d(i), dataSize);
00160 }
00161 }
00162 #endif
00163 return s;
00164 #endif
00165 }
00166
00167 static Status
00168 bTreeSearchFirst(void const * key, Oid oid, BIdxChain * c, BIdxChain * * last)
00169 {
00170 Boolean exact = False;
00171 for (;;) {
00172 Status s;
00173 if (s = c->blk.read(&oid))
00174 return s;
00175 int r;
00176 for (c->i = 0; c->i < c->blk.node->n && (r = c->blk.cmp(c->i, key, OP1_SWAP)) < 0; c->i++)
00177 ;
00178 if (c->blk.node->leaf) {
00179 if (!exact || (c->i < c->blk.node->n && r == 0))
00180 *last = c;
00181 return Success;
00182 }
00183 if (c->i < c->blk.node->n && r == 0) {
00184 *last = c;
00185 exact = True;
00186 }
00187 oid = c->blk.node->c[c->i];
00188 c = c->next();
00189 }
00190 }
00191
00192 static void *
00193 copyKey(int n, void const * key)
00194 {
00195 if (key == 0)
00196 return 0;
00197 return memcpy(new char[n], key, n);
00198 }
00199
00200 BIdxCursor::BIdxCursor
00201 (
00202 BIdx * idxIn,
00203 void const * sKeyIn,
00204 void const * eKeyIn,
00205 Boolean sExclusiveIn,
00206 Boolean eExclusiveIn,
00207 Boolean (*_user_cmp)(const void *key, void *cmp_arg),
00208 void *_cmp_arg
00209 )
00210 {
00211 idx = idxIn;
00212 sKey = copyKey(idx->keySize, sKeyIn);
00213 eKey = copyKey(idx->keySize, (eKeyIn == defaultSKey) ? sKeyIn : eKeyIn);
00214 sExclusive = sExclusiveIn;
00215 eExclusive = eExclusiveIn;
00216 chainFirst = chain = 0;
00217 user_cmp = _user_cmp;
00218 cmp_arg = _cmp_arg;
00219 }
00220
00221 static Status
00222 nextBIdxChain(BIdxChain * cp, BIdxChain * * out)
00223 {
00224 cp->i++;
00225 if (!cp->blk.node->leaf)
00226 while (!cp->blk.node->leaf) {
00227 BIdxChain * p = cp->next();
00228 Status s;
00229 if (s = p->blk.read(&cp->blk.node->c[cp->i]))
00230 return s;
00231 cp = p;
00232 cp->i = 0;
00233 }
00234 else if (cp->i >= cp->blk.node->n)
00235 while ((cp = cp->prev) && cp->i == cp->blk.node->n)
00236 ;
00237 *out = cp;
00238 return Success;
00239 }
00240
00241 Status BIdxCursor::next(Boolean *found, DataBuffer &data, Idx::Key *key)
00242 {
00243 return statusMake(NOT_YET_IMPLEMENTED, "BIdxCursor::next(Boolean *found, DataBuffer &data, Idx::Key *key)");
00244 }
00245
00246 Status
00247 BIdxCursor::next(unsigned int *found_cnt, Idx::Key *key)
00248 {
00249 *found_cnt = 0;
00250
00251 return statusMake(ERROR, "cannot use this type of cursor on non data_grouped_by_key hash index");
00252 }
00253
00254 Status
00255 BIdxCursor::next(Boolean * found, void * data, Idx::Key * key)
00256 {
00257 *found = False;
00258 for (;;) {
00259 if (backend_interrupt)
00260 return statusMake(BACKEND_INTERRUPTED, "");
00261 Status s;
00262 if (chain) {
00263 if (s = nextBIdxChain(chain, &chain))
00264 return s;
00265 }
00266 else {
00267 BIdx::BTree tree;
00268 if (idx->stat = idx->readBTree(tree))
00269 return idx->fatal();
00270 chainFirst = new BIdxChain(idx, 0);
00271 Status s;
00272 if (sKey) {
00273 if (s = bTreeSearchFirst(sKey, tree.root, chainFirst, &chain))
00274 return s;
00275 if (chain->i == chain->blk.node->n)
00276 if (s = nextBIdxChain(chain, &chain))
00277 return s;
00278 }
00279 else if (s = findFirst(tree.root, chainFirst, &chain))
00280 return s;
00281 }
00282 int r;
00283 while (chain && sKey &&
00284 ((r = idx->cmp(sKey, chain->blk.k(chain->i), OP2_SWAP)) > 0 ||
00285 (r == 0 && sExclusive)))
00286 if (s = nextBIdxChain(chain, &chain))
00287 return s;
00288
00289 if (!chain ||
00290 (eKey && ((r = idx->cmp(eKey, chain->blk.k(chain->i), OP2_SWAP)) < 0 ||
00291 (r == 0 && eExclusive)))) {
00292 *found = False;
00293 return Success;
00294 }
00295
00296
00297 if (idx->precmp) {
00298 void const * sk = sKey ? sKey : eKey;
00299 if (sk && idx->precmp(sk, chain->blk.k(chain->i),
00300 &idx->_keyType[0], r)) {
00301
00302 if (!sKey)
00303 continue;
00304 *found = False;
00305 return Success;
00306 }
00307 }
00308
00309
00310 if (user_cmp && !user_cmp(chain->blk.k(chain->i), cmp_arg))
00311 continue;
00312
00313 *found = True;
00314 #if 0
00315 if (key)
00316 key->setKey(chain->blk.k(chain->i), -idx->keySize, *idx->_keyType);
00317 #else
00318 if (key)
00319 key->setKey(chain->blk.k(chain->i), idx->keySize, *idx->_keyType);
00320 #endif
00321
00322 if (data)
00323 memcpy(data, chain->blk.d(chain->i), idx->dataSize);
00324 return Success;
00325 }
00326 }
00327
00328 BIdxCursor::~BIdxCursor()
00329 {
00330 delete [] (char **)sKey;
00331 delete [] (char **)eKey;
00332 delete chainFirst;
00333 }
00334
00335 char const BIdxCursor::defaultSKey[] = "";
00336 }