HIdx.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 #include <eyedbconfig.h>
00025 
00026 //#define CACHE_FOR_LOCK
00027 
00028 //#define TRUSS1_GC
00029 //#define TRUSS2_GC
00030 #define OPT_FREELIST
00031 
00032 #include <eyedbsm/eyedbsm.h>
00033 #include <eyedbsm/HIdx.h>
00034 #include "IdxP.h"
00035 #include <string.h>
00036 #include <stdlib.h>
00037 #include <stdio.h>
00038 #include <unistd.h>
00039 #include <assert.h>
00040 #include <eyedblib/rpc_lib.h>
00041 #include <eyedblib/performer.h>
00042 #include <eyedblib/strutils.h>
00043 #include <eyedbsm/xdr.h>
00044 #include <eyedblib/log.h>
00045 #include <eyedblib/m_mem.h>
00046 #include "lib/m_mem_p.h"
00047 
00048 #include <map>
00049 #include <vector>
00050 
00051 namespace eyedbsm {
00052   class MapHeader;
00053   class DbHeader;
00054   class DatafileDesc;
00055   class DataspaceDesc;
00056 
00057 #define OPTIM_LARGE_OBJECTS
00058 
00059 #define DATASZ_SIZE 4
00060 
00061 #define NEW_WAIT
00062 //#define MULTI_LIST
00063 
00064 //#define TRACK_MAP
00065 //#define TRACK_MAP_2
00066 
00067 #define HIDX_XDR
00068 #define HIDX_XDR_OID
00069 #define HIDX_XDR_OVERHEAD
00070 
00071 #define NO_EXTEND
00072 
00073 #define NullOffset (-1)
00074 
00075 //#define TRACE_HIDX
00076 //#define ESM_HIDX_REGISTER
00077 
00078 #define VARSZ_DATACNT
00079 
00080 #define NEW_HASH_KEY
00081 #define NEW_HASH_KEY_VERSION 206004
00082 
00083 #define STRTYPE(IDX) \
00084     ((IDX)->hidx.keytype == Idx::tString)
00085 
00086 #define IDXSZ(V) (sizeof(HIdx::_Idx))
00087 
00088   extern Boolean backend_interrupt;
00089 
00090 #define data_group_sz(I, THIS) \
00091  (THIS)->data_grouped_sizeof + (I) * (THIS)->hidx.datasz
00092 
00093 static void
00094 dump_keytype(const char *msg, const Idx::KeyType &keytype,
00095              const HIdx::_Idx &hidx)
00096 {
00097   printf("%s:\n"
00098          "    type=%s count=%d offset=%d\n", msg,
00099          Idx::typeString(keytype.type), keytype.count, keytype.offset);
00100   printf("    hidx.keytype=%s hidx.keysz=%d hidx.offset=%d\n",
00101          Idx::typeString((Idx::Type)hidx.keytype), hidx.keysz, hidx.offset);
00102 }
00103 
00104 static void cmp_offset(unsigned long off, const char *str)
00105 {
00106   printf("SAME OFFSET %s: %d\n", str, off);
00107 }
00108 
00109 #define mcp(D, S, N) \
00110 do { \
00111   int __n__ = (N); \
00112   char *__d__ = (char *)(D), *__s__ = (char *)(S); \
00113   while(__n__--) \
00114     *__d__++ = *__s__++; \
00115 } while(0)
00116 
00117 #define mset(D, V, N) \
00118 do { \
00119   int __n__ = (N); \
00120   char *__d__ = (char *)(D); \
00121   while(__n__--) \
00122     *__d__++ = V; \
00123 } while(0)
00124 
00125 static void x2h_idx(HIdx::_Idx *idx);
00126 static void h2x_idx(HIdx::_Idx *idx, const HIdx::_Idx *);
00127 static void x2h_chd(HIdx::CListHeader *);
00128 static void h2x_chd(HIdx::CListHeader *, const HIdx::CListHeader *);
00129 static void x2h_header(HIdx::CListObjHeader *);
00130 static void h2x_header(HIdx::CListObjHeader *, const HIdx::CListObjHeader *);
00131 static void x2h_overhead(HIdx::CellHeader *);
00132 static void h2x_overhead(HIdx::CellHeader *, const HIdx::CellHeader *);
00133 
00134 #define KEY_OFF (3)
00135 
00136 #define OFFSET(T, X) (unsigned long)(&((T *)0)->X)
00137 
00138 const char HIdxCursor::defaultSKey[] = "";
00139 
00140 #define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
00141 
00142 static const int IniSize_Default = 4096;
00143 //static const int IniObjCnt_Default = 256;
00144 
00145 static const unsigned int SmallThreshold_Default = 4;
00146 
00147 static const unsigned int IniSizeSmall_Default = 256;
00148 static const unsigned int IniObjCntSmall_Default = 8;
00149 
00150 static const int XCoef_Default = 1;
00151 
00152 static int
00153 get_iniobjcnt_def(const HIdx::_Idx &hidx)
00154 {
00155   if (hidx.keysz == HIdx::VarSize)
00156     return 0;
00157 
00158   return hidx.key_count <= SmallThreshold_Default ? IniObjCntSmall_Default :
00159     (hidx.mag_order+1) / hidx.key_count;
00160 }
00161 
00162 static int
00163 get_inisize_small_def(const HIdx::_Idx &hidx)
00164 {
00165   assert(hidx.key_count <= SmallThreshold_Default);
00166 
00167   if (hidx.keysz != HIdx::VarSize) {
00168     assert(hidx.impl_hints[HIdx::IniObjCnt_Hints]);
00169     return (sizeof(HIdx::CellHeader) + hidx.keysz + hidx.datasz) * 
00170       hidx.impl_hints[HIdx::IniObjCnt_Hints];
00171     // - sizeof(HIdx::CellHeader); necessary ?
00172   }
00173 
00174   return IniSizeSmall_Default;
00175 }
00176 
00177 static int
00178 get_inisize_def(const HIdx::_Idx &hidx)
00179 {
00180   if (hidx.key_count <= SmallThreshold_Default)
00181     return get_inisize_small_def(hidx);
00182 
00183   if (hidx.keysz != HIdx::VarSize) {
00184     assert(hidx.impl_hints[HIdx::IniObjCnt_Hints]);
00185     return (sizeof(HIdx::CellHeader) + hidx.keysz + hidx.datasz) * 
00186       hidx.impl_hints[HIdx::IniObjCnt_Hints];
00187     // - sizeof(HIdx::CellHeader); necessary ?
00188   }
00189 
00190   return IniSize_Default;
00191 }
00192 
00193 static int
00194 get_xcoef_def(const HIdx::_Idx &)
00195 {
00196   return XCoef_Default;
00197 }
00198 
00199 static int
00200 get_sizemax_def(const HIdx::_Idx &hidx)
00201 {
00202   assert(hidx.impl_hints[HIdx::XCoef_Hints] &&
00203          hidx.impl_hints[HIdx::IniSize_Hints]);
00204          
00205   int xcoef = hidx.impl_hints[HIdx::XCoef_Hints];
00206   return xcoef * xcoef * hidx.impl_hints[HIdx::IniSize_Hints];
00207 }
00208 
00209 static unsigned int
00210 key_offset(int x)
00211 {
00212   return x + KEY_OFF;
00213 }
00214 
00215 //#define IDX_DBG
00216 
00217 Boolean trace_idx;
00218 FILE *trace_idx_fd = stdout;
00219 Boolean trace_idx_sync;
00220 
00221 /*extern "C" */ unsigned int getDbVersion(void *);
00222 /*extern "C" */ Boolean isWholeMapped(void *);
00223 
00224 static Boolean
00225 isPower2(int x)
00226 {
00227   int n = 0;
00228   while(x) {
00229       if ((x & 1) && ++n > 1)
00230         return False;
00231 
00232       x >>= 1;
00233     }
00234 
00235   return True;
00236 }
00237 
00238 const unsigned int HIdx::MaxKeys = 0x800000;
00239 const unsigned int HIdx::VarSize = 0xffffffff;
00240 const unsigned int HIdx::MagorderKeycountCoef = 64;
00241 
00242 #define get_gkey(V) key_offset
00243 
00244 unsigned int
00245 computeKeyCount(unsigned int key_count, int &mag_order,
00246                 unsigned int maxkeys, Boolean &pow2)
00247 {
00248   if (key_count) {
00249     key_count = (key_count > maxkeys ? maxkeys : key_count);
00250     pow2 = isPower2(key_count);
00251   }
00252   else {
00253     unsigned int ncells = (mag_order/HIdx::MagorderKeycountCoef)+1;
00254     if (ncells >= maxkeys-1)
00255       key_count = maxkeys;
00256     else {
00257       key_count = 1;
00258       
00259       for (;;) {
00260         if (key_count >= ncells)
00261           break;
00262         key_count <<= 1;
00263       }
00264 
00265       pow2 = True;
00266     }
00267   }
00268 
00269   mag_order = key_count * HIdx::MagorderKeycountCoef-1;
00270   return key_count;
00271 }
00272 
00273 static unsigned int
00274 get_keyTypeCount(const HIdx::_Idx &hidx)
00275 {
00276   if (hidx.keysz == HIdx::VarSize)
00277     return HIdx::VarSize; // changed the 29/01/02: was return 0
00278 
00279   unsigned tsz = Idx::typeSize((Idx::Type)hidx.keytype);
00280   unsigned int count = (hidx.keysz - hidx.offset) / tsz;
00281   assert(count * tsz == (hidx.keysz - hidx.offset));
00282 
00283   return count;
00284 }
00285 
00286 //#define FORCE_COPY
00287 
00288 static Boolean _isUExtend(const HIdx::_Idx &hidx)
00289 {
00290   return (hidx.impl_hints[HIdx::XCoef_Hints] > 1) ? True : False;
00291 }
00292 
00293 static Boolean _isDataGroupedByKey(const HIdx::_Idx &hidx)
00294 {
00295   return (hidx.impl_hints[HIdx::DataGroupedByKey_Hints] != 0) ? True : False;
00296 }
00297 
00298 static unsigned int _dataGroupedByKeySize(const HIdx::_Idx &hidx)
00299 {
00300   return (unsigned int)hidx.impl_hints[HIdx::DataGroupedByKey_Hints];
00301 }
00302 
00303 void
00304 HIdx::init(DbHandle *_dbh, unsigned int _keytype,
00305               unsigned int keysz, unsigned int offset,
00306               unsigned int datasz, short _dspid, int mag_order,
00307               int key_count,
00308               const int *impl_hints,
00309               unsigned int impl_hints_cnt)
00310 {
00311   dbh = _dbh;
00312   version = getDbVersion(dbh);
00313 #ifdef FORCE_COPY
00314   nocopy = False;
00315 #else
00316   nocopy = isWholeMapped(dbh);
00317 #endif
00318   memset(&hidx, 0, sizeof(hidx));
00319 
00320   hidx.key_count = computeKeyCount(key_count, mag_order, MaxKeys, pow2);
00321 
00322   hidx.idxtype = HashType;
00323   hidx.mag_order = mag_order;
00324   hidx.object_count = 0;
00325   hidx.dspid = _dspid;
00326   hidx.keytype = _keytype;
00327 
00328   hidx.keysz = keysz;
00329   hidx.datasz = datasz;
00330   hidx.offset = offset;
00331 
00332   memset(&treeoid, 0, sizeof(treeoid));
00333 #ifdef NEW_HASH_TRACE
00334   keytype.type = (Type)hidx.keytype;
00335   keytype.count = get_keyTypeCount(hidx);
00336   dump_keytype("creating hash index", keytype, hidx);;
00337 #endif
00338 
00339   hash_data = 0;
00340   hash_key = 0;
00341 #ifdef NEW_HASH_KEY
00342   set_hash_key();
00343 #endif
00344 
00345   if (impl_hints)
00346     memcpy(hidx.impl_hints, impl_hints, impl_hints_cnt*sizeof(impl_hints[0]));
00347 
00348   if (hidx.keysz == HIdx::VarSize)
00349     hidx.impl_hints[IniObjCnt_Hints] = 0; // ignored
00350   else if (!hidx.impl_hints[IniObjCnt_Hints])
00351     hidx.impl_hints[IniObjCnt_Hints] = get_iniobjcnt_def(hidx);
00352 
00353   if (!hidx.impl_hints[IniSize_Hints])
00354     hidx.impl_hints[IniSize_Hints] = get_inisize_def(hidx);
00355 
00356   if (!hidx.impl_hints[XCoef_Hints])
00357     hidx.impl_hints[XCoef_Hints] = get_xcoef_def(hidx);
00358 
00359   if (!hidx.impl_hints[SzMax_Hints])
00360     hidx.impl_hints[SzMax_Hints] = get_sizemax_def(hidx);
00361 
00362   if (_isDataGroupedByKey(hidx) && isDataVarSize()) {
00363     stat = statusMake(NOT_YET_IMPLEMENTED, "data_grouped_by_key hash indexes does not yet support variable size data");
00364     return;
00365   }
00366 
00367   mask = hidx.key_count - 1;
00368   unsigned int (*gkey)(int) = get_gkey(version);
00369 
00370   int len = gkey(hidx.key_count);
00371   IDB_LOG(IDB_LOG_IDX_CREATE,
00372           ("Creating Hash Index: magorder=%u, entries=%u "
00373            "keysz=%u, datasz=%u, "
00374            "size=%u [%d objects of size %u + 1 object of size %u]\n",
00375            hidx.mag_order,
00376            hidx.key_count,
00377            hidx.keysz,
00378            hidx.datasz,
00379            sizeof(CListHeader)*hidx.key_count+len*sizeof(Oid),
00380            hidx.key_count,
00381            sizeof(CListHeader),
00382            len*sizeof(Oid)));
00383 
00384   CListHeader *chds;
00385   chds = new CListHeader[len];
00386 
00387   memset(chds, 0, sizeof(CListHeader) * len);
00388   _Idx xidx;
00389   h2x_idx(&xidx, &hidx);
00390   mcp(chds, &xidx, sizeof(xidx));
00391   assert(sizeof(xidx) <= KEY_OFF * sizeof(CListHeader));
00392 
00393   bsize = hidx.impl_hints[IniSize_Hints];
00394 
00395   /*
00396     printf("creating index header size=%d, magorder=%d\n", sizeof(Oid) * len,
00397     hidx.mag_order);
00398   */
00399 #ifdef TRACE_HIDX
00400   printf("creating index %d\n",  sizeof(Oid) * len);
00401 #endif
00402 
00403   CListHeader *tchds = new CListHeader[len];
00404   memcpy(tchds, chds, sizeof(CListHeader) * KEY_OFF);
00405   for (int i = KEY_OFF; i < len; i++)
00406     h2x_chd(&tchds[i], &chds[i]);
00407   stat = objectCreate(dbh, tchds, sizeof(CListHeader) * len, hidx.dspid,
00408                          &treeoid);
00409   delete [] tchds;
00410 
00411   if (!stat)
00412     IDB_LOG(IDB_LOG_IDX_CREATE,
00413             ("Have Created Hash Index: treeoid=%s\n",
00414              getOidString(&treeoid)));
00415   delete [] chds;
00416   uextend = _isUExtend(hidx);
00417   data_grouped_by_key = _isDataGroupedByKey(hidx);
00418   data_grouped_sizeof = _dataGroupedByKeySize(hidx);
00419 }
00420 
00421 HIdx::HIdx(DbHandle *_dbh, KeyType _keytype,
00422            unsigned int datasz, short _dspid,
00423            int _mag_order, int key_count,
00424            const int *impl_hints,
00425            unsigned int impl_hints_cnt)
00426   : Idx(False)
00427 {
00428   keytype = _keytype;
00429   init(_dbh, (unsigned int)keytype.type,
00430        ((unsigned int)keytype.count == VarSize ? VarSize :
00431         (typeSize(keytype.type) * keytype.count) + keytype.offset),
00432        keytype.offset,
00433        datasz, _dspid, _mag_order, key_count,
00434        impl_hints, impl_hints_cnt);
00435 }
00436 
00437 unsigned int
00438 HIdx::getMagOrder(unsigned int keycount)
00439 {
00440   return keycount * HIdx::MagorderKeycountCoef;
00441 }
00442 
00443 unsigned int
00444 HIdx::getKeyCount(unsigned int magorder)
00445 {
00446   unsigned int keycount = magorder / MagorderKeycountCoef;
00447 
00448   if (keycount >= MaxKeys)
00449     return MaxKeys;
00450 
00451   return keycount ? keycount : 1;
00452 }
00453 
00454 HIdx::HIdx(DbHandle *_dbh, const Oid *_oid,
00455                  hash_key_t _hash_key,
00456                  void *_hash_data,
00457                  Boolean (*precmp)(void const * p, void const * q,
00458                                       KeyType const * type, int & r))
00459   : Idx(True, precmp), dbh(_dbh)
00460 {
00461   version = getDbVersion(_dbh);
00462   stat = objectRead(dbh, 0, IDXSZ(version), &hidx, DefaultLock, 0, 0, _oid);
00463 
00464   /*
00465     printf("version = %d %d [%d vs. %d] status %d\n",
00466     version, IDXSZ(version), sizeof(HIdx::_Idx),
00467     sizeof(OIdx), stat);
00468   */
00469     
00470   if (stat)
00471     return;
00472 
00473 #ifdef FORCE_COPY
00474   nocopy = False;
00475 #else
00476   nocopy = isWholeMapped(dbh);
00477 #endif
00478   x2h_idx(&hidx);
00479 
00480   keytype.type = (Type)hidx.keytype;
00481   keytype.count = get_keyTypeCount(hidx);
00482 
00483   hash_key = _hash_key;
00484   hash_data = _hash_data;
00485   treeoid = *_oid;
00486 
00487 #ifdef NEW_HASH_KEY
00488   set_hash_key();
00489 #endif
00490 
00491   keytype.offset = hidx.offset;
00492 
00493   //dump_keytype("Idx::HIdx", keytype, hidx);;
00494 
00495   //unsigned int (*gkey)(int) = get_gkey(version);
00496   //int len = gkey(hidx.key_count);
00497   mask = hidx.key_count - 1;
00498   pow2 = isPower2(hidx.key_count);
00499   bsize = hidx.impl_hints[IniSize_Hints];
00500   uextend = _isUExtend(hidx);
00501   data_grouped_by_key = _isDataGroupedByKey(hidx);
00502   data_grouped_sizeof = _dataGroupedByKeySize(hidx);
00503 }
00504 
00505 #ifdef NEW_HASH_KEY
00506 
00507 //  mcp(&t, (unsigned char *)(key)+((HIdx::_Idx *)xhidx)->offset, sizeof(T));
00508 
00509 #define MK_DEF_HASH_KEY(T, F) \
00510 Status \
00511 HIdx::F(const void *key, unsigned int len, void *xhidx, unsigned int &x) \
00512 { \
00513   T t; \
00514   mcp(&t, (unsigned char *)key, sizeof(T)); \
00515   x = (int)t; \
00516   return Success; \
00517 }
00518 
00519 Status
00520 HIdx::get_def_oiddata_hash_key(const void *key, unsigned int len,
00521                                   void *xhidx, unsigned int &x)
00522 {
00523   Oid oid;
00524   mcp(&oid, (unsigned char *)(key), sizeof(oid));
00525   x = oid.getNX();
00526   return Success;
00527 }
00528 
00529 MK_DEF_HASH_KEY(eyedblib::int16, get_def_int16data_hash_key);
00530 MK_DEF_HASH_KEY(eyedblib::int32, get_def_int32data_hash_key);
00531 MK_DEF_HASH_KEY(eyedblib::int64, get_def_int64data_hash_key);
00532 MK_DEF_HASH_KEY(eyedblib::float32, get_def_float32data_hash_key);
00533 MK_DEF_HASH_KEY(eyedblib::float64, get_def_float64data_hash_key);
00534 
00535 void
00536 HIdx::set_hash_key()
00537 {
00538 #ifdef NEW_HASH_TRACE
00539   printf("hash_key for index %s [hash_key=%p]\n",
00540          getOidString(&treeoid), hash_key);
00541   dump_keytype("hash_key : ", keytype, hidx);;
00542 #endif
00543   if (hash_key) return;
00544 
00545   hash_data = 0;
00546   /*
00547   if (hidx.keytype == tString) {
00548     hash_key = get_def_string_hash_key;
00549     return;
00550   }
00551   */
00552 
00553   if (version >= NEW_HASH_KEY_VERSION) {
00554     hash_data = &hidx;
00555 
00556     switch(hidx.keytype) {
00557     case tString:
00558       hash_key = get_def_nstring_hash_key;
00559       return;
00560 
00561     case tInt16:
00562     case tUnsignedInt16:
00563       hash_key = get_def_int16data_hash_key;
00564       return;
00565 
00566     case tInt32:
00567     case tUnsignedInt32:
00568       hash_key = get_def_int32data_hash_key;
00569       return;
00570 
00571     case tInt64:
00572     case tUnsignedInt64:
00573       hash_key = get_def_int64data_hash_key;
00574       return;
00575 
00576     case tOid:
00577       hash_key = get_def_oiddata_hash_key;
00578       return;
00579 
00580     case tFloat32:
00581       hash_key = get_def_float32data_hash_key;
00582       return;
00583 
00584     case tFloat64:
00585       hash_key = get_def_float64data_hash_key;
00586       return;
00587     }
00588 
00589     hash_data = 0;
00590   }
00591 
00592   if (hidx.keytype == tString) {
00593     hash_key = get_def_string_hash_key;
00594     return;
00595   }
00596 
00597   hash_key = get_def_rawdata_hash_key;
00598 }
00599 #endif
00600 
00601 void
00602 HIdx::open(hash_key_t _hash_key,
00603               void *_hash_data,
00604               Boolean (*_precmp)(void const * p, void const * q,
00605                                     KeyType const * type, int & r))
00606 {
00607   keytype.type = (Type)hidx.keytype;
00608   keytype.count = get_keyTypeCount(hidx);
00609   keytype.offset = hidx.offset;
00610 
00611   hash_key = _hash_key;
00612   hash_data = _hash_data;
00613 #ifdef NEW_HASH_KEY
00614   set_hash_key();
00615   assert(hash_key);
00616 #endif
00617   precmp = _precmp;
00618   opened = True;
00619 }
00620 
00621 HIdx::~HIdx()
00622 {
00623   flush_cache(false);
00624 }
00625 
00626 Boolean trace_it;
00627 
00628 #define first_char ' '
00629 #define last_char  '~'
00630 #define asc(x) ((unsigned int)((x) - first_char))
00631 #define asc_len ((unsigned int)(last_char - first_char + 1))
00632 
00633 #define NEW_HASH_KEY2
00634 
00635 Status
00636 HIdx::get_def_string_hash_key(const void *key, unsigned int len, void *, unsigned int &x)
00637 {
00638 #ifdef NEW_HASH_KEY2
00639   unsigned char *k = (unsigned char *)key;
00640   x = 1;
00641   for (unsigned int i = 0; i < len; i++) {
00642     x *= *k++;
00643     x ^= x >> 8;
00644   }
00645 #else
00646   x = 0;
00647   char *k = (char *)key;
00648   for (unsigned int i = 0; i < len; i++)
00649     x += *k++ * (i+1); //x += *k++;
00650 
00651 #endif
00652   return Success;
00653 }
00654 
00655 Status
00656 HIdx::get_def_nstring_hash_key(const void *key, unsigned int len, void *, unsigned int &x)
00657 {
00658   unsigned char *k = (unsigned char *)key;
00659   if (len > 12)
00660     len = 12;
00661 #ifdef NEW_HASH_KEY2
00662   x = 1;
00663   for (unsigned int i = 0; i < len; i++) {
00664     x *= *k++;
00665     x ^= x >> 8;
00666   }
00667 #else
00668   int coef = 1;
00669   eyedblib::int64 r = 0;
00670   for (unsigned int n = 0; n < len; n++, k++) {
00671     r += coef * asc(*k);
00672     coef *= asc_len;
00673   }
00674 
00675   x = r;
00676 #endif
00677   return Success;
00678 }
00679 
00680 Status
00681 HIdx::get_string_hash_key(const void *key, unsigned int len, unsigned int &x) const
00682 {
00683 #ifdef NEW_HASH_KEY
00684   assert(hash_key);
00685 #endif
00686   if (hash_key)
00687     return hash_key(key, len, hash_data, x);
00688 
00689   abort();
00690   return get_def_string_hash_key(key, len, 0, x);
00691 }
00692 
00693 Status
00694 HIdx::get_def_rawdata_hash_key(const void *key, unsigned int len, void *, unsigned int &x)
00695 {
00696   x = 0;
00697   unsigned char *k = (unsigned char *)key;
00698   for (unsigned int i = 0; i < len; i++)
00699     x += *k++;
00700 
00701   return Success;
00702 }
00703 
00704 Status
00705 HIdx::get_rawdata_hash_key(const void *key, unsigned int len, unsigned int &x) const
00706 {
00707 #ifdef NEW_HASH_KEY
00708   assert(hash_key);
00709 #endif
00710   if (hash_key)
00711     return hash_key(key, len, hash_data, x);
00712 
00713   return get_def_rawdata_hash_key(key, len, 0, x);
00714 }
00715 
00716 static inline void const *
00717 fpos_(void const * p, int offset)
00718 {
00719   return (char const *)p + offset;
00720 }
00721 
00722 inline Status HIdx::get_key(unsigned int &n, const void *key, unsigned int *size) const
00723 {
00724   key = fpos_(key, keytype.offset);
00725   Status s;
00726   unsigned int x;
00727 
00728   unsigned int datasz = (isDataVarSize() ? 0 : hidx.datasz);
00729 
00730   if (STRTYPE(this)) {
00731     int len = strlen((char *)key);
00732     s = get_string_hash_key(key, len, x);
00733     if (s)
00734       return s;
00735     
00736     if (size) {
00737       if (hidx.keysz == VarSize) {
00738         *size = datasz + len + 1;
00739       }
00740       else {
00741         *size = datasz + hidx.keysz;
00742       }
00743     }
00744     
00745     n = (pow2 ? (x & mask) : (x % mask));
00746     return Success;
00747   }
00748 
00749   s = get_rawdata_hash_key(key, hidx.keysz - keytype.offset, x);
00750   if (s)
00751     return s;
00752 
00753   if (size) {
00754     *size = datasz + hidx.keysz;
00755   }
00756   
00757   n = (pow2 ? (x & mask) : (x % mask));
00758   return Success;
00759 }
00760 
00761 Status
00762 HIdx::suppressObjectFromFreeList(CListHeader &chd, unsigned int chd_k, CListObjHeader &h,
00763                                     const Oid &koid)
00764 {
00765 #ifdef TRACK_MAP
00766   printf("suppressObjectFromFreeList(%s)\n", getOidString(&koid));
00767 #endif  
00768   Status s;
00769 
00770   if (h.clobj_free_prev.getNX()) {
00771     Oid xoid;
00772     h2x_oid(&xoid, &h.clobj_free_next);
00773     s = objectWrite(dbh, OFFSET(CListObjHeader, clobj_free_next), sizeof(Oid),
00774                        &xoid, &h.clobj_free_prev);
00775     if (s)
00776       return s;
00777   }
00778   
00779   if (h.clobj_free_next.getNX()) {
00780     Oid xoid;
00781     h2x_oid(&xoid, &h.clobj_free_prev);
00782     s = objectWrite(dbh, OFFSET(CListObjHeader, clobj_free_prev), sizeof(Oid),
00783                        &xoid, &h.clobj_free_next);
00784     if (s)
00785       return s;
00786   }
00787   
00788   if (chd.clobj_free_first.getNX() == koid.getNX()) {
00789     chd.clobj_free_first = h.clobj_free_next;
00790     s = writeCListHeader(chd_k, chd);
00791     if (s)
00792       return s;
00793   }
00794 
00795   mset(&h.clobj_free_prev, 0, sizeof(h.clobj_free_prev));
00796   mset(&h.clobj_free_next, 0, sizeof(h.clobj_free_next));
00797 
00798   return Success;
00799 }
00800 
00801 Status
00802 HIdx::suppressObjectFromList(CListHeader &chd, unsigned int chd_k, CListObjHeader &h,
00803                                 const Oid &koid)
00804 {
00805 #ifdef TRACK_MAP
00806   printf("suppressObjectFromList(%s)\n", getOidString(&koid));
00807 #endif  
00808   Status s;
00809 
00810   if (h.clobj_prev.getNX()) {
00811     Oid xoid;
00812     h2x_oid(&xoid, &h.clobj_next);
00813     s = objectWrite(dbh, OFFSET(CListObjHeader, clobj_next), sizeof(Oid),
00814                        &xoid, &h.clobj_prev);
00815     if (s)
00816       return s;
00817   }
00818   
00819   if (h.clobj_next.getNX()) {
00820     Oid xoid;
00821     h2x_oid(&xoid, &h.clobj_prev);
00822     s = objectWrite(dbh, OFFSET(CListObjHeader, clobj_prev), sizeof(Oid),
00823                        &xoid, &h.clobj_next);
00824     if (s)
00825       return s;
00826   }
00827   
00828   Boolean write_chd = False;
00829   if (chd.clobj_first.getNX() == koid.getNX()) {
00830     chd.clobj_first = h.clobj_next;
00831     write_chd = True;
00832   }
00833 
00834   if (chd.clobj_last.getNX() == koid.getNX()) {
00835     chd.clobj_last = h.clobj_prev;
00836     write_chd = True;
00837   }
00838 
00839   if (write_chd) {
00840     s = writeCListHeader(chd_k, chd);
00841     if (s)
00842       return s;
00843   }
00844 
00845   return objectDelete(dbh, &koid);
00846 }
00847 
00848 Status
00849 HIdx::modifyObjectSize(int osize, int nsize, const Oid &koid, 
00850                        Oid &nkoid)
00851 {
00852   // ATTENTION:
00853   // 1. il ne faut utiliser cette fonction qui si koid est un oid physique
00854   //    test: if (isPhysicalOid(dbh, &koid))
00855   // 2. il faut creer le nouvel objet sur le meme dataspace !!
00856   //    => objectRead() permet de recuperer le datid mais objectCreate()
00857   //       necessite le dspid. Comment fait-on ?
00858   //       créer une fonction: datGetDspid(dbh, short datid, short *dspid)
00859   //printf("Modify Object Size from %d to %d\n", osize, nsize);
00860 
00861   unsigned char *data = new unsigned char[osize];
00862   short datid;
00863   Status s = objectRead(dbh, 0, osize, data, DefaultLock, &datid,
00864                               0, &koid);
00865   if (s) {
00866     delete [] data;
00867     return s;
00868   }
00869 
00870   short dspid;
00871   s = datGetDspid(dbh, datid, &dspid);
00872 
00873 #ifdef OPTIM_LARGE_OBJECTS
00874   if (!s)
00875     s = objectCreate(dbh, ObjectNone, nsize, dspid, &nkoid);
00876 #else
00877   if (!s)
00878     s = objectCreate(dbh, 0, nsize, dspid, &nkoid);
00879 #endif
00880 
00881   if (s) {
00882     delete[] data;
00883     return s;
00884   }
00885 
00886   s = objectWrite(dbh, 0, osize, data, &nkoid);
00887   delete [] data;
00888   if (s) {
00889     (void)objectDelete(dbh, &nkoid);
00890     return s;
00891   }
00892 
00893   s = objectDelete(dbh, &koid);
00894   if (s)
00895     (void)objectDelete(dbh, &nkoid);
00896 
00897   return s;
00898 }
00899 
00900 Status
00901 HIdx::replaceObjectInList(CListHeader &chd, unsigned int chd_k, CListObjHeader &h,
00902                              const Oid &koid, const Oid &nkoid)
00903 {
00904 #ifdef TRACK_MAP
00905   printf("replaceObjectFromList(%s, %s)\n", getOidString(&koid),
00906          getOidString(&nkoid));
00907   printf("CHD first=%s last=%s\n", getOidString(&chd.first), getOidString(&chd.last));
00908   printf("CHD2 free_first=%s\n",
00909          getOidString(&chd.free_first));
00910   printf("HEADER prev=%s, next=%s, free_prev=%s, free_next=%s\n",
00911          getOidString(&h.clobj_prev),
00912          getOidString(&h.clobj_next),
00913          getOidString(&h.clobj_free_prev),
00914          getOidString(&h.clobj_free_next));
00915 #endif  
00916   Status s;
00917 
00918   Oid xoid;
00919   h2x_oid(&xoid, &nkoid);
00920 
00921   if (h.clobj_prev.getNX()) {
00922     s = objectWrite(dbh, OFFSET(CListObjHeader, clobj_next), sizeof(Oid),
00923                        &xoid, &h.clobj_prev);
00924     if (s)
00925       return s;
00926   }
00927   
00928   if (h.clobj_next.getNX()) {
00929     s = objectWrite(dbh, OFFSET(CListObjHeader, clobj_prev), sizeof(Oid),
00930                        &xoid, &h.clobj_next);
00931     if (s)
00932       return s;
00933   }
00934   
00935   if (h.clobj_free_prev.getNX()) {
00936     s = objectWrite(dbh, OFFSET(CListObjHeader, clobj_free_next), sizeof(Oid),
00937                        &xoid, &h.clobj_free_prev);
00938     if (s)
00939       return s;
00940   }
00941   
00942   if (h.clobj_free_next.getNX()) {
00943     s = objectWrite(dbh, OFFSET(CListObjHeader, clobj_free_prev), sizeof(Oid),
00944                        &xoid, &h.clobj_free_next);
00945     if (s)
00946       return s;
00947   }
00948   
00949   Boolean write_chd = False;
00950   if (chd.clobj_first.getNX() == koid.getNX()) {
00951     chd.clobj_first = xoid;
00952     write_chd = True;
00953   }
00954 
00955   if (chd.clobj_last.getNX() == koid.getNX()) {
00956     chd.clobj_last = xoid;
00957     write_chd = True;
00958   }
00959 
00960   if (chd.clobj_free_first.getNX() == koid.getNX()) {
00961     chd.clobj_free_first = xoid;
00962     write_chd = True;
00963   }
00964 
00965   if (write_chd) {
00966     s = writeCListHeader(chd_k, chd);
00967     if (s)
00968       return s;
00969   }
00970 
00971   return Success;
00972 }
00973 
00974 //#define BUG_DATA_STORE
00975 #define BUG_DATA_STORE2
00976 
00977 Status
00978 HIdx::insert_realize(CListHeader &chd, unsigned int chd_k, const void *key,
00979                      unsigned int size, const void *xdata,
00980                      const Oid &koid,
00981                      CListObjHeader &h, int offset, CellHeader &o, unsigned int datasz)
00982 {
00983   int osize = o.size, onext = o.cell_free_next;
00984   int ovsize = size + sizeof(CellHeader);
00985   Status s;
00986 
00987   assert(o.free);
00988 
00989   /*
00990   printf("insert_realize offset %d o.free %d o.cell_free_next %d o.cell_free_prev %d\n",
00991          offset, o.free, o.cell_free_next, o.cell_free_prev);
00992   */
00993 
00994 #ifdef TRACK_MAP
00995   printf("insert_realize(%d vs. %d", osize, size);
00996   if (hidx.datasz >= sizeof(Oid)) {
00997     Oid xdata_oid;
00998     memcpy(&xdata_oid, xdata, sizeof(Oid));
00999     printf(". [%s]", getOidString(&xdata_oid));
01000   }
01001   printf("\n");
01002 #endif
01003 
01004 #ifdef BUG_DATA_STORE
01005   if (osize > size + sizeof(CellHeader))
01006     o.size = size;
01007   else
01008     ovsize += osize - size;
01009 #endif
01010 
01011 #ifdef HAS_ALLOC_BUFFER
01012   char *data = insert_buffer.alloc(ovsize);
01013 #else
01014   char *data = (char *)m_malloc(ovsize);
01015 #endif
01016   if (STRTYPE(this))
01017     memcpy(data + sizeof(CellHeader), key, strlen((char *)key)+1);
01018   else if (hidx.keytype == tUnsignedChar || hidx.keytype == tChar ||
01019            hidx.keytype == tSignedChar)
01020     memcpy(data + sizeof(CellHeader), key, size - datasz);
01021   else {
01022     char xkey[Idx_max_type_size];
01023     assert(size - datasz <= Idx_max_type_size);
01024     h2x(xkey, key, keytype);
01025     memcpy(data + sizeof(CellHeader), xkey, size - datasz);
01026   }
01027 
01028   if (o.cell_free_next != NullOffset) {
01029     CellHeader no;
01030     s = readCellHeader(o.cell_free_next, koid, no);
01031     if (s)
01032       return s;
01033     assert(no.free);
01034     no.cell_free_prev = o.cell_free_prev;
01035     s = writeCellHeader(o.cell_free_next, koid, no);
01036     if (s)
01037       return s;
01038   }
01039 
01040   if (o.cell_free_prev != NullOffset) {
01041     CellHeader no;
01042     s = readCellHeader(o.cell_free_prev, koid, no);
01043     if (s)
01044       return s;
01045     assert(no.free);
01046     no.cell_free_next = o.cell_free_next;
01047     s = writeCellHeader(o.cell_free_prev, koid, no);
01048     if (s)
01049       return s;
01050   }
01051   else {
01052     assert(h.cell_free_first == offset);
01053     h.cell_free_first = o.cell_free_next;
01054   }
01055 
01056 #if 0
01057   if (h.cell_free_first == offset) {
01058     printf("h.cell_free_first == offset %d\n", offset);
01059     if (o.cell_free_next != NullOffset) {
01060       CellHeader no;
01061       s = readCellHeader(o.cell_free_next, koid, no);
01062       if (s)
01063         return s;
01064       // EV : 3/05/07
01065       assert(no.free);
01066       no.cell_free_prev = NullOffset;
01067       s = writeCellHeader(o.cell_free_next, koid, no);
01068       if (s)
01069         return s;
01070     }
01071     h.cell_free_first = o.cell_free_next;
01072     printf("setting free_first to %d\n", h.cell_free_first);
01073   }
01074 #endif
01075 
01076 
01077 #ifndef BUG_DATA_STORE
01078   if (osize > size + sizeof(CellHeader))
01079     o.size = size;
01080 #endif
01081 
01082   o.free = 0;
01083   o.cell_free_next = NullOffset;
01084   o.cell_free_prev = NullOffset;
01085   CellHeader to;
01086   h2x_overhead(&to, &o);
01087   mcp(data, &to, sizeof(to));
01088   //  memcpy(data + ovsize - hidx.datasz, xdata, hidx.datasz);
01089   if (isDataVarSize()) {
01090     unsigned int xdatasz = h2x_u32(datasz);
01091     memcpy(data + ovsize - datasz - DATASZ_SIZE, &xdatasz, DATASZ_SIZE);
01092     memcpy(data + ovsize - datasz, xdata, datasz);
01093   }
01094   else {
01095     memcpy(data + ovsize - datasz, xdata, datasz);
01096   }
01097   //printf("writing OBJECT %s of size %d offset = %d total = %d\n", getOidString(&koid), ovsize, offset, offset+ovsize);
01098   s = objectWrite(dbh, offset, ovsize, data, &koid);
01099 #ifndef HAS_ALLOC_BUFFER
01100   free(data);
01101 #endif
01102   if (s)
01103     return s;  
01104 
01105   h.free_whole -= osize;
01106 
01107 #if 0
01108   assert(!writeCListObjHeader(koid, h));
01109 #endif
01110 
01111   if (osize == size) {
01112 #ifdef TRACK_MAP
01113     printf("exact size %d\n", size);
01114 #endif
01115   }
01116   else if (osize > size + sizeof(CellHeader)) {
01117     /* generation d'une nouvelle cellule */
01118 #ifdef TRACK_MAP
01119     printf("split cell %d %d %d %d\n", size+sizeof(CellHeader), osize, offset, h.cell_free_first);
01120 #endif
01121     int noffset = offset + size + sizeof(CellHeader);
01122     s = insertCell(noffset, osize - size - sizeof(CellHeader), h, koid);
01123     if (s)
01124       return s;
01125   }
01126 #ifdef TRACK_MAP
01127   else {
01128     printf("special case: we are loosing some place %s ?\n", getOidString(&koid));
01129   }
01130 #endif
01131 
01132   h.free_cnt--;
01133   h.alloc_cnt++;
01134 
01135   /*
01136   printf("insert: ovsize=%d, free_whole=%d, free_cnt=%d, alloc_cnt=%d\n",
01137          ovsize, h.free_whole, h.free_cnt, h.alloc_cnt);
01138   */
01139 
01140   // changed this test the 29/06/02 to allow to get rid of unuseful objects
01141 #ifdef OPT_FREELIST
01142   if (!h.free_cnt || (STRTYPE(this) && h.free_whole <= sizeof(CellHeader)+8))
01143 #else
01144   if (!h.free_cnt)
01145 #endif
01146     {
01147 #ifdef TRACK_MAP
01148     printf("making chain for new object\n");
01149 #endif
01150     Status s;
01151     // ASTUCE : si la taille n'est pas au maximum, alors ne pas supprimer
01152     // cet objet de la free list mais, au contraire, l'étendre en utilisant
01153     // hints[XCoef_Hints].
01154     if (!uextend || !candidateForExtension(h)) {
01155 #ifdef TRUSS2_GC
01156       if (h.free_cnt) {
01157         printf("get rid of this fucking object %d %s\n", h.free_whole, getOidString(&koid));
01158       }
01159 #endif
01160       s = suppressObjectFromFreeList(chd, chd_k, h, koid);
01161       if (s)
01162         return s;
01163     }
01164   }
01165 
01166   s = writeCListObjHeader(koid, h);
01167 
01168   if (!s)
01169     s = count_manage(dbh, 1);
01170 
01171   return s;
01172 }
01173 
01174 Status
01175 HIdx::count_manage(DbHandle *_dbh, int inc)
01176 {
01177   unsigned int count;
01178   Status s = objectRead(_dbh, sizeof(unsigned int),
01179                         sizeof(unsigned int), &count,
01180                         DefaultLock, 0, 0, &treeoid);
01181   if (s)
01182     return s;
01183   count = x2h_u32(count);
01184   unsigned int o_count = hidx.object_count;
01185 
01186   hidx.object_count = count + inc;
01187   count = h2x_u32(hidx.object_count);
01188 
01189   s = objectWrite(_dbh, sizeof(unsigned int),
01190                   sizeof(unsigned int), &count, &treeoid);
01191   
01192   if (s) hidx.object_count = o_count;
01193   return s;
01194 }
01195 
01196 Status
01197 HIdx::readCListHeader(unsigned int k, CListHeader &chd) const
01198 {
01199   Status s;
01200   unsigned int (*gkey)(int) = get_gkey(version);
01201 
01202   s = objectRead(dbh, gkey(k) * sizeof(CListHeader), sizeof(CListHeader), &chd,
01203                     DefaultLock, 0, 0, &treeoid);
01204   if (s)
01205     return s;
01206   x2h_chd(&chd);
01207   return Success;
01208 }
01209 
01210 Status
01211 HIdx::readCListObjHeader(const Oid &koid, CListObjHeader &h) const
01212 {
01213   Status s;
01214   s = objectRead(dbh, 0, sizeof(CListObjHeader), &h, DefaultLock,
01215                     0, 0, &koid);
01216   if (s)
01217     return s;
01218   x2h_header(&h);
01219   return Success;
01220 }
01221 
01222 Status
01223 HIdx::writeCListObjHeader(const Oid &koid, const CListObjHeader &h) const
01224 {
01225 #if 0
01226   if (h.cell_free_first != NullOffset) {
01227     CellHeader o = {0};
01228     Status s = readCellHeader(h.cell_free_first, koid, o);
01229     if (s)
01230       statusPrint(s, "...");
01231     assert(o.free);
01232   }
01233 #endif
01234   CListObjHeader th;
01235   h2x_header(&th, &h);
01236   return objectWrite(dbh, 0, sizeof(CListObjHeader), &th, &koid);
01237 }
01238 
01239 Status
01240 HIdx::readCellHeader(int offset, const Oid &koid, CellHeader &o) const
01241 {
01242   Status s;
01243   s = objectRead(dbh, offset, sizeof(CellHeader), &o, DefaultLock,
01244                     0, 0, &koid);
01245   if (s)
01246     return s;
01247   x2h_overhead(&o);
01248   return Success;
01249 }
01250 
01251 void HIdx::printCellHeader(const HIdx::CellHeader *o, int offset) const
01252 {
01253   printf("CellHeader at %d\n", offset);
01254   printf("  o.free %d\n", o->free);
01255   printf("  o.size %d\n", o->size);
01256   printf("  o.cell_free_prev %d\n", o->cell_free_prev);
01257   printf("  o.cell_free_next %d\n", o->cell_free_next);
01258 }
01259 
01260 void HIdx::checkCellHeader(int offset, const Oid *koid) const
01261 {
01262   HIdx::CellHeader o;
01263   readCellHeader(offset, *koid, o);
01264   printCellHeader(&o, offset);
01265 }
01266 
01267 void HIdx::printCListObjHeader(const HIdx::CListObjHeader *h) const
01268 {
01269   printf("CListObjHeader\n");
01270   printf("  h.size %u\n", h->size);
01271   printf("  h.free_cnt %d\n", h->free_cnt);
01272   printf("  h.alloc_cnt %d\n", h->alloc_cnt);
01273   printf("  h.free_whole %d\n", h->free_whole);
01274   printf("  h.cell_free_first %d\n", h->cell_free_first);
01275   printf("  h.clobj_free_prev %s\n", getOidString(&h->clobj_free_prev));
01276   printf("  h.clobj_free_next %s\n", getOidString(&h->clobj_free_next));
01277   printf("  h.clobj_prev %s\n", getOidString(&h->clobj_prev));
01278   printf("  h.clobj_next %s\n", getOidString(&h->clobj_next));
01279 }
01280 
01281 void HIdx::checkCListObjHeader(const Oid *koid) const
01282 {
01283   HIdx::CListObjHeader h;
01284   readCListObjHeader(*koid, h);
01285   printCListObjHeader(&h);
01286 }
01287 
01288 void HIdx::checkChain(const Oid *koid) const
01289 {
01290   CListObjHeader h;
01291   readCListObjHeader(*koid, h);
01292   int offset = h.cell_free_first;
01293   int prev = NullOffset;
01294   //printCListObjHeader(&h);
01295 
01296   for (unsigned int n = 0; offset != NullOffset && n < 100; n++) {
01297     CellHeader o;
01298     assert(!readCellHeader(offset, *koid, o));
01299     assert(o.free);
01300     assert(o.cell_free_prev == prev);
01301     prev = offset;
01302     //printCellHeader(&o, offset);
01303     offset = o.cell_free_next;
01304     if (n > 90)
01305       printf("chain loop\n");
01306   }
01307 }
01308 
01309 void HIdx::checkChain(const CListHeader *chd, const std::string &msg) const
01310 {
01311  Oid koid = chd->clobj_free_first;
01312 
01313  //printf("\nChecking chain %s {\n", msg.c_str());
01314 
01315   int cnt = 0;
01316   while (koid.getNX()) {
01317     CListObjHeader h;
01318     assert(!readCListObjHeader(koid, h));
01319     //printf("h.cell_free_first %d\n", h.cell_free_first);
01320     checkChain(&koid);
01321     koid = h.clobj_free_next;
01322     cnt++;
01323   }
01324   //printf("} %d found\n", cnt);
01325 }
01326 
01327 static bool dont_check = false;
01328 //static bool dont_check = true;
01329 
01330 Status
01331 HIdx::writeCellHeader(int offset, const Oid &koid,
01332                        const CellHeader &o) const
01333 {
01334   CellHeader to;
01335   h2x_overhead(&to, &o);
01336 
01337 #if 0
01338   if (!dont_check) {
01339     std::map<unsigned int, bool> map;
01340     map[offset] = true;
01341 
01342     unsigned off = o.cell_free_prev;
01343     bool loop = false;
01344     for (int n = 0; !loop && n < 10; n++) {
01345       if (off == NullOffset)
01346         break;
01347 
01348       if (loop) {
01349         printf("offset %u at #%d\n", off, n);
01350       }
01351 
01352       if (map.find(off) != map.end()) {
01353         printf("loop in writeCellHeader prev %u at #%d [prev %d]\n", off, n, o.cell_free_prev);
01354         loop = true;
01355       }
01356       map[off] = true;
01357       CellHeader no;
01358       readCellHeader(off, koid, no);
01359       off = no.cell_free_prev;
01360     }
01361     if (loop)
01362       printf("*** prev EOL\n");
01363 
01364     off = o.cell_free_next;
01365     loop = false;
01366     for (int n = 0; !loop && n < 10; n++) {
01367       if (off == NullOffset)
01368         break;
01369 
01370       if (loop) {
01371         printf("offset %u at #%d\n", off, n);
01372       }
01373 
01374       if (map.find(off) != map.end()) {
01375         printf("loop in writeCellHeader next %u at #%d [next %d]\n", off, n, o.cell_free_next);
01376         loop = true;
01377       }
01378       map[off] = true;
01379       CellHeader no;
01380       readCellHeader(off, koid, no);
01381       off = no.cell_free_next;
01382     }
01383     if (loop)
01384       printf("*** next EOL\n");
01385   }
01386 #endif
01387   return objectWrite(dbh, offset, sizeof(CellHeader), &to, &koid);
01388 }
01389 
01390 Status
01391 HIdx::readCListHeaders(CListHeader *&chds) const
01392 {
01393   Status s;
01394   int len = get_gkey(version)(hidx.key_count);
01395   chds = new CListHeader[len];
01396 
01397   s = objectRead(dbh, 0, len * sizeof(CListHeader), chds,
01398                     DefaultLock, 0, 0, &treeoid);
01399   if (s)
01400     return s;
01401   for (int i = KEY_OFF; i < len; i++)
01402     x2h_chd(&chds[i]);
01403   return Success;
01404 }
01405 
01406 Status
01407 HIdx::writeCListHeaders(const CListHeader *chds) const
01408 {
01409   int len = get_gkey(version)(hidx.key_count);
01410   CListHeader *nchds = new CListHeader[len];
01411   memcpy(nchds, chds, sizeof(CListHeader) * KEY_OFF);
01412   for (int i = KEY_OFF; i < len; i++)
01413     h2x_chd(&nchds[i], &chds[i]);
01414 
01415   Status s = objectWrite(dbh, 0, len * sizeof(CListHeader), nchds,
01416                                &treeoid);
01417   delete [] nchds;
01418   return s;
01419 }
01420 
01421 Status
01422 HIdx::writeCListHeader(unsigned int k, const CListHeader &chd) const
01423 {
01424   Status s;
01425   unsigned int (*gkey)(int) = get_gkey(version);
01426 
01427   CListHeader tchd;
01428   h2x_chd(&tchd, &chd);
01429   s = objectWrite(dbh, gkey(k) * sizeof(CListHeader), sizeof(CListHeader), &tchd,
01430                      &treeoid);
01431   if (s)
01432     return s;
01433   return Success;
01434 }
01435 
01436 Status
01437 HIdx::dumpMemoryMap(const CListHeader &chd, const char *msg, FILE *fd)
01438 {
01439   fprintf(fd, "%sFREE MEMORY MAP {\n", msg);
01440   Oid prev;
01441   Oid koid = chd.clobj_free_first;
01442   memset(&prev, 0, sizeof(prev));
01443 
01444   int cnt = 0;
01445   while (koid.getNX()) {
01446     Status s;
01447     CListObjHeader h;
01448     s = readCListObjHeader(koid, h);
01449     if (s)
01450       return s;
01451     fprintf(fd, "\tObject %s -> Free Whole: %d, Free Count: %d\n",
01452             getOidString(&koid), h.free_whole, h.free_cnt);
01453     assert(!memcmp(&h.clobj_free_prev, &prev, sizeof(prev)));
01454     prev = koid;
01455     koid = h.clobj_free_next;
01456     cnt++;
01457   }
01458   fprintf(fd, "} -> %d cells in FREE MAP\n\n", cnt);
01459 
01460   cnt = 0;
01461   memset(&prev, 0, sizeof(prev));
01462   koid = chd.clobj_first;
01463 
01464   fprintf(fd, "%sMEMORY MAP {\n", msg);
01465   fprintf(fd, "\tFirst Free %s\n", getOidString(&chd.clobj_free_first));
01466   while (koid.getNX()) {
01467     Status s;
01468     CListObjHeader h;
01469     s = readCListObjHeader(koid, h);
01470     if (s)
01471       return s;
01472     unsigned int sz = 0;
01473     s = objectSizeGet(dbh, &sz, DefaultLock, &koid);
01474     if (s)
01475       return s;
01476     int cur = sizeof(CListObjHeader);
01477     fprintf(fd, "\tObject %s {\n\t  First Free: %d\n\t  Free Whole: %d\n\t  "
01478             "Free Count: %d\n\t  Alloc Count: %d\n\t  Size: %d\n\t  "
01479             "Free Prev: %s\n\t  Free Next: %s\n",
01480             getOidString(&koid), h.cell_free_first,
01481             h.free_whole, h.free_cnt, h.alloc_cnt, sz,
01482             getOidString(&h.clobj_free_prev), getOidString(&h.clobj_free_next));
01483     assert(!memcmp(&h.clobj_prev, &prev, sizeof(prev)));
01484 
01485     int busy_cnt = 0;
01486     int free_cnt = 0;
01487     while (cur + sizeof(CellHeader) <= sz) {
01488       CellHeader to;
01489       s = readCellHeader(cur, koid, to);
01490       if (s)
01491         return s;
01492       fprintf(fd, "\t  #%d size %d %s", cur,
01493               to.size, (to.free ? "free" : "busy"));
01494 
01495       if (to.cell_free_prev != NullOffset)
01496         fprintf(fd, " free_prev %d", to.cell_free_prev);
01497 
01498       if (to.cell_free_next != NullOffset)
01499         fprintf(fd, " free_next %d", to.cell_free_next);
01500 
01501       fprintf(fd, "\n");
01502       if (to.free) free_cnt++;
01503       else busy_cnt++;
01504       cur += to.size + sizeof(CellHeader);
01505     }
01506 
01507     fprintf(fd, "\t}\n");
01508     // now checking
01509     assert(free_cnt == h.free_cnt);
01510     assert(busy_cnt == h.alloc_cnt);
01511     int free_cur = h.cell_free_first;
01512     int free_prev = NullOffset;
01513     int free_size = 0;
01514     while (free_cur != NullOffset) {
01515       CellHeader to;
01516       s = readCellHeader(free_cur, koid, to);
01517       if (s)
01518         return s;
01519       if (!to.free || to.cell_free_prev != free_prev) {
01520         fprintf(fd, "#%d free, free_prev %d %d\n", free_cur, to.cell_free_prev,
01521                 free_prev);
01522         assert(0);
01523       }
01524       assert(to.free);
01525       assert(to.cell_free_prev == free_prev);
01526       free_size += to.size;
01527       free_prev = free_cur;
01528       free_cur = to.cell_free_next;
01529     }
01530 
01531     assert(free_size == h.free_whole);
01532     prev = koid;
01533     koid = h.clobj_next;
01534     cnt++;
01535   }
01536   fprintf(fd, "} -> %d cells in MAP\n", cnt);
01537 
01538   return Success;
01539 }
01540 
01541 Status
01542 HIdx::makeObject(CListHeader &chd, unsigned int chd_k, Oid &koid, int &offset,
01543                     CListObjHeader &h, CellHeader &o, unsigned int objsize)
01544 {
01545 #ifdef TRACK_MAP
01546   printf("making object\n");
01547 #endif
01548   unsigned int bsz = bsize; // changed the 30/01/02
01549   objsize += sizeof(CellHeader); // added the 30/01/02
01550   int utsize = (bsz > objsize ? bsz : objsize);
01551   //int size = sizeof(CListObjHeader) + sizeof(CellHeader) + utsize;
01552   unsigned int size = sizeof(CListObjHeader) + utsize;
01553 
01554 #ifdef OPTIM_LARGE_OBJECTS
01555 
01556   int alloc_size = sizeof(CListObjHeader) + sizeof(CellHeader);
01557 #ifdef HAS_ALLOC_BUFFER
01558   char *d = makeobj_buffer.alloc(alloc_size);
01559 #else
01560   char *d = (char *)m_malloc(alloc_size);
01561 #endif
01562 
01563 #else
01564 
01565 #ifdef HAS_ALLOC_BUFFER
01566   char *d = makeobj_buffer.alloc(size);
01567 #else
01568   char *d = (char *)m_malloc(size);
01569 #endif
01570 
01571 #endif
01572 
01573   offset = sizeof(CListObjHeader);
01574   h.size = size;
01575   h.free_cnt = 1;
01576   h.alloc_cnt = 0;
01577   h.free_whole = utsize - sizeof(CellHeader);
01578   h.cell_free_first = sizeof(CListObjHeader);
01579   h.clobj_prev = chd.clobj_last;
01580   mset(&h.clobj_next, 0, sizeof(h.clobj_next));
01581   mset(&h.clobj_free_prev, 0, sizeof(h.clobj_free_prev));
01582 
01583   // changed the 20/05/02
01584   //mset(&h.clobj_free_next, 0, sizeof(h.clobj_free_next));
01585   h.clobj_free_next = chd.clobj_free_first;
01586 
01587   o.free = 1;
01588   o.size = utsize - sizeof(CellHeader); //  + sizeof(CellHeader); // 26/12/01: added '+ sizeof(CellHeader)'
01589   o.cell_free_next = NullOffset;
01590   o.cell_free_prev = NullOffset;
01591   CListObjHeader xh;
01592   h2x_header(&xh, &h);
01593   mcp(d, &xh, sizeof(CListObjHeader));
01594   CellHeader xo;
01595   h2x_overhead(&xo, &o);
01596   mcp(d + sizeof(CListObjHeader), &xo, sizeof(CellHeader));
01597   
01598 #ifdef OPTIM_LARGE_OBJECTS
01599   Status s = objectCreate(dbh, ObjectNone, size, hidx.dspid, &koid);
01600   if (s) {free (d); return s;}
01601   s = objectWrite(dbh, 0, alloc_size, d, &koid);
01602 #else
01603   Status s = objectCreate(dbh, d, size, hidx.dspid, &koid);
01604 #endif
01605 
01606 #ifndef HAS_ALLOC_BUFFER
01607   free(d);
01608 #endif
01609 
01610   if (s)
01611     return s;
01612 
01613   if (!chd.clobj_first.getNX())
01614     chd.clobj_first = koid;
01615   else {
01616     Oid xoid;
01617     h2x_oid(&xoid, &koid);
01618     s = objectWrite(dbh, OFFSET(CListObjHeader, clobj_next), sizeof(Oid), &xoid,
01619                        &chd.clobj_last);
01620     if (s)
01621       return s;
01622   }
01623 
01624   chd.clobj_last = koid;
01625   // changed the 20/05/02
01626   return insertObjectInFreeList(chd, chd_k, h, koid);
01627 }
01628 
01629 inline bool
01630 HIdx::inFreeList(const CListObjHeader &h, const CListHeader &chd, const Oid &koid)
01631 {
01632   return h.clobj_free_prev.getNX() || h.clobj_free_next.getNX() || chd.clobj_free_first.getNX() == koid.getNX();
01633 }
01634 
01635 Status
01636 HIdx::insertObjectInFreeList(CListHeader &chd, unsigned int chd_k, CListObjHeader &h,
01637                                 const Oid &koid)
01638 {
01639 #ifdef TRACK_MAP
01640   printf("hidx: insertion of a new cell!\n");
01641 #endif
01642   Status s;
01643   if (chd.clobj_free_first.getNX()) {
01644     Oid xoid;
01645     h2x_oid(&xoid, &koid);
01646     s = objectWrite(dbh, OFFSET(CListObjHeader, clobj_free_prev),
01647                        sizeof(Oid), &xoid, &chd.clobj_free_first);
01648     if (s)
01649       return s;
01650   }
01651 
01652   h.clobj_free_next = chd.clobj_free_first;
01653   chd.clobj_free_first = koid;
01654 
01655   return writeCListHeader(chd_k, chd);
01656 }
01657 
01658 Boolean
01659 HIdx::candidateForExtension(const CListObjHeader &h)
01660 {
01661   unsigned int size_n = hidx.impl_hints[XCoef_Hints] * h.size;
01662   return (size_n <= (unsigned int)hidx.impl_hints[SzMax_Hints] ? True : False);
01663 }
01664 
01665 Status
01666 HIdx::extendObject(unsigned int size, CListHeader &chd, unsigned int chd_k, Oid &koid,
01667                       CListObjHeader &h, int &offset, CellHeader &o,
01668                       Boolean &extended)
01669 {
01670   unsigned int size_n = hidx.impl_hints[XCoef_Hints] * h.size;
01671   unsigned int size_inc = size_n - h.size;
01672 
01673   printf("extendObject %s [%d > %d && %d > %d] ?\n", getOidString(&koid),
01674          size_n, hidx.impl_hints[SzMax_Hints],
01675          size_inc + h.free_whole, size);
01676 
01677   if (size_n > (unsigned int)hidx.impl_hints[SzMax_Hints] &&
01678       (!size || size_inc + h.free_whole >= size)) {
01679     extended = False;
01680     return Success;
01681   }
01682     
01683   Status s;
01684   memset(&o, 0, sizeof(CellHeader));
01685   offset = h.cell_free_first;
01686   int lastoffset = NullOffset;
01687   while (offset != NullOffset) {
01688     s = readCellHeader(offset, koid, o);
01689     if (s)
01690       return s;
01691     lastoffset = offset;
01692     offset = o.cell_free_next;
01693   }
01694 
01695   Oid nkoid;
01696   if (o.free) {
01697 #ifdef TRACK_MAP        
01698     printf("object %s can be extended from %d to %d -> extend overhead\n",
01699            getOidString(&koid), h.size, size_n);
01700 #endif
01701     o.size += size_inc;
01702     offset = lastoffset;
01703     s = writeCellHeader(offset, koid, o);
01704     if (s)
01705       return s;
01706     extended = True;
01707     h.free_whole += size_inc;
01708     int osize = h.size;
01709     h.size = size_n;
01710     s = writeCListObjHeader(koid, h);
01711     if (s)
01712       return s;
01713     if (isPhysicalOid(dbh, &koid)) {
01714       s = modifyObjectSize(osize, size_n, koid, nkoid);
01715       if (s)
01716         return s;
01717       s = replaceObjectInList(chd, chd_k, h, koid, nkoid);
01718       if (s)
01719         return s;
01720       koid = nkoid;
01721       return Success;
01722     }
01723     return objectSizeModify(dbh, size_n, True, &koid);
01724   }
01725 
01726   if (!size || size_inc >= size) {
01727     // must done a new overhead AND must chain with last overhead !
01728 #ifdef TRACK_MAP        
01729     printf("object %s can be extended from %d to %d (diff=%d) -> new overhead\n",
01730            getOidString(&koid), h.size, size_n, size_inc - size);
01731 #endif
01732     if (isPhysicalOid(dbh, &koid)) {
01733       s = modifyObjectSize(h.size, size_n, koid, nkoid);
01734       if (s)
01735         return s;
01736       s = replaceObjectInList(chd, chd_k, h, koid, nkoid);
01737       koid = nkoid;
01738     }
01739     else
01740       s = objectSizeModify(dbh, size_n, True, &koid);
01741     if (s)
01742       return s;
01743     offset = h.size;
01744     if (lastoffset != NullOffset) {
01745       o.cell_free_next = offset;
01746       s = writeCellHeader(lastoffset, koid, o);
01747       if (s)
01748         return s;
01749     }
01750     else
01751       h.cell_free_first = offset;
01752 
01753     o.size = size_inc - sizeof(CellHeader);
01754     o.free = 1;
01755     o.cell_free_prev = lastoffset;
01756     o.cell_free_next = NullOffset;
01757     extended = True;
01758     h.free_cnt++;
01759     h.free_whole += size_inc - sizeof(CellHeader);
01760     h.size = size_n;
01761     if (!inFreeList(h, chd, koid)) {
01762       //      printf("not in free list ?\n");
01763       s = insertObjectInFreeList(chd, chd_k, h, koid);
01764       if (s)
01765         return s;
01766     }
01767     s = writeCListObjHeader(koid, h);
01768     if (s)
01769       return s;
01770     return writeCellHeader(offset, koid, o);
01771   }
01772   //printf("not extended\n");
01773   return Success;
01774 }
01775 
01776 #ifndef NO_EXTEND
01777 Status
01778 HIdx::getObjectToExtend(unsigned int size, CListHeader &chd, unsigned int chd_k,
01779                            Oid &koid, CListObjHeader &h, int &offset, CellHeader &o,
01780                            Boolean &found)
01781 {
01782   ------ CODE NOT USED ----
01783   found = False;
01784   Status s;
01785   koid = chd.first;
01786 
01787   while (koid.getNX()) {
01788     s = readCListObjHeader(koid, h);
01789     if (s)
01790       return s;
01791     /*
01792     printf("KOID %s h.clobj_prev %s h.clobj_next %s\n", getOidString(&koid),
01793            getOidString(&h.clobj_prev),
01794            getOidString(&h.clobj_next));
01795     */
01796     unsigned int size_n = hidx.impl_hints[XCoef_Hints] * h.size;
01797     unsigned int size_inc = size_n - h.size;
01798     if (size_n <= hidx.impl_hints[SzMax_Hints] &&
01799         size_inc + h.free_whole >= size) {
01800       memset(&o, 0, sizeof(CellHeader));
01801       offset = h.cell_free_first;
01802       int lastoffset = NullOffset;
01803       while (offset != NullOffset) {
01804         s = readCellHeader(offset, koid, o);
01805         if (s)
01806           return s;
01807         lastoffset = offset;
01808         offset = o.cell_free_next;
01809       }
01810 
01811       Oid nkoid;
01812       if (o.free) {
01813 #ifdef TRACK_MAP        
01814         printf("object %s can be extended from %d to %d -> extend overhead\n",
01815                getOidString(&koid), h.size, size_n);
01816 #endif
01817         o.size += size_inc;
01818         offset = lastoffset;
01819         s = writeCellHeader(offset, koid, o);
01820         if (s)
01821           return s;
01822         found = True;
01823         h.free_whole += size_inc;
01824         int osize = h.size;
01825         h.size = size_n;
01826         s = writeCListObjHeader(koid, h);
01827         if (s)
01828           return s;
01829         if (isPhysicalOid(dbh, &koid)) {
01830           s = modifyObjectSize(osize, size_n, koid, nkoid);
01831           if (s)
01832             return s;
01833           s = replaceObjectInList(chd, chd_k, h, koid, nkoid);
01834           if (s)
01835             return s;
01836           koid = nkoid;
01837           return Success;
01838         }
01839         return objectSizeModify(dbh, size_n, True, &koid);
01840       }
01841       else if (size_inc >= size) {
01842         // must done a new overhead AND must chain with last overhead !
01843 #ifdef TRACK_MAP        
01844         printf("object %s can be extended from %d to %d -> new overhead\n",
01845                getOidString(&koid), h.size, size_n);
01846 #endif
01847         if (isPhysicalOid(dbh, &koid)) {
01848           s = modifyObjectSize(h.size, size_n, koid, nkoid);
01849           if (s)
01850             return s;
01851           s = replaceObjectInList(chd, chd_k, h, koid, nkoid);
01852           koid = nkoid;
01853         }
01854         else
01855           s = objectSizeModify(dbh, size_n, True, &koid);
01856         if (s)
01857           return s;
01858         offset = h.size;
01859         if (lastoffset != NullOffset) {
01860   ------ CODE NOT USED ----
01861           o.cell_free_next = offset;
01862           s = writeCellHeader(lastoffset, koid, o);
01863           if (s)
01864             return s;
01865         }
01866         else
01867           h.cell_free_first = offset;
01868 
01869         o.size = size_inc - sizeof(CellHeader);
01870         o.free = 1;
01871         o.cell_free_prev = lastoffset;
01872         o.cell_free_next = NullOffset;
01873         found = True;
01874         h.free_cnt++;
01875         h.free_whole += size_inc - sizeof(CellHeader);
01876         h.size = size_n;
01877         if (!inFreeList(h, chd, koid)) {
01878           s = insertObjectInFreeList(chd, chd_k, h, koid);
01879           if (s)
01880             return s;
01881         }
01882         s = writeCListObjHeader(koid, h);
01883         if (s)
01884           return s;
01885         return writeCellHeader(offset, koid, o);
01886       }
01887     }
01888     koid = h.clobj_next;
01889   }
01890 
01891 #ifdef TRACK_MAP
01892   printf("no candidates for extension\n");
01893 #endif
01894   return Success;
01895 }
01896 #endif
01897 
01898 int hidx_gccnt;
01899 
01900 Status
01901 HIdx::getCell(unsigned int size, CListHeader &chd, unsigned int chd_k,
01902                  Oid &koid, CListObjHeader &h, int &offset, CellHeader &o)
01903 {
01904   Status s;
01905   koid = chd.clobj_free_first;
01906   hidx_gccnt = 0;
01907 #ifdef TRUSS1_GC
01908   unsigned int total_whole = 0, min_whole = ~0, max_whole = 0;
01909 #endif
01910 #ifdef TRUSS2_GC
01911   printf("getcell size %d\n", size);
01912 #endif
01913 
01914   while (koid.getNX()) {
01915     s = readCListObjHeader(koid, h);
01916     if (s)
01917       return s;
01918 
01919     Boolean extended;
01920     if (uextend) {
01921       if (h.free_whole < size) {
01922         s = extendObject(size, chd, chd_k, koid, h, offset, o, extended);
01923         if (s)
01924           return s;
01925       }
01926     }
01927 
01928 #ifdef TRUSS1_GC
01929     total_whole += h.free_whole;
01930     if (h.free_whole > max_whole)
01931       max_whole = h.free_whole;
01932     if (h.free_whole < min_whole)
01933       min_whole = h.free_whole;
01934 #endif
01935 #ifdef TRUSS2_GC
01936     printf("getcell free_whole %d #%d\n", h.free_whole, hidx_gccnt);
01937 #endif
01938     if (h.free_whole >= size) { // optimisation added 29/01/02
01939       offset = h.cell_free_first;
01940       for (unsigned int n = 0; offset != NullOffset; n++) {
01941         if (n && offset == h.cell_free_first || n > 100) {
01942           //printf("free_whole %u %d looping #%d\n", h.free_whole, size, n);
01943           break;
01944         }
01945         s = readCellHeader(offset, koid, o);
01946         if (s)
01947           return s;
01948         if (o.free && o.size >= size) {
01949           //printf("object found free_next %d size %d\n", o.cell_free_next, o.size);
01950           return Success;
01951         }
01952 
01953         if (uextend) {
01954           s = extendObject(size, chd, chd_k, koid, h, offset, o, extended);
01955           if (s)
01956             return s;
01957           if (extended && o.free && o.size >= size) {
01958             //printf("object extended and found\n");
01959             return Success;
01960           }
01961         }
01962 
01963         //COMPARE_OFFSET(offset, o.cell_free_next, "looping");
01964         offset = o.cell_free_next;
01965       }
01966     }
01967     koid = h.clobj_free_next;
01968 #ifdef TRUSS1_GC
01969     if (hidx_gccnt == 10000) {
01970       printf("hidx getcell size=%d, avg_whole=%f, min_whole=%d, "
01971              "max_whole=%d\n",
01972              size, (float)total_whole/hidx_gccnt, min_whole, max_whole);
01973       fflush(stdout);
01974     }
01975 #endif
01976 #ifdef OPT_FREELIST
01977     if (hidx.keysz != VarSize)
01978       break;
01979     // WARNING : 29/06/02 this test is to avoid too many search in free list
01980     // but this can make holes in the free list !
01981     if (hidx_gccnt > 4) {
01982       break;
01983     }
01984 #endif
01985     hidx_gccnt++;
01986   }
01987 
01988 #ifndef NO_EXTEND
01989   Boolean found;
01990   s = getObjectToExtend(size, chd, chd_k, koid, h, offset, o, found);
01991   if (s || found) return s;
01992 #endif
01993 
01994   // not found
01995   return makeObject(chd, chd_k, koid, offset, h, o, size);
01996 }
01997 
01998 #ifdef CI_STORE
01999 static char *
02000 lowstring(const char *key)
02001 {
02002   char *q = new char[strlen(key)+1];
02003   char c, *p;
02004 
02005   for (p = q; c = *key++; p++) {
02006     if (c >= 'A' && c <= 'Z')
02007       *p = c + 'a' - 'A';
02008     else
02009       *p = c;
02010   }
02011 
02012   *p = 0;
02013   return q;
02014 }
02015 #endif
02016 
02017 void stop_imm1() { }
02018 
02019 static int WRITE_HEADER;
02020 
02021 HIdx::HKey::HKey(HIdx *hidx, const void *_key, bool copy) : hidx(hidx)
02022 {
02023   if (copy) {
02024     Boolean isstr = hidx->hidx.keytype == Idx::tString ? True : False;
02025     key = copy_key(_key, hidx->hidx.keysz, isstr);
02026     _garbage = true;
02027   }
02028   else {
02029     key = _key;
02030     _garbage = false;
02031   }
02032 }
02033 
02034 HIdx::HKey::HKey(const HIdx::HKey &hkey)
02035 {
02036   _garbage = false;
02037   key = 0;
02038   hidx = 0;
02039   *this = hkey;
02040 }
02041 
02042 HIdx::HKey& HIdx::HKey::operator=(const HIdx::HKey &hkey)
02043 {
02044   if (this == &hkey)
02045     return *this;
02046 
02047   garbage();
02048 
02049   _garbage = hkey._garbage;
02050   hidx = hkey.hidx;
02051 
02052   if (_garbage) {
02053     Boolean isstr = hkey.hidx->hidx.keytype == Idx::tString ? True : False;
02054     key = copy_key(hkey.key, hkey.hidx->hidx.keysz, isstr);
02055   }
02056   else {
02057     key = hkey.key;
02058   }
02059 
02060   return *this;
02061 }
02062 
02063 Status HIdx::insert_cache(const void *key, const void *xdata)
02064 {
02065   std::vector<const void *> xdata_v;
02066   xdata_v.push_back(xdata);
02067   return insert_cache(key, xdata_v);
02068 }
02069 
02070 Status HIdx::insert_cache(const void *key, std::vector<const void *> &xdata_v)
02071 {
02072   if (isDataVarSize()) {
02073     return statusMake(ERROR, "Variable data size hash index: cannot use cache");
02074   }
02075 
02076   unsigned int xdata_v_cnt = xdata_v.size();
02077   HKey hkey(this, key, true);
02078   std::vector<const void *> &v = cache_map[hkey];
02079   for (unsigned int n = 0; n < xdata_v_cnt; n++) {
02080     unsigned char *data = new unsigned char[hidx.datasz];
02081     memcpy(data, xdata_v[n], hidx.datasz);
02082     v.push_back((const void *)data);
02083   }
02084   return Success;
02085 }
02086 
02087 Status HIdx::flush_cache(bool insert_data)
02088 {
02089   std::map<HKey, std::vector<const void *> >::iterator begin = cache_map.begin();
02090   std::map<HKey, std::vector<const void *> >::iterator end = cache_map.end();
02091 
02092   while (begin != end) {
02093     std::vector<const void *> &v = (*begin).second;
02094     if (insert_data) {
02095       Status s = insert((*begin).first.getKey(), v);
02096       if (s)
02097         return s;
02098     }
02099 
02100     std::vector<const void *>::iterator b = v.begin();
02101     std::vector<const void *>::iterator e = v.end();
02102     while (b != e) {
02103       delete [] (unsigned char *)(*b);
02104       ++b;
02105     }
02106     v.clear();
02107     ++begin;
02108   }
02109 
02110   cache_map.clear();
02111   return Success;
02112 }
02113 
02114 Status HIdx::insert(const void *key, const void *xdata)
02115 { 
02116   if (isDataVarSize()) {
02117     return statusMake(ERROR, "Variable data size hash index: the data size must be given at insertion, use HIdx::insert(const void *key, const void *data, unsigned int datasz)");
02118   }
02119 
02120   return insert_perform(key, xdata, 0);
02121 }
02122 
02123 Status HIdx::insert(const void *key, const void *data, unsigned int datasz)
02124 {
02125   if (!isDataVarSize() && hidx.datasz != datasz) {
02126     return statusMake(ERROR, "Fixed size hash index: the data size must be equals to %u", hidx.datasz);
02127   }
02128 
02129   return insert_perform(key, data, datasz);
02130 }
02131 
02132 Status HIdx::insert(const void *key, std::vector<const void *> &xdata_v)
02133 { 
02134   if (isDataVarSize()) {
02135     return statusMake(ERROR, "Variable data size hash index: the method HIdx::insert(const void *key, std::vector<const void *> &data_v) is not supported");
02136   }
02137 
02138   return insert_perform(key, xdata_v, 0);
02139 }
02140 
02141 Status HIdx::insert_perform(const void *key, const void *xdata, unsigned int datasz)
02142 {
02143   std::vector<const void *> xdata_v;
02144   xdata_v.push_back(xdata);
02145   return insert_perform(key, xdata_v, datasz);
02146 }
02147 
02148 Status HIdx::insert_perform(const void *key, std::vector<const void *> &xdata_v, unsigned int xdatasz)
02149 { 
02150   Status s;
02151 
02152   if (stat)
02153     return stat;
02154 
02155   if (s = checkOpened())
02156     return s;
02157 
02158 #ifdef CACHE_FOR_LOCK
02159   // oplist.insertObjectLast(new INSLink(this, key));
02160   // return Success;
02161 #endif
02162 
02163   unsigned int datasz = xdatasz;
02164 
02165   unsigned int x;
02166   unsigned int size;
02167   unsigned int (*gkey)(int) = get_gkey(version);
02168   s = get_key(x, key, &size);
02169   if (s)
02170     return s;
02171 
02172   IdxLock lockx(dbh, treeoid);
02173   s = lockx.lock();
02174   if (s)
02175     return s;
02176 
02177   int xdata_v_cnt = xdata_v.size();
02178 
02179   /*
02180   CListHeader chd;
02181   s = readCListHeader(x, chd);
02182   if (s)
02183     return s;
02184   */
02185 
02186 #ifdef TRACK_MAP
02187   printf("\nINSERT at #%d\n", x);
02188 #endif
02189   unsigned char *rdata = 0;
02190   const void *xdata = 0;
02191   bool direct;
02192   if (datasz) {
02193     assert(xdata_v_cnt == 1);
02194     direct = true;
02195     if (isDataVarSize()) {
02196       size += datasz + DATASZ_SIZE;
02197     }
02198     else {
02199       size += datasz - hidx.datasz;
02200     }
02201   }
02202   else {
02203     direct = false;
02204     datasz = hidx.datasz;
02205   }
02206 
02207   if (data_grouped_by_key && !direct) {
02208 #ifdef CHECK_CHAIN
02209     CListHeader chd2;
02210     s = readCListHeader(x, chd2);
02211     if (s)
02212       return s;
02213     
02214     checkChain(&chd2, "before remove");
02215 #endif
02216     Boolean found = False;
02217     unsigned int datacnt = 0;
02218     s = remove_perform(key, 0, 0, &found, &rdata, &datacnt, 0, xdata_v_cnt);
02219     if (s)
02220       return s;
02221 
02222 #ifdef TRACE_DGK
02223     printf("remove_perform(found=%d)\n", found);
02224 #endif
02225     if (!found) {
02226       rdata = new unsigned char[data_group_sz(xdata_v_cnt, this)];
02227     }
02228 
02229     //  size += data_group_sz(datacnt, this);
02230     //  size += data_group_sz(datacnt, this) + (xdata_v_cnt - 1) * hidx.datasz;
02231     size += data_group_sz(datacnt + xdata_v_cnt - 1, this);
02232 #ifdef TRACE_DGK
02233     printf("insert(datacnt = %d)\n", datacnt);
02234 #endif
02235     for (unsigned int nn = 0; nn < xdata_v_cnt; nn++) {
02236       memcpy(rdata + data_group_sz(datacnt + nn, this), xdata_v[nn], hidx.datasz);
02237     }
02238     datacnt += xdata_v_cnt;
02239 #ifdef VARSZ_DATACNT
02240     s = h2x_datacnt_cpy(rdata, &datacnt);
02241     if (s)
02242       return s;
02243 #else
02244     h2x_32_cpy(rdata, &datacnt);
02245 #endif
02246     xdata = (const void *)rdata;
02247     datasz = data_group_sz(datacnt, this);
02248     
02249     /*
02250       1. one must search for key
02251       2. if (found) {
02252       get the entry (ddata and dsize) : datacnt data(s)
02253       copy the entry : new unsigned char[dsize + datasz], memcpy(ndata, ddata, dsize)
02254       recompute the size : size += datasz
02255       remove the full entry by calling removeDataGroup
02256       [add W: ++datacnt data(s)+datai by calling insertDataGroup()]:
02257       memcpy(ndata + dsize, data, datasz)
02258       ++ndata.datacnt
02259       xdata = ndata
02260       => all in only one index scan
02261       }
02262       else {
02263       create the entry : ndata = new unsigned char[size + sizeof(datacnt)]
02264       recompute the size : size += sizeof(datacnt)
02265       ndata.datacnt = 1;
02266       memcpy(ndata + sizeof(datacnt), data, datasz)
02267       xdata = ndata
02268       }
02269       // at the end of the method: delete [] ndata
02270     */
02271   }
02272   else {
02273     if (xdata_v_cnt == 1) {
02274       xdata = xdata_v[0];
02275     }
02276     else {
02277       assert(!xdatasz);
02278       // 18/09/07: this is wrong !!
02279       rdata = new unsigned char[hidx.datasz * xdata_v_cnt];
02280       for (unsigned int nn = 0; nn < xdata_v_cnt; nn++) {
02281         memcpy(rdata + nn * hidx.datasz, xdata_v[nn], hidx.datasz);
02282       }
02283       xdata = (const void *)rdata;
02284     }
02285   }
02286 
02287   CListHeader chd;
02288   s = readCListHeader(x, chd);
02289   if (s)
02290     return s;
02291 
02292 #ifdef CHECK_CHAIN
02293   checkChain(&chd, "before getcell");
02294 #endif
02295 
02296   CellHeader o;
02297   CListObjHeader h;
02298   Oid koid;
02299   int offset = 0;
02300   s = getCell(size, chd, x, koid, h, offset, o);
02301   if (s) {
02302     delete [] rdata;
02303     return s;
02304   }
02305 
02306 #ifdef CHECK_CHAIN
02307   CListHeader chd2;
02308   s = readCListHeader(x, chd2);
02309   if (s)
02310     return s;
02311 
02312   checkChain(&chd2, "after getcell");
02313 #endif
02314 
02315 #ifdef TRACK_MAP
02316   printf("GETTING CELL offset=%d, koid=%s\n", offset,
02317          getOidString(&koid));
02318 #endif
02319 
02320 #ifdef TRACK_MAP_2
02321   (void)dumpMemoryMap(chd, "before inserting ");
02322 #endif
02323   s = insert_realize(chd, x, key, size, xdata, koid, h, offset, o, datasz);
02324 #ifdef TRACK_MAP_2
02325   (void)dumpMemoryMap(chd, "after inserting ");
02326 #endif
02327   delete [] rdata;
02328 
02329 #ifdef CHECK_CHAIN
02330   s = readCListHeader(x, chd2);
02331   if (s)
02332     return s;
02333     
02334   checkChain(&chd2, "after insert_realize");
02335 #endif
02336   return s;
02337 }
02338 
02339 Status
02340 HIdx::suppressCell(int offset, CListObjHeader &h, const Oid &koid) const
02341 {
02342   Status s;
02343   CellHeader o;
02344   s = readCellHeader(offset, koid, o);
02345   if (s)
02346     return s;
02347 #ifdef TRACK_MAP
02348   printf("suppressing cell at #%d size %d free_first is %d free_prev %d "
02349          "free_next %d\n", offset, o.size, h.cell_free_first, o.cell_free_prev,
02350          o.cell_free_next);
02351 #endif
02352   CellHeader po, no;
02353   if (o.cell_free_prev != NullOffset) {
02354     s = readCellHeader(o.cell_free_prev, koid, po);
02355     if (s)
02356       return s;
02357     po.cell_free_next = o.cell_free_next;
02358     s = writeCellHeader(o.cell_free_prev, koid, po);
02359     if (s)
02360       return s;
02361   }
02362   else
02363     h.cell_free_first = o.cell_free_next;
02364 
02365   if (o.cell_free_next != NullOffset) {
02366     s = readCellHeader(o.cell_free_next, koid, no);
02367     if (s)
02368       return s;
02369     no.cell_free_prev = o.cell_free_prev;
02370     s = writeCellHeader(o.cell_free_next, koid, no);
02371     if (s)
02372       return s;
02373   }
02374 
02375 #ifdef TRACK_MAP
02376   printf("now free_first %d\n", h.cell_free_first);
02377 #endif
02378   h.free_cnt--;
02379   h.free_whole -= o.size;
02380   o.cell_free_next = NullOffset;
02381   o.cell_free_prev = NullOffset;
02382   o.free = 0;
02383   return writeCellHeader(offset, koid, o);
02384 }
02385 
02386 Status
02387 HIdx::insertCell(int offset, unsigned int size, CListObjHeader &h,
02388                     const Oid &koid) const
02389 {
02390 #ifdef TRACK_MAP
02391   printf("inserting cell at #%d size %d [free_first %d]\n", offset, size,
02392          h.cell_free_first);
02393 #endif
02394   CellHeader o;
02395   o.size = size;
02396   o.free = 1;
02397   o.cell_free_next = h.cell_free_first;
02398   o.cell_free_prev = NullOffset;
02399 
02400   if (h.cell_free_first != NullOffset) {
02401     CellHeader po;
02402     Status s = readCellHeader(h.cell_free_first, koid, po);
02403     if (s)
02404       return s;
02405 #ifdef TRACK_MAP
02406     printf("making prev link for #%d -> #%d next #%d\n", h.cell_free_first, offset, po.cell_free_next);
02407 #endif
02408     assert(po.free);
02409     po.cell_free_prev = offset;
02410     bool old_dont_check = dont_check;
02411     dont_check = true;
02412     s = writeCellHeader(h.cell_free_first, koid, po);
02413     dont_check = old_dont_check;
02414     if (s)
02415       return s;
02416 #ifdef TRACK_MAP
02417     s = readCellHeader(h.cell_free_first, koid, po);
02418     if (s)
02419       return s;
02420     printf("PO.offset = %d\n", po.cell_free_prev);
02421 #endif
02422   }
02423 
02424   h.cell_free_first = offset;
02425   h.free_cnt++;
02426   h.free_whole += o.size;
02427   return writeCellHeader(offset, koid, o);
02428 }
02429 
02430 //#define SIMPLE_REMOVE
02431 #ifdef SIMPLE_REMOVE
02432   h.free_whole += o->size;
02433   CellHeader co;
02434   co.free = 1;
02435   co.size = o->size;
02436   co.next = h.cell_free_first;
02437   int offset = (eyedblib::int32)(curcell - start);
02438   h.cell_free_first = offset;
02439   h.free_cnt++;
02440   h.alloc_cnt--;
02441 #endif
02442 
02443 Status
02444 HIdx::remove_realize(CListHeader *chd, unsigned int chd_k,
02445                         const char *curcell, const char *prevcell,
02446                         const char *start, const CellHeader *o,
02447                         const Oid *koid)
02448 {
02449   Status s;
02450   CListObjHeader h;
02451 
02452   mcp(&h, start, sizeof(CListObjHeader));
02453   x2h_header(&h);
02454 
02455   CellHeader no, po;
02456   const char *nextcell = curcell + sizeof(CellHeader) + o->size;
02457   if ((eyedblib::int32)(nextcell - start) < h.size) {
02458     mcp(&no, nextcell, sizeof(CellHeader));
02459     x2h_overhead(&no);
02460   }
02461   else
02462     no.free = 0;
02463 
02464   if (prevcell) {
02465     mcp(&po, prevcell, sizeof(CellHeader));
02466     x2h_overhead(&po);
02467   }
02468   else
02469     po.free = 0;
02470 
02471 #ifdef TRACK_MAP
02472   printf("co = #%d, no = #%d, po = #%d\n", curcell-start,
02473          (curcell-start) + sizeof(CellHeader) + o->size,
02474          (prevcell ? prevcell-start : 0));
02475   printf("fo = #%d", h.cell_free_first);
02476 #endif
02477   CellHeader fo;
02478   if (h.cell_free_first >= 0) {
02479     mcp(&fo, h.cell_free_first + start, sizeof(CellHeader));
02480     x2h_overhead(&fo);
02481 #ifdef TRACK_MAP
02482     printf(", fo.free = %d, fo.size = %d, fo.next = %d",
02483            fo.free, fo.size, fo.cell_free_next);
02484 #endif
02485   }
02486 
02487 #ifdef TRACK_MAP
02488   printf("\n");
02489 #endif
02490 
02491   if (no.free && po.free) {
02492     s = suppressCell(prevcell-start, h, *koid);
02493     if (s)
02494       return s;
02495     s = suppressCell(nextcell-start, h, *koid);
02496     if (s)
02497       return s;
02498     s = insertCell(prevcell-start,
02499                    o->size + po.size + no.size + 2 * sizeof(CellHeader),
02500                    h, *koid);
02501     if (s)
02502       return s;
02503 
02504       //h.free_whole += o->size + 2 * sizeof(CellHeader);
02505 #ifdef TRACK_MAP
02506       printf("case no.free && po.free\n");
02507 #endif
02508     }
02509   else if (no.free) {
02510     s = suppressCell(nextcell-start, h, *koid);
02511     if (s)
02512       return s;
02513       // 24/04/07: BUG ?
02514     s = insertCell(curcell-start,
02515                    o->size + no.size + sizeof(CellHeader),
02516                    h, *koid);
02517     //h.free_whole += o->size + sizeof(CellHeader);
02518 #ifdef TRACK_MAP
02519     printf("case no.free\n");
02520 #endif
02521     }
02522   else if (po.free) {
02523     // WARNING: 24/04/07 these 2 lines have been swapped !
02524     s = suppressCell(prevcell-start, h, *koid);
02525     if (s)
02526       return s;
02527     s = insertCell(prevcell-start,
02528                    o->size + po.size + sizeof(CellHeader),
02529                    h, *koid);
02530       //h.free_whole += o->size + sizeof(CellHeader);
02531 #ifdef TRACK_MAP
02532       printf("case po.free\n");
02533 #endif
02534     }
02535   else {
02536     s = insertCell(curcell-start, o->size, h, *koid);
02537     if (s)
02538       return s;
02539       //h.free_whole += o->size;
02540 #ifdef TRACK_MAP
02541       printf("case *no* free\n");
02542 #endif
02543     }
02544   
02545   // EV: 3/05/07: WHY ??
02546   h.alloc_cnt--;
02547 
02548   Boolean rmobj = False;
02549   if (!h.alloc_cnt) {
02550     s = suppressObjectFromFreeList(*chd, chd_k, h, *koid);
02551     if (s)
02552       return s;
02553     s = suppressObjectFromList(*chd, chd_k, h, *koid);
02554     if (s)
02555       return s;
02556     rmobj = True;
02557   }
02558   else if (!inFreeList(h, *chd, *koid)) {
02559     s = insertObjectInFreeList(*chd, chd_k, h, *koid);
02560     if (s)
02561       return s;
02562   }
02563 
02564   //printf("writing header %d: po.free %d, no.free %d %d %d %d\n", !rmobj, po.free, no.free, h.alloc_cnt, h.cell_free_first, h.free_cnt);
02565   if (!rmobj) {
02566     s = writeCListObjHeader(*koid, h);
02567     if (s)
02568       return s;
02569   }
02570 
02571 #ifdef TRACK_MAP
02572   CListObjHeader xh;
02573   h2x_header(&xh, &h);
02574   memcpy((void *)start, &xh, sizeof(xh));
02575 #endif
02576 
02577   return count_manage(dbh, -1);
02578 }
02579 
02580 #define get_off(X, THIS) \
02581  ((THIS)->hidx.keysz != HIdx::VarSize ? (THIS)->hidx.keysz : strlen(X) + 1)
02582 
02583 Status HIdx::remove(const void *key, const void *data, unsigned int datasz, Boolean *found)
02584 {
02585   if (!isDataVarSize() && hidx.datasz != datasz) {
02586     return statusMake(ERROR, "Fixed size hash index: the data size must be equals to %u", hidx.datasz);
02587   }
02588 
02589   return remove_perform(key, data, datasz, found, 0, 0, 0, 0);
02590 }
02591 
02592 Status HIdx::remove(const void *key, const void *xdata, Boolean *found)
02593 {
02594   if (isDataVarSize()) {
02595     return statusMake(ERROR, "Variable data size hash index: the data size must be given at removing, use HIdx::remove(const void *key, const void *data, unsigned int datasz, Boolean *found)");
02596   }
02597 
02598   unsigned char *rdata = 0;
02599 
02600   if (data_grouped_by_key) {
02601     Boolean xfound = False;
02602     unsigned int datacnt = 0;
02603     int found_idx = -1;
02604     Status s = remove_perform(key, xdata, 0, &xfound, &rdata, &datacnt, &found_idx, 0);
02605     if (s)
02606       return s;
02607 
02608     if (found)
02609       *found = xfound;
02610 
02611     if (!xfound)
02612       return Success;
02613 
02614 #ifdef TRACE_DGK
02615     printf("found_idx %d\n", found_idx);
02616 #endif
02617     assert(found_idx >= 0);
02618     if (--datacnt) {
02619       memmove(rdata + data_group_sz(found_idx, this),
02620               rdata + data_group_sz(found_idx + 1, this),
02621               (datacnt - found_idx) * hidx.datasz);
02622 #ifdef VARSZ_DATACNT
02623       s = h2x_datacnt_cpy(rdata, &datacnt);
02624       if (s)
02625         return s;
02626 #else
02627       h2x_32_cpy(rdata, &datacnt);
02628 #endif
02629 #ifdef TRACE_DGK
02630       printf("insert_perforn(%d)\n", data_group_sz(datacnt, this));
02631 #endif
02632       s = insert_perform(key, rdata, data_group_sz(datacnt, this));
02633     }
02634     delete [] rdata;
02635     return s;
02636   }
02637   else {
02638     return remove_perform(key, xdata, 0, found, 0, 0, 0, 0);
02639   }
02640 }
02641 
02642 Status
02643 HIdx::remove_perform(const void *key, const void *xdata, unsigned int datasz, Boolean *found, unsigned char **prdata, unsigned int *pdatacnt, int *found_idx, unsigned int incr_alloc)
02644 {
02645   Status s;
02646   
02647   if (stat)
02648     return stat;
02649 
02650   if (s = checkOpened())
02651     return s;
02652 
02653   if (!datasz) {
02654     datasz = hidx.datasz;
02655   }
02656 
02657 #ifdef CACHE_FOR_LOCK
02658   // remove(const void *key, const void *xdata, found?)
02659   // oplist.insertObjectLast(new RMVLink(this, key, xdata, ?found));
02660   // return Success;
02661 
02662   // TRES IMPORTANT : il faut changer la stratégie relative au found, par
02663   // exemple :
02664   // remove(const void *key, const void *xdata,
02665   //        Status (*if_not_found)(void *arg) = 0, void *arg = 0)
02666   // oplist.insertObjectLast(new RMVLink(this, key, xdata, if_not_found, arg));
02667   // return Success;
02668   // Mais ce système risque (1) d'être contraignant pour l'utilisateur
02669   // de cette méthode, (2) de poser un pb de memory leak si arg est un
02670   // pointeur d'une spécialement allouée pour if_not_found : il faudrait alors
02671   // une autre fonction releaarg(void *) ou bien :
02672   // struct IfNotFound {
02673   //   private : void *arg;
02674   //   public: Status ifnot();
02675   //   public: Status release();
02676   // }; et remove(...., IfNotFound *if_not_found) en dernier argument !
02677   // autre solution : on supprime l'argument pour found et le client
02678   // devra faire Idx::search avant s'il veut savoir si la key/data existe
02679   // ou non
02680   // à noter que cela est utilisé uniquement dans : attr.cc et idbkern.cc
02681 #endif
02682   if (found)
02683     *found = False;
02684 
02685   unsigned int x;
02686   unsigned int (*gkey)(int) = get_gkey(version);
02687   s = get_key(x, key);
02688   if (s)
02689     return s;
02690 
02691 #ifdef TRACK_MAP
02692   printf("\nREMOVE at #%d\n", x);
02693 #endif
02694   IdxLock lockx(dbh, treeoid);
02695   s = lockx.lock();
02696   if (s)
02697     return s;
02698 
02699   CListHeader chd;
02700   s = readCListHeader(x, chd);
02701   if (s)
02702     return s;
02703 
02704 #ifdef IDX_DBG
02705   if (STRTYPE(this)) {
02706       printf("hidx: removing '%s' '%s'\n", key, getOidString((const Oid *)xdata));
02707     }
02708 #endif
02709   Oid koid = chd.clobj_first;
02710   while (koid.getNX() > 0) {
02711     unsigned int size;
02712       s = objectSizeGet(dbh, &size, DefaultLock, &koid);
02713       if (s)
02714         statusPrint(s, "HIdx::remove() treeoid %s", getOidString(&treeoid));
02715 
02716       if (s)
02717         return s;
02718 
02719       char *start = (char *)m_malloc(size);
02720       s = objectRead(dbh, 0, size, start, DefaultLock, 0, 0, &koid);
02721       
02722       if (s) {
02723           free(start);
02724           return s;
02725         }
02726       
02727       char *curcell, *end = start + size, *prevcell = 0;
02728       for (curcell = start + sizeof(CListObjHeader); curcell < end; ) {
02729           CellHeader o;
02730           mcp(&o, curcell, sizeof(CellHeader));
02731           x2h_overhead(&o);
02732           curcell += sizeof(CellHeader);
02733           
02734           if (!o.free && !cmp(key, curcell, OP2_SWAP)) {
02735             int r = 1;
02736             if (prdata) {
02737               assert(data_grouped_by_key);
02738               assert(pdatacnt);
02739 #ifdef VARSZ_DATACNT
02740               s = x2h_datacnt_cpy(pdatacnt, (unsigned char *)(curcell + get_off(curcell, this)));
02741               if (s)
02742                 return s;
02743 #else
02744               x2h_32_cpy(pdatacnt, curcell + get_off(curcell, this));
02745 #endif
02746 #ifdef TRACE_DGK
02747               printf("DATACNT %d\n", *pdatacnt);
02748 #endif
02749               unsigned int size;
02750               if (xdata) {
02751                 assert(found_idx);
02752                 *found_idx = -1;
02753                 for (unsigned int n = 0; n < *pdatacnt; n++) {
02754                   r = memcmp(xdata, curcell + get_off(curcell, this) + data_group_sz(n, this), datasz);
02755                   if (!r) {
02756                     *found_idx = n;
02757                     break;
02758                   }
02759                 }
02760                 assert(!incr_alloc);
02761                 size = data_group_sz(*pdatacnt, this);
02762               }
02763               else {
02764                 size = data_group_sz((*pdatacnt)+incr_alloc, this);
02765                 r = 0;
02766               }
02767 
02768               unsigned int cpsize = data_group_sz(*pdatacnt, this);
02769               *prdata = new unsigned char[size];
02770               memcpy(*prdata, curcell + get_off(curcell, this), cpsize);
02771             }
02772             else {
02773 #ifdef BUG_DATA_STORE2
02774               if (isDataVarSize()) {
02775                 unsigned int xdatasz;
02776                 memcpy(&xdatasz, curcell + get_off(curcell, this), DATASZ_SIZE);
02777                 unsigned ndatasz = x2h_u32(xdatasz);
02778                 if (ndatasz != datasz) {
02779                   r = -1;
02780                 }
02781                 else {
02782                   r = memcmp(xdata, curcell + get_off(curcell, this) + DATASZ_SIZE, datasz);
02783                 }
02784               }
02785               else {
02786                 r = memcmp(xdata, curcell + get_off(curcell, this), datasz);
02787               }
02788 #else
02789               assert(0);
02790               r = memcmp(xdata, curcell + o.size - datasz, datasz);
02791 #endif
02792             }
02793             if (!r) {
02794 #ifdef TRACK_MAP
02795               CListObjHeader h;
02796               memcpy(&h, start, sizeof(h));
02797               x2h_header(&h);
02798               dumpMemoryMap(chd, "before remove_realize ");
02799 #endif
02800               s = remove_realize(&chd, x, curcell - sizeof(CellHeader),
02801                                  prevcell, start, &o, &koid);
02802 #ifdef TRACK_MAP
02803               memcpy(&h, start, sizeof(h));
02804               x2h_header(&h);
02805               dumpMemoryMap(chd, "after remove_realize ");
02806 #endif
02807 
02808               if (!s && found) {
02809                 *found = True;
02810               }
02811               free(start);
02812               return s;
02813             }
02814           }
02815           
02816           prevcell = curcell - sizeof(CellHeader);
02817           curcell += o.size;
02818         }
02819 
02820       CListObjHeader h;
02821       mcp(&h, start, sizeof(CListObjHeader));
02822       x2h_header(&h);
02823       //koid = h.clobj_free_next;
02824       koid = h.clobj_next;
02825       free(start);
02826     }
02827 
02828   return Success;
02829 }
02830 
02831 unsigned int
02832 HIdx::getCount() const
02833 {
02834   return hidx.object_count;
02835 }
02836 
02837 short
02838 HIdx::getDefaultDspid() const
02839 {
02840   return hidx.dspid;
02841 
02842 }
02843 
02844 void
02845 HIdx::setDefaultDspid(short dspid)
02846 {
02847   hidx.dspid = dspid;
02848   dspid = h2x_16(dspid);
02849   objectWrite(dbh, 4*sizeof(unsigned int), sizeof(short),
02850                  &dspid, &treeoid);
02851 }
02852 
02853 static void
02854 add(Oid *&oids, unsigned int &cnt, unsigned int &alloc_cnt,
02855     const Oid &oid)
02856 {
02857   if (cnt >= alloc_cnt) {
02858     alloc_cnt = cnt + 32;
02859     oids = (Oid *)m_realloc(oids, alloc_cnt * sizeof(Oid));
02860   }
02861 
02862   oids[cnt++] = oid;
02863 }
02864 
02865 static const char *
02866 implHintsStr(int hints)
02867 {
02868   if (hints == HIdx::IniSize_Hints)
02869     return "Initial Size";
02870 
02871   if (hints == HIdx::IniObjCnt_Hints)
02872     return "Initial Object Count";
02873 
02874   if (hints == HIdx::XCoef_Hints)
02875     return "Extends Coeficient";
02876 
02877   if (hints == HIdx::SzMax_Hints)
02878     return "Maximal Hash Object Size";
02879 
02880   if (hints == HIdx::DataGroupedByKey_Hints)
02881     return "Data Grouped by Key";
02882 
02883   return "<unimplemented>";
02884 }
02885 
02886 std::string
02887 HIdx::_Idx::toString() const
02888 {
02889   std::string s;
02890   s = std::string("Key Count: ") + str_convert((long)key_count);
02891   s += std::string("Magnitude Order: ") + str_convert((long)mag_order);
02892   s += std::string("Object Count: ") + str_convert((long)object_count);
02893   s += std::string("Dataspace ID: ") + str_convert((long)(dspid == DefaultDspid ? -1 : dspid));
02894   s += std::string("Key Type: ") + typeString((Idx::Type)keytype);
02895   s += std::string("Key Size: ") + str_convert((long)keysz);
02896   s += std::string("Data Size: ") + str_convert((long)datasz);
02897   s += std::string("Data Offset: ") + str_convert((long)offset);
02898   s += "Implementation Hint:\n";
02899   for (int i = 0; i < HIdxImplHintsCount; i++)
02900     s += std::string("  ") + implHintsStr(i) + ": " + str_convert((long)impl_hints[i]);
02901   return s;
02902 }
02903 
02904 void
02905 HIdx::_Idx::trace(FILE *fd) const
02906 {
02907   fprintf(fd, "Key Count: %d\n", key_count);
02908   fprintf(fd, "Magnitude Order: %d\n", mag_order);
02909   fprintf(fd, "Object Count: %d\n", object_count);
02910   fprintf(fd, "Dataspace ID: %d\n", (dspid == DefaultDspid ? -1 : dspid));
02911   fprintf(fd, "Key Type: %s\n", typeString((Idx::Type)keytype));
02912   fprintf(fd, "Key Size: %d\n", keysz);
02913   fprintf(fd, "Data Size: %d\n", datasz);
02914   fprintf(fd, "Data Offset: %d\n", offset);
02915   fprintf(fd, "Implementation Hint:\n");
02916   for (int i = 0; i < HIdxImplHintsCount; i++)
02917     fprintf(fd, "  %s: %d\n", implHintsStr(i), impl_hints[i]);
02918 }
02919 
02920 Status
02921 HIdx::getObjects(Oid *&oids, unsigned int &cnt) const
02922 {
02923   unsigned int alloc_cnt = 0;
02924   cnt = 0;
02925   oids = 0;
02926   unsigned int (*gkey)(int) = get_gkey(version);
02927 
02928   for (int i = 0; i < hidx.key_count; i++) {
02929     HIdx::CListHeader chd;
02930     Status s = readCListHeader(i, chd);
02931     if (s)
02932       return s;
02933 
02934     Oid koid = chd.clobj_first;
02935     while (koid.getNX()) {
02936       add(oids, cnt, alloc_cnt, koid);
02937       HIdx::CListObjHeader h;
02938       s = objectRead(dbh, 0, sizeof(HIdx::CListObjHeader), &h,
02939                         DefaultLock, 0, 0, &koid);
02940       if (s)
02941         return s;
02942       x2h_header(&h);
02943       koid = h.clobj_next;
02944     }
02945   }
02946 
02947   return Success;
02948 }
02949 
02950 static void adapt(unsigned char *&clist_data, unsigned int &clist_data_size,
02951                   unsigned int &clist_data_alloc_size,
02952                   unsigned int size)
02953 {
02954   if (clist_data_size + size > clist_data_alloc_size) {
02955     //    clist_data_alloc_size = clist_data_size + size + 2048;
02956     clist_data_alloc_size = (clist_data_size + size) * 2;
02957     unsigned char *n_clist_data = new unsigned char[clist_data_alloc_size];
02958     memcpy(n_clist_data, clist_data, clist_data_size);
02959     delete [] clist_data;
02960     clist_data = n_clist_data;
02961   }
02962 }
02963 
02964 Status
02965 HIdx::collapse()
02966 {
02967   return collapse_realize(hidx.dspid, 0);
02968 }
02969 
02970 //#define COLLAPSE_TRACE
02971 
02972 Status
02973 HIdx::collapse_realize(short dspid, HIdx *idx_n)
02974 {
02975   IdxLock lockx(dbh, treeoid);
02976   Status s = lockx.lock();
02977   if (s)
02978     return s;
02979 
02980   unsigned int clist_data_alloc_size = 0;
02981   unsigned char *clist_data = 0;
02982   unsigned int clistobj_data_alloc_size = 0;
02983   unsigned char *clistobj_data = 0;
02984 
02985   for (unsigned int chd_k = 0; chd_k < hidx.key_count; chd_k++) {
02986     HIdx::CListHeader chd;
02987     s = readCListHeader(chd_k, chd);
02988     if (s)
02989       return s;
02990 
02991     unsigned int clistobj_cnt = 0;
02992     Oid koid = chd.clobj_first;
02993     std::vector<Oid> oid_v;
02994     if (koid.getNX()) {
02995 #ifdef COLLAPSE_TRACE
02996       printf("Key #%d {\n", chd_k);
02997 #endif
02998       unsigned int total_busy_cell_cnt = 0;
02999       unsigned int total_busy_size = 0;
03000       unsigned int total_free_size = 0;
03001       unsigned int clist_data_size = 0;
03002       adapt(clist_data, clist_data_size, clist_data_alloc_size, sizeof(CListObjHeader));
03003       clist_data_size = sizeof(CListObjHeader);
03004 
03005       while (koid.getNX()) {
03006         oid_v.push_back(koid);
03007         unsigned int busy_size = 0;
03008         unsigned int free_size = 0;
03009         unsigned int busy_cell_cnt = 0;
03010         unsigned int sz = 0;
03011         s = objectSizeGet(dbh, &sz, DefaultLock, &koid);
03012         if (s)
03013           return s;
03014 
03015         if (sz > clistobj_data_alloc_size) {
03016           clistobj_data_alloc_size = sz;
03017           clistobj_data = new unsigned char[clistobj_data_alloc_size];
03018         }
03019 
03020         CListObjHeader h;
03021         s = objectRead(dbh, 0, 0, clistobj_data, DefaultLock, 0, 0, &koid);
03022         if (s)
03023           return s;
03024         unsigned char *d, *edata = clistobj_data + sz;
03025         for (d = clistobj_data + sizeof(CListObjHeader); d < edata; ) {
03026           CellHeader o;
03027           mcp(&o, d, sizeof(CellHeader));
03028           x2h_overhead(&o);
03029           if (!o.free) {
03030             total_busy_size += o.size;
03031             busy_size += o.size;
03032             unsigned int cpsize = o.size + sizeof(CellHeader);
03033             adapt(clist_data, clist_data_size, clist_data_alloc_size, cpsize);
03034             memcpy(clist_data + clist_data_size, d, cpsize);
03035             clist_data_size += cpsize;
03036             busy_cell_cnt++;
03037             total_busy_cell_cnt++;
03038           }
03039           else {
03040             total_free_size += o.size;
03041             free_size += o.size;
03042           }
03043 
03044           d += sizeof(CellHeader);
03045           d += o.size;
03046         }
03047 
03048 #ifdef COLLAPSE_TRACE
03049         printf("  KOID %s [%d b] {\n", getOidString(&koid), sz);
03050         printf("    busy_cell_cnt: %d\n", busy_cell_cnt);
03051         printf("    busy_size: %u b\n", busy_size);
03052         printf("    free_size: %u b\n", free_size);
03053         printf("  }\n");
03054 #endif
03055         memcpy(&h, clistobj_data, sizeof(h));
03056         x2h_header(&h);
03057         koid = h.clobj_next;
03058         clistobj_cnt++;
03059       }
03060       
03061       if (idx_n || (clistobj_cnt > 1 && total_free_size != 0)) {
03062         CListObjHeader h;
03063         memset(&h, 0, sizeof(h));
03064         h.free_cnt = 0;
03065         // JE PENSE QUE CELA EST FAUX: alloc_cnt indique le nombre de cells
03066         // et pas le nombre de hashobject
03067         // h.alloc_cnt = busy_cell_cnt; ???
03068         //h.alloc_cnt = 1;
03069         h.alloc_cnt = total_busy_cell_cnt;
03070         h.free_whole = 0;
03071         h.cell_free_first = NullOffset;
03072         CListObjHeader xh;
03073         h2x_header(&xh, &h);
03074         memcpy(clist_data, &xh, sizeof(xh));
03075         
03076         memset(&chd, 0, sizeof(chd));
03077         s = objectCreate(dbh, clist_data, clist_data_size, dspid,
03078                          &chd.clobj_first);
03079         if (s)
03080           return s;
03081         
03082         // Corrected: 4/03/08
03083         //chd.clobj_last = chd.clobj_last;
03084         chd.clobj_last = chd.clobj_first;
03085         
03086         if (idx_n) {
03087           s = idx_n->writeCListHeader(chd_k, chd);
03088         }
03089         else {
03090           s = writeCListHeader(chd_k, chd);
03091         }
03092 
03093         if (s)
03094           return s;
03095 
03096 #ifdef COLLAPSE_TRACE
03097         printf("  collapse oids: %s\n", getOidString(&chd.clobj_first));
03098 #endif
03099         if (!idx_n) {
03100           std::vector<Oid>::iterator begin = oid_v.begin();
03101           std::vector<Oid>::iterator end = oid_v.end();
03102           unsigned int del_obj_cnt = 0;
03103           while (begin != end) {
03104             s = objectDelete(dbh, &(*begin));
03105             if (s)
03106               return s;
03107             ++begin;
03108             del_obj_cnt++;
03109           }
03110 #ifdef COLLAPSE_TRACE
03111           printf("  deleted obj: %d\n", del_obj_cnt);
03112 #endif
03113         }
03114       }
03115 #ifdef COLLAPSE_TRACE
03116       else
03117         printf("  NO COLLAPSE\n");
03118 #endif
03119 
03120       // must delete all koid
03121 #ifdef COLLAPSE_TRACE
03122       printf("  clistobj_cnt: %u\n", clistobj_cnt);
03123       printf("  total_busy_cell_cnt: %u\n", total_busy_cell_cnt);
03124       printf("  total_busy_size: %u b\n", total_busy_size);
03125       printf("  total_free_size: %u b\n", total_free_size);
03126       printf("  clist_data_size: %u\n", clist_data_size);
03127       printf("  clist_data_alloc_size: %u\n", clist_data_alloc_size);
03128       printf("}\n");
03129 #endif
03130     }
03131   }
03132 
03133   if (idx_n) {
03134     idx_n->hidx.object_count = hidx.object_count;
03135     unsigned int count = h2x_u32(idx_n->hidx.object_count);
03136     s = objectWrite(dbh, sizeof(unsigned int),
03137                     sizeof(unsigned int), &count, &idx_n->treeoid);
03138     if (s)
03139       return s;
03140   }
03141 
03142   delete [] clistobj_data;
03143   delete [] clist_data;
03144   return Success;
03145 }
03146 
03147 int
03148 HIdx::cmp(const void *key, const void *d, unsigned char bswap) const
03149 {
03150   return compare(key, d, &keytype, bswap);
03151 }
03152 
03153 Status HIdx::searchAny(const void *key, Boolean *found, void *xdata)
03154 {
03155   if (isDataVarSize() && xdata) {
03156     return statusMake(ERROR, "Variable data size hash index: cannot use the HIdx::searchAny(const void *key, Boolean *found, void *data) method when data is not null");
03157   }
03158 
03159   unsigned int found_cnt;
03160   Status s = search_realize(key, &found_cnt, True, xdata);
03161   if (s) {
03162     return s;
03163   }
03164   *found = (found_cnt != 0) ? eyedbsm::True : eyedbsm::False;
03165   return Success;
03166 }
03167 
03168 Status HIdx::search(const void *key, unsigned int *found_cnt)
03169 {
03170   return search_realize(key, found_cnt, False, 0);
03171 }
03172 
03173 Status HIdx::search_realize(const void *key, unsigned int *found_cnt, Boolean found_any, void *xdata)
03174 {
03175   Status s;
03176   
03177   if (stat)
03178     return stat;
03179 
03180   if (s = checkOpened())
03181     return s;
03182 
03183   unsigned int x;
03184 
03185   *found_cnt = 0;
03186 
03187   unsigned int (*gkey)(int) = get_gkey(version);
03188   s = get_key(x, key);
03189   if (s)
03190     return s;
03191 
03192   CListHeader chd;
03193   s = readCListHeader(x, chd);
03194   if (s)
03195     return s;
03196 
03197   // EV: 23/04/07 it seems tchd this method search key, and can find it several time:
03198   // but the returned xdata will contained the last data and the count
03199   // will not be returned (only found == true)
03200   // => we changed this method by (at least) changing Boolean found to unsigned int found_cnt
03201   // or we add a break in case of *found == true as shown below:
03202   // idea:
03203   // 1. add the break, and rename the methode searchAny
03204   // 2. add a methode ::search(const void *key, unsigned int *found_cnt)
03205   Oid koid = chd.clobj_first;
03206   while (koid.getNX() > 0) {
03207     if (backend_interrupt)
03208       return statusMake(BACKEND_INTERRUPTED, "");
03209     unsigned int size;
03210     Status s = objectSizeGet(dbh, &size, DefaultLock, &koid);
03211     if (s)
03212       return s;
03213     char *data = (char *)m_malloc(size);
03214     s = objectRead(dbh, 0, size, data, DefaultLock, 0, 0, &koid);
03215       
03216     if (s) {
03217       free(data);
03218       return s;
03219     }
03220       
03221     char *d, *edata = data + size;
03222     for (d = data + sizeof(CListObjHeader); d < edata; ) {
03223       CellHeader o;
03224       mcp(&o, d, sizeof(CellHeader));
03225       x2h_overhead(&o);
03226       d += sizeof(CellHeader);
03227 
03228       if (!o.free && !cmp(key, d, OP2_SWAP)) {
03229         unsigned int offset;
03230         if (data_grouped_by_key) {
03231           unsigned int datacnt;
03232 #ifdef VARSZ_DATACNT
03233           s = x2h_datacnt_cpy(&datacnt, (unsigned char *)(d + get_off(d, this)));
03234           if (s)
03235             return s;
03236 #else
03237           x2h_32_cpy(&datacnt, d + get_off(d, this));
03238 #endif
03239           *found_cnt += datacnt;
03240           offset = data_grouped_sizeof;
03241 #if 0
03242           for (unsigned int n = 0; n < datacnt; n++) {
03243             if (hidx.datasz == sizeof(Oid)) { // perharps an Oid
03244               Oid oo;
03245               memcpy(&oo, d + get_off(d, this) + data_group_sz(n, this), hidx.datasz);
03246               printf("Data oid[%d]: %s\n", n, getOidString(&oo));
03247             }
03248           }
03249 #endif
03250         }
03251         else {
03252           offset = 0;
03253           (*found_cnt)++;
03254         }
03255 
03256         if (xdata) {
03257           // NOTE: in case of data_grouped_by_key, only one data is copied
03258 #ifdef BUG_DATA_STORE2
03259           memcpy(xdata, d + get_off(d, this) + offset, hidx.datasz);
03260 #else
03261           memcpy(xdata, d + o.size - hidx.datasz, hidx.datasz);
03262 #endif
03263         }
03264 
03265         if (found_any)
03266           break;
03267       }
03268           
03269       d += o.size;
03270     }
03271       
03272     CListObjHeader h;
03273     mcp(&h, data, sizeof(CListObjHeader));
03274     x2h_header(&h);
03275     //koid = h.clobj_free_next;
03276     koid = h.clobj_next;
03277     free(data);
03278 
03279     // break added in case of *found == true
03280     if (*found_cnt && found_any) {
03281       break;
03282     }
03283   }
03284 
03285   return Success;
03286 }
03287 
03288 Status HIdx::destroy()
03289 {
03290   Status s = destroy_r();
03291   if (s)
03292     return s;
03293   return objectDelete(dbh, &treeoid);
03294 }
03295 
03296 Status HIdx::destroy_r()
03297 {
03298   for (int n = 0; n < hidx.key_count; n++) {
03299     CListHeader chd;
03300     Status s = readCListHeader(n, chd);
03301     if (s)
03302       return s;
03303 
03304     Oid koid = chd.clobj_first;
03305 
03306     while (koid.getNX()) {
03307       CListObjHeader h;
03308       Status s = readCListObjHeader(koid, h);
03309       if (s)
03310         return s;
03311 
03312       s = objectDelete(dbh, &koid);
03313       if (s)
03314         return s;
03315 
03316       koid = h.clobj_next;
03317     }
03318   }
03319 
03320   return Success;
03321 }
03322 
03323 Status
03324 HIdx::headPrint(FILE *fd, int n, Oid *koid, int &count) const
03325 {
03326   CListObjHeader h;
03327   Status s = objectRead(dbh, 0, sizeof(CListObjHeader), &h, DefaultLock, 0,
03328                               0, koid);
03329 
03330   if (s)
03331     return s;
03332   x2h_header(&h);
03333 
03334   count = h.alloc_cnt;
03335   fprintf(fd, "\tsubcell[%d] %s {\n", n, getOidString(koid));
03336   fprintf(fd, "\t\tsize       = %d;\n", h.size);
03337   fprintf(fd, "\t\tnfree      = %d;\n", h.free_cnt);
03338   fprintf(fd, "\t\tnalloc     = %d;\n", h.alloc_cnt);
03339   fprintf(fd, "\t\tfree_whole = %d;\n", h.free_whole);
03340   fprintf(fd, "\t\tfirstfree  = %d;\n", h.cell_free_first);
03341   fprintf(fd, "\t\tprev       = %s;\n", getOidString(&h.clobj_prev));
03342   fprintf(fd, "\t\tnext       = %s;\n", getOidString(&h.clobj_next));
03343   fprintf(fd, "\t\tfree_prev  = %s;\n", getOidString(&h.clobj_free_prev));
03344   fprintf(fd, "\t\tfree_next  = %s;\n", getOidString(&h.clobj_free_next));
03345   fprintf(fd, "\t};\n");
03346   *koid = h.clobj_next;
03347 
03348   return Success;
03349 }
03350 
03351 Status
03352 HIdx::getHashObjectBusySize(const Oid *koid, unsigned int &osize, unsigned int &count, unsigned int size) const
03353 {
03354   if (!STRTYPE(this) && !data_grouped_by_key) {
03355     CListObjHeader h;
03356     Status s = objectRead(dbh, 0, sizeof(CListObjHeader), &h, DefaultLock, 0,
03357                                 0, koid);
03358     
03359     if (s)
03360       return s;
03361     x2h_header(&h);
03362   
03363     osize = h.alloc_cnt * (sizeof(CellHeader) + hidx.keysz + hidx.datasz) + sizeof(CListObjHeader);
03364     count = h.alloc_cnt;
03365     return Success;
03366   }
03367 
03368   Status s;
03369   if (!size) {
03370     s = objectSizeGet(dbh, &size, DefaultLock, koid);
03371     if (s)
03372       return s;
03373   }
03374 
03375   osize = sizeof(CListObjHeader);
03376 
03377   char *data;
03378   if (nocopy) {
03379     s = objectReadNoCopy(dbh, 0, size, &data, DefaultLock, 0, 0, koid);
03380   }
03381   else {
03382     data = (char *)m_malloc(size);
03383     s = objectRead(dbh, 0, size, data, DefaultLock, 0, 0, koid);
03384   }
03385 
03386   if (s) {if (!nocopy) free(data); return s;}
03387 
03388   count = 0;
03389   int cur = sizeof(CListObjHeader);
03390   while (cur + sizeof(CellHeader) <= size) {
03391     CellHeader to;
03392     s = readCellHeader(cur, *koid, to);
03393     if (s) {if (!nocopy) free(data); return s;}
03394     cur += sizeof(CellHeader);
03395     if (!to.free) {
03396       //      osize += sizeof(CellHeader) + strlen(data+cur)+1 + hidx.datasz;
03397       osize += sizeof(CellHeader) + to.size;
03398       if (data_grouped_by_key) {
03399         unsigned int datacnt;
03400 #ifdef VARSZ_DATACNT
03401         s = x2h_datacnt_cpy(&datacnt, (unsigned char *)(data + cur + get_off(data + cur, this)));
03402         if (s)
03403           return s;
03404 #else
03405         x2h_32_cpy(&datacnt, data + cur + get_off(data + cur, this));
03406 #endif
03407         count += datacnt;
03408       }
03409       else
03410         count++;
03411     }
03412     //    printf("SIZES '%s' %d %d %d free=%d\n", data+cur, to.size + sizeof(CellHeader), sizeof(CellHeader) + strlen(data+cur)+1, hidx.datasz, to.free);
03413     cur += to.size;
03414   }
03415 
03416   if (!nocopy)
03417     free(data);
03418   return Success;
03419 }
03420 
03421 Status
03422 HIdx::getEntryCount(Oid *koid, unsigned int &count) const
03423 {
03424   if (koid->getNX() == 0) {
03425     count = 0;
03426     return Success;
03427   }
03428 
03429   CListObjHeader h;
03430   Status s = objectRead(dbh, 0, sizeof(CListObjHeader), &h, DefaultLock, 0,
03431                               0, koid);
03432 
03433   if (s)
03434     return s;
03435   x2h_header(&h);
03436 
03437   count = h.alloc_cnt;
03438   *koid = h.clobj_next;
03439 
03440   return Success;
03441 }
03442 
03443 //#define ALL_STATS
03444 
03445 Status
03446 HIdx::dumpMemoryMap(FILE *fd)
03447 {
03448   for (int n = 0; n < hidx.key_count; n++) {
03449     CListHeader chd;
03450     Status s = readCListHeader(n, chd);
03451     if (s)
03452       return s;
03453     Oid koid = chd.clobj_first;
03454     if (!koid.getNX()) continue;
03455     if (s)
03456       return s;
03457     s = dumpMemoryMap(chd, (std::string("Entry #") + str_convert((long)n) + " ").c_str(),
03458                       fd);
03459     if (s)
03460       return s;
03461   }
03462 
03463   return Success;
03464 }
03465 
03466 Status HIdx::printStat(FILE *fd) const
03467 {
03468   //const Oid *koid;
03469   int n, total;
03470 
03471   if (!fd)
03472     fd = stdout;
03473 
03474 #ifdef ALL_STATS
03475   fprintf(fd, "index bsize = 0x%x\n", hidx.impl_hints[IniSize_Hints]);
03476 #endif
03477   fprintf(fd, "\tkey_count = %d\n", hidx.key_count);
03478   fflush(fd);
03479 
03480   total = 0;
03481 
03482   for (int n = 0; n < hidx.key_count; n++) {
03483     CListHeader chd;
03484     Status s = readCListHeader(n, chd);
03485     if (s)
03486       return s;
03487 
03488 #ifdef ALL_STATS
03489     fprintf(fd, "cell[%d] = {\n", n);
03490     fprintf(fd, "\tfirst      = %s;\n", getOidString(&chd.clobj_first));
03491     fprintf(fd, "\tlast       = %s;\n", getOidString(&chd.clobj_last));
03492     fprintf(fd, "\tfree_first = %s;\n", getOidString(&chd.clobj_free_first));
03493 #endif
03494 
03495     Oid toid;
03496     toid = chd.clobj_first;
03497     int cell_count = 0;
03498 
03499     while (toid.getNX() > 0) {
03500       unsigned int count;
03501       if (backend_interrupt) {
03502         /*
03503         fprintf(fd, "Interrupted!\n");
03504         fprintf(fd, "\tpartial total count = %d\n", total);
03505         fflush(fd);
03506         */
03507         return statusMake(BACKEND_INTERRUPTED, "");
03508       }
03509 
03510       s = getEntryCount(&toid, count);
03511       if (s) {
03512         statusPrint(s, "");
03513         fflush(fd);
03514         return s;
03515       }
03516       cell_count += count;
03517     }
03518 #ifdef ALL_STATS
03519 #ifndef PRINT_DETAILS
03520     fprintf(fd, "\tcount      = %d;\n", cell_count);
03521 #endif
03522 #else
03523     if (cell_count) {
03524       fprintf(fd, "\tcell[%d] -> %d\n", n, cell_count);
03525       fflush(fd);
03526     }
03527 #endif
03528     total += cell_count;
03529 #ifdef ALL_STATS
03530     fprintf(fd, "};\n\n");
03531 #endif
03532   }
03533 
03534   fprintf(fd, "\ttotal count = %d [%d]\n", total, getCount());
03535   fflush(fd);
03536   return Success;
03537 }
03538 
03539 #define ONE_LIST
03540 
03541 struct Link {
03542 
03543   Link(unsigned int sz) {
03544     data = new unsigned char[sz];
03545     next = 0;
03546   }
03547 
03548   ~Link() {
03549     delete [] data;
03550   }
03551 
03552   Idx::Key key;
03553   unsigned char *data;
03554   Link *next;
03555 
03556 private:
03557   // forbidden
03558   Link(const Link &);
03559   Link &operator=(const Link &);
03560 };
03561 
03562 class HIdxCursor::LinkList {
03563 
03564 public:
03565   LinkList() {first = last = 0; cnt = 0;}
03566 
03567   void insert(Link *l) {
03568     eyedblib::MutexLocker _(mt);
03569     if (last)
03570       last->next = l;
03571     if (!first)
03572       first = l;
03573     last = l;
03574     cnt++;
03575   }
03576 
03577   Link *peek() {
03578     eyedblib::MutexLocker _(mt);
03579     if (first) {
03580       Link *l = first;
03581       first = first->next;
03582       if (!first) last = 0;
03583       cnt--;
03584       return l;
03585     }
03586     return 0;
03587   }
03588 
03589   int getCount() const {
03590     eyedblib::MutexLocker _(mt);
03591     return cnt;
03592   }
03593 
03594   ~LinkList() {
03595     eyedblib::MutexLocker _(mt);
03596     Link *l = first;
03597     while (l) {
03598       Link *next = l->next;
03599       delete l;
03600       l = next;
03601     }
03602   }
03603 
03604 private:
03605   mutable eyedblib::Mutex mt;
03606   Link *first, *last;
03607   int cnt;
03608 };
03609 
03610 extern eyedblib::ThreadPool *getThreadPool();
03611 
03612 #define MIN_OBJCNT_FOR_PARALLEL 10
03613 //#define MIN_KEYCNT_FOR_PARALLEL 10
03614 
03615 static eyedblib::ThreadPerformerArg
03616 cursor_perform_wrapper(eyedblib::ThreadPerformerArg xarg)
03617 {
03618   HIdxCursor *cur = (HIdxCursor *)xarg.data;
03619   for (;;) {
03620     Boolean found;
03621     Status s = cur->next(&found);
03622     if (s)
03623       return eyedblib::ThreadPerformerArg((void *)s);
03624     if (!found)
03625       return 0;
03626   }
03627   return 0;
03628 }
03629 
03630 static int user_cmp_mod;
03631 
03632 static Boolean 
03633 user_cmp(const void *, void *)
03634 {
03635   static eyedblib::Mutex mt;
03636   //  eyedblib::MutexLocker _(mt);
03637   static int cnt;
03638   for (int n = 0; n < 50; n++) ;
03639   if (!(cnt++ % user_cmp_mod)) return True;
03640   return False;
03641 }
03642 
03643 Boolean
03644 HIdxCursor::parallelInit(int thread_cnt)
03645 {
03646   /*
03647   if ((skey && ekey) || !user_cmp ||
03648       idx->hidx.object_count <= MIN_OBJCNT_FOR_PARALLEL)
03649     return False;
03650   */
03651 
03652   if (thread_cnt < 2 || idx->hidx.object_count <= MIN_OBJCNT_FOR_PARALLEL ||
03653       (skey && ekey && !idx->cmp(skey, ekey, OPS_NOSWAP))) /*(skey && ekey) || */ // WARNING : 24/02/03 !!
03654     return False;
03655 
03656   thrpool = getThreadPool();
03657   if (!thrpool)
03658     return False;
03659 
03660   perf_cnt = thrpool->getThreadCount();
03661 
03662   if (perf_cnt > thread_cnt)
03663     perf_cnt = thread_cnt;
03664 
03665   if (perf_cnt < 1)
03666     return False;
03667 
03668   unsigned int itv = idx->hidx.key_count / perf_cnt;
03669 
03670   if (itv < 1)
03671     return False;
03672 
03673   /*
03674   printf("Hash Cursor %s candidate for parallelization: perf_cnt=%d, itv=%d, "
03675          "max_threads=%d\n",
03676          getOidString(&idx->treeoid),
03677          perf_cnt, itv,  thrpool->getThreadCount());
03678   */
03679 
03680   master = True;
03681 #ifdef MULTI_LIST
03682   lists = new LinkList*[perf_cnt];
03683   list = 0;
03684 #else
03685   list = new LinkList();
03686   lists = 0;
03687 #endif
03688   perf_curs = new HIdxCursor*[perf_cnt];
03689 
03690   /*
03691   const char *s = getenv("ESM_STD_USER_CMP");
03692   if (s) {
03693     user_cmp = user_cmp;
03694     user_cmp_mod = atoi(s);
03695   }
03696   */
03697 
03698   for (int n = 0; n < perf_cnt; n++) {
03699 #ifdef MULTI_LIST
03700     lists[n] = new LinkList();
03701     perf_curs[n] = new HIdxCursor
03702       (idx,
03703        n*itv,
03704        (n == perf_cnt-1 ? idx->hidx.key_count : (n+1)*itv),
03705        skey, ekey,
03706        sexcl, eexcl,
03707        user_cmp, cmp_arg,
03708        lists[n]);
03709 #else
03710     perf_curs[n] = new HIdxCursor
03711       (idx,
03712        n*itv,
03713        (n == perf_cnt-1 ? idx->hidx.key_count : (n+1)*itv),
03714        skey, ekey,
03715        sexcl, eexcl,
03716        user_cmp, cmp_arg,
03717        list);
03718 #endif
03719   }
03720 
03721   /*
03722   s = getenv("ESM_MAX_PERF_CNT");
03723   if (s) {
03724     unsigned int cnt = atoi(getenv("ESM_MAX_PERF_CNT"));
03725     if (perf_cnt > cnt) {
03726       perf_cnt = cnt;
03727       printf("limited perf_cnt to %d\n", perf_cnt);
03728     }
03729   }
03730   */
03731 
03732   thrpool->reset();
03733   perfs = new eyedblib::ThreadPerformer*[perf_cnt];
03734 
03735   for (int n = 0; n < perf_cnt; n++) {
03736     perfs[n] = thrpool->start(cursor_perform_wrapper, perf_curs[n]);
03737   }
03738 
03739 #ifdef NEW_WAIT
03740   perf_end_cnt = 0;
03741 #endif
03742   return True;
03743 }
03744 
03745 void HIdxCursor::init(DbHandle *dbh)
03746 {
03747   state = True;
03748   master = False;
03749   slave = False;
03750 
03751   sdata = 0;
03752   memset(&koid, 0, sizeof(koid));
03753   skey = ekey = 0;
03754   sdata = 0;
03755 
03756   perf_cnt = 0;
03757   perf_curs = 0;
03758   perfs = 0;
03759 #ifdef FORCE_COPY
03760   nocopy = False;
03761 #else
03762   nocopy = isWholeMapped(dbh);
03763 #endif
03764   data_tofree = False;
03765 
03766   datacnt = 0;
03767   idata = 0;
03768   jumpsize = 0;
03769 }
03770 
03771 HIdxCursor::HIdxCursor(const HIdx *_idx,
03772                              unsigned int _k_cur,
03773                              unsigned int _k_end,
03774                              const void *_skey, const void *_ekey,
03775                              Boolean _sexcl, Boolean _eexcl,
03776                              Boolean (*_user_cmp)(const void *, void *),
03777                              void *_cmp_arg,
03778                              LinkList *_list) :
03779   idx(_idx),
03780   user_cmp(_user_cmp), cmp_arg(_cmp_arg),
03781   k_cur(_k_cur), k_end(_k_end), list(_list),
03782   sexcl(_sexcl), eexcl(_eexcl)
03783 {
03784   init(idx->dbh);
03785   if (idx->isDataVarSize()) {
03786     // cannot have data variable size and parallel mode
03787     state = False;
03788     return;
03789   }
03790   slave = True;
03791   equal = False;
03792   Boolean isstr = (STRTYPE(idx) ? True : False);
03793   skey = HIdx::copy_key(_skey, idx->hidx.keysz, isstr, &state);
03794   ekey = HIdx::copy_key((_ekey == defaultSKey) ? _skey : _ekey, idx->hidx.keysz, isstr, &state);
03795   //printf("k_cur %d -> %d : %d\n", k_cur, k_end, idx->hidx.key_count);
03796 }
03797 
03798 HIdxCursor::HIdxCursor(const HIdx *_idx,
03799                              const void *_skey, const void *_ekey,
03800                              Boolean _sexcl, Boolean _eexcl,
03801                              Boolean (*_user_cmp)(const void *, void *),
03802                              void *_cmp_arg,
03803                              int thread_cnt) :
03804   idx(_idx), sexcl(_sexcl),
03805   eexcl(_eexcl),
03806   user_cmp(_user_cmp),
03807   cmp_arg(_cmp_arg)
03808 {
03809   assert(!idx->status());
03810   assert(idx->isOpened());
03811 
03812   init(idx->dbh);
03813   list = 0;
03814   lists = 0;
03815 
03816   Status s;
03817   Boolean isstr = (STRTYPE(idx) ? True : False);
03818   skey = HIdx::copy_key(_skey, idx->hidx.keysz, isstr, &state);
03819   ekey = HIdx::copy_key((_ekey == defaultSKey) ? _skey : _ekey, idx->hidx.keysz, isstr, &state);
03820 
03821   if (!state)
03822     return;
03823 
03824   if (parallelInit(thread_cnt))
03825     return;
03826 
03827   if (skey && ekey && !idx->cmp(skey, ekey, OPS_NOSWAP)) {
03828     equal = True;
03829     s = idx->get_key(k_cur, skey);
03830     if (s) state = False;
03831   }
03832   else {
03833     k_cur = 0;
03834     equal = False;
03835   }
03836     
03837   k_end = idx->hidx.key_count;
03838 }
03839 
03840 #define NO_COPY
03841 
03842 Status
03843 HIdxCursor::read(Boolean &eox)
03844 {
03845   unsigned int size = 0;
03846   Status s;
03847   int n;
03848 
03849   HIdx::CListObjHeader h;
03850 
03851   unsigned int (*gkey)(int) = get_gkey(idx->version);
03852   //  printf("enter HIdxCursor::read()\n");
03853   for (n = 0; ; n++) {
03854     /*
03855     printf("@%d koid = %s k_cur=%d, k_end=%d\n", pthread_self(),
03856            getOidString(&koid), k_cur, k_end);
03857     */
03858     if (backend_interrupt)
03859       return statusMake(BACKEND_INTERRUPTED, "");
03860 
03861     if (koid.getNX() == 0) {
03862       if (k_cur >= k_end) {
03863         eox = True;
03864         return Success;
03865       }
03866 
03867       HIdx::CListHeader chd;
03868       s = idx->readCListHeader(k_cur, chd);
03869       if (s)
03870         return s;
03871       koid = chd.clobj_first;
03872 
03873       if (equal) {
03874         if (koid.getNX() == 0) {
03875           eox = True;
03876           return Success;
03877         }
03878       }
03879       else
03880         k_cur++;
03881       
03882       if (koid.getNX() == 0)
03883         continue;
03884     }     
03885 
03886     s = objectRead(idx->dbh, 0, sizeof(HIdx::CListObjHeader), &h,
03887                    DefaultLock, 0, &size, &koid);
03888     if (s)
03889       return s;
03890     x2h_header(&h);
03891     
03892     if (h.alloc_cnt)
03893       break;
03894 
03895     koid = h.clobj_next;
03896     
03897     if (equal && koid.getNX() == 0) {
03898       eox = True;
03899       return Success;
03900     }
03901   }      
03902 
03903   eox = False;
03904 
03905   Boolean nocopy_failed = False;
03906 
03907   if (data_tofree)
03908     free(sdata);
03909 
03910   if (nocopy) {
03911     s =  objectReadNoCopy(idx->dbh, 0, size, &sdata, DefaultLock, 0, 0,
03912                              &koid);
03913     if (!s) {
03914       edata = sdata + size;
03915       cur = sdata + sizeof(HIdx::CListObjHeader);
03916       data_tofree = False;
03917     }
03918     else {
03919       //printf("nocopy failed for %s\n", getOidString(&koid));
03920       nocopy_failed = True;
03921     }
03922   }
03923 
03924   if (!nocopy || nocopy_failed) {
03925     sdata = (char *)m_malloc(size);
03926     data_tofree = True;
03927     edata = sdata + size;
03928     cur = sdata + sizeof(HIdx::CListObjHeader);
03929     
03930     s =  objectRead(idx->dbh, 0, size, sdata, DefaultLock, 0, 0, &koid);
03931   }
03932 
03933   koid = h.clobj_next;
03934 
03935   return s;
03936 }
03937 
03938 void *HIdx::copy_key(const void *key, unsigned int keysz, Boolean isstr, Boolean *state)
03939 {
03940   if (state)
03941     *state = True;
03942 
03943   if (!key)
03944     return 0;
03945 
03946   if (keysz == HIdx::VarSize)
03947     return strdup((char *)key);
03948 
03949   char *k = (char *)m_malloc(keysz);
03950   assert(k);
03951 
03952   if (isstr) {
03953     int len = strlen((char *)key)+1;
03954 
03955     if (len > keysz) { // was if (len >= keysz)
03956       if (state)
03957         *state = False;
03958     }
03959     else {
03960       memcpy(k, key, len);
03961       memset(k+len, 0, keysz-len);
03962     }
03963   }
03964   else
03965     memcpy(k, key, keysz);
03966 
03967   return k;
03968 }
03969 
03970 inline int
03971 HIdxCursor::cmp_realize(const void *xkey, const void *ykey,
03972                            Boolean excl, unsigned char bswap) const
03973 {
03974   int c = idx->cmp(xkey, ykey, bswap);
03975 
03976   if (c == 0) {
03977     if (excl)
03978       return 1;
03979     return 0;
03980   }
03981   
03982   return (c > 0);
03983 }
03984 
03985 inline int
03986 HIdxCursor::cmp(const void *key) const
03987 {
03988   if (equal)
03989     return idx->cmp(skey, key, OP2_SWAP);
03990 
03991   if (!skey && !ekey)
03992     return 0;
03993 
03994   if (skey && ekey)
03995     return cmp_realize(skey, key, sexcl, OP2_SWAP) ||
03996       cmp_realize(key, ekey, eexcl, OP1_SWAP);
03997 
03998   if (skey)
03999     return cmp_realize(skey, key, sexcl, OP2_SWAP);
04000 
04001   if (ekey)
04002     return cmp_realize(key, ekey, eexcl, OP1_SWAP);
04003 
04004   abort();
04005   return 1;
04006 }
04007 
04008 void HIdxCursor::append_next(void *data, Idx::Key *key, unsigned int n, DataBuffer *dataBuffer)
04009 {
04010   int off = get_off(cur, idx);
04011 
04012   Link *l;
04013   if (slave) {
04014     l = new Link(idx->hidx.datasz);
04015     data = l->data;
04016     key = &l->key;
04017   }
04018   else {
04019     l = 0;
04020   }
04021 
04022   if (data || dataBuffer) {
04023     if (idx->isDataGroupedByKey()) {
04024       if (dataBuffer) {
04025         dataBuffer->setData(cur + off + data_group_sz(n, idx), idx->hidx.datasz);
04026       }
04027       else if (data) {
04028         memcpy(data, cur + off + data_group_sz(n, idx), idx->hidx.datasz);
04029       }
04030     }
04031     else {
04032       if (idx->isDataVarSize()) {
04033         unsigned int xdatasz, datasz;
04034 
04035         memcpy(&xdatasz, cur + off, DATASZ_SIZE);
04036         datasz = x2h_u32(xdatasz);
04037 
04038         if (dataBuffer) {
04039           dataBuffer->setData(cur + off + DATASZ_SIZE, datasz);
04040         }
04041         else if (data) {
04042           memcpy(data, cur + off + DATASZ_SIZE, datasz);
04043         }
04044       }
04045       else {
04046         if (dataBuffer) {
04047           dataBuffer->setData(cur + off, idx->hidx.datasz);
04048         }
04049         else if (data) {
04050           memcpy(data, cur + off, idx->hidx.datasz);
04051         }
04052       }
04053     }
04054   }
04055         
04056   if (key) {
04057     key->setKey(cur, (idx->hidx.keysz != HIdx::VarSize ?
04058                       idx->hidx.keysz : strlen(cur) + 1),
04059                 idx->keytype);
04060   }
04061   
04062   if (slave) {
04063     list->insert(l);
04064   }
04065 }
04066 
04067 Status HIdxCursor::next(unsigned int *found_cnt, Idx::Key *key)
04068 {
04069   if (!idx->isDataGroupedByKey()) {
04070     *found_cnt = 0;
04071     // for now
04072     return statusMake(ERROR, "cannot use this type of cursor on non data_grouped_by_key hash index");
04073   }
04074 
04075   Boolean found;
04076   return next(&found, found_cnt, 0, key, 0);
04077 }
04078 
04079 Status HIdxCursor::next(Boolean *found, void *data, Idx::Key *key)
04080 {
04081   return next(found, 0, data, key, 0);
04082 }
04083 
04084 Status HIdxCursor::next(Boolean *found, DataBuffer &dataBuffer, Idx::Key *key)
04085 {
04086   return next(found, 0, 0, key, &dataBuffer);
04087 }
04088 
04089 Status
04090 HIdxCursor::next(Boolean *found, unsigned int *found_cnt, void *data, Idx::Key *key, DataBuffer *dataBuffer)
04091 {
04092   if (!state) {
04093     if (found_cnt)
04094       *found_cnt = 0;
04095     *found = False;
04096     return Success;
04097   }
04098 
04099   if (master) {
04100     for (;;) {
04101       LinkList *tlist;
04102 #ifdef MULTI_LIST
04103       for (int n = 0; n < perf_cnt; n++) {
04104         tlist = lists[n];
04105 #else
04106         tlist = list;
04107 #endif
04108         Link *l = tlist->peek();
04109         if (l) {
04110           if (dataBuffer) {
04111             dataBuffer->setData(l->data, idx->hidx.datasz);
04112           }
04113           else if (data) {
04114             memcpy(data, l->data, idx->hidx.datasz);
04115           }
04116 
04117           if (key) {
04118             key->setKey(l->key.getKey(), l->key.getSize(), idx->keytype);
04119           }
04120 
04121           delete l;
04122           *found = True;
04123           return Success;
04124         }
04125 #ifdef MULTI_LIST
04126       }
04127 #endif
04128 
04129 #ifdef NEW_WAIT
04130       if (perf_end_cnt == perf_cnt) {
04131         thrpool->waitAll();
04132         if (found_cnt)
04133           *found_cnt = 0;
04134         *found = False;
04135         return Success;
04136       }
04137 
04138       eyedblib::ThreadPerformer *perf;
04139       eyedblib::ThreadPerformerArg arg = thrpool->wait(perf);
04140       if (arg.data) {
04141         thrpool->waitAll(); // should advert thread to stop immediately !
04142         return (Status)arg.data;
04143       }
04144 
04145       perf_end_cnt++;
04146 #else
04147       int n;
04148       for (n = 0; n < perf_cnt; n++) {
04149         if (!perfs[n]->isIdle())
04150           break;
04151       }
04152 
04153       bool cond = (n == perf_cnt);
04154       if (!cond) { // at least one is still running
04155         eyedblib::ThreadPerformer *perf;
04156         eyedblib::ThreadPerformerArg arg = thrpool->wait(perf);
04157         if (arg.data) {
04158           thrpool->waitAll(); // should advert thread to stop immediately !
04159           return (Status)arg.data;
04160         }
04161       }
04162       else if (cond) { // all performers have finished
04163         thrpool->waitAll();
04164         if (found_cnt)
04165           *found_cnt = 0;
04166         *found = False;
04167         return Success;
04168       }
04169 #endif
04170     }
04171   }
04172 
04173   if (!sdata) {
04174     Boolean eox;
04175     Status s = read(eox);
04176     if (s)
04177       return s;
04178     
04179     if (eox) {
04180       if (found_cnt)
04181         *found_cnt = 0;
04182       *found = False;
04183       return Success;
04184     }
04185   }
04186 
04187   if (found_cnt) {
04188     cur += jumpsize;
04189     datacnt = 0;
04190     jumpsize = 0;
04191   }
04192   else if (++idata < datacnt) {
04193 #ifdef TRACE_DGK
04194     printf("...CURSOR DATACNT %d idata=%d\n", datacnt, idata);
04195 #endif
04196     *found = True;
04197     append_next(data, key, idata, dataBuffer);
04198     return Success;
04199   }
04200   else if (datacnt) {
04201 #ifdef TRACE_DGK
04202     printf("...CURSOR jumping\n");
04203 #endif
04204     cur += jumpsize;
04205     datacnt = 0;
04206     jumpsize = 0;
04207   }
04208 
04209   for (;;) {
04210     // changed the 8/12/99
04211     // for (; cur < edata; )
04212     for (; cur+sizeof(HIdx::CellHeader) <= edata; ) {
04213       if (backend_interrupt)
04214         return statusMake(BACKEND_INTERRUPTED, "");
04215       HIdx::CellHeader o;
04216       mcp(&o, cur, sizeof(HIdx::CellHeader));
04217       x2h_overhead(&o);
04218       cur += sizeof(HIdx::CellHeader);
04219           
04220       if (!o.free && !cmp(cur)) {
04221         if (idx->precmp) {
04222           int r;
04223           void const * sk = skey ? skey : ekey;
04224           if (sk && idx->precmp(sk, cur, &idx->keytype, r)) {
04225             //printf("skipping entry\n");
04226             if (!skey) {
04227               cur += o.size; // 23/12/01: was not test with this statement
04228               continue;
04229             }
04230 
04231             if (found_cnt)
04232               *found_cnt = 0;
04233             *found = False;
04234             return Success;
04235           }
04236         }
04237         
04238         if (user_cmp && !user_cmp(cur, cmp_arg)) {
04239           cur += o.size;
04240           continue;
04241         }
04242 
04243         if (idx->isDataGroupedByKey()) {
04244 #ifdef VARSZ_DATACNT
04245           Status s = idx->x2h_datacnt_cpy(&datacnt, (unsigned char *)(cur + get_off(cur, idx)));
04246           if (s)
04247             return s;
04248 #else
04249           x2h_32_cpy(&datacnt, cur + get_off(cur, idx));
04250 #endif
04251           idata = 0;
04252 #ifdef TRACE_DGK
04253           printf("CURSOR DATACNT %d idata=%d\n", datacnt, idata);
04254 #endif
04255           jumpsize = o.size;
04256         }
04257         else
04258           datacnt = 1;
04259 
04260         if (found_cnt)
04261           *found_cnt = datacnt;
04262 
04263         *found = True;
04264         append_next(data, key, 0, dataBuffer);
04265 
04266         if (!idx->isDataGroupedByKey())
04267           cur += o.size;
04268         return Success;
04269       }
04270           
04271       cur += o.size;
04272     }
04273       
04274     if (equal && !koid.getNX()) {
04275       if (found_cnt)
04276         *found_cnt = 0;
04277       *found = False;
04278       state = False;
04279       return Success;
04280     }
04281 
04282     Boolean eox;
04283     Status s = read(eox);
04284           
04285     if (s)
04286       return s;
04287 
04288     if (eox) {
04289       if (found_cnt)
04290         *found_cnt = 0;
04291       *found = False;
04292       state = False;
04293       return Success;
04294     }
04295   }
04296 }
04297 
04298 HIdxCursor::~HIdxCursor()
04299 {
04300   free(skey);
04301   free(ekey);
04302   if (data_tofree)
04303     free(sdata);
04304   delete [] perf_curs;
04305   delete [] perfs;
04306 #ifdef MULTI_LIST
04307   if (lists) {
04308     for (int n = 0; n < perf_cnt; n++)
04309       delete lists[n];
04310     delete lists;
04311   }
04312 #else
04313   delete list;
04314 #endif
04315 }
04316 
04317 Status
04318 HIdx::getStats(std::string &stats) const
04319 {
04320   unsigned int total;
04321   int n;
04322 
04323   stats  = std::string("  Index type: 'hash'\n");
04324 
04325   stats += std::string("  Key count: ") + str_convert((long)hidx.key_count) + "\n";
04326   stats += std::string("  Magnitude Order: ") + str_convert((int)hidx.mag_order) + "\n";
04327   stats += std::string("  Key Type: ") + typeString((Type)hidx.keytype) + "\n";
04328   stats += std::string("  Implementation Hints:\n");
04329   for (int i = 0; i < HIdxImplHintsCount; i++)
04330     stats += std::string("    ") + implHintsStr(i) + ": " +
04331       str_convert((int)hidx.impl_hints[i]) + "\n";
04332   stats += std::string("  Dataspace ID: ") + str_convert((int)(hidx.dspid == DefaultDspid ? -1 : hidx.dspid)) + "\n";
04333   stats += std::string("  Data Size: ") + str_convert((long)hidx.datasz) + "\n";
04334   stats += std::string("  Key Size: ") + str_convert((int)hidx.keysz) + "\n";
04335   stats += std::string("  Magnitude Order: ") + str_convert((long)hidx.mag_order) + "\n";
04336 
04337   total = 0;
04338   unsigned int total_objs = 0;
04339   unsigned int max = 0;
04340   unsigned int min = ~0;
04341   unsigned int free = 0, busy = 0;
04342 
04343   for (n = 0; n < hidx.key_count; n++) {
04344     CListHeader chd;
04345     Status s = readCListHeader(n, chd);
04346     if (s)
04347       return s;
04348 
04349     Oid toid;
04350     toid = chd.clobj_first;
04351     unsigned int cell_count = 0;
04352     unsigned int nobjs = 0;
04353     while (toid.getNX() > 0) {
04354       unsigned int count;
04355       if (backend_interrupt)
04356         return statusMake(BACKEND_INTERRUPTED, "");
04357 
04358       s = getEntryCount(&toid, count);
04359       if (s)
04360         return s;
04361 
04362       cell_count += count;
04363       nobjs++;
04364     }
04365 
04366     total_objs += nobjs;
04367 
04368     if (cell_count > max)
04369       max = cell_count;
04370     if (cell_count < min)
04371       min = cell_count;
04372 
04373     if (cell_count) {
04374       busy++;
04375       stats += std::string("  Cell #") + str_convert(n) + ": " + str_convert((long)cell_count) + " object" + (cell_count != 1 ? "s" : "") + ", " + str_convert((long)nobjs) + " hash object" + (nobjs != 1 ? "s" : "") + "\n";
04376       total += cell_count;
04377     }
04378     else
04379       free++;
04380   }
04381 
04382   stats += std::string("  Total object count: ") + str_convert((long)total) +
04383     " {computed: " + str_convert((long)getCount()) + "}\n";
04384   stats += std::string("  Min object per entry: ") + str_convert((long)min) + "\n";
04385   stats += std::string("  Max entries per entry: ") + str_convert((long)max) + "\n";
04386   stats += std::string("  Free entry count: ") + str_convert((long)free) + "\n";
04387   stats += std::string("  Busy entry count: ") + str_convert((long)busy) + "\n";
04388   stats += std::string("  Total hash object count: 1+") +
04389     str_convert((long)total_objs) + "\n";
04390   return Success;
04391 }
04392 
04393 Status
04394 HIdx::getStats(HIdx::Stats &stats) const
04395 {
04396   memset(&stats, 0, sizeof(stats));
04397   memcpy(&stats.idx, &hidx, sizeof(hidx));
04398 
04399   unsigned int (*gkey)(int) = get_gkey(version);
04400   // the tree object:
04401   stats.total_hash_object_count = 1;
04402   stats.total_hash_object_size = sizeof(CListHeader) * gkey(hidx.key_count);
04403 
04404   stats.entries = new Stats::Entry[hidx.key_count];
04405   memset(stats.entries, 0, sizeof(Stats::Entry) * hidx.key_count);
04406   stats.min_objects_per_entry = ~0;
04407 
04408   Stats::Entry *entry = stats.entries;
04409   for (int n = 0; n < hidx.key_count; n++, entry++) {
04410     CListHeader chd;
04411     Status s = readCListHeader(n, chd);
04412     if (s)
04413       return s;
04414 #if 1
04415     checkChain(&chd, "getStats");
04416 #endif
04417     Oid koid;
04418     koid = chd.clobj_first;
04419     while (koid.getNX() > 0) {
04420       unsigned int count;
04421       if (backend_interrupt)
04422         return statusMake(BACKEND_INTERRUPTED, "");
04423       
04424       unsigned int size, busysize;
04425       s = objectSizeGet(dbh, &size, DefaultLock, &koid);
04426       if (s)
04427         return s;
04428 
04429       s = getHashObjectBusySize(&koid, busysize, count, size);
04430       if (s)
04431         return s;
04432 
04433       unsigned int ncount;
04434       s = getEntryCount(&koid, ncount);
04435       if (s)
04436         return s;
04437       
04438       /*
04439       if (ncount != count) {
04440         printf("HIdx: count differ %d %d\n", count, ncount);
04441       }
04442       else {
04443         printf("HIdx: count equal %d %d\n", count, ncount);
04444       }
04445       */
04446 
04447       entry->object_count += count;
04448       entry->hash_object_busy_size += busysize;
04449       entry->hash_object_count++;
04450       entry->hash_object_size += size;
04451     }
04452 
04453     if (entry->object_count > stats.max_objects_per_entry)
04454       stats.max_objects_per_entry = entry->object_count;
04455     if (entry->object_count < stats.min_objects_per_entry)
04456       stats.min_objects_per_entry = entry->object_count;
04457 
04458     stats.total_hash_object_count += entry->hash_object_count;
04459     stats.total_hash_object_busy_size += entry->hash_object_busy_size;
04460     stats.total_object_count += entry->object_count;
04461     stats.total_hash_object_size += entry->hash_object_size;
04462 
04463     if (entry->object_count)
04464       stats.busy_key_count++;
04465     else
04466       stats.free_key_count++;
04467   }
04468 
04469   return Success;
04470 }
04471 
04472 HIdx::Stats::Stats()
04473 {
04474   entries = 0;
04475 }
04476 
04477 std::string
04478 HIdx::Stats::toString(Boolean full) const
04479 {
04480   std::string s = idx.toString();
04481   Entry *entry = entries;
04482 
04483   if (full) {
04484     for (int i = 0; i < idx.key_count; i++, entry++)
04485       if (entry->object_count) {
04486         s += std::string("Entry #") + str_convert((long)i) + " {\n";
04487         s += std::string("\tObject count: ") + str_convert((long)entry->object_count) +
04488           "\n";
04489         s += std::string("\tObject size: ")  + 
04490           str_convert((long)entry->hash_object_busy_size) + "\n";
04491         s += std::string("\tHash object count: ") +
04492           str_convert((long)entry->hash_object_count) + "\n";
04493         s += std::string("\tHash object size: ")  + 
04494           str_convert((long)entry->hash_object_size) + "b\n}\n";
04495       }
04496 
04497     s += "\n";
04498   }
04499 
04500   s += std::string("Min objects per entry: ") +
04501     str_convert((long)min_objects_per_entry) + "\n";
04502   s += std::string("Max objects per entry: ") +
04503     str_convert((long)max_objects_per_entry) + "\n";
04504   s += std::string("Total object count: ") +
04505     str_convert((long)total_object_count) + "\n";
04506   s += std::string("Total object size: ") +
04507     str_convert((long)total_hash_object_busy_size) + "b\n";
04508   s += std::string("Total hash object count: ") + 
04509     str_convert((long)total_hash_object_count) + "\n";
04510   s += std::string("Total hash object size: ") +
04511     str_convert((long)total_hash_object_size) + "b\n";
04512   s += std::string("Busy entry count: ") +
04513     str_convert((long)busy_key_count) + "\n";
04514   s += std::string("Free entry count: ") +
04515     str_convert((long)free_key_count) + "\n";
04516   return s;
04517 }
04518 
04519 void
04520 HIdx::Stats::trace(Boolean full, FILE *fd) const
04521 {
04522   idx.trace(fd);
04523   Entry *entry = entries;
04524 
04525   if (full) {
04526     for (int i = 0; i < idx.key_count; i++, entry++)
04527       if (entry->object_count) {
04528         fprintf(fd, "Entry #%d {\n", i);
04529         fprintf(fd, "\tObject count: %d\n", entry->object_count);
04530         fprintf(fd, "\tHash object count: %d\n", entry->hash_object_count);
04531         fprintf(fd, "\tHash object size: %db\n", entry->hash_object_size);
04532         fprintf(fd, "\tHash object busy size: %db\n", entry->hash_object_busy_size);
04533         fprintf(fd, "}\n");
04534       }
04535     fprintf(fd, "\n");
04536   }
04537 
04538   fprintf(fd, "Min objects per entry: %d\n", min_objects_per_entry);
04539   fprintf(fd, "Max objects per entry: %d\n", max_objects_per_entry);
04540   fprintf(fd, "Total object count: %d\n", total_object_count);
04541   fprintf(fd, "Total hash object count: %d\n", total_hash_object_count);
04542   fprintf(fd, "Total hash object size: %db\n", total_hash_object_size);
04543   fprintf(fd, "Total hash object busy size: %db\n", total_hash_object_busy_size);
04544   fprintf(fd, "Busy entry count: %d\n", busy_key_count);
04545   fprintf(fd, "Free entry count: %d\n", free_key_count);
04546 }
04547 
04548 HIdx::Stats::~Stats()
04549 {
04550   delete [] entries;
04551 }
04552 
04553 Status
04554 HIdx::copy(HIdx *&idx_n, int key_count, int mag_order, short dspid,
04555               const int *impl_hints, unsigned int impl_hints_cnt,
04556               hash_key_t _hash_key,
04557               void *_hash_data, KeyType *ktype) const
04558 {
04559   key_count = (key_count > MaxKeys ? MaxKeys : key_count);
04560 
04561   idx_n = new HIdx(dbh, (ktype ? *ktype : getKeyType()), hidx.datasz,
04562                       (dspid == DefaultDspid ? hidx.dspid : dspid),
04563                       (mag_order == 0 ? hidx.mag_order : mag_order),
04564                       key_count,
04565                       (impl_hints == 0 ? hidx.impl_hints : impl_hints),
04566                       (impl_hints == 0 ? HIdxImplHintsCount : impl_hints_cnt));
04567 
04568   if (idx_n->status())
04569     return idx_n->status();
04570 
04571   idx_n->open(_hash_key, _hash_data);
04572   
04573   return copy_realize(idx_n);
04574 }
04575 
04576 Status
04577 HIdx::copy_realize(Idx *idx) const
04578 {
04579   Status s = Success;
04580   HIdxCursor curs(this);
04581   unsigned char *data = new unsigned char[hidx.datasz];
04582 
04583   for (;;) {
04584     Boolean found;
04585     Idx::Key key;
04586 
04587     s = curs.next(&found, data, &key);
04588     if (s) goto error;
04589 
04590     if (!found) break;
04591 
04592     s = idx->insert(key.getKey(), data);
04593     if (s) goto error;
04594   }
04595 
04596  error:
04597   delete [] data;
04598   return s;
04599 }
04600 
04601 Status
04602 HIdx::reimplementToBTree(Oid &newoid, int degree, short dspid)
04603 {
04604   BIdx bidx(dbh, hidx.datasz, &keytype,
04605                (dspid == DefaultDspid ? hidx.dspid : dspid),
04606                degree, 1);
04607 
04608   if (bidx.status())
04609     return bidx.status();
04610 
04611   bidx.open();
04612 
04613   Status s = copy_realize(&bidx);
04614   if (s)
04615     return s;
04616   s = destroy();
04617   if (s)
04618     return s;
04619 
04620   newoid = bidx.oid();
04621   return Success;
04622 }
04623 
04624 Status HIdx::move(short dspid, eyedbsm::Oid &newoid,
04625                   hash_key_t hash_key, void *hash_data)
04626 {
04627   // for now
04628   /*
04629   return reimplementToHash(newoid, hidx.key_count, hidx.mag_order, dspid, hidx.impl_hints, HIdxImplHintsCount, hash_key, hash_data);
04630   */
04631   // construction d'un index comme dans copy
04632   // parcours de tous les objets comme dans collapse, puis writeCListHeader sur le nouvel index, sans destruction (le destroy se fait ensuite) => en fait, il faut dupliquer collapse, c'est trop different
04633   // note: le collapse est-il obligatoire ? ou bien c'est une option a ajouter dans le mvidx et a passer a Index::move puis a Index::realize (via les UserData) ?
04634   // dans un 1er temps, on peut le faire obligatoire
04635 #if 1
04636   if (getenv("MOVE_IS_COLLAPSE")) {
04637     printf("move is collapse only\n");
04638     newoid = oid();
04639     return collapse();
04640   }
04641 #endif
04642 
04643   HIdx *idx_n = new HIdx(dbh,
04644                          getKeyType(),
04645                          hidx.datasz,
04646                          dspid,
04647                          hidx.mag_order,
04648                          hidx.key_count,
04649                          hidx.impl_hints,
04650                          HIdxImplHintsCount);
04651 
04652   if (idx_n->status())
04653     return idx_n->status();
04654 
04655   idx_n->open(hash_key, hash_data);
04656 
04657   IdxLock lockx_n(dbh, idx_n->treeoid);
04658   Status s = lockx_n.lock();
04659   if (s)
04660     return s;
04661 
04662 #if 0
04663   s = copy_realize(idx_n);
04664 #else
04665   s = collapse_realize(dspid, idx_n);
04666 #endif
04667   if (s)
04668     return s;
04669 
04670   s = destroy();
04671   if (s)
04672     return s;
04673 
04674   newoid = idx_n->oid();
04675 
04676   delete idx_n;
04677 
04678   return Success;
04679 }
04680 
04681 Status
04682 HIdx::reimplementToHash(Oid &newoid, int key_count, int mag_order,
04683                            short dspid, const int *impl_hints,
04684                            unsigned int impl_hints_cnt,
04685                            hash_key_t _hash_key, void *_hash_data,
04686                            KeyType *ktype)
04687 {
04688   IdxLock lockx(dbh, treeoid);
04689   Status s = lockx.lock();
04690   if (s)
04691     return s;
04692 
04693   printf("reimplementToHash:\n");
04694   printf("OLD: kc: %d dspid: %d hints: %d %d %d %d %d %d\n", hidx.key_count, hidx.dspid, hidx.impl_hints[0],hidx.impl_hints[1],hidx.impl_hints[2],hidx.impl_hints[3],hidx.impl_hints[4],hidx.impl_hints[5],hidx.impl_hints[6]);
04695   printf("NEW: kc: %d dspid: %d hints: %d %d %d %d %d %d\n", key_count, dspid, impl_hints[0],impl_hints[1],impl_hints[2],impl_hints[3],impl_hints[4],impl_hints[5],impl_hints[6]);
04696 
04697   // si tous les parametres sont identiques sauf le dspid, alors il suffit de
04698   // reorganiser l'index, et il ne faut pas le reimplementer !
04699 
04700   HIdx *idx_n = 0;
04701   s = copy(idx_n, key_count, mag_order, dspid, impl_hints,
04702            impl_hints_cnt, _hash_key, _hash_data, ktype);
04703   if (s)
04704     return s;
04705 
04706   s = destroy();
04707   if (s)
04708     return s;
04709   newoid = idx_n->oid();
04710   delete idx_n;
04711   return Success;
04712 }
04713 
04714 Status
04715 HIdx::simulate(Stats &stats, int key_count, int mag_order,
04716                   const int *impl_hints, unsigned int impl_hints_cnt,
04717                   hash_key_t _hash_key,
04718                   void *_hash_data) const
04719 {
04720   HIdx *idx_n;
04721   Status s = copy(idx_n, key_count, mag_order, hidx.dspid, impl_hints,
04722                      impl_hints_cnt, _hash_key, _hash_data, 0);
04723   if (s)
04724     return s;
04725 
04726   s = idx_n->getStats(stats);
04727   idx_n->destroy();
04728   delete idx_n;
04729   return s;
04730 }
04731 
04732 static void x2h_idx(HIdx::_Idx *idx)
04733 {
04734 #ifdef HIDX_XDR
04735   idx->idxtype = x2h_u32(idx->idxtype);
04736   idx->object_count = x2h_u32(idx->object_count);
04737   idx->mag_order = x2h_u32(idx->mag_order);
04738   idx->key_count = x2h_u32(idx->key_count);
04739   idx->dspid = x2h_16(idx->dspid);
04740   idx->keytype = x2h_u32(idx->keytype);
04741   idx->keysz = x2h_u32(idx->keysz);
04742   idx->datasz = x2h_u32(idx->datasz);
04743   idx->offset = x2h_u32(idx->offset);
04744   for (int i = 0; i < HIdxImplHintsCount; i++)
04745     idx->impl_hints[i] = x2h_u32(idx->impl_hints[i]);
04746 #endif
04747 }
04748 
04749 static void h2x_idx(HIdx::_Idx *xidx, const HIdx::_Idx *hidx)
04750 {
04751 #ifdef HIDX_XDR
04752   xidx->idxtype = h2x_u32(hidx->idxtype);
04753   xidx->object_count = h2x_u32(hidx->object_count);
04754   xidx->mag_order = h2x_u32(hidx->mag_order);
04755   xidx->key_count = h2x_u32(hidx->key_count);
04756   xidx->dspid = h2x_16(hidx->dspid);
04757   xidx->keytype = h2x_u32(hidx->keytype);
04758   xidx->keysz = h2x_u32(hidx->keysz);
04759   xidx->datasz = h2x_u32(hidx->datasz);
04760   xidx->offset = h2x_u32(hidx->offset);
04761   for (int i = 0; i < HIdxImplHintsCount; i++)
04762     xidx->impl_hints[i] = h2x_u32(hidx->impl_hints[i]);
04763 #else
04764   if (xidx != hidx)
04765     memcpy(xidx, hidx, sizeof(*xidx));
04766 #endif
04767 }
04768 
04769 static void x2h_chd(HIdx::CListHeader *chd)
04770 {
04771 #ifdef HIDX_XDR
04772   x2h_oid(&chd->clobj_first, &chd->clobj_first);
04773   x2h_oid(&chd->clobj_last, &chd->clobj_last);
04774   x2h_oid(&chd->clobj_free_first, &chd->clobj_free_first);
04775 #endif
04776 }
04777 
04778 static void h2x_chd(HIdx::CListHeader *xchd, const HIdx::CListHeader *hchd)
04779 {
04780 #ifdef HIDX_XDR
04781   h2x_oid(&xchd->clobj_first, &hchd->clobj_first);
04782   h2x_oid(&xchd->clobj_last, &hchd->clobj_last);
04783   h2x_oid(&xchd->clobj_free_first, &hchd->clobj_free_first);
04784 #else
04785   if (xchd != hchd)
04786     memcpy(xchd, hchd, sizeof(*xchd));
04787 #endif
04788 }
04789 
04790 static void x2h_header(HIdx::CListObjHeader *h)
04791 {
04792 #ifdef HIDX_XDR
04793   h->size = x2h_32(h->size);
04794   h->free_cnt = x2h_u16(h->free_cnt);
04795   h->alloc_cnt = x2h_u16(h->alloc_cnt);
04796   h->free_whole = x2h_u32(h->free_whole);
04797   h->cell_free_first = x2h_u32(h->cell_free_first);
04798   x2h_oid(&h->clobj_free_prev, &h->clobj_free_prev);
04799   x2h_oid(&h->clobj_free_next, &h->clobj_free_next);
04800   x2h_oid(&h->clobj_prev, &h->clobj_prev);
04801   x2h_oid(&h->clobj_next, &h->clobj_next);
04802 #endif
04803 }
04804 
04805 static void h2x_header(HIdx::CListObjHeader *xh, const HIdx::CListObjHeader *hh)
04806 {
04807 #ifdef HIDX_XDR
04808   xh->size = h2x_32(hh->size);
04809   xh->free_cnt = h2x_u16(hh->free_cnt);
04810   xh->alloc_cnt = h2x_u16(hh->alloc_cnt);
04811   xh->free_whole = h2x_u32(hh->free_whole);
04812   xh->cell_free_first = h2x_32(hh->cell_free_first);
04813   h2x_oid(&xh->clobj_free_prev, &hh->clobj_free_prev);
04814   h2x_oid(&xh->clobj_free_next, &hh->clobj_free_next);
04815   h2x_oid(&xh->clobj_prev, &hh->clobj_prev);
04816   h2x_oid(&xh->clobj_next, &hh->clobj_next);
04817 #else
04818   if (xh != hh)
04819     memcpy(xh, hh, sizeof(*xh));
04820 #endif
04821 }
04822 
04823 static void x2h_overhead(HIdx::CellHeader *o)
04824 {
04825 #ifdef HIDX_XDR_OVERHEAD
04826   unsigned int x;
04827   mcp(&x, o, sizeof(x));
04828   x = x2h_u32(x);
04829   o->free = x >> 31;
04830   o->size = x & 0xefffffff;
04831   o->cell_free_next = x2h_32(o->cell_free_next);
04832   o->cell_free_prev = x2h_32(o->cell_free_prev);
04833 #endif
04834 }
04835 
04836 static void h2x_overhead(HIdx::CellHeader *xo, const HIdx::CellHeader *ho)
04837 {
04838 #ifdef HIDX_XDR_OVERHEAD
04839   unsigned int x = h2x_u32((ho->free << 31) | ho->size);
04840   mcp(xo, &x, sizeof(x));
04841   xo->cell_free_next = h2x_32(ho->cell_free_next);
04842   xo->cell_free_prev = h2x_32(ho->cell_free_prev);
04843 #else
04844   if (xo != ho)
04845     memcpy(xo, ho, sizeof(*xo));
04846 #endif
04847 }
04848 
04849 static const char out_of_bounds_fmt[] =
04850 "out of bounds data grouped sizeof: maximum data count per key is %u";
04851 
04852 static const char unsupported_sizeof_fmt[] =
04853 "unsupported data grouped sizeof in hash index %u";
04854 
04855 static Status out_of_bounds(unsigned int data_grouped_sizeof)
04856 {
04857   return statusMake(ERROR, out_of_bounds_fmt,
04858                     (1 << (8 * data_grouped_sizeof)) - 1);
04859 }
04860 
04861 Status HIdx::h2x_datacnt_cpy(unsigned char *rdata, const unsigned int *pdatacnt) const
04862 {
04863   if (data_grouped_sizeof == 4) {
04864     h2x_32_cpy(rdata, pdatacnt);
04865     return Success;
04866   }
04867 
04868   if (data_grouped_sizeof == 2) {
04869     unsigned short sdatacnt = *pdatacnt;
04870     if ((unsigned int)sdatacnt != *pdatacnt) {
04871       return out_of_bounds(data_grouped_sizeof);
04872     }
04873     h2x_16_cpy(rdata, &sdatacnt);
04874     return Success;
04875   }
04876 
04877   if (data_grouped_sizeof == 1) {
04878     *rdata = *pdatacnt;
04879     if ((unsigned int)*rdata != *pdatacnt) {
04880       return out_of_bounds(data_grouped_sizeof);
04881     }
04882 
04883     return Success;
04884   }
04885 
04886   return statusMake(ERROR, unsupported_sizeof_fmt, data_grouped_sizeof);
04887 }
04888 
04889 Status HIdx::x2h_datacnt_cpy(unsigned int *pdatacnt, const unsigned char *pdata) const
04890 {
04891   if (data_grouped_sizeof == 4) {
04892     x2h_32_cpy(pdatacnt, pdata);
04893     return Success;
04894   }
04895 
04896   if (data_grouped_sizeof == 2) {
04897     unsigned short sdatacnt;
04898     x2h_16_cpy(&sdatacnt, pdata);
04899     *pdatacnt = sdatacnt;
04900     if ((unsigned int)sdatacnt != *pdatacnt) {
04901       return out_of_bounds(data_grouped_sizeof);
04902     }
04903     return Success;
04904   }
04905 
04906   if (data_grouped_sizeof == 1) {
04907     *pdatacnt = *pdata;
04908 
04909     if ((unsigned int)*pdata != *pdatacnt) {
04910       return out_of_bounds(data_grouped_sizeof);
04911     }
04912 
04913     return Success;
04914   }
04915 
04916   return statusMake(ERROR, unsupported_sizeof_fmt, data_grouped_sizeof);
04917 }
04918 }
04919 

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