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 #include <stdlib.h>
00027
00028 #include <kern_p.h>
00029 #include <eyedblib/rpc_lib.h>
00030
00031
00032
00033 #define 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
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
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
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
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
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201 }
00202
00203
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
00240
00241
00242
00243 if (!defrag_map[datid]) {
00244
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
00271
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
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)
00350 memcpy(addr + sizeof(ObjectHeader), object, size);
00351 else
00352 memset(addr + sizeof(ObjectHeader), 0, size);
00353 }
00354
00355
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
00421
00422
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)
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
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
00564 OidLoc oidloc = oidLocGet_(dbh, n_oid->getNX());
00565 nxSet(dbh, o_oid->getNX(), oidloc.ns,
00566 (keepDatid >= 0 ? keepDatid : oidloc.datid));
00567
00568
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
00629
00630
00631
00632
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
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
00652 if (se = ESM_objectDelete(dbh, oid, opmode))
00653 goto error;
00654
00655
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
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
00695
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
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
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
00810
00811
00812
00813
00814
00815
00816 #ifdef ESM_POST_RECOVERY
00817
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
00863
00864
00865
00866
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
00891
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
00901
00902 }
00903 else
00904 {
00905 dbaddr = oid2addr_(oidloc.ns, oidloc.datid, dbh, l, &dbaddr, &hdl1, 0) +
00906 sizeof(ObjectHeader);
00907
00908
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
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
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
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
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
01097
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
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
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
01182 if (se = ESM_objectDelete(dbh, oid, opmode))
01183 goto error;
01184
01185
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 }