kern_map.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 #include <sys/types.h>
00027 
00028 #include "kern_p.h"
00029 
00030 //#define TRACE1
00031 
00032 #define ABS(x) ((off_t)( (long long)(x) > 0 ? (long long)(x) : -(long long)(x) ))
00033 #define DIST(MMD, s, e) ABS((MMD)->s_start - (s))
00034 #define IS_IN(x,y,z) ( (x) >= (y) && (x) < (z) )
00035 /*#define ESM_MMAP_WIDE_SEGMENT   1000*/
00036 /*
00037 #define ESM_MMAP_WIDE_SEGMENT   2000
00038 #define ESM_MMAP_WIDE_2_SEGMENT (ESM_MMAP_WIDE_SEGMENT >> 1)
00039 */
00040 
00041 namespace eyedbsm {
00042 
00043   void
00044   hdl_release(MmapH *hdl)
00045   {
00046     MmapDesc *mmd = hdl->mmd;
00047 
00048     if (mmd && mmd->locked)
00049       {
00050         //printf("hdl_release mmd=%p, pos=%d, npts=%d\n", mmd, hdl->pos, mmd->npts);
00051         mmd->pts[hdl->pos] = 0;
00052         *hdl->pt = 0;
00053         if (!--mmd->npts)
00054           {
00055             mmd->locked = False;
00056             m_unlock(mmd->m);
00057           }
00058       }
00059   }
00060 
00061 
00062   static void
00063   garb_trig(void *arg)
00064   {
00065     MmapDesc *mmd = (MmapDesc *)arg;
00066 #ifdef TRACE
00067     utlog("garb_trig %x mapaddr 0x%x %d\n", mmd, mmd->mapaddr, mmd->locked);
00068 #endif
00069     ESM_ASSERT_ABORT(!mmd->locked, 0, 0);
00070     mmd->ismapped = False;
00071     mmd->ref = 0;
00072     mmd->locked = False;
00073   }
00074 
00075   static void display_dmd(DatDesc *dmd)
00076   {
00077     MmapDesc *mmd, *mmd1, *fmmd = 0, *mmend = &dmd->mmd[MAX_MMAP_SEGMENTS];
00078 
00079     unsigned int n = 0;
00080     for (mmd = dmd->mmd; mmd < mmend; mmd++, n++) {
00081       if (mmd->ismapped) {
00082         fprintf(stdout, "segment #%u %llx - %llx (%s)\n", n, mmd->s_start, mmd->s_end,
00083                 mmd->locked ? "locked" : "not locked");
00084       }
00085     }
00086   }
00087 
00088   static void check_dmd(DatDesc *dmd)
00089   {
00090     MmapDesc *mmd, *mmd1, *fmmd = 0, *mmend = &dmd->mmd[MAX_MMAP_SEGMENTS];
00091     unsigned int n;
00092 
00093     bool should_display = false;
00094     for (mmd = dmd->mmd, n = 0; mmd < mmend; mmd++, n++) {
00095       if (mmd->ismapped) {
00096         off_t ws_start = mmd->s_start, ws_end = mmd->s_end;
00097         unsigned int m = n + 1;
00098         for (mmd1 = dmd->mmd + m; mmd1 < mmend; mmd1++, m++) {
00099           if (mmd1->ismapped)   {
00100 #if 1
00101             if (IS_IN(ws_start, mmd1->s_start, mmd1->s_end)) {
00102               fprintf(stdout, "multimap segment #%u start: %llx in #%u %llx - %llx (%s)\n", n, ws_start, m, mmd1->s_start, mmd1->s_end, mmd1->locked ? "locked" : "not locked");
00103               should_display = true;
00104             }
00105 
00106             if (IS_IN(ws_end-1, mmd1->s_start, mmd1->s_end)) {
00107               fprintf(stdout, "multimap segment #%u end: %llx in #%u %llx - %llx (%s)\n", n, ws_end, m, mmd1->s_start, mmd1->s_end, mmd1->locked ? "locked" : "not locked");
00108               should_display = true;
00109             }
00110 #else
00111             ESM_ASSERT_ABORT(!IS_IN(ws_start, mmd1->s_start, mmd1->s_end), 0, 0);
00112             ESM_ASSERT_ABORT(!IS_IN(ws_end-1, mmd1->s_start, mmd1->s_end), 0, 0);
00113 #endif
00114           }
00115         }
00116       }
00117     }
00118 
00119     if (should_display)
00120       display_dmd(dmd);
00121   }
00122 
00123   static MmapDesc *
00124   find_segment(register DatDesc *dmd, off_t ws_start, off_t ws_end)
00125   {
00126     off_t delta = 0, uv;
00127     unsigned long ref = curref+1;
00128 
00129     MmapDesc *mmd, *fmmd = 0, *mmend = &dmd->mmd[MAX_MMAP_SEGMENTS];
00130 
00131     for (mmd = dmd->mmd; mmd < mmend; mmd++) {
00132       if (mmd->ismapped && !mmd->locked) {
00133         if (mmd->ref < ref)
00134           if ((uv = DIST(mmd, ws_start, ws_end)) > delta) {
00135             ref = mmd->ref;
00136             fmmd = mmd;
00137           }
00138       }
00139     }
00140                 
00141     ESM_ASSERT_ABORT(fmmd, 0, 0);
00142   
00143     SEGMENT_UNMAP(fmmd);
00144     return fmmd;
00145   }
00146 
00147   static void stop_it_man() {}
00148 
00149   static int
00150   mmd_add(MmapDesc *mmd, char **pt)
00151   {
00152     char ***p;
00153     int pos;
00154 
00155     if (mmd->npts >= mmd->nalloc) {
00156       int inc = 6;
00157       if (!mmd->nalloc) {
00158         mmd->nalloc = inc;
00159         mmd->pts = (char ***)m_calloc(sizeof(char **)*mmd->nalloc, 1);
00160       }
00161       else {
00162         mmd->nalloc += inc;
00163         mmd->pts = (char ***)m_realloc(mmd->pts, sizeof(char **)*mmd->nalloc);
00164         memset(mmd->pts+(mmd->nalloc-inc), 0, sizeof(char **)*inc);
00165       }
00166     }
00167 
00168     for (p = mmd->pts, pos = 0; pos < mmd->nalloc; p++, pos++)
00169       if (!*p) {
00170         mmd->pts[pos] = pt;
00171         mmd->npts++;
00172         mmd->locked = True;
00173         assert(mmd->npts < 6); /* garde-fou stupide */
00174         //printf("mmd_add mmd=%p, pos=%d, npts=%d\n", mmd, pos, mmd->npts);
00175         return pos;
00176       }
00177     ESM_ASSERT_ABORT(0, 0, 0);
00178   }
00179 
00180   /*
00181     OPTIMISATION:
00182     on pourrait ajouter dans vd, le champ `all_mapped' qui indique
00183     que toute la base est mappée.
00184     cela permettrait de ne pas rentrer dans cette fonction slot2addr.
00185     #define SLOT2ADDR(dbh, ws_start, size, pt, ...) \
00186     (dbh->vd->all_mapped ? (char *)(((ws_start - mmd->s_start) * sizeslot) +
00187     mmd->mapaddr) : slot2addr(dbh, ws_start, ...)
00188     Bien sur, la gestion du all_mapped doit etre siouks!
00189     Et notamment tenir compte de l'extension d'un volume en ecriture.
00190   */
00191 
00192   char *
00193   oidloc2addr(const DbHandle *dbh, const OidLoc &oidloc,
00194               unsigned int size, char **pt, MmapH *hdl, int *up)
00195   {
00196     return slot2addr(dbh, oidloc.ns, oidloc.datid, size, pt, hdl, up);
00197   }
00198 
00199   char *
00200   slot2addr(const DbHandle *dbh, off_t ws_start, short datid,
00201             unsigned int size, char **pt, MmapH *hdl, int *up)
00202   {
00203     ESM_ASSERT_ABORT(size > 0, 0, 0);
00204 
00205     if (ws_start == (off_t) (-NS_OFFSET))
00206       return (char *)0;
00207 
00208     MapHeader t_mp = DAT2MP(dbh, datid);
00209     MapHeader *mp = &t_mp;
00210     DatDesc *dmd = &dbh->vd->dmd[datid];
00211 
00212     unsigned int sizeslot = x2h_u32(mp->sizeslot());
00213 
00214     if (dmd->m_dat) {
00215       hdl->mmd = 0;
00216       if (up) *up = 0;
00217       return (char *)((ws_start * sizeslot) + dmd->addr);
00218     }
00219 
00220     off_t delta_left = 0xffffffff, delta_right = 0xffffffff;
00221     MmapDesc *mmd, *mmend, *fmmd = 0, *mmd_left, *mmd_right;
00222     int fop, inc, inc1, v, wide, wide2, n;
00223     off_t startslot, ws_end, start, end, wa_start, wa_end, dum, uv,
00224       t_start, t_end;
00225     int nreloc=0;
00226     int pow2 = x2h_u32(mp->pow2());
00227     MmapDesc *mmd_reloc[MAX_MMAP_SEGMENTS];
00228     Mutex *mt = SLT_MTX(dbh);
00229     unsigned int xid = dbh->vd->xid;
00230     int x;
00231     Status status;
00232     TransactionContext *trctx = DBH2TRCTX(dbh);
00233 
00234     ws_end = ws_start + (off_t)((size + sizeslot-1) >> pow2);
00235 
00236     startslot = 0;
00237 
00238     mmend = &dmd->mmd[MAX_MMAP_SEGMENTS];
00239 
00240     /* try to find a segment which includes interval [ws_start, ws_end] */
00241     t_start = ws_start;
00242     t_end   = ws_end;
00243 
00244   try_again:
00245     /* WARNING (8/01/99): locks are not set in case of the database is opened in
00246        transless mode: but is this really a problem?
00247        in a more general way, this lock is useful only in multi-threaded
00248        environment and not in multi-processus environment because mmap()
00249        operation is private to the process!
00250        so, this mutex could be a static mutex (i.e. static Mutex mp) */
00251     /*
00252       if (NEED_LOCK(trctx))
00253       MUTEX_LOCK_VOID(mt, xid);
00254     */
00255 
00256     for (mmd = dmd->mmd; mmd < mmend; mmd++) {
00257       if (mmd->ismapped) {
00258         Boolean left = False, right = False;
00259 
00260         if (IS_IN(t_start, mmd->s_start, mmd->s_end))
00261           left = True;
00262         if (IS_IN(t_end-1, mmd->s_start, mmd->s_end))
00263           right = True;
00264 
00265         if (left && right) { /* this segment includes the interval: returns */
00266           mmd->ref = ++curref;
00267           m_access(mmd->m);
00268           hdl->mmd = mmd;
00269           hdl->pos = mmd_add(mmd, pt);
00270           hdl->pt  = pt;
00271           /*
00272             if (NEED_LOCK(trctx))
00273             MUTEX_UNLOCK(mt, xid);
00274           */
00275           if (up)
00276             *up = mmd->s_end;
00277           return (char *)(((ws_start - mmd->s_start) * sizeslot) +
00278                           mmd->mapaddr);
00279         }
00280         else if (left || right) {/* the interval crosses the segment:
00281                                     must unmmaped this segment */
00282           if (mmd->locked) {
00283             caddr_t t_addr = mmd->mapaddr;
00284 #ifdef TRACE1
00285             printf("should relocate really!\n");
00286 #endif
00287             mmd_reloc[nreloc++] = mmd;
00288             if (left)
00289               t_start = mmd->s_start;
00290             else if (right)
00291               t_end = mmd->s_end;
00292 
00293             IDB_LOG(IDB_LOG_MMAP,
00294                     ("slot2addr: interval cross segment [1]: must unmap\n"));
00295 
00296             SEGMENT_UNMAP(mmd);
00297             mmd->mapaddr = t_addr;
00298 
00299             mmd->locked = True;
00300 
00301             /*
00302               if (NEED_LOCK(trctx))
00303               MUTEX_UNLOCK(mt, xid);
00304             */
00305             IDB_LOG(IDB_LOG_MMAP, ("slot2addr: must try again\n"));
00306             goto try_again;
00307           }
00308           else {
00309             IDB_LOG(IDB_LOG_MMAP,
00310                     ("slot2addr: interval cross segment [2]: must unmap\n"));
00311             SEGMENT_UNMAP(mmd);
00312           }
00313         }
00314       }
00315       /* else if (!mmd->locked) optimisation (11/09/98) : */
00316       else if (!fmmd && !mmd->locked) /* finds a free segment: keeps it */
00317         fmmd = mmd;
00318     }
00319 
00320     /* if no segment free,  find a segment */
00321     if (!fmmd) {
00322       IDB_LOG(IDB_LOG_MMAP, ("slot2addr: no more segment available\n"));
00323       fmmd = find_segment(dmd, t_start, t_end);
00324     }
00325 
00326     /*
00327       wide  = ESM_MMAP_WIDE_SEGMENT   * pgsize;
00328       wide2 = ESM_MMAP_WIDE_2_SEGMENT * pgsize;
00329     */
00330     wide  = dbh->vd->mapwide;
00331     wide2 = dbh->vd->mapwide2;
00332 
00333     /* convert slot to offset ... */
00334     wa_start = (t_start - startslot) * sizeslot;
00335     wa_end   = (t_end   - startslot) * sizeslot;
00336 
00337     /* and round on a page boundary */
00338     wa_start = (wa_start/pgsize) * pgsize;
00339     wa_end   = ((wa_end+pgsize-1)/pgsize) * pgsize;
00340 
00341     /* to get the immediate left and right neighbours of the
00342        interval [t_start, t_end] */
00343     mmd_left = mmd_right = 0;
00344     for (mmd = dmd->mmd; mmd < mmend; mmd++) {
00345       if (mmd->ismapped) {
00346         if ((long long)((uv = t_start - mmd->s_end)) >= 0 && uv < delta_left) {
00347           delta_left = uv;
00348           mmd_left = mmd;
00349         }
00350         if ((long long)((uv = mmd->s_start - t_end)) >= 0 && uv < delta_right) {
00351           delta_right = uv;
00352           mmd_right = mmd;
00353         }
00354       }
00355     }
00356 
00357     if (!mmd_left) {
00358       if (((long long)(start = wa_start - wide2)) >= 0)
00359         inc = wide2;
00360       else {
00361         inc = 0;
00362         start = 0;
00363       }
00364     }
00365     else {
00366       off_t leftend = mmd_left->a_end;
00367       for (inc = wide2; inc >= 0; inc -= pgsize) {
00368         start = wa_start - inc;
00369         if (((long long)start) >= 0 && start >= leftend)
00370           break;
00371       }
00372     
00373       ESM_ASSERT_ABORT(inc >= 0, mt, xid);
00374     }
00375 
00376     if (!mmd_right)
00377       end = wa_end + wide - inc;
00378     else {
00379       off_t rightstart = mmd_right->a_start;
00380       for (inc1 = wide-inc; inc1 >= 0; inc1 -= pgsize) {
00381         end = wa_end + inc1;
00382         if (end <= rightstart)
00383           break;
00384       }
00385     
00386       ESM_ASSERT_ABORT(inc1 >= 0, mt, xid);
00387     }
00388 
00389     fop = ((dbh->vd->flags & VOLREAD) ? PROT_READ : PROT_READ|PROT_WRITE);
00390 
00391 #ifdef TRACE1
00392     printf("%s: eyedbsm MMAP start=0x%x, end=0x%x, wa_start=0x%x, wa_end=0x%x, inc=0x%x, size=0x%x, ws_start=%d\n",
00393            get_time(), start, end, wa_start, wa_end, inc, size, ws_start);
00394 #endif
00395 
00396     IDB_LOG(IDB_LOG_MMAP_DETAIL, ("slot2addr needs memory segment\n"));
00397     if (!(fmmd->m = m_mmap(0, end-start, fop, MAP_SHARED, dmd->fd,
00398                            start, &fmmd->mapaddr, dmd->file, ws_start,
00399                            ws_start+size-1))) {
00400       /*
00401         if (NEED_LOCK(trctx))
00402         MUTEX_UNLOCK(mt, xid);
00403       */
00404       IDB_LOG(IDB_LOG_MMAP, ("slot2addr: m_mmap failed definitively in slot2addr %p\n",
00405                              fmmd->m));
00406       return (char *)0;
00407     }
00408 
00409 #ifdef TRACE1
00410     printf("mmapaddr 0x%x\n", fmmd->mapaddr);
00411 #endif
00412 
00413     m_gtrig_set(fmmd->m, garb_trig, fmmd);
00414     m_lock(fmmd->m);
00415 
00416     fmmd->a_start  = start;
00417     fmmd->a_end    = end;
00418     fmmd->s_start  = (start>>pow2) + startslot;
00419     fmmd->s_end    = (end>>pow2) + startslot;
00420     fmmd->ismapped = True;
00421 
00422     hdl->mmd = fmmd;
00423     hdl->pos = mmd_add(fmmd, pt);
00424     hdl->pt  = pt;
00425 
00426     for (n = 0; n < nreloc; n++) {
00427       MmapDesc *mmd = mmd_reloc[n];
00428       char ***p;
00429       int cnt = mmd->npts, pos;
00430 
00431 #ifdef TRACE1
00432       printf("mmd->npts %d\n", mmd->npts);
00433 #endif
00434 
00435       for (p = mmd->pts, pos = 0; pos < mmd->nalloc; p++, pos++) {
00436         if (*p) {
00437 #ifdef TRACE1
00438           printf("must reloc 0x%x (0x%x) 0x%x\n", *p, **p,
00439                  mmd->mapaddr);
00440           printf("START %d %d\n", mmd->s_start, fmmd->s_start);
00441 #endif
00442           if (mmd->s_start >= fmmd->s_start) {
00443 #ifdef TRACE1
00444             printf("hips!\n");
00445 #endif
00446             /*
00447             **p = (char *)((mmd->s_start - fmmd->s_start)*sizeslot+
00448             (u_long)fmmd->mapaddr+
00449             ((u_long)**p)-((u_long)mmd->mapaddr));
00450             */
00451             **p = (char *)((mmd->s_start - fmmd->s_start) * sizeslot +
00452                            (fmmd->mapaddr + (off_t)**p) -
00453                            mmd->mapaddr);
00454 #ifdef TRACE1
00455             printf("after 0x%x\n", **p);
00456 #endif
00457             memset(mmd->pts, 0, sizeof(char **)*mmd->nalloc);
00458             mmd->npts = 0;
00459             mmd->locked = False;
00460           }
00461           if (!--cnt)
00462             break;
00463         }
00464       }
00465     }
00466 
00467 #ifdef TRACE1
00468     printf("new mapped [%d]: %d %d %x %x (%x) %d\n", dmd->fd,
00469            fmmd->s_start, fmmd->s_end, start, end, fmmd, startslot);
00470 #endif
00471 
00472     // 18/09/07: disconnected because it seems that this check is not good
00473     // but warning...
00474 #if 0
00475     check_dmd(dmd);
00476 #endif
00477     fmmd->ref = ++curref;
00478 
00479     /*
00480       if (NEED_LOCK(trctx))
00481       MUTEX_UNLOCK(mt, xid);
00482     */
00483 
00484     /* added the 2/07/99 because of a bug in EMBL importation */
00485     if (up)
00486       *up = fmmd->s_end;
00487 
00488     return (char *)(((ws_start - fmmd->s_start) * sizeslot) + fmmd->mapaddr);
00489   }
00490 }

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