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 #include "kern_p.h"
00029
00030 #ifdef LINKMAP_SUPPORT
00031
00032 #define TOP_CELL(VD, DATID) ((LinkmapCell *)VD->dmp_addr[DATID])
00033 #define CELL(TOP, W) ((TOP)[W])
00034 #define WHICH_CELL(TOP, TC) \
00035 (((long)(TC) - (long)&CELL(TOP, 0)) / sizeof(LinkmapCell))
00036
00037 #define InvalidCell (u_int)-1
00038
00039 #endif
00040
00041 namespace eyedbsm {
00042
00043 #ifdef LINKMAP_SUPPORT
00044 static void
00045 cellFree(DbDescription *vd, short datid, LinkmapCell *cell)
00046 {
00047 MapHeader *mp = DAT2MP_(vd, datid);
00048 LinkmapCell *top = TOP_CELL(vd, datid);
00049
00050 if (cell == &CELL(top, mp->LMH.firstcell))
00051 mp->LMH.firstcell = cell->next;
00052
00053 if (cell->prev != InvalidCell)
00054 CELL(top, cell->prev).next = cell->next;
00055
00056 if (cell->next != InvalidCell)
00057 CELL(top, cell->next).prev = cell->prev;
00058
00059 cell->size = 0;
00060 }
00061
00062 static LinkmapCell *
00063 cellFreeGet(DbDescription *vd, short datid)
00064 {
00065 MapHeader *mp = DAT2MP_(vd, datid);
00066 LinkmapCell *cell;
00067 LinkmapCell *top = TOP_CELL(vd, datid);
00068 int wcell;
00069
00070 for (cell = &CELL(top, 0), wcell = 0; wcell < MAX_FREE_CELLS;
00071 cell++, wcell++)
00072 if (!cell->size)
00073 return cell;
00074 return 0;
00075 }
00076
00077 static void
00078 cellInsert(DbDescription *vd, NS ns, short datid, unsigned int size)
00079 {
00080 MapHeader *mp = DAT2MP_(vd, datid);
00081 LinkmapCell *cell, *pcell;
00082 int wcell;
00083 LinkmapCell *top = TOP_CELL(vd, datid);
00084
00085 #ifdef ESM_DBG1
00086 printf("cellInsert %d %d\n", ns, size);
00087 #endif
00088 pcell = 0;
00089 if (mp->LMH.firstcell == InvalidCell)
00090 {
00091
00092 #ifdef ESM_DBG1
00093 printf("NO MORE FREE CELL!\n");
00094 #endif
00095 mp->LMH.firstcell = 0;
00096 cell = &CELL(top, 0);
00097 cell->size = size;
00098 cell->ns = ns;
00099 cell->prev = cell->next = InvalidCell;
00100 }
00101 else
00102 for (cell = &CELL(top, mp->LMH.firstcell), wcell = mp->LMH.firstcell; ; )
00103 {
00104 #ifdef ESM_DBG1
00105 printf("INSERT 0x%x %d %d %d %d\n", cell, cell->size, cell->ns, cell->prev,
00106 cell->next);
00107 #endif
00108 assert(cell->size);
00109
00110 if (cell->ns >= ns + size)
00111 {
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 if (pcell && pcell->ns + pcell->size == ns &&
00124 ns + size == cell->ns)
00125 {
00126 #ifdef ESM_DBG1
00127 printf("MUST MERGE ALL!\n");
00128 #endif
00129 pcell->size += size + cell->size;
00130 cellFree(vd, datid, cell);
00131 }
00132 else if (pcell && pcell->ns + pcell->size == ns)
00133 {
00134 #ifdef ESM_DBG1
00135 printf("MERGE PREVIOUS!\n");
00136 #endif
00137 pcell->size += size;
00138 }
00139 else if (ns + size == cell->ns)
00140 {
00141 #ifdef ESM_DBG1
00142 printf("MERGE NEXT!\n");
00143 #endif
00144 cell->ns = ns;
00145 cell->size += size;
00146 }
00147 else
00148 {
00149 LinkmapCell *ncell = cellFreeGet(vd, datid);
00150 int which = WHICH_CELL(top, ncell);
00151 #ifdef ESM_DBG1
00152 printf("NO MERGE\n");
00153 #endif
00154 ncell->size = size;
00155 ncell->ns = ns;
00156 ncell->prev = (pcell ? WHICH_CELL(top, pcell) : InvalidCell);
00157 ncell->next = WHICH_CELL(top, cell);
00158
00159 if (pcell)
00160 pcell->next = which;
00161 else
00162 mp->LMH.firstcell = which;
00163
00164 cell->prev = which;
00165 }
00166
00167 break;
00168 }
00169
00170 if ((wcell = cell->next) == InvalidCell)
00171 {
00172 LinkmapCell *ncell = cellFreeGet(vd, datid);
00173 int which = WHICH_CELL(top, ncell);
00174
00175 ncell->size = size;
00176 ncell->ns = ns;
00177 ncell->prev = WHICH_CELL(top, cell);
00178 ncell->next = InvalidCell;
00179
00180 cell->next = which;
00181
00182 #ifdef ESM_DBG1
00183 printf("DO SOMETHING!\n");
00184 #endif
00185 return;
00186 }
00187
00188 pcell = cell;
00189 cell = &CELL(top, wcell);
00190 }
00191 }
00192
00193 static void
00194 ESM_cellsTraceRealize(DbHandle *dbh, short datid)
00195 {
00196 MapHeader *mp = DAT2MP(dbh, datid);
00197 DbDescription *vd = dbh->vd;
00198 LinkmapCell *cell;
00199 LinkmapCell *top = TOP_CELL(vd, datid);
00200 int wcell, n = 0, ns = -1;
00201
00202 if (mp->mtype == LinkmapType)
00203 {
00204 unsigned int size = 0;
00205 printf("\n--------------- Cells Tracing --------------------\n");
00206 if (mp->LMH.firstcell == InvalidCell)
00207 printf("\t\tNo more free cell\n");
00208 else
00209 for (cell = &CELL(top, mp->LMH.firstcell), wcell = mp->LMH.firstcell; ; )
00210 {
00211 n++;
00212 ESM_ASSERT_ABORT(cell->size, 0, 0);
00213
00214 size += cell->size;
00215 printf("Free cell[%d] size %d, ns %d, prev %d, next %d\n",
00216 wcell, cell->size, cell->ns, cell->prev, cell->next);
00217
00218 ESM_ASSERT_ABORT((int)cell->ns > ns, 0, 0);
00219 if ((wcell = cell->next) == InvalidCell)
00220 break;
00221
00222 ns = cell->ns;
00223 cell = &CELL(top, wcell);
00224 }
00225 printf("\n%d cells found, total free size %d [whole %d]\n", n, size,
00226 size - cell->size);
00227 printf("--------------------------------------------------\n\n");
00228 }
00229 }
00230 #endif
00231
00232 static Status
00233 mapAllocRealize(DbHandle const *dbh, MapHeader *xmp, short datid,
00234 unsigned int size, NS *pns, NS *pneedslots, NS *pmax_free_slots)
00235 {
00236 x2h_prologue(xmp, mp);
00237 DbDescription *vd = dbh->vd;
00238 NS needslots = SZ2NS(size, mp);
00239 assert(needslots*mp->sizeslot() >= size);
00240 Status se;
00241
00242 *pns = INVALID_NS;
00243
00244 NS max_free_slots = 0;
00245 if (pneedslots)
00246 *pneedslots = needslots;
00247 if (pmax_free_slots)
00248 *pmax_free_slots = 0;
00249
00250 switch(mp->mtype()) {
00251 case BitmapType:
00252 {
00253 char *s, *start = vd->dmp_addr[datid],
00254 *end = vd->dmp_addr[datid] + mp->nslots() / BITS_PER_BYTE;
00255 NS ns, nb, o;
00256 int b;
00257
00258 unsigned long ds = mp->u_bmh_slot_cur()/BITS_PER_BYTE;
00259 for (s = start + ds,
00260 nb = (mp->u_bmh_slot_cur()/BITS_PER_BYTE)*BITS_PER_BYTE,
00261 o = 0; s < end; s++, ds++) {
00262 if (ds >= x2h_u32(LASTNSBLKALLOC(dbh, datid))) {
00263 if (se = nsFileSizeExtends(dbh, datid, ds)) {
00264 h2x_epilogue(xmp, mp);
00265 return se;
00266 }
00267 }
00268
00269 char v = *s;
00270 for (b = BITS_PER_BYTE-1; b >= 0; b--) {
00271 if (!(v & (1 << b))) {
00272 if (!o)
00273 ns = nb;
00274 o++;
00275 if (o > max_free_slots)
00276 max_free_slots = o;
00277
00278 if (o == needslots) {
00279 int obj_count = mp->mstat_u_bmstat_obj_count()++;
00280
00281 mapMark(vd, ns, datid, needslots, 1);
00282
00283 mp->u_bmh_slot_cur() = nb+1;
00284 if (nb > mp->u_bmh_slot_lastbusy())
00285 mp->u_bmh_slot_lastbusy() = nb;
00286 mp->u_bmh_retry() = False;
00287 mp->mstat_u_bmstat_busy_size() += size;
00288 mp->mstat_u_bmstat_busy_slots() += needslots;
00289 mp->mstat_u_bmstat_hole_size() += mp->sizeslot() -
00290 (size & ((1 << mp->pow2()-1)));
00291 h2x_epilogue(xmp, mp);
00292 *pns = ns;
00293
00294 return Success;
00295 }
00296 }
00297 else if (o)
00298 o = 0;
00299 nb++;
00300 }
00301 }
00302
00303 if (!mp->u_bmh_retry()) {
00304 mp->u_bmh_retry() = True;
00305 mp->u_bmh_slot_cur() = 0;
00306 h2x_epilogue(xmp, mp);
00307 return mapAllocRealize(dbh, xmp, datid, size, pns, pneedslots, pmax_free_slots);
00308 }
00309
00310 h2x_epilogue(xmp, mp);
00311 *pns = INVALID_NS;
00312 if (pmax_free_slots)
00313 *pmax_free_slots = max_free_slots;
00314 return Success;
00315 }
00316
00317 #ifdef LINKMAP_SUPPORT
00318 case LinkmapType:
00319 {
00320
00321 LinkmapCell *top = TOP_CELL(vd, datid);
00322 int cnt = 0;
00323 LinkmapCell *cell;
00324 #ifdef BEST_FIT
00325 LinkmapCell *kcell = 0;
00326 #endif
00327 int wcell = mp->LMH.firstcell;
00328 for (cell = &CELL(top, wcell); ; cnt++)
00329 {
00330 #ifdef ESM_DBG1
00331 printf("CELL 0x%x %d %d %d %d\n", cell, cell->size, cell->ns, cell->prev,
00332 cell->next);
00333 #endif
00334 #ifdef BEST_FIT
00335 if (cell->size == needslots)
00336 {
00337 NS ns = cell->ns;
00338 cellFree(vd, cell);
00339 *pns = ns;
00340 return Success;
00341 }
00342 else if (!kcell && cell->size > needslots)
00343 kcell = cell;
00344 #else
00345 if (cell->size >= needslots)
00346 {
00347 NS ns = cell->ns, n_size, n_ns;
00348
00349 n_size = cell->size - needslots;
00350 n_ns = cell->ns + needslots;
00351
00352 cellFree(vd, datid, cell);
00353
00354 if (n_size > 0)
00355 cellInsert(vd, n_ns, datid, n_size);
00356
00357 #ifdef ESM_DBG1
00358 printf("linkmap mapAlloc: %d loops for %d\n", cnt, needslots);
00359 #endif
00360 *pns = ns;
00361 return Success;
00362 }
00363 #endif
00364
00365 if ((wcell = cell->next) == InvalidCell)
00366 {
00367 #ifdef BEST_FIT
00368 if (kcell)
00369 {
00370 NS ns = kcell->ns, n_size, n_ns;
00371
00372 n_size = kcell->size - needslots;
00373 n_ns = kcell->ns + needslots;
00374
00375 cellFree(vd, kcell);
00376
00377 if (n_size > 0)
00378 cellInsert(vd, n_ns, n_size);
00379
00380 *pns = ns;
00381 return Success;
00382 }
00383 else
00384 #endif
00385 {
00386 *pns = INVALID_NS;
00387 return Success;
00388 }
00389 }
00390 cell = &CELL(top, wcell);
00391 }
00392 }
00393 #endif
00394
00395 default:
00396 ESM_ASSERT_ABORT(0, 0, 0);
00397 }
00398
00399 h2x_epilogue(xmp, mp);
00400 *pns = INVALID_NS;
00401 return Success;
00402 }
00403
00404 Status
00405 mapAlloc(DbHandle const *dbh, short datid, unsigned int size, NS *pns,
00406 NS *pneedslots, NS *pmax_free_slots)
00407 {
00408 MapHeader t_mp = DAT2MP(dbh, datid);
00409 MapHeader *mp = &t_mp;
00410
00411 Mutex *mt = MAP_MTX(dbh);
00412 unsigned int xid = dbh->vd->xid;
00413 Status se;
00414 TransactionContext *trctx = DBH2TRCTX(dbh);
00415
00416 if (NEED_LOCK(trctx))
00417 MUTEX_LOCK_VOID(mt, xid);
00418 se = mapAllocRealize(dbh, mp, datid, size, pns, pneedslots, pmax_free_slots);
00419 if (NEED_LOCK(trctx))
00420 MUTEX_UNLOCK(mt, xid);
00421
00422 return se;
00423 }
00424
00425 void
00426 mapFree(DbDescription *vd, NS ns, short datid, unsigned int size)
00427 {
00428 MapHeader t_mp = DAT2MP_(vd, datid);
00429 MapHeader *xmp = &t_mp;
00430 x2h_prologue(xmp, mp);
00431
00432 int needslots = SZ2NS(size, mp);
00433
00434 switch(mp->mtype())
00435 {
00436 case BitmapType:
00437 mapMark(vd, ns, datid, needslots, 0);
00438 mp->mstat_u_bmstat_obj_count()--;
00439 mp->mstat_u_bmstat_busy_size() -= size;
00440 mp->mstat_u_bmstat_busy_slots() -= needslots;
00441 mp->mstat_u_bmstat_hole_size() -= mp->sizeslot() -
00442 (size & ((1 << mp->pow2())-1));
00443 break;
00444
00445 #ifdef LINKMAP_SUPPORT
00446 case LinkmapType:
00447 cellInsert(vd, ns, datid, needslots);
00448 break;
00449 #endif
00450
00451 default:
00452 ESM_ASSERT_ABORT(0, 0, 0);
00453 }
00454
00455
00456 h2x_epilogue(xmp, mp);
00457 }
00458
00459 #define MARK_OPTIM
00460
00461
00462 void
00463 mapMark(DbDescription *vd, NS ns, short datid, unsigned int needslots, int value)
00464 {
00465 MapHeader t_mp = DAT2MP_(vd, datid);
00466 MapHeader *mp = &t_mp;
00467 char *s, *start = vd->dmp_addr[datid],
00468 *end = vd->dmp_addr[datid] + x2h_u32(mp->nslots()) / BITS_PER_BYTE;
00469 int nb, b, o = 0;
00470
00471
00472 for (s = start + ns/BITS_PER_BYTE, nb = (ns/BITS_PER_BYTE)*BITS_PER_BYTE;
00473 s < end; s++) {
00474
00475
00476 #ifdef MARK_OPTIM
00477 if (needslots - o > BITS_PER_BYTE && nb >= ns) {
00478
00479 if (value) {
00480 #ifdef MARK_SECURE
00481 assert(!*s);
00482 #endif
00483 *s = 0xff;
00484 }
00485 else {
00486 #ifdef MARK_SECURE
00487 assert(*s == 0xff);
00488 #endif
00489 *s = 0;
00490 }
00491 o += BITS_PER_BYTE;
00492 nb += BITS_PER_BYTE;
00493 }
00494 else
00495 #endif
00496 for (b = BITS_PER_BYTE-1; b >= 0; b--) {
00497 if (o >= needslots)
00498 return;
00499
00500 if (nb >= ns) {
00501 if (value) {
00502 #ifdef MARK_SECURE
00503 assert(!(*s & (1 << b)));
00504 #endif
00505 *s |= (1 << b);
00506 }
00507 else {
00508 #ifdef MARK_SECURE
00509 if (!(*s & (1 << b)))
00510 printf("start = %p, end = %p, needslots = %d, nb = %d, "
00511 "ns = %d, o = %d, *start = %d, *s = %d\n",
00512 start, end, needslots, nb, ns, o, *start, *s);
00513 assert((*s & (1 << b)));
00514 #endif
00515 *s &= ~(1 << b);
00516 }
00517 o++;
00518 }
00519 nb++;
00520 }
00521 }
00522 }
00523
00524
00525 NS
00526 mapNextBusyGet(DbDescription *vd, short datid, NS ns)
00527 {
00528 MapHeader t_mp = DAT2MP_(vd, datid);
00529 MapHeader *mp = &t_mp;
00530 char *s, *start = vd->dmp_addr[datid],
00531 *end = vd->dmp_addr[datid] + x2h_u32(mp->nslots()) / BITS_PER_BYTE;
00532 int nb, b, o = 0;
00533
00534 unsigned int lastbusy = x2h_u32(mp->u_bmh_slot_lastbusy());
00535 for (s = start + ns/BITS_PER_BYTE,
00536 nb = (ns/BITS_PER_BYTE)*BITS_PER_BYTE; s < end; s++)
00537 {
00538
00539 if (nb >= lastbusy)
00540 return INVALID_NS;
00541
00542 char v = *s;
00543 for (b = BITS_PER_BYTE-1; b >= 0; b--)
00544 {
00545 if (nb >= ns && (v & (1 << b)))
00546 return nb;
00547 nb++;
00548 }
00549 }
00550
00551 return INVALID_NS;
00552 }
00553
00554 Status
00555 ESM_firstOidGet_map(DbHandle const *dbh, short datid, Oid *oid,
00556 Boolean *found)
00557 {
00558 *found = False;
00559
00560 if (!check_dbh(dbh))
00561 return statusMake_s(INVALID_DB_HANDLE);
00562
00563 DbHeader _dbh(DBSADDR(dbh));
00564 if (getDatType(&_dbh, datid) != PhysicalOidType)
00565 return statusMake(ERROR, "cannot use firstOidGet() on a logical "
00566 "oid type based datafile");
00567
00568 NS ns;
00569 if ((ns = mapNextBusyGet(dbh->vd, datid, 0)) == INVALID_NS)
00570 return Success;
00571
00572 OidLoc oidloc;
00573
00574 oidloc.ns = ns;
00575 oidloc.datid = datid;
00576
00577 oidCopySlot_(dbh, oidloc.ns, oidloc, oid, 0);
00578
00579
00580 oid->setNX(oid->getNX() + NS_OFFSET);
00581
00582 *found = True;
00583 return Success;
00584 }
00585
00586 Status
00587 ESM_nextOidGet_map(DbHandle const *dbh, short datid,
00588 Oid const *const baseoid, Oid *nextoid,
00589 Boolean *found)
00590 {
00591 *found = False;
00592
00593 if (!check_dbh(dbh))
00594 return statusMake_s(INVALID_DB_HANDLE);
00595
00596 if (!check_oid(dbh, baseoid))
00597 return statusMake_s(INVALID_OID);
00598
00599 DbHeader _dbh(DBSADDR(dbh));
00600 if (getDatType(&_dbh, datid) != PhysicalOidType)
00601 return statusMake(ERROR, "cannot use firstOidGet() on a logical "
00602 "oid type based datafile");
00603
00604 OidLoc oidloc;
00605 oidloc.datid = datid;
00606
00607 oidloc.ns = baseoid->getNX() - NS_OFFSET;
00608
00609 NS ns = oidLastSlotGet(dbh, oidloc);
00610
00611 if ((ns = mapNextBusyGet(dbh->vd, datid, ns + 1)) == INVALID_NS)
00612 return Success;
00613
00614 oidloc.ns = ns;
00615 oidCopySlot_(dbh, oidloc.ns, oidloc, nextoid, 0);
00616
00617 nextoid->setNX(nextoid->getNX() + NS_OFFSET);
00618
00619 *found = True;
00620 return Success;
00621 }
00622
00623 #ifdef LINKMAP_SUPPORT
00624 void
00625 ESM_cellsTrace(DbHandle *dbh)
00626 {
00627 unsigned int ndat = x2h_u32(DBSADDR(dbh)->__ndat);
00628 for (int i = 0; i < ndat; i++)
00629 if (isDatValid(dbh, i))
00630 ESM_cellsTraceRealize(dbh, i);
00631 }
00632 #endif
00633 }