00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <eyedbconfig.h>
00025
00026
00027
00028
00029
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
00063
00064
00065
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
00076
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
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
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
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
00216
00217 Boolean trace_idx;
00218 FILE *trace_idx_fd = stdout;
00219 Boolean trace_idx_sync;
00220
00221 unsigned int getDbVersion(void *);
00222 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;
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
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;
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
00397
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
00466
00467
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
00494
00495
00496
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
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
00548
00549
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);
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
00853
00854
00855
00856
00857
00858
00859
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
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
00991
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
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
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
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
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
01137
01138
01139
01140
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
01152
01153
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
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
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
01314
01315 int cnt = 0;
01316 while (koid.getNX()) {
01317 CListObjHeader h;
01318 assert(!readCListObjHeader(koid, h));
01319
01320 checkChain(&koid);
01321 koid = h.clobj_free_next;
01322 cnt++;
01323 }
01324
01325 }
01326
01327 static bool dont_check = false;
01328
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
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;
01549 objsize += sizeof(CellHeader);
01550 int utsize = (bsz > objsize ? bsz : objsize);
01551
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
01584
01585 h.clobj_free_next = chd.clobj_free_first;
01586
01587 o.free = 1;
01588 o.size = utsize - 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
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
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
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
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
01793
01794
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
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) {
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
01943 break;
01944 }
01945 s = readCellHeader(offset, koid, o);
01946 if (s)
01947 return s;
01948 if (o.free && o.size >= size) {
01949
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
01959 return Success;
01960 }
01961 }
01962
01963
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
01980
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
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
02160
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
02181
02182
02183
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
02230
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
02251
02252
02253
02254
02255
02256
02257
02258
02259
02260
02261
02262
02263
02264
02265
02266
02267
02268
02269
02270
02271 }
02272 else {
02273 if (xdata_v_cnt == 1) {
02274 xdata = xdata_v[0];
02275 }
02276 else {
02277 assert(!xdatasz);
02278
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
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
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
02514 s = insertCell(curcell-start,
02515 o->size + no.size + sizeof(CellHeader),
02516 h, *koid);
02517
02518 #ifdef TRACK_MAP
02519 printf("case no.free\n");
02520 #endif
02521 }
02522 else if (po.free) {
02523
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
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
02540 #ifdef TRACK_MAP
02541 printf("case *no* free\n");
02542 #endif
02543 }
02544
02545
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
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
02659
02660
02661
02662
02663
02664
02665
02666
02667
02668
02669
02670
02671
02672
02673
02674
02675
02676
02677
02678
02679
02680
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
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
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
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
03066
03067
03068
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
03083
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
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
03198
03199
03200
03201
03202
03203
03204
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)) {
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
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
03276 koid = h.clobj_next;
03277 free(data);
03278
03279
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
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
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
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
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
03504
03505
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
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
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
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
03648
03649
03650
03651
03652 if (thread_cnt < 2 || idx->hidx.object_count <= MIN_OBJCNT_FOR_PARALLEL ||
03653 (skey && ekey && !idx->cmp(skey, ekey, OPS_NOSWAP)))
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
03675
03676
03677
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
03692
03693
03694
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
03723
03724
03725
03726
03727
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
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
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
03853 for (n = 0; ; n++) {
03854
03855
03856
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
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) {
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
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();
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) {
04155 eyedblib::ThreadPerformer *perf;
04156 eyedblib::ThreadPerformerArg arg = thrpool->wait(perf);
04157 if (arg.data) {
04158 thrpool->waitAll();
04159 return (Status)arg.data;
04160 }
04161 }
04162 else if (cond) {
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
04211
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
04226 if (!skey) {
04227 cur += o.size;
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
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
04440
04441
04442
04443
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
04628
04629
04630
04631
04632
04633
04634
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
04698
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