kern_alloc.cc

00001 /* 
00002    EyeDB Object Database Management System
00003    Copyright (C) 1994-2008 SYSRA
00004    
00005    EyeDB is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009    
00010    EyeDB is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014    
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with this library; if not, write to the Free Software
00017    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA 
00018 */
00019 
00020 /*
00021    Author: Eric Viara <viara@sysra.com>
00022 */
00023 
00024 #include <eyedbconfig.h>
00025 
00026 //#define LINKMAP_SUPPORT
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         /* means that there are no more free cell */
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               /* four cases:
00113                  1) prev cell merges with new cell
00114                  -> does not change link
00115                  2) next cell merges with new cell
00116                  -> does not change link
00117                  3) next and prev cells merge with new cell
00118                  -> changes link
00119                  4) no merge
00120                  -> changes link
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                 //printf("returning %d\n", ns);
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         /*#define BEST_FIT*/
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     //printf("Ns free [%d, %d[\n", ns, ns+needslots);
00456     h2x_epilogue(xmp, mp);
00457   }
00458 
00459 #define MARK_OPTIM
00460   //#define MARK_SECURE
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     //printf("marking %s from ns=%d\n", value ? "busy" : "free", ns);
00472     for (s = start + ns/BITS_PER_BYTE, nb = (ns/BITS_PER_BYTE)*BITS_PER_BYTE;
00473          s < end; s++) {
00474       // 27/05/02: optimized by writing directly *s = 0xff
00475       // when BITS_PER_BYTE ...
00476 #ifdef MARK_OPTIM
00477       if (needslots - o > BITS_PER_BYTE && nb >= ns) {
00478         //printf("optimisation %d %d %d %d\n", needslots, o, nb, ns);
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   // born again from idb 1994 version
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         // EV patch 26/04/07
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     // 4/10/05
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 }

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