kern_obj.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 <stdlib.h>
00027 
00028 #include <kern_p.h>
00029 #include <eyedblib/rpc_lib.h>
00030 
00031 //int last_objsize;
00032 
00033 #define MSYNC(x,y,z) /* msync(x,y,z) */
00034 #define SLOT_INC 400
00035 #define CHECK_NS_OID(DBH, NS, DATID, OID) \
00036 ((DATID) >= 0 && (NS) >= 0 && \
00037  (NS) <= x2h_u32(DbHeader(DBSADDR(DBH)).dat(DATID).__lastslot()) && \
00038  OIDDBIDGET(OID) == (DBH)->vd->dbid)
00039 
00040 namespace eyedbsm {
00041 
00042   const Oid::NX Oid::INVALID_NX = ~0U;
00043   const size_t Oid::SIZE = 12;
00044   const Oid Oid::nullOid = Oid::makeNullOid();
00045 
00046   Oid  Oid::makeNullOid()
00047   {
00048     Oid oid;
00049     oid.setNX(0);
00050     oid.setDbID(0);
00051     oid.setUnique(0);
00052     return oid;
00053   }
00054 
00055   inline static TransactionOP
00056   makeTOP(LockMode lockmode, TransactionOP op, Status &se)
00057   {
00058     se = Success;
00059 
00060     if (lockmode == DefaultLock)
00061       return op;
00062 
00063     if (lockmode == LockS)
00064       return (TransactionOP)(op | LOCKS);
00065 
00066     if (lockmode == LockX)
00067       return (TransactionOP)(op | LOCKX);
00068 
00069     if (lockmode == LockSX)
00070       return (TransactionOP)(op | LOCKSX);
00071 
00072     if (lockmode == LockN)
00073       return (TransactionOP)(op | LOCKN);
00074 
00075     se = statusMake(ERROR, "invalid lock mode for reading %d", lockmode);
00076     return op;
00077   }
00078 
00079   Boolean
00080   isPhy(DbHandle const *dbh, const Oid *oid)
00081   {
00082     if (getDbVersion((void *)dbh) < PHYOID_VERSION)
00083       return False;
00084     return (oid->getUnique() & PHYOID_BITMASK) ? True : False;
00085   }
00086 
00087   void
00088   setPhyInfo(Oid *oid, NS ns, short datid)
00089   {
00090     // 6/04/02: added NS_OFFSET
00091     oid->setNX(ns + NS_OFFSET);
00092     oid->setUnique(oid->getUnique() | (PHYOID_BITMASK | (datid << PHYDATID_SHIFT)));
00093   }
00094 
00095   void
00096   getPhyInfo(const Oid *oid, NS *pns, short *datid)
00097   {
00098     // 6/04/02: added NS_OFFSET
00099     *pns = oid->getNX() - NS_OFFSET;
00100     *datid = ((oid->getUnique() & ~PHYOID_BITMASK) >> PHYDATID_SHIFT);
00101   }
00102 
00103   static double ratio_o = (float)(0x3fffff - UNIQUE_BASE)/RAND_MAX;
00104   static double ratio_n_log = (float)(0xfffff - UNIQUE_BASE)/RAND_MAX;
00105   static double ratio_n_phy = (float)(0x1fff - UNIQUE_BASE)/RAND_MAX;
00106 
00107   static unsigned int
00108   uniqueGet_logical(DbHandle const *dbh)
00109   {
00110     double ratio = 
00111       (getDbVersion((void *)dbh) >= PHYOID_VERSION) ? ratio_n_log : ratio_o;
00112     return (unsigned int)(((double)rand()*ratio) + UNIQUE_BASE);
00113   }       
00114 
00115   static unsigned int
00116   uniqueGet_physical(DbHandle const *dbh)
00117   {
00118     return (unsigned int)(((double)rand()*ratio_n_phy) + UNIQUE_BASE);
00119   }       
00120 
00121   static void
00122   oidMake_logical(DbHandle const *dbh, Oid::NX nx, Oid *oid)
00123   {
00124     oid->setNX(nx);
00125     OIDDBIDMAKE(oid, dbh->vd->dbid);
00126     oid->setUnique(uniqueGet_logical(dbh));
00127   }
00128 
00129   static void
00130   oidMake_physical(DbHandle const *dbh, NS ns, short datid, Oid *oid)
00131   {
00132     OIDDBIDMAKE(oid, dbh->vd->dbid);
00133     oid->setUnique(uniqueGet_physical(dbh));
00134     setPhyInfo(oid, ns, datid);
00135   }
00136 
00137   /*
00138     static Status
00139     checkPhyLogOid(DbHandle const *dbh, short datid, unsigned int create_flags)
00140     {
00141     DatafileDesc *dat = &DBSADDR(dbh)->dat[datid];
00142     DatType dtype = getDatType(DBSADDR(dbh), datid);
00143 
00144     if ((create_flags & LogicalOid) && dtype != LogicalOidType)
00145     return statusMake(ERROR, "cannot create a logical oid on a physical "
00146     "oid type based datafile '%s'", (*dat->name ?
00147     std::string(dat->name) :
00148     std::string("#") +
00149     std::string(datid)));
00150 
00151     if ((create_flags & PhysicalOid) && dtype != PhysicalOidType)
00152     return statusMake(ERROR, "cannot create a physical oid on a logical "
00153     "oid type based datafile '%s'", (*dat->name ?
00154     std::string(dat->name) :
00155     std::string("#") +
00156     std::string(datid)));
00157 
00158     return Success;
00159     }
00160   */
00161 
00162   //#define AUTO_DEFRAG
00163   static Status
00164   ESM_objectCreate_server(DbHandle const *dbh, void const *const object,
00165                           unsigned int size, short datid, short dspid, Oid *oid,
00166                           rpc_ServerData *data, OPMode opmode)
00167   {
00168     Status se;
00169     Boolean opsync = False;
00170 
00171     if (opmode != OPGrowingPhase)
00172       return statusMake(ERROR, "internal error: unexpected opmode %d",
00173                         opmode);
00174 #undef PR
00175 #define PR "objectCreate: "
00176     if (!check_dbh(dbh))
00177       return statusMake(INVALID_DB_HANDLE, PR IDBH);
00178 
00179     if (!(dbh->vd->flags & VOLRW))
00180       return statusMake(WRITE_FORBIDDEN, PR WF, dbh->dbfile);
00181 
00182     if (size < 0)
00183       return statusMake(INVALID_OBJECT_SIZE, PR "object size is negative: `%d'", size);
00184 
00185     int tridx = dbh->vd->tr_cnt-1;
00186     TransactionContext *trctx = &dbh->vd->trctx[tridx];
00187 
00188     if (trctx->params.recovmode == RecoveryFull ||
00189         trctx->params.recovmode == RecoveryPartial)
00190       {
00191         //printf("should perform incomplete creation\n");
00192         // 1. create an oid (nx from lastidxbusy cache) and unique
00193         // 2. objectLock(..., &tro);
00194         // 3. addr = ESM_trobjDataGet(dbh, tro, size);
00195         // 4. memcpy(addr, &objh, sizeof(ObjectHeader));
00196         // 5. if (data) ... (partie actuelle finale du code de
00197         //    ESM_objectCreate_server)
00198         /*return statusMake(ERROR,
00199           "recovery on mode is not yet implemented");
00200         */
00201       }
00202 
00203     //OidLoc oidloc = {0};
00204     OidLoc oidloc;
00205     memset(&oidloc, 0, sizeof(oidloc));
00206 
00207     unsigned rsize = size + sizeof(ObjectHeader);
00208     MmapH hdl;
00209     const MapHeader *mp;
00210 
00211     DbHeader _dbh(DBSADDR(dbh));
00212 
00213 #ifdef AUTO_DEFRAG
00214     std::map<short, bool> defrag_map;
00215 #endif
00216 
00217     for (;;) {
00218       MapHeader t_mp = DAT2MP(dbh, datid);
00219       mp = &t_mp;
00220       oidloc.datid = datid;
00221 
00222       NS needslots, max_free_slots;
00223       se = mapAlloc(dbh, datid, rsize, &oidloc.ns, &needslots, &max_free_slots);
00224       if (se)
00225         return se;
00226 
00227       if (oidloc.ns != INVALID_NS) {
00228 #ifdef AUTO_DEFRAG
00229         if (defrag_map[datid]) {
00230           printf("Defragmentation succesful for %u slots needed\n", needslots);
00231         }
00232 
00233         defrag_map[datid] = false;
00234 #endif
00235         break;
00236       }
00237 
00238 #ifdef AUTO_DEFRAG
00239       // 19/09/07 : try a defragmentation if and only if:
00240       // - no defragmentation has been attempted
00241       // - datid is a logical datafile
00242       // 20/09/07: this does not work: should try another type of defragmentation (in place)
00243       if (!defrag_map[datid]) {
00244         //&& getDatType(dbh, datid) == LogicalOidType) {
00245         defrag_map[datid] = true;
00246         char datfile[32];
00247         sprintf(datfile, "%d", datid);
00248         printf("Try defragmentation (%u slots needed / %u contiguous free slots available)\n", needslots, max_free_slots);
00249         se = ESM_datDefragment(dbh, datfile, 0, 0);
00250         if (!se) {
00251           continue;
00252         }
00253         statusPrint(se, "DEFRAGMENT ERROR");
00254       }
00255 #endif
00256 
00257       if (dspid == DefaultDspid || !ESM_getNextDatafile(dbh, dspid, datid)) {
00258         return statusMake(NO_DATAFILESPACE_LEFT,
00259                           PR "database '%s' %s (%u slots needed / %u contiguous free slots available) ",
00260                           dbh->dbfile,
00261                           (dspid != DefaultDspid ?
00262                            std::string("dataspace ") +
00263                            _dbh.dsp(dspid).name() :
00264                            std::string("unspecified dataspace")).c_str(),
00265                           needslots, max_free_slots);
00266       }
00267     }
00268 
00269     /*
00270       if (se = checkPhyLogOid(dbh, oidloc.datid, create_flags))
00271       return se;
00272     */
00273 
00274     ObjectHeader objh;
00275     char *addr;
00276     unsigned int sizeslot = x2h_u32(mp->sizeslot());
00277     NS ls = oidloc.ns + SZ2NS_XDR(rsize, mp);
00278     Mutex *mt = LSL_MTX(dbh);
00279     unsigned int xid = dbh->vd->xid;
00280     DatType dtype = getDatType(&_dbh, datid);
00281     if (dtype == LogicalOidType) {
00282       Oid::NX nx;
00283       Status se = nxAlloc(dbh, oidloc, &nx);
00284       if (se) return se;
00285 
00286       if (nx == Oid::INVALID_NX)
00287         return statusMake(TOO_MANY_OBJECTS, PR "database '%s'", dbh->dbfile);
00288 
00289       oidMake_logical(dbh, nx, oid);
00290     }
00291     else if (getDbVersion((void *)dbh) < PHYOID_VERSION)
00292       return statusMake(INVALID_DB_HANDLE, PR "cannot use physical oid "
00293                         "on versions previous to %d", PHYOID_VERSION);
00294     else
00295       oidMake_physical(dbh, oidloc.ns, oidloc.datid, oid);
00296 
00297     if (se = ESM_objectLock(dbh, oid, OCREATE, 0, 0))
00298       return se;
00299 
00300     objh.unique = h2x_u32(oid->getUnique());
00301     objh.size = h2x_u32(makeInvalid(rsize));
00302 
00303     memset(&objh.prot_oid, 0, sizeof(Oid));
00304 
00305     if (NEED_LOCK(trctx))
00306       MUTEX_LOCK(mt, xid);
00307 
00308     // was: if (ls >= dbh->vd->dbhead->lastslot)
00309     if (ls >= x2h_u32(_dbh.dat(datid).__lastslot())) {
00310       static char zero = 0;
00311       NS ls1 = ls + SLOT_INC;
00312       int fd = dbh->vd->dmd[datid].fd;
00313       
00314       if (se = syscheck(PR, lseek(fd, ((off_t)ls1 * sizeslot) - 1,
00315                                   0), "")) {
00316         if (NEED_LOCK(trctx))
00317           MUTEX_UNLOCK(mt, xid);
00318         std::cerr << "lseek error: fd=" << fd << " ls=" << ls1 << ", off=" << ((off_t)ls1 * sizeslot)  << '\n';
00319         return se;
00320       }
00321       
00322       if (se = syscheckn(PR, write(fd, &zero, sizeof(char)), sizeof(char), "")) {
00323         if (NEED_LOCK(trctx))
00324           MUTEX_UNLOCK(mt, xid);
00325         std::cerr << "write error\n";
00326         return se;
00327       }
00328 
00329       _dbh.dat(datid).__lastslot() = h2x_u32(ls1);
00330     }
00331     
00332     if (NEED_LOCK(trctx))
00333       MUTEX_UNLOCK(mt, xid);
00334 
00335     addr = oidloc2addr_(oidloc, dbh, rsize, &addr, &hdl);
00336 
00337     memcpy(addr, &objh, sizeof(ObjectHeader));
00338 
00339     if (data) {
00340       if (data->data != ObjectNone) {
00341         if (data->data)
00342           rpc_socketRead(data->fd, addr + sizeof(ObjectHeader),
00343                          size);
00344         else
00345           memset(addr + sizeof(ObjectHeader), 0, size);
00346       }
00347     }
00348     else if (object != ObjectNone) {
00349       if (object) /* != ObjectZero */
00350         memcpy(addr + sizeof(ObjectHeader), object, size);
00351       else
00352         memset(addr + sizeof(ObjectHeader), 0, size);
00353     }
00354 
00355     //MSYNC((caddr_t)ROUND_PAGE(addr), ROUND_UP_PAGE(rsize), MS_ASYNC);
00356 
00357     hdl_release(&hdl);
00358     ESM_REGISTER(dbh, CreateOP, ESM_addToRegisterCreate(dbh, oid, size));
00359 
00360     return Success;
00361   }
00362 
00363   Status
00364   ESM_objectCreate(DbHandle const *dbh, void const *const object,
00365                    unsigned int size, short dspid, Oid *oid, OPMode opmode)
00366   {
00367     short datid;
00368     Status s = ESM_getDatafile(dbh, dspid, datid);
00369     if (s) return s;
00370 
00371     return ESM_objectCreate_server(dbh, object, size, datid, dspid, oid, 0,
00372                                    opmode);
00373   }
00374 
00375   Status
00376   ESM_objectDelete(DbHandle const *dbh, Oid const *const oid,
00377                    OPMode opmode)
00378   {
00379 #undef PR
00380 #define PR "objectDelete: "
00381     Status se;
00382     Boolean opsync = False;
00383 
00384 #ifndef SHR_SECURE
00385     if (opmode != OPShrinkingPhase)
00386 #endif
00387       {
00388         if (!check_dbh(dbh))
00389           return statusMake(INVALID_DB_HANDLE, PR IDBH);
00390         if (!(dbh->vd->flags & VOLRW))
00391           return statusMake(WRITE_FORBIDDEN, PR WF, dbh->dbfile);
00392         if (!check_oid(dbh, oid))
00393           return statusMake(INVALID_OID, PR "invalid oid '%s'", getOidString(oid));
00394 
00395         if (se = ESM_objectLock(dbh, oid, ODELETE, &opsync, 0))
00396           return se;
00397       }
00398 
00399     if (opsync || opmode != OPGrowingPhase)
00400       {
00401         MmapH hdl;
00402         ObjectHeader *objh;
00403         Boolean oid2addr_failed;
00404         if (!(objh = oid2objh(oid, dbh, &objh, &hdl, &oid2addr_failed)))
00405           {
00406             if (oid2addr_failed)
00407               return statusMake(FATAL_ERROR, PR "failed to map segment for oid '%s'", getOidString(oid));
00408             return statusMake(INVALID_OID, PR "invalid oid '%s'", getOidString(oid));
00409           }
00410 
00411         OidLoc oidloc = oidLocGet(dbh, oid);
00412         mapFree(dbh->vd, oidloc.ns, oidloc.datid, x2h_getSize(objh->size));
00413 
00414         if (!isPhy(dbh, oid))
00415           nxFree(dbh, oid->getNX());
00416 
00417         memset(objh, 0, sizeof(ObjectHeader));
00418       
00419         /*
00420           if (trace_it0)
00421           printf("ESM_objectDelete(oid=%s, size=%d)\n", getOidString(oid),
00422           getSize(objh->size));
00423         */
00424         hdl_release(&hdl);
00425         ESM_REGISTER(dbh, DeleteOP, ESM_addToRegisterDelete(dbh, oid));
00426       }
00427 
00428     return Success;
00429   }
00430 
00431   Status
00432   ESM_objectDeleteByOidLoc(DbHandle const *dbh, Oid const *const oid,
00433                            NS ns, short datid)
00434   {
00435 #undef PR
00436 #define PR "objectDelete: "
00437     Status se;
00438     MmapH hdl;
00439     ObjectHeader *objh;
00440     Boolean dummy;
00441     OidLoc oidloc_o = oidLocGet_(dbh, oid->getNX());
00442     nxSet(dbh, oid->getNX(), ns, datid);
00443 
00444     objh = oid2objh(oid, dbh, &objh, &hdl, &dummy);
00445 
00446     OidLoc oidloc = oidLocGet(dbh, oid);
00447     mapFree(dbh->vd, oidloc.ns, oidloc.datid, x2h_getSize(objh->size));
00448 
00449     nxSet(dbh, oid->getNX(), oidloc_o.ns, oidloc_o.datid);
00450     memset(objh, 0, sizeof(ObjectHeader));
00451       
00452     hdl_release(&hdl);
00453     return Success;
00454   }
00455 
00456   Status
00457   ESM_objectRestore(DbHandle const *dbh, Oid const *const oid,
00458                     NS ns, short datid)
00459   {
00460 #undef PR
00461 #define PR "objectRestore: "
00462 
00463     nxSet(dbh, oid->getNX(), ns, datid);
00464 
00465     return Success;
00466   }
00467 
00468   Status
00469   ESM_objectSizeGet(DbHandle const *dbh, unsigned int *size,
00470                     LockMode lockmode, Oid const *const oid,
00471                     OPMode opmode)
00472   {
00473 #undef PR
00474 #define PR "objectSizeGet: "
00475     if (!check_dbh(dbh))
00476       return statusMake(INVALID_DB_HANDLE, PR IDBH);
00477     else
00478       {
00479         if (!check_oid(dbh,oid))
00480           return statusMake(INVALID_OID, PR "invalid oid '%s'", getOidString(oid));
00481         else
00482           {
00483             MmapH hdl;
00484             ObjectHeader *objh;
00485             Status se;
00486             Boolean oid2addr_failed;
00487 
00488             TransactionOP lop = makeTOP(lockmode, OREAD, se);
00489             if (se) return se;
00490 
00491             if (se = ESM_objectLock(dbh, oid, lop, 0, 0))
00492               return se;
00493 
00494             if (!(objh = oid2objh(oid, dbh, &objh, &hdl, &oid2addr_failed)))
00495               {
00496                 if (oid2addr_failed)
00497                   return statusMake(FATAL_ERROR, PR "failed to map segment for oid '%s'", getOidString(oid));
00498                 return statusMake(INVALID_OID, PR "invalid oid '%s'", getOidString(oid));
00499               }
00500 
00501             *size = x2h_getSize(objh->size) - sizeof(ObjectHeader);
00502           
00503             ESM_REGISTER(dbh, SizeGetOP, ESM_addToRegisterSizeGet(dbh, oid));
00504             hdl_release(&hdl);
00505             return Success;
00506           }
00507       }
00508   }
00509 
00510   Status
00511   ESM_objectValidate(DbHandle const *dbh, Oid const *const oid)
00512   {
00513 #undef PR
00514 #define PR "objectValidate: "
00515     MmapH hdl;
00516     ObjectHeader *objh;
00517     Boolean oid2addr_failed;
00518 
00519     if (!(objh = oid2objh(oid, dbh, &objh, &hdl, &oid2addr_failed)))
00520       {
00521         if (oid2addr_failed)
00522           return statusMake(FATAL_ERROR, PR "failed to map segment for oid '%s'", getOidString(oid));
00523         return statusMake(INVALID_OID, PR "invalid oid '%s'", getOidString(oid));
00524       }
00525 
00526     objh->size = h2x_u32(x2h_makeValid(objh->size));
00527 
00528     hdl_release(&hdl);
00529     return Success;
00530   }
00531 
00532   static Status
00533   ESM_objectBornAgain(DbHandle const *dbh,
00534                       ObjectHeader *objh,
00535                       Oid const *const o_oid,
00536                       Oid const *const n_oid,
00537                       int keepDatid,
00538                       const OidLoc &xoidloc, Boolean opsync) // added 18/07/01
00539   {
00540     MmapH hdl0;
00541     Boolean dummy;
00542 
00543     if (isPhy(dbh, o_oid))
00544       return statusMake(INVALID_OID, PR "cannot move a physical oid");
00545 
00546     if (isPhy(dbh, n_oid))
00547       return statusMake(INVALID_OID, PR "cannot move an oid to a physical oid type based datafile");
00548 
00549     /* 1/ copy the old oid into the new oid */
00550     objh = oid2objh(n_oid, dbh, &objh, &hdl0, &dummy);
00551 #if 0
00552     OidLoc oidloc1 = oidLocGet_(dbh, n_oid->nx);
00553     OidLoc oidloc2 = oidLocGet_(dbh, o_oid->nx);
00554     printf("setting unique %s %s %d => %d [%d %d]\n", getOidString(n_oid),
00555            getOidString(o_oid), objh->unique, o_oid->unique,
00556            oidloc1.ns, oidloc2.ns);
00557 #endif
00558 
00559     objh->unique = h2x_u32(o_oid->getUnique());
00560 
00561     hdl_release(&hdl0);
00562   
00563     /* 2/ born again the nx of the old object */
00564     OidLoc oidloc = oidLocGet_(dbh, n_oid->getNX());
00565     nxSet(dbh, o_oid->getNX(), oidloc.ns,
00566           (keepDatid >= 0 ? keepDatid : oidloc.datid));
00567 
00568     /* 3/ free the nx of the new object */
00569     nxFree(dbh, n_oid->getNX());
00570 
00571     if (!opsync)
00572       ESM_bornAgainEpilogue(dbh, o_oid, n_oid, xoidloc.ns, xoidloc.datid);
00573 
00574     return Success;
00575   }
00576 
00577   Status
00578   ESM_objectSizeModify(DbHandle const *dbh, unsigned int size, Boolean copy,
00579                        Oid const *const oid, OPMode opmode)
00580   {
00581 #undef PR
00582 #define PR "objectSizeModify: "
00583     Status se = Success;
00584     MmapH hdl0;
00585     ObjectHeader *objh;
00586     int osize;
00587     PObject *po = 0;
00588     Boolean opsync = False;
00589     char *buf = 0;
00590     Boolean oid2addr_failed;
00591     DbHeader _dbh(DBSADDR(dbh));
00592 
00593     if (isPhy(dbh, oid))
00594       return statusMake(INVALID_OID, PR "cannot change the size of a "
00595                         "physical oid");
00596 #ifndef SHR_SECURE
00597     if (opmode != OPShrinkingPhase)
00598 #endif
00599       {
00600         if (!check_dbh(dbh))
00601           return statusMake(INVALID_DB_HANDLE, PR IDBH);
00602 
00603         if (!check_oid(dbh,oid))
00604           return statusMake(INVALID_OID, PR "invalid oid '%s'", getOidString(oid));
00605         if (se = ESM_objectLock(dbh, oid, OCHSIZE, &opsync, 0))
00606           return se;
00607       }
00608 
00609     if (!(objh = oid2objh(oid, dbh, &objh, &hdl0, &oid2addr_failed)))
00610       {
00611         if (oid2addr_failed)
00612           return statusMake(FATAL_ERROR, PR "failed to map segment for oid '%s'", getOidString(oid));
00613         return statusMake(INVALID_OID, PR "invalid oid '%s'", getOidString(oid));
00614       }
00615 
00616     osize = x2h_getSize(objh->size) - sizeof(ObjectHeader);
00617   
00618     hdl_release(&hdl0);
00619   
00620     if (osize != size)
00621       {
00622         Oid noid;
00623         OidLoc oidloc;
00624         int cpsize;
00625 
00626         oidloc = oidLocGet_(dbh, oid->getNX());
00627 
00628         /* 1/ create new object of size 'size' */
00629         /* changed the 23/08/01 */
00630         /*
00631           if (se = ESM_objectCreate_server(dbh, 0, size, oidloc.datid, DefaultDspid, &noid, 0, OPDefault))
00632           goto error;
00633         */
00634         if (se = ESM_objectCreate(dbh, 0, size, getDataspace(&_dbh, oidloc.datid), &noid, OPDefault))
00635           goto error;
00636 
00637         if (copy)
00638           {
00639             cpsize = MIN(size, osize);
00640             buf = (char *)m_malloc(cpsize);
00641 
00642             /* 2/ copy old object into new object (at most size) */
00643             if (se = ESM_objectRead(dbh, 0, cpsize, buf, LockS, 0, 0, oid,
00644                                     OPDefault))
00645               goto error;
00646 
00647             if (se = ESM_objectWrite(dbh, 0, cpsize, buf, &noid, opmode))
00648               goto error;
00649           }
00650 
00651         /* 3/ remove old object, but keep its oid */
00652         if (se = ESM_objectDelete(dbh, oid, opmode))
00653           goto error;
00654 
00655         /* 4/ oid management */
00656         if (se = ESM_objectBornAgain(dbh, objh, oid, &noid, -1, oidloc, opsync))
00657           goto error;
00658 
00659         ESM_REGISTER(dbh, SizeModOP, ESM_addToRegisterSizeMod(dbh, oid, size));
00660       }
00661 
00662 
00663   error:
00664     free(buf);
00665     return se;
00666   }
00667 
00668   Status
00669   ESM_objectCheckAccess(DbHandle const *dbh, Boolean write,
00670                         Oid const *const oid, Boolean *access)
00671   {
00672     ObjectHeader objh;
00673     MmapH hdl;
00674     ObjectHeader *pobjh;
00675     const Protection *prot;
00676     Boolean oid2addr_failed;
00677 
00678     /* really? */
00679     if (OIDDBIDGET(oid) != dbh->vd->dbid)
00680       {
00681         *access = True;
00682         return Success;
00683       }
00684 
00685     if (!(pobjh = oid2objh(oid, dbh, &pobjh, &hdl, &oid2addr_failed)))
00686       {
00687         if (oid2addr_failed)
00688           return statusMake(FATAL_ERROR, PR "failed to map segment for oid '%s'", getOidString(oid));
00689 
00690         return statusMake(INVALID_OID, "invalid oid '%s'", getOidString(oid));
00691       }
00692 
00693 
00694     /* should perharps look in tro->prot_oid is tro exists for this
00695        object and if tro->prot_oid_set */
00696     prot = protGet(dbh, ESM_getProtection(dbh, oid, &pobjh->prot_oid),
00697                    getUid(dbh));
00698 
00699     hdl_release(&hdl);
00700 
00701     if (prot->r != ReadAll || (write && prot->w != WriteAll))
00702       {
00703         *access = False;
00704         return Success;
00705       }
00706 
00707     *access = True;
00708     return Success;
00709   }
00710       
00711   Status
00712   ESM_objectReadCache(DbHandle const *dbh, int start, void **object,
00713                       LockMode lockmode, Oid const *const oid)
00714   {
00715     static const char *pre = "objectReadCache";
00716     if (!check_dbh(dbh))
00717       return statusMake(INVALID_DB_HANDLE, "%s%s", pre, IDBH);
00718 
00719     Status se;
00720     TransactionOP lop;
00721 
00722     lop = makeTOP(lockmode, OREAD, se);
00723     if (se) return se;
00724 
00725     Boolean mustExist = True;
00726     TRObject *tro = 0;
00727     if (se = ESM_objectLockCheck(dbh, oid, lop, 0, &mustExist, &tro))
00728       return se;
00729 
00730     if (!mustExist) {
00731       *(char **)object = 0;
00732       return Success; 
00733     }
00734 
00735     char *addr = ESM_trobjDataGetIfExist(dbh, tro);
00736     if (!addr) {
00737       *(char **)object = 0;
00738       return Success; 
00739     }
00740 
00741     *(char **)object = addr + start;
00742     return Success;
00743   }
00744 
00745   Status
00746   ESM_objectWriteCache(DbHandle const *dbh, int __start,
00747                        void const * const __object, Oid const *const oid)
00748   {
00749     static const char *pre = "objectWriteCache";
00750     if (!check_dbh(dbh))
00751       return statusMake(INVALID_DB_HANDLE, "%s%s", pre, IDBH);
00752 
00753     Status se;
00754     TransactionOP lop;
00755     TRObject *tro;
00756 
00757     lop = makeTOP(LockS, OWRITE, se);
00758     if (se) return se;
00759 
00760     return ESM_objectLock(dbh, oid, lop, 0, &tro);
00761   }
00762 
00763   static Status
00764   read_write(const char *pre, DbHandle const *dbh, int start,
00765              int length, void *object, Oid const *const oid,
00766              short *pdatid, unsigned int *psize, TransactionOP op,
00767              LockMode lockmode, rpc_ServerData *data, OPMode opmode,
00768              Boolean nocopy = False)
00769   {
00770     TransactionOP lop;
00771     ObjectHeader objh;
00772     Status status;
00773     MmapH hdl0, hdl1;
00774     ObjectHeader *pobjh;
00775     unsigned int size;
00776     Status se;
00777     Boolean opsync = False;
00778     TRObject *tro = 0;
00779     int immediate;
00780     int up, must_release = 1;
00781     Boolean oid2addr_failed;
00782 
00783     //printf("read_write(%s, uid = %d)\n", getOidString(oid), dbh->vd->uid);
00784     if (nocopy) {
00785       if (dbh->vd->hints.maph != WholeMap)
00786         return statusMake(ERROR, "no-copy read may be only used in "
00787                           "whole-map opened databases");
00788       //printf("reading %s with no copy\n", getOidString(oid));
00789     }
00790 
00791     OidLoc oidloc = oidLocGet(dbh, oid);
00792     if (pdatid) *pdatid = oidloc.datid;
00793 
00794 #ifndef SHR_SECURE
00795     if (opmode != OPShrinkingPhase)
00796 #endif
00797       {
00798         if (!check_dbh(dbh))
00799           return statusMake(INVALID_DB_HANDLE, "%s%s", pre, IDBH);
00800         if ((op == OWRITE || op == PWRITE )&& !(dbh->vd->flags & VOLRW))
00801           return statusMake(WRITE_FORBIDDEN, "%s%s", pre, WF_P);
00802         if (start < 0)
00803           return statusMake(INVALID_OFFSET, "%soffset is negative: `%d'", pre, start);
00804         if (length < 0)
00805           return statusMake(INVALID_SIZE, "%ssize is negative: `%d'", pre, length);
00806         if (!CHECK_NS_OID(dbh, oidloc.ns, oidloc.datid, oid))
00807           {
00808             /*
00809               printf("INVALID OID oidloc = 0x%x %d [nx=%d]\n",
00810               oidloc.ns, oidloc.datid, oid->nx);
00811               if (oidloc.datid >= 0)
00812               printf("... lastslot %d %d %d\n",
00813               x2h_u32(DBSADDR(dbh)->dat[oidloc.datid].__lastslot),
00814               OIDDBIDGET(oid), (dbh)->vd->dbid);
00815             */
00816 #ifdef ESM_POST_RECOVERY
00817             /* all this is !!NULL!! */
00818             if (post_recovery)
00819               {
00820                 if (length)
00821                   memset(object, 0, length);
00822 
00823                 if (post_recovery != 2)
00824                   {
00825                     utlog("EyeDB Recovery System: %sinvalid oid '%s'", pre, getOidString(oid));
00826                     fprintf(stderr, "EyeDB Recovery System: %sinvalid oid '%s'", pre, getOidString(oid));
00827                   }
00828                 return Success;
00829               }
00830 #endif
00831 #if 0
00832             Oid xoid;
00833             x2h_oid(&xoid, oid);
00834             printf("INVALID: %s\n", getOidString(&xoid));
00835 #endif
00836             return statusMake(INVALID_OID, "%sinvalid oid '%s'", pre, getOidString(oid));
00837           }
00838 
00839         lop = makeTOP(lockmode, op, se);
00840         if (se) return se;
00841 
00842         if (se = ESM_objectLock(dbh, oid, lop, &opsync, &tro))
00843           return se;
00844       }
00845 
00846     if (!(pobjh = oid2objh_(oid, oidloc.ns, oidloc.datid, dbh, &pobjh, &hdl0, &up, &oid2addr_failed)))
00847       {
00848         if (oid2addr_failed)
00849           return statusMake(FATAL_ERROR, "%sfailed to map segment for oid '%s'", pre, getOidString(oid));
00850         return statusMake(INVALID_OID, "%sinvalid oid '%s'", pre, getOidString(oid));
00851       }
00852 
00853     if (!length && start) {
00854       hdl_release(&hdl0);
00855       return statusMake(INVALID_SIZE, "%soffset must be null when length "
00856                         "is not specified", pre);
00857     }
00858 
00859     size = x2h_getSize(pobjh->size) - sizeof(ObjectHeader);
00860 
00861     /*
00862     // 4/07/01: this should be in the argument of the function instead
00863     // of an horrible global variable!
00864     last_objsize = size;
00865     */
00866     // 17/05/02: replaced by a parameter
00867     if (psize) *psize = size;
00868 
00869     if (length != 0 && (start + length > size))
00870       {
00871         hdl_release(&hdl0);
00872         return statusMake(INVALID_SIZE, "%sobject size exceeded: `%d', object size is `%d' [%s]", pre, start+length, size, getOidString(oid));
00873       }
00874     else
00875       {
00876         char *addr, *dbaddr = 0, *traddr = 0;
00877         MapHeader t_mp = DAT2MP(dbh, oidloc.datid);
00878         MapHeader *mp = &t_mp;
00879         unsigned int pow2 = x2h_u32(mp->pow2());
00880         unsigned int sizeslot = x2h_u32(mp->sizeslot());
00881         const Protection *prot;
00882       
00883         length = ((length == 0) ? size : length);
00884       
00885         immediate = (opmode != OPGrowingPhase || opsync);
00886 
00887         if (immediate || op == OREAD)
00888           {
00889             /*
00890               faire un test pour voir si:
00891               - ce range a deja ete mappé
00892             */
00893             int l = length + sizeof(ObjectHeader) + start;
00894             int l1 = l >> pow2;
00895 
00896             if (!up || (oidloc.ns+l1+1) < up)
00897               {
00898                 dbaddr = ((char *)pobjh) + sizeof(ObjectHeader);
00899                 must_release = 0;
00900                 /*printf("already in range [ns = %d, l/sizeslot %d, up %d]\n",
00901                   ns, l/sizeslot, up);*/
00902               }
00903             else
00904               {
00905                 dbaddr = oid2addr_(oidloc.ns, oidloc.datid, dbh, l, &dbaddr, &hdl1, 0) +
00906                   sizeof(ObjectHeader);
00907                 /*printf("not in range [ns = %d, l/sizeslot %d, up %d]\n",
00908                   ns, l/sizeslot, up); */
00909               }
00910           }
00911 
00912         if (!immediate)
00913           {
00914             traddr = ESM_trobjDataGet(dbh, tro, size);
00915             if (!traddr) {
00916               hdl_release(&hdl0);
00917               if (must_release && (immediate || op == OREAD))
00918                 hdl_release(&hdl1);
00919               return statusMake(NO_SHMSPACE_LEFT, "for object size %d",
00920                                 size);
00921             }
00922           }
00923       
00924         addr = (immediate ? dbaddr : traddr);
00925 
00926         /* protection check */
00927         prot = protGet(dbh, (tro && tro->prot_oid_set ? &tro->prot_oid :
00928                              &pobjh->prot_oid), getUid(dbh));
00929       
00930         switch(op)
00931           {
00932           case OWRITE:
00933             if (prot->w == WriteAll || (start + length) <= (int)prot->w) {
00934               if (data)
00935                 rpc_socketRead(data->fd, addr, length);
00936               else
00937                 ESM_trobjDataWrite(addr, (const char *)object, start, length, opmode, opsync);
00938               
00939               //MSYNC((caddr_t)ROUND_PAGE(addr), ROUND_UP_PAGE(length), MS_ASYNC);      
00940               status = Success;
00941             }
00942             else
00943               status = statusMake(OBJECT_PROTECTED, "%sobject '%s' is protected", pre, getOidString(oid));
00944             ESM_REGISTER(dbh, WriteOP, ESM_addToRegisterWrite(dbh, oid, start, length));
00945             break;
00946           
00947           case OREAD:
00948             if (prot->r == ReadAll || (start + length) <= (int)prot->r) {
00949               if (data) {
00950                 if (length <= data->buff_size) {
00951                   memcpy(data->data, addr, length);
00952                   data->status = rpc_BuffUsed;
00953                 }
00954                 else {
00955                   data->data = addr;
00956                   data->status = rpc_PermDataUsed;
00957                 }
00958               
00959                 data->size = length;
00960                 status = Success;
00961               }
00962               else
00963                 status = ESM_trobjDataRead((char *)object, addr, dbaddr, start,
00964                                            length, opsync, nocopy);
00965 
00966               ESM_REGISTER(dbh, ReadOP, ESM_addToRegisterRead(dbh, oid, start, length));
00967             }
00968             else {
00969 #ifdef TRACE
00970               printf("protected '%d %d'\n", pobjh->prot_oid.ns,
00971                      pobjh->prot_oid.unique);
00972 #endif
00973               status = statusMake(OBJECT_PROTECTED, "%sobject is protected: '%s'", pre, getOidString(oid));
00974             }
00975             break;
00976           
00977           case PWRITE:
00978             if (immediate)
00979               memcpy(&pobjh->prot_oid, object, sizeof(Oid));
00980             else
00981               ESM_transactionObjectProtSet(tro, (Oid *)object);
00982             status = Success;
00983             break;
00984           
00985           case PREAD:
00986             memcpy(object, &pobjh->prot_oid, sizeof(Oid));
00987             status = Success;
00988             break;
00989 
00990           default:
00991             status = statusMake(ERROR, "internal error: "
00992                                 "unexpected object operation: %x", op);
00993             break;
00994           }
00995       
00996         hdl_release(&hdl0);
00997 
00998         if (must_release && (immediate || op == OREAD))
00999           hdl_release(&hdl1);
01000       
01001         return status;
01002       }
01003   }
01004 
01005   /*
01006     Status
01007     ESM_objectWrite_server(DbHandle const *dbh, int start, int length,
01008     void const *const object, Oid const *const oid,
01009     rpc_ServerData *data, OPMode opmode)
01010     {
01011     return read_write("objectWrite: ", dbh, start, length,
01012     (void *)object, oid, 0, 0, OWRITE, LockS, data,
01013     opmode);
01014     }
01015 
01016     Status
01017     ESM_objectRead_server(DbHandle const *dbh, int start, int length,
01018     void *object, Oid const *const oid,
01019     rpc_ServerData *data, OPMode opmode)
01020     {
01021     assert(0);
01022     return read_write("objectRead: ", dbh, start, length, object,
01023     oid, 0, OREAD, DefaultLock, data, opmode);
01024     }
01025   */
01026 
01027   Status
01028   ESM_objectWrite(DbHandle const *dbh, int start, int length,
01029                   void const *const object, Oid const *const oid,
01030                   OPMode opmode)
01031   {
01032     return read_write("objectWrite: ", dbh, start, length,
01033                       (void *)object, oid, 0, 0, OWRITE, LockS, 0,
01034                       opmode);
01035   }
01036 
01037   Status
01038   ESM_objectRead(DbHandle const *dbh, int start, int length, void *object,
01039                  LockMode lockmode, short *pdatid, unsigned int *psize, 
01040                  Oid const *const oid, OPMode opmode)
01041   {
01042     return read_write("objectRead: ", dbh, start, length, object,
01043                       oid, pdatid, psize, OREAD, lockmode, 0, opmode);
01044   }
01045 
01046   Status
01047   ESM_objectReadNoCopy(DbHandle const *dbh, int start, int length,
01048                        void *object, LockMode lockmode, short *pdatid,
01049                        unsigned int *psize, Oid const *const oid, OPMode opmode)
01050   {
01051     return read_write("objectRead: ", dbh, start, length, object,
01052                       oid, pdatid, psize, OREAD, lockmode, 0, opmode,
01053                       True);
01054   }
01055 
01056   Status
01057   ESM_objectsMoveDatDsp(DbHandle const *dbh, Oid const *const oid,
01058                         unsigned int oid_cnt, short datid, short dspid,
01059                         Boolean keepDatid, OPMode opmode)
01060   {
01061     Status s;
01062     for (int i = 0; i < oid_cnt; i++)
01063       if (s = ESM_objectMoveDatDsp(dbh, &oid[i], datid, dspid, keepDatid, opmode))
01064         return s;
01065 
01066     return Success;
01067   }
01068 
01069   Boolean
01070   isDatInDsp(DbHandle const *dbh, short dspid, short datid)
01071   {
01072     DataspaceDesc dsp = DbHeader(DBSADDR(dbh)).dsp(dspid);
01073     unsigned int ndat = x2h_u32(dsp.__ndat());
01074     for (int i = 0; i < ndat; i++)
01075       if (x2h_16(dsp.__datid(i)) == datid)
01076         return True;
01077     return False;
01078   }
01079 
01080   Status
01081   ESM_objectMoveDatDsp(DbHandle const *dbh, Oid const *const oid,
01082                        short datid, short dspid, Boolean keepDatid,
01083                        OPMode opmode)
01084   {
01085 #undef PR
01086 #define PR "objectMoveDatDsp: "
01087     Status se = Success;
01088     MmapH hdl0;
01089     ObjectHeader *objh;
01090     unsigned int size;
01091     PObject *po = 0;
01092     Boolean opsync = False;
01093     Boolean oid2addr_failed;
01094 
01095     /*
01096       if (isPhy(dbh, oid))
01097       return statusMake(INVALID_OID, PR "cannot move a physical oid");
01098     */
01099 
01100     DbHeader _dbh(DBSADDR(dbh));
01101 #ifndef SHR_SECURE
01102     if (opmode != OPShrinkingPhase)
01103 #endif
01104       {
01105         if (!check_dbh(dbh))
01106           return statusMake(INVALID_DB_HANDLE, PR IDBH);
01107 
01108         if (datid >= 0) {
01109           if (!isDatValid(dbh, datid))
01110             return statusMake(INVALID_DATAFILE, PR "invalid datafile '%d'",
01111                               datid);
01112         }
01113         else {
01114           if (!isDspValid(dbh, dspid))
01115             return statusMake(INVALID_DATASPACE,
01116                               PR "invalid dataspace '%d'", dspid);
01117         }
01118 
01119         if (!check_oid(dbh, oid))
01120           return statusMake(INVALID_OID, PR "invalid oid '%s'", getOidString(oid));
01121 
01122         if (datid >= 0 &&
01123             getDatType(&_dbh, datid) == PhysicalOidType)
01124           return statusMake(INVALID_OID, PR "cannot move an oid to a "
01125                             "physical oid type based datafile");
01126 
01127         if (se = ESM_objectLock(dbh, oid, OCHSIZE, &opsync, 0))
01128           return se;
01129       }
01130 
01131     if (!(objh = oid2objh(oid, dbh, &objh, &hdl0, &oid2addr_failed)))
01132       {
01133         if (oid2addr_failed)
01134           return statusMake(FATAL_ERROR, PR "failed to map segment for oid '%s'", getOidString(oid));
01135         return statusMake(INVALID_OID, PR "invalid oid '%s'", getOidString(oid));
01136       }
01137 
01138     size = x2h_getSize(objh->size) - sizeof(ObjectHeader);
01139   
01140     hdl_release(&hdl0);
01141   
01142     Oid noid;
01143     OidLoc oidloc;
01144   
01145     oidloc = oidLocGet_(dbh, oid->getNX());
01146   
01147     if (datid >= 0) {
01148       if (oidloc.datid == datid)
01149         return Success;
01150     }
01151     else if (isDatInDsp(dbh, dspid, oidloc.datid))
01152       return Success;
01153 
01154     if (isPhy(dbh, oid))
01155       return statusMake(INVALID_OID, PR "cannot move a physical oid");
01156 
01157     char *buf = 0;
01158     /* 1/ create new object of size 'size' */
01159     if (datid >= 0) {
01160       if (se = ESM_objectCreate_server(dbh, 0, size, datid, DefaultDspid, &noid, 0, opmode))
01161         goto error;
01162     }
01163     else {
01164       if (se = ESM_objectCreate(dbh, 0, size, dspid, &noid, opmode))
01165         goto error;
01166     }
01167       
01168     if (isPhy(dbh, &noid))
01169       return statusMake(INVALID_OID, PR "cannot move an oid to a "
01170                         "physical oid type based datafile");
01171 
01172     buf = (char *)m_malloc(size);
01173 
01174     /* 2/ copy old object into new object (at most size) */
01175     if (se = ESM_objectRead(dbh, 0, size, buf, LockS, 0, 0, oid, opmode))
01176       goto error;
01177 
01178     if (se = ESM_objectWrite(dbh, 0, size, buf, &noid, opmode))
01179       goto error;
01180 
01181     /* 3/ remove old object, but keep its oid */
01182     if (se = ESM_objectDelete(dbh, oid, opmode))
01183       goto error;
01184       
01185     /* 4/ oid management */
01186     if (se = ESM_objectBornAgain(dbh, objh, oid, &noid,
01187                                  (keepDatid ? oidloc.datid : -1),
01188                                  oidloc, opsync))
01189       goto error;
01190 
01191   error:
01192     free(buf);
01193     return se;
01194   }
01195 
01196   Status
01197   ESM_objectProtectionSet(DbHandle const *dbh, Oid const *const oid,
01198                           Oid const *const protoid, OPMode opmode)
01199   {
01200     if (protGet(dbh, protoid, getUid(dbh)) == &p_none)
01201       return statusMake_s(PROTECTION_NOT_FOUND);
01202 
01203     return read_write("objectProtectionSet: ", dbh, 0, 4,
01204                       (void *)protoid, oid, 0, 0, PWRITE, LockS, 0,
01205                       opmode);
01206   }
01207 
01208   Status
01209   ESM_objectProtectionGet(DbHandle const *dbh, Oid const *const oid,
01210                           Oid *protoid)
01211   {
01212     return read_write("objectProtectionGet: ", dbh, 0, 4,
01213                       (void *)protoid, oid, 0, 0, PREAD, LockS, 0,
01214                       OPDefault);
01215   }
01216 
01217 }

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