IndexImpl.cc

00001 /* 
00002    EyeDB Object Database Management System
00003    Copyright (C) 1994-2008 SYSRA
00004    
00005    EyeDB is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009    
00010    EyeDB is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014    
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with this library; if not, write to the Free Software
00017    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA 
00018 */
00019 
00020 /*
00021    Author: Eric Viara <viara@sysra.com>
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     //kvarr.trace();
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     //printf("indeximpl:: construct %p\n", this);
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     //printf("indeximpl:: garbage %p\n", this);
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     //memset(this, 0, sizeof(*this));
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 }

Generated on Mon Dec 22 18:15:56 2008 for eyedb by  doxygen 1.5.3