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 "eyedb_p.h"
00026 #include "odl.h"
00027 #include "CollectionBE.h"
00028 #include <eyedblib/butils.h>
00029
00030 namespace eyedb {
00031
00032 struct KeyValue {
00033 const char *key;
00034 const char *value;
00035 void set(const char *_key, const char *_value) {
00036 key = _key;
00037 value = _value;
00038 }
00039 };
00040
00041 struct KeyValueArray {
00042 int kalloc;
00043 int cnt;
00044 KeyValue *kvalues;
00045 KeyValueArray() {
00046 kalloc = cnt = 0;
00047 kvalues = 0;
00048 }
00049 void add(const char *k, const char *v) {
00050 if (cnt >= kalloc) {
00051 kalloc += 8;
00052 kvalues = (KeyValue *)realloc(kvalues, kalloc * sizeof(KeyValue));
00053 }
00054 kvalues[cnt++].set(k, v);
00055 }
00056 void trace() {
00057 for (int i = 0; i < cnt; i++)
00058 printf("'%s' <-> '%s'\n", kvalues[i].key, (kvalues[i].value ?
00059 kvalues[i].value : "NULL"));
00060 }
00061 ~KeyValueArray() {
00062 free(kvalues);
00063 }
00064 };
00065
00066 static char *
00067 trim(char *p)
00068 {
00069 while (*p == ' ' || *p == '\t' || *p == '\n')
00070 p++;
00071 int len = strlen(p);
00072 char *q = p + strlen(p) - 1;
00073 while (*q == ' ' || *q == '\t' || *q == '\n')
00074 *q-- = 0;
00075 return p;
00076 }
00077
00078 static char *
00079 make(const char *xhints, KeyValueArray &kvarr)
00080 {
00081 char *hints = strdup(xhints);
00082 char *p = hints;
00083 char *q = hints;
00084 char *key = 0, *value = 0, *last = hints;
00085 for (;;) {
00086 char c = *p;
00087 if (c == '=') {
00088 *p = 0;
00089 key = trim(last);
00090 last = p+1;
00091 }
00092 else if (c == ';' || c == ',' || !c) {
00093 *p = 0;
00094 value = trim(last);
00095 last = p+1;
00096 if (!key)
00097 kvarr.add(value, 0);
00098 else
00099 kvarr.add(key, value);
00100 if (!c) break;
00101 key = 0;
00102 }
00103 p++;
00104 }
00105
00106
00107 return hints;
00108 }
00109
00110 const char *IndexImpl::hashHintToStr(unsigned int hints, Bool cap)
00111 {
00112 if (hints == eyedbsm::HIdx::IniSize_Hints)
00113 return cap ? "Initial Size" : "initial_size";
00114
00115 if (hints == eyedbsm::HIdx::IniObjCnt_Hints)
00116 return cap ? "Initial Object Count" : "initial_object_count";
00117
00118 if (hints == eyedbsm::HIdx::XCoef_Hints)
00119 return cap ? "Extend Coeficient" : "extend_coef";
00120
00121 if (hints == eyedbsm::HIdx::SzMax_Hints)
00122 return cap ? "Maximal Hash Object Size" : "size_max";
00123
00124 if (hints == eyedbsm::HIdx::DataGroupedByKey_Hints)
00125 return cap ? "Data Grouped by Key" : "data_grouped_by_key";
00126
00127 return "<unimplemented>";
00128 }
00129
00130 bool IndexImpl::isHashHintImplemented(unsigned int hints)
00131 {
00132 return hints <= eyedbsm::HIdx::DataGroupedByKey_Hints;
00133 }
00134
00135 #define MAKE(H) \
00136 if (!strcasecmp(k, hashHintToStr(eyedbsm::HIdx::H))) { \
00137 if (!v || !eyedblib::is_number(v)) { \
00138 if (errmsg.size()) errmsg += "\n"; \
00139 errmsg += std::string(hashHintToStr(eyedbsm::HIdx::H)) + ": expected a number"; \
00140 } \
00141 else \
00142 impl_hints[eyedbsm::HIdx::H] = atoi(v); \
00143 }
00144
00145 static Signature *
00146 makeSign(Schema *m)
00147 {
00148 Signature *sign = new Signature();
00149 ArgType *type;
00150
00151 type = sign->getRettype();
00152 *type = *ArgType::make(m, int32_class_name);
00153
00154 type->setType((ArgType_Type)(type->getType() | OUT_ARG_TYPE), False);
00155
00156 sign->setNargs(2);
00157
00158 sign->setTypesCount(2);
00159 type = sign->getTypes(0);
00160 *type = *ArgType::make(m, "rawdata");
00161
00162 type->setType((ArgType_Type)(type->getType() | IN_ARG_TYPE), False);
00163
00164 sign->setTypesCount(2);
00165 type = sign->getTypes(1);
00166 *type = *ArgType::make(m, int32_class_name);
00167 type->setType((ArgType_Type)(type->getType() | IN_ARG_TYPE), False);
00168
00169 return sign;
00170 }
00171 static Signature *
00172 getHashSignature(Schema *m)
00173 {
00174 static Signature *sign;
00175
00176 if (!sign)
00177 sign = makeSign(m);
00178
00179 return sign;
00180 }
00181
00182 static Status
00183 findMethod(Database *db, const char *key_function, const char *mthname,
00184 const Class *xcls, Method *&mth)
00185 {
00186 Signature *sign = getHashSignature(db->getSchema());
00187 Status s;
00188
00189 LinkedList *mthlist = (LinkedList *)xcls->getUserData(odlMTHLIST);
00190 if (mthlist) {
00191 LinkedListCursor c(mthlist);
00192 while (c.getNext((void *&)mth)) {
00193 if (!strcmp(mth->getEx()->getExname().c_str(), mthname) &&
00194 *sign == *mth->getEx()->getSign())
00195 return Success;
00196 }
00197 }
00198
00199 s = const_cast<Class *>(xcls)->getMethod(mthname, mth, sign);
00200 if (s) return s;
00201
00202 if (!mth) {
00203 s = const_cast<Class *>(xcls)->getMethod(mthname, mth);
00204 if (s) return s;
00205 if (!mth)
00206 return Exception::make(IDB_ERROR, "no method '%s' in class '%s'",
00207 mthname, xcls->getName());
00208 return Exception::make(IDB_ERROR, "invalid hash method signature: "
00209 "must be classmethod int %s(in rawdata, in int)",
00210 key_function);
00211 }
00212
00213 return Success;
00214 }
00215
00216 Status
00217 get_key_function(Database *db, const char *key_function,
00218 BEMethod_C *&be_mth)
00219 {
00220 be_mth = 0;
00221 if (!key_function || !*key_function)
00222 return Success;
00223
00224 if (!db)
00225 return Exception::make(IDB_ERROR, "database should be set when a "
00226 "hash method is specified");
00227
00228 const Class *xcls = 0;
00229 Status s;
00230 const char *q = strchr(key_function, ':');
00231 const char *mthname;
00232 if (q) {
00233 int len = q-key_function;
00234 char *clsname = new char[len+1];
00235 strncpy(clsname, key_function, len);
00236 clsname[len] = 0;
00237 xcls = db->getSchema()->getClass(clsname);
00238 if (!xcls) {
00239 s = Exception::make(IDB_ERROR, "invalid key function '%s': "
00240 "cannot find class '%s'", key_function, clsname);
00241 delete [] clsname;
00242 return s;
00243 }
00244 delete [] clsname;
00245 mthname = q+2;
00246 }
00247 else
00248 return Exception::make(IDB_ERROR, "key function must be under the form "
00249 "'classname::methodname'");
00250
00251 Method *mth;
00252 s = findMethod(db, key_function, mthname, xcls, mth);
00253 if (s) return s;
00254
00255 be_mth = mth->asBEMethod_C();
00256
00257 if (!be_mth)
00258 return Exception::make(IDB_ERROR, "method '%s' in class '%s' is not "
00259 "a server method",
00260 mthname, xcls->getName());
00261 return Success;
00262 }
00263
00264 Status
00265 IndexImpl::makeHash(Database *db, const char *hints,
00266 IndexImpl *&idximpl, Bool is_string)
00267 {
00268 idximpl = 0;
00269 int key_count = 0;
00270 std::string dspname;
00271 int impl_hints_cnt = eyedbsm::HIdxImplHintsCount;
00272 int impl_hints[eyedbsm::HIdxImplHintsCount];
00273 memset(impl_hints, 0, sizeof(int) * eyedbsm::HIdxImplHintsCount);
00274 std::string key_function;
00275 char *x = 0;
00276
00277 if (hints) {
00278 std::string errmsg;
00279 KeyValueArray kvarr;
00280 x = eyedb::make(hints, kvarr);
00281 for (int n = 0; n < kvarr.cnt; n++) {
00282 KeyValue *kv = &kvarr.kvalues[n];
00283 const char *k = kv->key;
00284 const char *v = kv->value;
00285 if (!strcasecmp(k, "key_count")) {
00286 if (!v || !eyedblib::is_number(v))
00287 errmsg += std::string("key_count expected a number\n");
00288 else
00289 key_count = atoi(v);
00290 }
00291 else if (!strcasecmp(k, "dataspace")) {
00292 if (!v)
00293 errmsg += std::string("dataspace expected a value\n");
00294 dspname = v;
00295 }
00296 else MAKE(IniSize_Hints)
00297 else MAKE(IniObjCnt_Hints)
00298 else MAKE(XCoef_Hints)
00299 else MAKE(SzMax_Hints)
00300 else MAKE(DataGroupedByKey_Hints)
00301 else if (!strcasecmp(k, "key_function"))
00302 key_function = v;
00303 else if (*k || (v && *v)) {
00304 if (errmsg.size()) errmsg += "\n";
00305 errmsg += std::string("unknown hint: ") + k;
00306 }
00307 }
00308
00309 if (errmsg.size()) {
00310 errmsg += "\nhash index hints grammar: 'key_count = <intval>; "
00311 "initial_size = <intval>; "
00312 "initial_object_count = <intval>; "
00313 "extend_coef = <intval>; "
00314 "size_max = <intval>; "
00315 "data_grouped_by_key = <intval>; "
00316 "key_function = <class>::<method>; "
00317 "dataspace = <name>';";
00318 return Exception::make(IDB_ERROR, errmsg.c_str());
00319 }
00320 }
00321
00322 free(x);
00323 Status s;
00324 const Dataspace *dataspace = 0;
00325 if (dspname.size()) {
00326 if (db->isOpened()) {
00327 s = db->getDataspace(dspname.c_str(), dataspace);
00328 if (s) return s;
00329 }
00330 }
00331
00332 BEMethod_C *mth;
00333 s = get_key_function(db, key_function.c_str(), mth);
00334 if (s) return s;
00335
00336 if (is_string && impl_hints[eyedbsm::HIdx::IniObjCnt_Hints]) {
00337 return Exception::make(IDB_ERROR,
00338 "one cannot define "
00339 "the initial_object_count hint "
00340 "on a string index");
00341 }
00342
00343 if (impl_hints[eyedbsm::HIdx::IniObjCnt_Hints] &&
00344 impl_hints[eyedbsm::HIdx::IniSize_Hints]) {
00345 return Exception::make(IDB_ERROR,
00346 "one cannot define "
00347 "both the initial_object_count "
00348 "and the initial_size hints "
00349 "on an index");
00350 }
00351
00352
00353 idximpl =
00354 new IndexImpl(Hash, dataspace, key_count, mth, impl_hints,
00355 impl_hints_cnt);
00356 return Success;
00357 }
00358
00359 Status
00360 IndexImpl::makeBTree(Database *db, const char *hints,
00361 IndexImpl *&idximpl, Bool)
00362 {
00363 int degree = 0;
00364 char *x = 0;
00365 std::string dspname;
00366 int impl_hints_cnt = eyedbsm::HIdxImplHintsCount;
00367 int impl_hints[eyedbsm::HIdxImplHintsCount];
00368 memset(impl_hints, 0, sizeof(int) * eyedbsm::HIdxImplHintsCount);
00369
00370 if (hints) {
00371 std::string errmsg;
00372 KeyValueArray kvarr;
00373 x = eyedb::make(hints, kvarr);
00374 for (int n = 0; n < kvarr.cnt; n++) {
00375 KeyValue *kv = &kvarr.kvalues[n];
00376 const char *k = kv->key;
00377 const char *v = kv->value;
00378 if (!strcasecmp(k, "degree")) {
00379 if (!v || !eyedblib::is_number(v))
00380 errmsg += std::string("defree expected a number\n");
00381 else
00382 degree = atoi(v);
00383 }
00384 else if (!strcasecmp(k, "dataspace")) {
00385 if (!v)
00386 errmsg += std::string("dataspace expected a value\n");
00387 dspname = v;
00388 }
00389 else if (*k || (v && *v)) {
00390 if (errmsg.size()) errmsg += "\n";
00391 errmsg += std::string("unknown hint: ") + k;
00392 }
00393 }
00394
00395 if (errmsg.size()) {
00396 errmsg += "\nbtree index hints grammar: 'degree = <intval>; "
00397 "dataspace = <name>;'";
00398 return Exception::make(IDB_ERROR, errmsg.c_str());
00399 }
00400 }
00401
00402 free(x);
00403 Status s;
00404 const Dataspace *dataspace = 0;
00405 if (dspname.size()) {
00406 if (db->isOpened()) {
00407 s = db->getDataspace(dspname.c_str(), dataspace);
00408 if (s) return s;
00409 }
00410 }
00411
00412 idximpl = new IndexImpl(BTree, dataspace, degree, 0,
00413 impl_hints, impl_hints_cnt);
00414
00415 return Success;
00416 }
00417
00418 IndexImpl::IndexImpl(Type _type,
00419 const Dataspace *_dataspace,
00420 unsigned int keycount_or_degree,
00421 BEMethod_C *mth,
00422 const int _impl_hints[],
00423 unsigned int _impl_hints_cnt)
00424 {
00425
00426 int impl_hints_def[eyedbsm::HIdxImplHintsCount];
00427 type = _type;
00428 dataspace = _dataspace;
00429
00430 u.hash.mth = 0;
00431 u.hash.keycount = 0;
00432 u.degree = 0;
00433
00434 if (type == Hash) {
00435 u.hash.keycount = keycount_or_degree;
00436 u.hash.mth = mth;
00437 }
00438 else {
00439 u.degree = keycount_or_degree;
00440 }
00441
00442 impl_hints_cnt = _impl_hints_cnt;
00443
00444 if (impl_hints_cnt) {
00445 impl_hints = new int[impl_hints_cnt];
00446 memcpy(impl_hints, _impl_hints, impl_hints_cnt * sizeof(impl_hints[0]));
00447 }
00448 else
00449 impl_hints = 0;
00450
00451 setTag("eyedb::IndexImpl");
00452 }
00453
00454 IndexImpl::IndexImpl(const IndexImpl &)
00455 {
00456 abort();
00457 }
00458
00459 IndexImpl& IndexImpl::operator=(const IndexImpl &)
00460 {
00461 abort();
00462 return *this;
00463 }
00464
00465 Status
00466 IndexImpl::make(Database *db, Type type, const char *hints,
00467 IndexImpl *&idximpl, Bool is_string)
00468 {
00469 if (type == Hash)
00470 return makeHash(db, hints, idximpl, is_string);
00471 if (type == BTree)
00472 return makeBTree(db, hints, idximpl, is_string);
00473
00474 return Exception::make(IDB_ERROR,
00475 "index implementation type is not valid");
00476 }
00477
00478 #define CHECK_X(I) \
00479 if ((I) == eyedbsm::HIdx::IniSize_Hints && impl_hints[eyedbsm::HIdx::IniObjCnt_Hints]) continue;
00480
00481 std::string
00482 IndexImpl::getHintsString() const
00483 {
00484 std::string hints;
00485 if (dataspace) {
00486 const char *dspname = dataspace->getName();
00487 hints += std::string("dataspace = ") +
00488 (*dspname ? std::string(dspname) :
00489 str_convert((long)dataspace->getId())) + ";";
00490 }
00491
00492 if (type == BTree) {
00493 if (u.degree) {
00494 if (hints.size()) hints += " ";
00495 hints += std::string("degree = ") + str_convert((long)u.degree) + ";";
00496 }
00497 return hints;
00498 }
00499
00500 if (u.hash.keycount) {
00501 if (hints.size()) hints += " ";
00502 hints += std::string("key_count = ") + str_convert((long)u.hash.keycount) + ";";
00503 }
00504
00505 if (u.hash.mth) {
00506 if (hints.size()) hints += " ";
00507 hints += std::string("key_function = ") +
00508 u.hash.mth->getClassOwner()->getName() + "::" +
00509 u.hash.mth->getEx()->getExname() + ";";
00510 }
00511
00512 int cnt = impl_hints_cnt;
00513 #ifdef IDB_SKIP_HASH_XCOEF
00514 if (cnt > eyedbsm::HIdx::XCoef_Hints) cnt = eyedbsm::HIdx::XCoef_Hints;
00515 #endif
00516 for (int i = 0; i < cnt ; i++) {
00517 CHECK_X(i);
00518 int val = impl_hints[i];
00519 if (val) {
00520 if (hints.size()) hints += " ";
00521 hints += std::string(hashHintToStr(i)) + " = " + str_convert(val) + ";";
00522 }
00523 }
00524
00525 return hints;
00526 }
00527
00528 std::string
00529 IndexImpl::toString(const char *xindent) const
00530 {
00531 std::string indent = xindent;
00532 std::string hints = indent + "Type: ";
00533 if (type == BTree) {
00534 hints += "BTree\n";
00535 if (dataspace) {
00536 const char *dspname = dataspace->getName();
00537 hints += indent + "Dataspace: " +
00538 (*dspname ? std::string(dspname) :
00539 str_convert((long)dataspace->getId())) + "\n";
00540 }
00541 if (u.degree)
00542 hints += indent + "Degree: " + str_convert((long)u.degree) + "\n";
00543 return hints;
00544 }
00545
00546 hints += "Hash\n";
00547 if (dataspace) {
00548 const char *dspname = dataspace->getName();
00549 hints += indent + "Dataspace: " +
00550 (*dspname ? std::string(dspname) :
00551 str_convert((long)dataspace->getId())) + "\n";
00552 }
00553
00554 if (u.hash.keycount)
00555 hints += indent + "Key Count: " + str_convert((long)u.hash.keycount) + "\n";
00556
00557
00558 if (u.hash.mth) {
00559 hints += indent + "Key Function: " +
00560 u.hash.mth->getClassOwner()->getName() + "::" +
00561 u.hash.mth->getEx()->getExname() + "\n";
00562 }
00563
00564 int cnt = impl_hints_cnt;
00565 #ifdef IDB_SKIP_HASH_XCOEF
00566 if (cnt > eyedbsm::HIdx::XCoef_Hints) cnt = eyedbsm::HIdx::XCoef_Hints;
00567 #endif
00568 for (int i = 0; i < cnt; i++) {
00569 CHECK_X(i);
00570 int val = impl_hints[i];
00571 if (val)
00572 hints += indent + hashHintToStr(i, True) + ": " + str_convert(val) + "\n";
00573 }
00574
00575 return hints;
00576 }
00577
00578 IndexImpl *
00579 IndexImpl::clone() const
00580 {
00581 assert(getRefCount() > 0);
00582 if (type == Hash)
00583 return new IndexImpl(type, dataspace, u.hash.keycount, u.hash.mth,
00584 impl_hints, impl_hints_cnt);
00585
00586 return new IndexImpl(type, dataspace, u.degree, 0,
00587 impl_hints, impl_hints_cnt);
00588 }
00589
00590 Bool
00591 IndexImpl::compare(const IndexImpl *idximpl) const
00592 {
00593 if (idximpl->type != type)
00594 return False;
00595
00596 if (type == Hash)
00597 return IDBBOOL
00598 (!(idximpl->u.hash.keycount != u.hash.keycount ||
00599 (idximpl->u.hash.mth && !u.hash.mth) ||
00600 (!idximpl->u.hash.mth && u.hash.mth) ||
00601 (u.hash.mth && (idximpl->u.hash.mth->getOid() != u.hash.mth->getOid() ||
00602 idximpl->u.hash.mth != u.hash.mth)) ||
00603 idximpl->impl_hints_cnt != impl_hints_cnt ||
00604 memcmp(idximpl->impl_hints, impl_hints,
00605 impl_hints_cnt * sizeof(impl_hints[0]))));
00606
00607 return IDBBOOL
00608 (!(idximpl->u.degree != u.degree ||
00609 idximpl->impl_hints_cnt != impl_hints_cnt ||
00610 memcmp(idximpl->impl_hints, impl_hints,
00611 impl_hints_cnt * sizeof(impl_hints[0]))));
00612 }
00613
00614 unsigned int
00615 IndexImpl::getMagorder(unsigned int def_magorder) const
00616 {
00617 if (type == Hash) {
00618 if (!u.hash.keycount)
00619 return def_magorder;
00620 return eyedbsm::HIdx::getMagOrder(u.hash.keycount);
00621 }
00622
00623 if (!u.degree)
00624 return def_magorder;
00625
00626 return eyedbsm::BIdx::getMagOrder(u.degree);
00627 }
00628
00629 unsigned int
00630 IndexImpl::estimateHashKeycount(unsigned int magorder)
00631 {
00632 return eyedbsm::HIdx::getKeyCount(magorder);
00633 }
00634
00635 unsigned int
00636 IndexImpl::estimateBTreeDegree(unsigned int magorder)
00637 {
00638 return eyedbsm::BIdx::getDegree(magorder);
00639 }
00640
00641 IndexImpl::~IndexImpl()
00642 {
00643 garbageRealize();
00644 }
00645
00646 void IndexImpl::garbage()
00647 {
00648
00649 delete [] impl_hints;
00650 }
00651
00652
00653 Status
00654 IndexImpl::code(Data &data, Offset &offset,
00655 Size &alloc_size,
00656 const IndexImpl &idximpl)
00657 {
00658 static eyedblib::int32 zero = 0;
00659 char idxtype = idximpl.getType();
00660 char_code (&data, &offset, &alloc_size, &idxtype);
00661 short dspid = (idximpl.dataspace ? idximpl.dataspace->getId() :
00662 Dataspace::DefaultDspid);
00663 int16_code (&data, &offset, &alloc_size, &dspid);
00664
00665 if (idximpl.getType() == IndexImpl::Hash) {
00666 eyedblib::int32 x = idximpl.getKeycount();
00667 int32_code (&data, &offset, &alloc_size, &x);
00668 if (idximpl.getHashMethod()) {
00669 const Oid &xoid = idximpl.getHashMethod()->getOid();
00670 if (!xoid.isValid())
00671 return Exception::make(IDB_ERROR, "while coding collection, "
00672 "non persistent hash method found");
00673
00674 oid_code (&data, &offset, &alloc_size, xoid.getOid());
00675 }
00676 else
00677 oid_code (&data, &offset, &alloc_size, Oid::nullOid.getOid());
00678 }
00679 else {
00680 eyedblib::int32 x = idximpl.getDegree();
00681 int32_code (&data, &offset, &alloc_size, &x);
00682 oid_code (&data, &offset, &alloc_size, Oid::nullOid.getOid());
00683 }
00684
00685 unsigned int impl_hints_cnt;
00686 const int *impl_hints = idximpl.getImplHints(impl_hints_cnt);
00687 assert(impl_hints_cnt <= IDB_MAX_HINTS_CNT);
00688 for (int i = 0; i < impl_hints_cnt; i++)
00689 int32_code (&data, &offset, &alloc_size, &impl_hints[i]);
00690 for (int i = impl_hints_cnt; i < IDB_MAX_HINTS_CNT; i++)
00691 int32_code (&data, &offset, &alloc_size, &zero);
00692
00693 return Success;
00694 }
00695
00696 void
00697 IndexImpl::setHashMethod(BEMethod_C *mth)
00698 {
00699 if (type == Hash)
00700 u.hash.mth = mth;
00701 }
00702
00703 Status
00704 IndexImpl::decode(Database *db, Data data,
00705 Offset &offset, IndexImpl *&idximpl)
00706 {
00707 IndexImpl::Type impl_type;
00708 eyedblib::int32 implinfo;
00709 eyedblib::int32 impl_hints[IDB_MAX_HINTS_CNT];
00710 Oid mthoid;
00711 BEMethod_C *mth = 0;
00712
00713 char c;
00714 char_decode (data, &offset, &c);
00715 impl_type = (IndexImpl::Type)c;
00716 short dspid;
00717 int16_decode (data, &offset, &dspid);
00718 int32_decode (data, &offset, &implinfo);
00719 oid_decode (data, &offset, mthoid.getOid());
00720
00721 Status s;
00722 const Dataspace *dataspace = 0;
00723 if (dspid != Dataspace::DefaultDspid) {
00724 s = db->getDataspace(dspid, dataspace);
00725 if (s) return s;
00726 }
00727
00728 if (mthoid.isValid()) {
00729 s = db->loadObject(mthoid, (Object *&)mth);
00730 if (s) return s;
00731 }
00732
00733 for (int i = 0; i < IDB_MAX_HINTS_CNT; i++)
00734 int32_decode (data, &offset, &impl_hints[i]);
00735
00736 idximpl = new IndexImpl(impl_type, dataspace, implinfo, mth, impl_hints,
00737 IDB_MAX_HINTS_CNT);
00738 return Success;
00739 }
00740
00741 IndexStats::IndexStats()
00742 {
00743 idximpl = 0;
00744 }
00745
00746 IndexStats::~IndexStats()
00747 {
00748 if (idximpl)
00749 idximpl->release();
00750 }
00751
00752 HashIndexStats::HashIndexStats()
00753 {
00754
00755 key_count = 0;
00756 entries = 0;
00757 }
00758
00759 HashIndexStats::~HashIndexStats()
00760 {
00761 delete [] entries;
00762 }
00763
00764 #define ONE_K 1024
00765 #define ONE_M (ONE_K*ONE_K)
00766
00767 static std::string
00768 get_string_size(unsigned int _sz)
00769 {
00770 unsigned int sz1, sz2;
00771 unsigned int sz;
00772
00773 sz = _sz;
00774 std::string s = str_convert((long)sz) + "b";
00775 sz = _sz / ONE_K;
00776
00777 if (sz) {
00778 s += std::string(", ~") + str_convert((long)sz) + "Kb";
00779
00780 sz = _sz / ONE_M;
00781 if (sz) {
00782 sz1 = sz * ONE_M;
00783 sz2 = (sz+1) * ONE_M;
00784 if ((sz2 - _sz) < (_sz - sz1))
00785 sz = sz+1;
00786 s += std::string(", ~") + str_convert((long)sz) + "Mb";
00787 }
00788 }
00789
00790 return s;
00791 }
00792
00793 std::string
00794 HashIndexStats::toString(Bool dspImpl, Bool full, const char *xindent)
00795 {
00796 std::string indent = xindent;
00797 std::string s;
00798 if (dspImpl)
00799 s = idximpl ? idximpl->toString(xindent) : std::string("");
00800 Entry *entry = entries;
00801
00802 if (dspImpl && !idximpl)
00803 s += indent + "Key count: " + str_convert((long)key_count) + "\n";
00804
00805 if (full) {
00806 for (int i = 0; i < key_count; i++, entry++)
00807 if (entry->object_count || entry->hash_object_count) {
00808 char buf[2048];
00809 sprintf(buf,
00810 "%sKey #%d {\n "
00811 "\t%sObject count: %d\n"
00812 "\t%sHash object count: %d\n"
00813 "\t%sHash object size: %s\n"
00814 "\t%sHash object busy size: %s\n"
00815 "\t%sHash object free size: %s\n%s}\n",
00816 indent.c_str(), i,
00817 indent.c_str(), entry->object_count,
00818
00819 indent.c_str(), entry->hash_object_count,
00820 indent.c_str(), get_string_size(entry->hash_object_size).c_str(),
00821 indent.c_str(), get_string_size(entry->hash_object_busy_size).c_str(),
00822 indent.c_str(), get_string_size(entry->hash_object_size - entry->hash_object_busy_size).c_str(),
00823 indent.c_str());
00824 s += buf;
00825 }
00826 }
00827
00828 s += indent + std::string("Min objects per entry: ") +
00829 str_convert((long)min_objects_per_entry) + "\n";
00830 s += indent + std::string("Max objects per entry: ") +
00831 str_convert((long)max_objects_per_entry) + "\n";
00832 s += indent + std::string("Total object count: ") +
00833 str_convert((long)total_object_count) + "\n";
00834 s += indent + std::string("Total hash object count: ") +
00835 str_convert((long)total_hash_object_count) + "\n";
00836 s += indent + std::string("Total hash object size: ") +
00837 get_string_size(total_hash_object_size) + "\n";
00838 s += indent + std::string("Total hash object busy size: ") +
00839 get_string_size(total_hash_object_busy_size) + "\n";
00840 s += indent + std::string("Total hash object free size: ") +
00841 get_string_size(total_hash_object_size - total_hash_object_busy_size) + "\n";
00842 s += indent + std::string("Busy entry count: ") +
00843 str_convert((long)busy_key_count) + "\n";
00844 s += indent + std::string("Free entry count: ") +
00845 str_convert((long)free_key_count) + "\n";
00846 return s;
00847 }
00848
00849 std::string
00850 BTreeIndexStats::toString(Bool dspImpl, Bool full, const char *xindent)
00851 {
00852 std::string s;
00853 std::string indent = xindent;
00854
00855 if (dspImpl) {
00856 s = indent + "Type: BTree\n";
00857 s += indent + "Degree: " + str_convert((long)degree) + "\n";
00858 s += indent + "Data size: " + str_convert((long)dataSize) + "\n";
00859 s += indent + "Key size: " + str_convert((long)keySize) + "\n";
00860 s += indent + "Key type: " + eyedbsm::Idx::typeString((eyedbsm::Idx::Type)keyType) + "\n";
00861 s += indent + "Key offset: " + str_convert((long)keyOffset) + "\n";
00862 }
00863
00864 s += indent + "Total object count: " + str_convert((long)total_object_count) + "\n";
00865 s += indent + "Total btree object count: " + str_convert((long)total_btree_object_count) + "\n";
00866 s += indent + "Total btree node count: " + str_convert((long)total_btree_node_count) + "\n";
00867 s += indent + "Btree node size: " + str_convert((long)btree_node_size) + "\n";
00868 s += indent + "Btree key object size: " +
00869 get_string_size(btree_key_object_size) + "\n";
00870 s += indent + "Btree data object size: " +
00871 get_string_size(btree_data_object_size) + "\n";
00872 s += indent + "Total btree object size: " +
00873 get_string_size(total_btree_object_size) + "\n";
00874 return s;
00875 }
00876
00877 BTreeIndexStats::BTreeIndexStats()
00878 {
00879 }
00880
00881 BTreeIndexStats::~BTreeIndexStats()
00882 {
00883 }
00884
00885
00886 class HIdxStatsFormat {
00887
00888 public:
00889 enum Type {
00890 Num,
00891 ObjCnt,
00892 HObjCnt,
00893 HSz,
00894 BSz,
00895 FSz,
00896 LAST
00897 };
00898
00899 HIdxStatsFormat(const char *_fmt);
00900
00901 bool hasFormat() const {
00902 return fmt != 0;
00903 }
00904
00905 const char *getError() const {
00906 if (errmsg.size())
00907 return errmsg.c_str();
00908 return 0;
00909 }
00910
00911 void print(int values[], FILE *fd = stdout);
00912
00913 ~HIdxStatsFormat() {
00914 delete [] fmt;
00915 }
00916
00917 private:
00918 std::string errmsg;
00919 static const int maxprms = 7;
00920 char *fmt;
00921 int pos[maxprms];
00922 unsigned int pos_cnt;
00923 };
00924
00925 HIdxStatsFormat::HIdxStatsFormat(const char *_fmt)
00926 {
00927 fmt = (_fmt ? new char[strlen(_fmt)+1] : 0);
00928 if (!fmt) return;
00929 pos_cnt = 0;
00930 const char *s = _fmt;
00931 char *p = fmt;
00932 char c;
00933 while (c = *s) {
00934 if (c == '%') {
00935 *p++ = '%';
00936 c = *++s;
00937 if (c == 'n') {
00938 pos[pos_cnt++] = Num;
00939 *p++ = 'd';
00940 }
00941 else if (c == 'O') {
00942 pos[pos_cnt++] = ObjCnt;
00943 *p++ = 'd';
00944 }
00945 else if (c == 'o') {
00946 pos[pos_cnt++] = HObjCnt;
00947 *p++ = 'd';
00948 }
00949 else if (c == 's') {
00950 pos[pos_cnt++] = HSz;
00951 *p++ = 'd';
00952 }
00953 else if (c == 'b') {
00954 pos[pos_cnt++] = BSz;
00955 *p++ = 'd';
00956 }
00957 else if (c == 'f') {
00958 pos[pos_cnt++] = FSz;
00959 *p++ = 'd';
00960 }
00961 else if (c == '%')
00962 *p++ = '%';
00963 else {
00964 printf("ERROR !!!!\n");
00965 errmsg = std::string("unknown format sequence: %%n, %%o, %%h or %%z expected\n");
00966 delete [] fmt;
00967 fmt = 0;
00968 return;
00969 }
00970 }
00971 else if (c == '\\') {
00972 c = *++s;
00973 #define _ESC_(X, Y) case X: *p++ = Y; break
00974 switch(c) {
00975 _ESC_('a', '\a');
00976 _ESC_('b', '\b');
00977 _ESC_('f', '\f');
00978 _ESC_('n', '\n');
00979 _ESC_('r', '\r');
00980 _ESC_('t', '\t');
00981 _ESC_('v', '\v');
00982 _ESC_('\'', '\'');
00983 _ESC_('\"', '"');
00984 _ESC_('\\', '\\');
00985
00986 default:
00987 *p++ = '\\';
00988 *p++ = c;
00989 }
00990 }
00991 else
00992 *p++ = c;
00993
00994 s++;
00995 }
00996 *p = 0;
00997 }
00998
00999 void
01000 HIdxStatsFormat::print(int values[], FILE *fd)
01001 {
01002 int v[maxprms];
01003 for (int i = 0; i < pos_cnt; i++)
01004 v[i] = values[pos[i]];
01005 fprintf(fd, fmt, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
01006 }
01007
01008 Status
01009 HashIndexStats::printEntries(const char *fmt, FILE *fd)
01010 {
01011 HIdxStatsFormat f(fmt);
01012 if (f.getError())
01013 return Exception::make(IDB_ERROR, f.getError());
01014
01015 for (int i = 0; i < key_count; i++) {
01016 int values[HIdxStatsFormat::LAST];
01017 HashIndexStats::Entry *e = &entries[i];
01018 values[HIdxStatsFormat::Num] = i;
01019 values[HIdxStatsFormat::ObjCnt] = e->object_count;
01020 values[HIdxStatsFormat::HObjCnt] = e->hash_object_count;
01021 values[HIdxStatsFormat::HSz] = e->hash_object_size;
01022 values[HIdxStatsFormat::BSz] = e->hash_object_busy_size;
01023 values[HIdxStatsFormat::FSz] = e->hash_object_size - e->hash_object_busy_size;
01024 f.print(values, fd);
01025 }
01026
01027 return Success;
01028 }
01029
01030 const char HashIndexStats::fmt_help[] =
01031 " <fmt> is a printf-like string where:\n"
01032 " %%n denotes the number of keys,\n"
01033 " %%O denotes the count of object entries for this key,\n"
01034 " %%o denotes the count of hash objects for this key,\n"
01035 " %%s denotes the size of hash objects for this key,\n"
01036 " %%b denotes the busy size of hash objects for this key,\n"
01037 " %%f denotes the free size of hash objects for this key.\n"
01038 "\n For instance:\n"
01039 " --fmt=\"%%n %%O\\n\"\n"
01040 " --fmt=\"%%n -> %%O, %%o, %%s\\n\"\n";
01041
01042 }