00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "eyedbconfig.h"
00036
00037 #include <iostream>
00038 #include <sys/types.h>
00039 #include <grp.h>
00040
00041 #include "eyedblib/filelib.h"
00042 #include "eyedblib/rpc_lib.h"
00043 #include "kern_p.h"
00044 #include <eyedbsm/smd.h>
00045 #include <map>
00046 #include "lib/compile_builtin.h"
00047
00048 static const char defDsp[] = "DEFAULT";
00049
00050
00051
00052
00053 namespace eyedbsm {
00054 unsigned long curref;
00055 const void *ObjectZero = 0, *ObjectNone = (void *)-1;
00056 Boolean backend_interrupt = False;
00057 Boolean backend = False;
00058 unsigned int import_xid;
00059 const int INVALID = -1;
00060
00061
00062
00063 #define SHM_DEFSIZE 0x4000000
00064
00065 #define DBS_DEFSIZE (size_t)DbHeader_SIZE
00066 #define OIDMAP_SIZE(NOBJS) \
00067 (((((unsigned long long)NOBJS * OIDLOCSIZE) / pgsize) + 1) * pgsize)
00068
00069 #define ALIGN4(x) \
00070 x = (u_long *)(((u_long)(x)&0x3) ? ((u_long)(x) + 0x4-((u_long)(x)&0x3)) : (u_long)x)
00071
00072
00073 #define ESM_DEF_NBOBJS 100000000
00074 #define MAXTRIES 0
00075
00076 const char ompext[] = ".omp";
00077 const char shmext[] = ".shm";
00078 const char dbsext[] = ".dbs";
00079 const char datext[] = ".dat";
00080 const char dmpext[] = ".dmp";
00081
00082 int dbsext_len = 4;
00083 int datext_len = 4;
00084
00085 static Status
00086 dbCleanupRealize(const char *shmfile, int sm_fdshm);
00087
00088 static Status
00089 dbcreate_error(Status status, const char *dbfile,
00090 const DbCreateDescription *dbc, int n, DBFD *dbfd)
00091 {
00092 char pwd[DEFAULT_PWD_SIZE];
00093 push_dir(dbfile, pwd, sizeof pwd);
00094
00095 unlink(dbfile);
00096 unlink(objmapfileGet(dbfile));
00097 unlink(shmfileGet(dbfile));
00098
00099 close(dbfd->dbsfd);
00100 close(dbfd->ompfd);
00101 close(dbfd->shmfd);
00102
00103 for (int j = 0; j < n; j++) {
00104 unlink(dbc->dat[j].file);
00105 unlink(dmpfileGet(dbc->dat[j].file));
00106 close(dbfd->fd_dat[j]);
00107 close(dbfd->fd_dmp[j]);
00108 }
00109
00110 pop_dir(pwd);
00111 return status;
00112 }
00113
00114 static int fileCreate(const char *file, mode_t file_mode, gid_t file_gid)
00115 {
00116 int fd;
00117
00118 umask(0);
00119
00120 if ((fd = creat(file, file_mode)) < 0)
00121 return -1;
00122
00123 if (chmod(file, file_mode) < 0)
00124 return -1;
00125
00126 if (file_gid != (gid_t)-1) {
00127 if (chown(file, (uid_t)-1, file_gid) < 0) {
00128 close(fd);
00129 unlink(file);
00130 return -2;
00131 }
00132 }
00133 return fd;
00134 }
00135
00136 static int
00137 dbsfileCreate(const char *dbfile, mode_t file_mode, gid_t file_gid)
00138 {
00139 int dbsfd;
00140
00141 if ((dbsfd = fileCreate(dbfile, file_mode, file_gid)) < 0)
00142 return dbsfd;
00143
00144 if (ftruncate(dbsfd, DBS_DEFSIZE) < 0)
00145 return -1;
00146 return dbsfd;
00147 }
00148
00149 static int
00150 shmfileCreate(const char *dbfile, mode_t file_mode, gid_t file_gid)
00151 {
00152 int shmfd;
00153
00154 if ((shmfd = fileCreate(shmfileGet(dbfile), file_mode, file_gid)) < 0)
00155 return shmfd;
00156
00157 if (ftruncate(shmfd, SHM_DEFSIZE) < 0)
00158 return -1;
00159 return shmfd;
00160 }
00161
00162 static Status
00163 check_dbCreate_1(const char *pr, int dbid, const char *dbfile,
00164 Oid::NX nbobjs, int ndat)
00165 {
00166 int dbfile_len = strlen(dbfile);
00167
00168 if (dbid <= 0 || dbid >= MAX_DBID)
00169 return statusMake(INVALID_DBID,
00170 "%sinvalid database identifier `%d'", pr, dbid);
00171
00172 if (dbfile_len <= dbsext_len ||
00173 strcmp(&dbfile[dbfile_len-dbsext_len], dbsext))
00174 return statusMake(INVALID_DBFILE,
00175 "%sinvalid database file extension for `%s' "
00176 "(must be %s)", pr, dbfile, dbsext);
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186 if (ndat <= 0)
00187 return statusMake(INVALID_DATAFILE_CNT,
00188 "%sinvalid datafile number: %d",
00189 pr, ndat);
00190
00191 if (ndat >= MAX_DATAFILES)
00192 return statusMake(INVALID_DATAFILE_CNT,
00193 "%sdatafile number too large: %d, maximum is %u", pr, ndat, MAX_DATAFILES);
00194
00195 return Success;
00196 }
00197
00198 static Status
00199 check_dbCreate_2(const char *pr, const char *dbfile, DBFD *dbfd, mode_t file_mode, gid_t file_gid)
00200 {
00201 if ((dbfd->dbsfd = open(dbfile, O_RDONLY)) >= 0)
00202 return statusMake(INVALID_DBFILE,
00203 "%sdatabase file already exists: '%s'",
00204 pr, dbfile);
00205
00206 if ((dbfd->ompfd = open(objmapfileGet(dbfile), O_RDONLY)) >= 0)
00207 return statusMake(INVALID_DBFILE,
00208 "%smap file already exists: '%s'",
00209 pr, objmapfileGet(dbfile));
00210
00211 if ((dbfd->shmfd = open(shmfileGet(dbfile), O_RDONLY)) >= 0)
00212 return statusMake(INVALID_SHMFILE,
00213 "%sshm file already exists: '%s'",
00214 pr, shmfileGet(dbfile));
00215
00216 if ((dbfd->dbsfd = dbsfileCreate(dbfile, file_mode, file_gid)) < 0)
00217 return statusMake(INVALID_DBFILE,
00218 "%scannot create database file: '%s' [%s]",
00219 pr, dbfile, strerror(errno));
00220
00221 return Success;
00222 }
00223
00224 static Status
00225 check_dbCreate_3(const char *pr, const char *dbfile, DBFD *dbfd, mode_t file_mode, gid_t file_gid)
00226 {
00227 if ((dbfd->ompfd = fileCreate(objmapfileGet(dbfile), file_mode, file_gid))
00228 < 0)
00229 return statusMake(INVALID_DBFILE,
00230 "%scannot create map file: '%s' [%s]",
00231 pr, objmapfileGet(dbfile), strerror(errno));
00232
00233 if ((dbfd->shmfd = shmfileCreate(dbfile, file_mode, file_gid)) < 0)
00234 return statusMake(INVALID_SHMFILE,
00235 "%scannot create shm file: '%s' [%s]",
00236 pr, shmfileGet(dbfile), strerror(errno));
00237
00238 return Success;
00239 }
00240
00241 Status checkDatafileSize(unsigned long long nslots_l,
00242 const char *datfile, unsigned int sizeslot,
00243 unsigned long long newmaxsize)
00244 {
00245 if (nslots_l >= ~0U) {
00246 return statusMake(SIZE_TOO_LARGE,
00247 "datafile %s (slotsize %u) maximum size is too large: "
00248 "%llu MB, maximum allowed size is %u MB",
00249 datfile,
00250 sizeslot,
00251 newmaxsize/ONE_K, SLOT2KB(((unsigned long long)~0U)-1, sizeslot)/ONE_K);
00252 }
00253
00254 return Success;
00255 }
00256
00257 Status checkDatafile(const char *pr, const char *dbfile, DbHeader *dbh,
00258 const DbCreateDescription *dbc,
00259 int i, DBFD *dbfd,
00260 mode_t file_mode, gid_t file_gid,
00261 Boolean can_be_null,
00262 Boolean *is_null, Boolean out_place)
00263 {
00264 if (!*dbc->dat[i].file) {
00265 if (can_be_null) {
00266 if (is_null)
00267 *is_null = True;
00268 return Success;
00269 }
00270 return statusMake(INVALID_DBFILE, "%sinvalid null database", pr);
00271 }
00272
00273 DatType dtype = (DatType)dbc->dat[i].dtype;
00274
00275 if (dtype != LogicalOidType &&
00276 dtype != PhysicalOidType)
00277 return statusMake(ERROR, "datafile creation: "
00278 "invalid datatype %d", dtype);
00279
00280 if (is_null)
00281 *is_null = False;
00282 const char *dmpfile = dmpfileGet(dbc->dat[i].file);
00283 short mtype;
00284 int datfile_len = strlen(dbc->dat[i].file);
00285 Status status;
00286 unsigned int sizeslot;
00287
00288 char pwd[DEFAULT_PWD_SIZE];
00289 status = push_dir(dbfile, pwd, sizeof pwd);
00290 if (status) return status;
00291
00292 if (datfile_len <= datext_len ||
00293 strcmp(&dbc->dat[i].file[datfile_len-datext_len], datext)) {
00294 pop_dir(pwd);
00295 return statusMake(INVALID_DBFILE,
00296 "%sinvalid database file extension for `%s' "
00297 "(must be %s)", pr, dbc->dat[i].file, datext);
00298 }
00299
00300 if ((status = checkVolMaxSize(dbc->dat[i].maxsize))) {
00301 pop_dir(pwd);
00302 return status;
00303 }
00304
00305 if ((dbfd->fd_dat[i] = open(dbc->dat[i].file, O_RDONLY)) >= 0) {
00306 pop_dir(pwd);
00307 close(dbfd->fd_dat[i]);
00308 return statusMake(INVALID_DATAFILE,
00309 "%sdatafile already exists: '%s'",
00310 pr, dbc->dat[i].file);
00311 }
00312
00313 if (status = checkNewDatafile(dbh, dbc->dat[i].file, dbc->dat[i].name)) {
00314 pop_dir(pwd);
00315 return status;
00316 }
00317
00318 if ((dbfd->fd_dmp[i] = open(dmpfile, O_RDONLY)) >= 0) {
00319 pop_dir(pwd);
00320 close(dbfd->fd_dmp[i]);
00321 return statusMake(INVALID_DMPFILE,
00322 "%sdata map file already exists: '%s'",
00323 pr, dmpfile);
00324 }
00325
00326
00327 if ((dbfd->fd_dat[i] = fileCreate(dbc->dat[i].file, file_mode, file_gid)) <
00328 0) {
00329 pop_dir(pwd);
00330 return statusMake(INVALID_DATAFILE,
00331 "%scannot create datafile: '%s' [%s]",
00332 pr, dbc->dat[i].file, strerror(errno));
00333 }
00334
00335 if ((dbfd->fd_dmp[i] = fileCreate(dmpfile, file_mode, file_gid)) <
00336 0) {
00337 unlink(dbc->dat[i].file);
00338 pop_dir(pwd);
00339 return statusMake(INVALID_DMPFILE,
00340 "%scannot create data map file: '%s' [%s]",
00341 pr, dmpfile, strerror(errno));
00342 }
00343
00344 if (status = syscheck(pr, close(dbfd->fd_dat[i]),
00345 "closing datafile: '%s'",
00346 dbc->dat[i].file)) {
00347 unlink(dmpfile);
00348 unlink(dbc->dat[i].file);
00349 pop_dir(pwd);
00350 return status;
00351 }
00352
00353 strcpy(dbh->dat(i).file(), dbc->dat[i].file);
00354 strcpy(dbh->dat(i).name(), dbc->dat[i].name);
00355 dbh->dat(i).__dspid() = 0;
00356 if (out_place) {
00357 dbh->dat(i).__maxsize() = h2x_u32(dbc->dat[i].maxsize);
00358 setDataspace(dbh, i, DefaultDspid);
00359 setDatType(dbh, i, dtype);
00360 }
00361 else {
00362 dbh->dat(i).__maxsize() = dbc->dat[i].maxsize;
00363 setDataspace_inplace(dbh, i, DefaultDspid);
00364 setDatType_inplace(dbh, i, dtype);
00365 }
00366
00367 dbh->dat(i).__lastslot() = 0;
00368 dbh->dat(i).mp()->memzero();
00369
00370 mtype = dbc->dat[i].mtype;
00371
00372 if (mtype == LinkmapType) {
00373 unlink(dmpfile);
00374 unlink(dbc->dat[i].file);
00375 pop_dir(pwd);
00376 return statusMake(INVALID_MAPTYPE, "%slinkmap type is not supported", pr);
00377 }
00378
00379 if (mtype != BitmapType) {
00380 unlink(dmpfile);
00381 unlink(dbc->dat[i].file);
00382 pop_dir(pwd);
00383 return statusMake(INVALID_MAPTYPE, "%smap type is invalid: '%d'", pr, mtype);
00384 }
00385
00386 sizeslot = ((dbc->dat[i].mtype == BitmapType) ? dbc->dat[i].sizeslot :
00387 sizeof(eyedblib::int32));
00388
00389 DatafileDesc dat = dbh->dat(i);
00390 MapHeader *xmp = dat.mp();
00391
00392 xmp->pow2() = power2(sizeslot);
00393 if (xmp->pow2() < 0) {
00394 unlink(dmpfile);
00395 unlink(dbc->dat[i].file);
00396 pop_dir(pwd);
00397 return statusMake(INVALID_SIZESLOT,
00398 "%sslot size %d is not a power of two", pr, sizeslot);
00399 }
00400
00401 if (mtype == BitmapType &&
00402 (sizeslot < MIN_SIZE_SLOT ||
00403 sizeslot > MAX_SIZE_SLOT ||
00404 (pgsize % sizeslot) != 0)) {
00405 unlink(dmpfile);
00406 unlink(dbc->dat[i].file);
00407 pop_dir(pwd);
00408 return statusMake(INVALID_SIZESLOT,
00409 "dbCreate: slot size is invalid: `%d'", sizeslot);
00410 }
00411
00412 xmp->sizeslot() = sizeslot;
00413 xmp->mtype() = mtype;
00414 xmp->sizeslot() = dbc->dat[i].sizeslot;
00415 unsigned long long nslots_l;
00416 if (mtype == BitmapType) {
00417 nslots_l = KB2SLOT(dbc->dat[i].maxsize, xmp->pow2());
00418 }
00419 else {
00420 nslots_l = ((unsigned long long)(dbc->dat[i].maxsize)*ONE_K)/32;
00421 }
00422
00423 if (status = checkDatafileSize(nslots_l, dbc->dat[i].file, xmp->sizeslot(), dbc->dat[i].maxsize)) {
00424 unlink(dmpfile);
00425 unlink(dbc->dat[i].file);
00426 pop_dir(pwd);
00427 return status;
00428 }
00429
00430 xmp->nslots() = (unsigned int)nslots_l;
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441 if (status = syscheck(pr, close(dbfd->fd_dmp[i]),
00442 "closing data map file: '%s'", dmpfile)) {
00443 unlink(dmpfile);
00444 unlink(dbc->dat[i].file);
00445 pop_dir(pwd);
00446 return status;
00447 }
00448
00449 pop_dir(pwd);
00450
00451 if (out_place) {
00452 h2x_mapHeader(dbh->dat(i).mp(), xmp);
00453 }
00454
00455 return Success;
00456 }
00457
00458 static char **datfilesBuild(unsigned int ndat)
00459 {
00460 char **datfiles = new char *[ndat];
00461 for (int n = 0; n < ndat; n++) {
00462 char buf[16];
00463 sprintf(buf, "%d", n);
00464 datfiles[n] = strdup(buf);
00465 }
00466
00467 return datfiles;
00468 }
00469
00470 static void datfilesFree(char **datfiles, unsigned int ndat)
00471 {
00472 for (int n = 0; n < ndat; n++)
00473 free(datfiles[n]);
00474
00475 delete [] datfiles;
00476 }
00477
00478 Status
00479 getFileMaskGroup(mode_t &file_mode, gid_t &file_gid, mode_t file_mask, const char *file_group)
00480 {
00481 file_mode = (file_mask | DEFAULT_CREATION_MODE);
00482 if (file_group && *file_group) {
00483 struct group *grp = getgrnam(file_group);
00484 if (!grp) {
00485 return statusMake(DATABASE_CREATION_ERROR, "invalid file group: %s", file_group);
00486 }
00487 file_gid = grp->gr_gid;
00488 }
00489 else
00490 file_gid = (gid_t)-1;
00491
00492 return Success;
00493 }
00494
00495 Status
00496 dbCreate(const char *dbfile, unsigned int version,
00497 const DbCreateDescription *dbc, mode_t file_mask, const char *file_group)
00498 {
00499 DBFD dbfd;
00500 int dbid = dbc->dbid, sizeslot, i,
00501 ndat = dbc->ndat, szhead, rszhead;
00502
00503 Oid::NX nbobjs = dbc->nbobjs;
00504 int n;
00505 DbHeader dbh;
00506
00507 DbHandle *pdbh;
00508 DbShmHeader dbhshm;
00509 char *p;
00510 Status status;
00511 int dbfile_len = strlen(dbfile);
00512
00513 #undef PR
00514 #define PR "dbCreate: "
00515 mode_t file_mode;
00516 gid_t file_gid;
00517 status = getFileMaskGroup(file_mode, file_gid, file_mask, file_group);
00518 if (status)
00519 return status;
00520
00521 status = check_dbCreate_1(PR, dbid, dbfile, nbobjs, ndat);
00522 if (status)
00523 return status;
00524
00525 status = check_dbCreate_2(PR, dbfile, &dbfd, file_mode, file_gid);
00526 if (status)
00527 return status;
00528
00529 status = check_dbCreate_3(PR, dbfile, &dbfd, file_mode, file_gid);
00530 if (status)
00531 return dbcreate_error(status, dbfile, dbc, 0, &dbfd);
00532
00533 memset(&dbhshm, 0, sizeof(dbhshm));
00534 dbhshm.magic = MAGIC;
00535 dbhshm.version = h2x_u32(version);
00536 if ((n = write(dbfd.shmfd, (char *)&dbhshm, sizeof(dbhshm))) !=
00537 sizeof(dbhshm))
00538 return dbcreate_error(statusMake(DATABASE_CREATION_ERROR, PR "unexpected writing header in shmfile: '%s'", shmfileGet(dbfile)),
00539 dbfile, dbc, 0, &dbfd);
00540
00541 if (status = syscheck(PR, close(dbfd.shmfd), "closing shm file: '%s'", shmfileGet(dbfile)))
00542 return dbcreate_error(status, dbfile, dbc, 0, &dbfd);
00543
00544 dbh.memzero();
00545
00546 char pwd[DEFAULT_PWD_SIZE];
00547 status = push_dir(dbfile, pwd, sizeof pwd);
00548 if (status) return status;
00549
00550 Boolean ok = False;
00551 dbh.__magic() = MAGIC;
00552 for (i = 0; i < ndat; i++) {
00553 Boolean is_null;
00554 status = checkDatafile(PR, dbfile, &dbh, dbc, i, &dbfd,
00555 file_mode, file_gid, True, &is_null);
00556 if (!is_null) ok = True;
00557 if (status) {
00558 pop_dir(pwd);
00559 return dbcreate_error(status, dbfile, dbc, i, &dbfd);
00560 }
00561 }
00562
00563 if (!ok) {
00564 pop_dir(pwd);
00565 return statusMake(DATABASE_CREATION_ERROR, PR " at least one datafile must not be null");
00566 }
00567
00568 strcpy(dbh.shmfile(), shmfileGet(dbfile));
00569 dbh.__ndat() = dbc->ndat;
00570 dbh.__lastidxbusy() = 0;
00571 dbh.__curidxbusy() = 0;
00572 dbh.__dbid() = dbid;
00573 dbh.__guest_uid() = (short)INVALID_UID;
00574 dbh.__nbobjs() = nbobjs;
00575
00576 dbh.state() = OPENING_STATE;
00577
00578 DbHeader xdbh;
00579 h2x_dbHeader(&xdbh, &dbh);
00580
00581 if ((n = write(dbfd.dbsfd, xdbh._addr(), DbHeader_SIZE)) != DbHeader_SIZE) {
00582 pop_dir(pwd);
00583 return dbcreate_error(statusMake(DATABASE_CREATION_ERROR, PR "unexpected error reported by write on database file: '%s'", dbfile), dbfile, dbc, ndat, &dbfd);
00584 }
00585
00586 if (status = syscheck(PR, close(dbfd.dbsfd), "closing database file: '%s'", dbfile)) {
00587 pop_dir(pwd);
00588 return dbcreate_error(status, dbfile, dbc, ndat, &dbfd);
00589 }
00590
00591 if (status = syscheck(PR, close(dbfd.ompfd), "closing map oid file: '%s'",
00592 objmapfileGet(dbfile))) {
00593 pop_dir(pwd);
00594 return dbcreate_error(status, dbfile, dbc, ndat, &dbfd);
00595 }
00596
00597 if (status = ESM_dbOpen(dbfile, VOLRW, 0, 0, 0, 1, 0, 0, &pdbh)) {
00598 pop_dir(pwd);
00599 return dbcreate_error(statusMake(DATABASE_CREATION_ERROR, PR "database open error reported: '%s'", statusGet(status)), dbfile, dbc, ndat, &dbfd);
00600 }
00601
00602 char **datfiles = datfilesBuild(ndat);
00603
00604
00605 if (status = ESM_dspCreate(pdbh, defDsp, (const char **)datfiles, ndat, True)) {
00606 datfilesFree(datfiles, ndat);
00607 pop_dir(pwd);
00608 return dbcreate_error(statusMake(DATABASE_CREATION_ERROR, PR "database open error reported: '%s'", statusGet(status)), dbfile, dbc, ndat, &dbfd);
00609 }
00610
00611
00612 datfilesFree(datfiles, ndat);
00613
00614 if (status = ESM_dspSetDefault(pdbh, defDsp, True)) {
00615 pop_dir(pwd);
00616 return dbcreate_error(statusMake(DATABASE_CREATION_ERROR, PR "database open error reported: '%s'", statusGet(status)), dbfile, dbc, ndat, &dbfd);
00617 }
00618
00619 if (status = protectionInit(pdbh)) {
00620 pop_dir(pwd);
00621 return dbcreate_error(statusMake(DATABASE_CREATION_ERROR, PR "database protection init error reported: '%s'", statusGet(status)), dbfile, dbc, ndat, &dbfd);
00622 }
00623
00624 pop_dir(pwd);
00625 DbHeader _xpdbh(pdbh->vd->dbs_addr);
00626 _xpdbh.state() = OPENED_STATE;
00627
00628 ESM_dbClose(pdbh);
00629
00630 return Success;
00631 }
00632
00633 Status
00634 dbDelete(const char *dbfile)
00635 {
00636 Status s;
00637 DbHandle *dbh;
00638 int i;
00639
00640 #undef PR
00641 #define PR "dbDelete: "
00642 if (s = ESM_dbOpen(dbfile, VOLRW, 0, 0, 0, 0, 0, 0, &dbh))
00643 return s;
00644
00645 char pwd[DEFAULT_PWD_SIZE];
00646 s = push_dir(dbfile, pwd, sizeof pwd);
00647 if (s) return s;
00648
00649 DbHeader _dbh(DBSADDR(dbh));;
00650 unsigned int ndat = x2h_u32(_dbh.__ndat());
00651 for (i = 0; i < ndat; i++) {
00652 if (*_dbh.dat(i).file()) {
00653 if (unlink(_dbh.dat(i).file()) < 0) {
00654 pop_dir(pwd);
00655 return fcouldnot(PR, "unlink", _dbh.dat(i).file());
00656 }
00657
00658 if (unlink(dmpfileGet(_dbh.dat(i).file())) < 0) {
00659 pop_dir(pwd);
00660 return fcouldnot(PR, "unlink", dmpfileGet(_dbh.dat(i).file()));
00661 }
00662 }
00663 }
00664
00665 ESM_dbClose(dbh);
00666
00667 if (unlink(dbfile) < 0) {
00668 pop_dir(pwd);
00669 return fcouldnot(PR, "unlink", dbfile);
00670 }
00671
00672 if (unlink(shmfileGet(dbfile)) < 0) {
00673 pop_dir(pwd);
00674 return fcouldnot(PR, "unlink", shmfileGet(dbfile));
00675 }
00676
00677 if (unlink(objmapfileGet(dbfile)) < 0) {
00678 pop_dir(pwd);
00679 return fcouldnot(PR, "unlink", objmapfileGet(dbfile));
00680 }
00681
00682 return pop_dir(pwd);
00683 }
00684
00685 Status
00686 dbInfo(const char *dbfile, DbInfoDescription *info)
00687 {
00688 DbHeader xdbh;
00689 int fd;
00690 Status se;
00691
00692 #undef PR
00693 #define PR "dbInfo: "
00694 if (se = checkFileAccess(DATABASE_OPEN_FAILED, "database file",
00695 dbfile, R_OK))
00696 return se;
00697
00698 if ((se = dopen(PR, dbfile, O_RDONLY, &fd, 0)) != Success)
00699 return se;
00700
00701 if (se = syscheckn(PR, read(fd, xdbh._addr(), DbHeader_SIZE), DbHeader_SIZE,
00702 "reading database file: '%s'", dbfile))
00703 return se;
00704
00705 DbHeader dbh;
00706 x2h_dbHeader(&dbh, &xdbh);
00707
00708 if (dbh.__magic() != MAGIC) {
00709 if (se = syscheck(PR, close(fd), "closing database file: '%s'",
00710 dbfile))
00711 return se;
00712 return statusMake(INVALID_DBFILE,
00713 PR "database file '%s' is not a valid eyedbsm database "
00714 "file", dbfile);
00715 }
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727 info->dbid = dbh.__dbid();
00728 info->ndat = dbh.__ndat();
00729 info->ndsp = dbh.__ndsp();
00730 info->nbobjs = dbh.__nbobjs();
00731
00732 if (se = fileSizesGet(dbfile,
00733 info->dbsfilesize, info->dbsfileblksize))
00734 return se;
00735
00736 if (se = fileSizesGet(objmapfileGet(dbfile),
00737 info->ompfilesize, info->ompfileblksize))
00738 return se;
00739
00740 if (se = fileSizesGet(shmfileGet(dbfile),
00741 info->shmfilesize, info->shmfileblksize))
00742 return se;
00743
00744 if (se = syscheck(PR, close(fd), "closing database file: '%s'", dbfile))
00745 return se;
00746
00747 for (int i = 0; i < dbh.__ndsp(); i++) {
00748 Dataspace *ds = &info->dsp[i];
00749 DataspaceDesc _dsd = dbh.dsp(i);
00750 DataspaceDesc *dsd = &_dsd;
00751
00752 strcpy(ds->name, dsd->name());
00753 ds->ndat = dsd->__ndat();
00754 memcpy(ds->datid, dsd->__datid_ref(), sizeof(short) * dsd->__ndat());
00755 }
00756
00757 for (int i = 0; i < dbh.__ndat(); i++) {
00758 Datafile *df = &info->dat[i];
00759 DatafileDesc _dfd = dbh.dat(i);
00760 DatafileDesc *dfd = &_dfd;
00761
00762 strcpy(df->file, dfd->file());
00763 strcpy(df->name, dfd->name());
00764 df->dspid = getDataspace_inplace(&dbh, i);
00765 df->dtype = getDatType_inplace(&dbh, i);
00766 df->maxsize = dfd->__maxsize();
00767 df->mtype = dfd->mp()->mtype();
00768 df->sizeslot = dfd->mp()->sizeslot();
00769
00770 if (!access(df->file, R_OK|W_OK))
00771 df->extflags = R_OK|W_OK;
00772 else if (!access(df->file, W_OK))
00773 df->extflags = W_OK;
00774 else if (!access(df->file, R_OK))
00775 df->extflags = R_OK;
00776 else
00777 df->extflags = 0;
00778 }
00779
00780 return Success;
00781 }
00782
00783
00784
00785
00786
00787 #define XSTR(F) ((F) ? "copy" : "move")
00788
00789
00790 char *
00791 makefile(const char *dir, const char *file)
00792 {
00793 static int buf_ind;
00794 #define NN 8
00795 static char *buf[NN];
00796 char *s;
00797
00798 if (buf_ind >= NN)
00799 buf_ind = 0;
00800
00801 free(buf[buf_ind]);
00802
00803 if (!dir || !*dir || *file == '/') {
00804 buf[buf_ind] = strdup(file);
00805 return buf[buf_ind++];
00806 }
00807
00808 s = (char *)m_malloc(strlen(dir)+strlen(file)+2);
00809 strcpy(s, dir);
00810 strcat(s, "/");
00811 strcat(s, file);
00812
00813 buf[buf_ind] = s;
00814 return buf[buf_ind++];
00815 }
00816
00817 Status
00818 copyfile(const char *from, const char *to,
00819 const char *fromdbdir, const char *todbdir,
00820 int sparsify)
00821 {
00822 int fd1, fd2;
00823 struct stat st;
00824 Status se;
00825 char *xfrom = makefile(fromdbdir, from);
00826 char *xto = makefile(todbdir, to);
00827
00828 #if 1
00829 sparsify = 0;
00830 #endif
00831
00832 errno = 0;
00833
00834 #ifdef MVCP_TRACE
00835 printf("copying '%s' to '%s' [%s . %s]\n", xfrom, xto, fromdbdir, todbdir);
00836 #endif
00837
00838 if (!access(xto, F_OK))
00839 return syserror("target file '%s' already exists", xto);
00840
00841 if ((fd1 = open(xfrom, O_RDONLY)) < 0)
00842 return syserror("opening file '%s' for reading", xfrom);
00843
00844 if ((fd2 = creat(xto, DEFAULT_CREATION_MODE)) < 0) {
00845 close(fd1);
00846 return syserror("creating file '%s'", xto);
00847 }
00848
00849
00850 if (fstat(fd1, &st) < 0)
00851 return syserror("stating file '%s'", xfrom);
00852 fchmod(fd2, st.st_mode);
00853
00854 if (!sparsify) {
00855 char buf[2048];
00856 int n;
00857 while ((n = read(fd1, buf, sizeof buf)) > 0)
00858 if (write(fd2, buf, n) != n) {
00859 close(fd1); close(fd2); unlink(xto);
00860 return syserror("writing to file '%s'", xto);
00861 }
00862
00863 if (n < 0) {
00864 close(fd1); close(fd2); unlink(xto);
00865 return syserror("reading from file '%s'", xfrom);
00866 }
00867 }
00868 else {
00869 char buf[512];
00870 static char const zero[sizeof buf] = { 0 };
00871 int n;
00872 off_t zeros = 0;
00873
00874 while ((n = read(fd1, buf, sizeof buf)) > 0) {
00875 if (memcmp(buf, zero, n) == 0)
00876 zeros += n;
00877 else {
00878 if (zeros) {
00879 if (lseek(fd2, zeros, SEEK_CUR) < 0) {
00880 close(fd1); close(fd2); unlink(xto);
00881 return syserror("seeking file '%s'", xto);
00882 }
00883 zeros = 0;
00884 }
00885 if (write(fd2, buf, n) != n) {
00886 close(fd1); close(fd2); unlink(xto);
00887 return syserror("writing to file '%s'", xto);
00888 }
00889 }
00890 }
00891
00892 if (n < 0) {
00893 close(fd1); close(fd2); unlink(xto);
00894 return syserror("reading from file '%s'", xfrom);
00895 }
00896
00897 if (zeros) {
00898 if (lseek(fd2, zeros - 1, SEEK_CUR) < 0) {
00899 close(fd1); close(fd2); unlink(xto);
00900 return syserror("seeking file '%s'", xto);
00901 }
00902
00903 if (write(fd2, zero, 1) != 1) {
00904 close(fd1); close(fd2); unlink(xto);
00905 return syserror("writing to file '%s'", xto);
00906 }
00907 }
00908 }
00909
00910 close(fd1);
00911 close(fd2);
00912 return Success;
00913 }
00914
00915 Status
00916 renamefile(char const * from, char const * to,
00917 const char *fromdbdir, const char *todbdir, int sparsify)
00918 {
00919 char *xfrom = makefile(fromdbdir, from);
00920 char *xto = makefile(todbdir, to);
00921
00922 #ifdef MVCP_TRACE
00923 printf("renaming '%s' to '%s' [%s . %s]\n", from, to, fromdbdir, todbdir);
00924 #endif
00925
00926 if (rename(xfrom, xto) < 0) {
00927 Status se;
00928 if (errno != EXDEV)
00929 return syserror("renaming file '%s' to '%s'", xfrom, xto);
00930
00931 #ifdef MVCP_TRACE
00932 printf("cannot rename file across 2 file systems\n");
00933 #endif
00934
00935 se = copyfile(from, to, fromdbdir, todbdir, sparsify);
00936 if (se)
00937 return statusMake(se->err, "renaming file '%s' to '%s': %s", xfrom, xto, se->err_msg);
00938
00939 if (unlink(xfrom) < 0)
00940 return syserror("unlinking file '%s'", xfrom);
00941 }
00942
00943 return Success;
00944 }
00945
00946 static Status
00947 mvcp_immediate(const char *xstr, const char *from,
00948 const char *to, const char *fromdbdir, const char *todbdir,
00949 Status (*mvcp)(const char *, const char *,
00950 const char *, const char *, int))
00951 {
00952 Status s;
00953 if (strcmp(from, to) && (s = mvcp(from, to, fromdbdir, todbdir, 1)))
00954 return statusMake(INVALID_SHMFILES_COPY,
00955 "%s operation failed between "
00956 "'%s' and '%s': %s",
00957 xstr, from, to, s->err_msg);
00958 return Success;
00959 }
00960
00961 static Status
00962 mvcp_datafiles(DbCreateDescription *dbc,
00963 DbHandle *dbh,
00964 DbHeader *db_header, int fd,
00965 const char *fromdbdir, const char *todbdir,
00966 const char *dbfile,
00967 int flag,
00968 Status (*mvcp)(const char *, const char *,
00969 const char *, const char *, int))
00970 {
00971 int i;
00972 Status s;
00973 for (i = 0; i < dbc->ndat; i++) {
00974 DbHeader _dbh(DBSADDR(dbh));
00975 char *from = makefile(fromdbdir, _dbh.dat(i).file());
00976 char *to = makefile(todbdir, dbc->dat[i].file);
00977
00978 if (strcmp(from, to)) {
00979 if (s = mvcp(_dbh.dat(i).file(),
00980 dbc->dat[i].file, fromdbdir, todbdir, 0))
00981 return statusMake(INVALID_DATAFILES_COPY,
00982 "%s operation failed between "
00983 "'%s' and '%s': %s",
00984 XSTR(flag), from, to, s->err_msg);
00985
00986 if (s = mvcp(dmpfileGet(_dbh.dat(i).file()),
00987 dmpfileGet(dbc->dat[i].file), fromdbdir, todbdir, 0))
00988 return statusMake(INVALID_DATAFILES_COPY,
00989 "%s operation failed between "
00990 "'%s' and '%s': %s",
00991 XSTR(flag),
00992 dmpfileGet(from),
00993 dmpfileGet(to),
00994 s->err_msg);
00995 }
00996
00997 strcpy(db_header->dat(i).file(), dbc->dat[i].file);
00998
00999 if (lseek(fd, 0, 0) < 0)
01000 return syserror("rewing database file '%s'", dbfile);
01001
01002 if (write(fd, db_header->_addr(), DbHeader_SIZE) != DbHeader_SIZE)
01003 return syserror("writing database file '%s'", dbfile);
01004 }
01005
01006 return Success;
01007 }
01008
01009 static Status
01010 mvcp_check(const char *fname, DbCreateDescription *dbc,
01011 DbHandle *dbh,
01012 const char *fromdbdir, const char *todbdir,
01013 const char *dbfile, const char *ndbfile,
01014 int flag)
01015 {
01016 int i;
01017 Status s;
01018
01019 DbHeader _dbh(DBSADDR(dbh));
01020 unsigned int ndat = x2h_u32(_dbh.__ndat());
01021 if (dbc->ndat != ndat)
01022 return statusMake(INVALID_DATAFILE_CNT,
01023 "%s: different datafiles number: `%d' vs. `%d'",
01024 fname, dbc->ndat, ndat);
01025
01026 for (i = 0; i < dbc->ndat; i++) {
01027 unsigned int maxsize = x2h_u32(_dbh.dat(i).__maxsize());
01028 if (!dbc->dat[i].maxsize)
01029 dbc->dat[i].maxsize = maxsize;
01030 else if (dbc->dat[i].maxsize != maxsize)
01031 return statusMake(INVALID_MAXSIZE,
01032 "%s: different maximum size: `%d' vs. `%d' "
01033 "on datafile #%d",
01034 fname, dbc->dat[i].maxsize,
01035 maxsize, i);
01036 }
01037
01038 if (!strcmp(dbfile, ndbfile)) {
01039 if (flag)
01040 return statusMake(DBFILES_IDENTICAL,
01041 "%s: identical database files: '%s'",
01042 fname, dbfile);
01043 }
01044
01045 if (flag) {
01046 if (!access(ndbfile, F_OK))
01047 return statusMake(DBFILE_ALREADY_EXISTS,
01048 "%s: target database file already exists: '%s'",
01049 fname, ndbfile);
01050 if (!access(shmfileGet(ndbfile), F_OK))
01051 return statusMake(SHMFILE_ALREADY_EXISTS,
01052 "%s: target shm file already exists: '%s'",
01053 fname, shmfileGet(ndbfile));
01054 if (!access(objmapfileGet(ndbfile), F_OK))
01055 return statusMake(OBJMAPFILE_ALREADY_EXISTS,
01056 "%s: target oid map file already exists: '%s'",
01057 fname, objmapfileGet(ndbfile));
01058 }
01059
01060
01061 for (i = 0; i < dbc->ndat; i++) {
01062 char *to = makefile(todbdir, dbc->dat[i].file);
01063 char *from = makefile(fromdbdir, _dbh.dat(i).file());
01064
01065 if (flag && !strcmp(from, to))
01066 return statusMake(DATAFILES_IDENTICAL,
01067 "%s: identical data files: '%s'",
01068 fname, to);
01069 if (strcmp(from, to) && !access(to, F_OK))
01070 return statusMake(DATAFILE_ALREADY_EXISTS,
01071 "%s: target data file already exists: '%s'",
01072 fname, to);
01073 }
01074 return Success;
01075 }
01076
01077 static Status
01078 mvcp_realize(const char *fname, const char *dbfile,
01079 const DbMoveDescription *xdmv, int flag)
01080 {
01081 DbMoveDescription dmv = *xdmv;
01082 DbHandle *dbh;
01083 DbHeader db_header;
01084 Status s;
01085 DbCreateDescription *dbc = &dmv.dcr;
01086 int i, fd;
01087 Status (*mvcp)(const char *, const char *,
01088 const char *, const char *, int);
01089 const char *fromdbdir = get_dir(dbfile);
01090 const char *todbdir = get_dir(dmv.dbfile);
01091
01092 if (s = ESM_dbOpen(dbfile, VOLREAD, 0, 0, 0, 0, 0, 0, &dbh) )
01093 return s;
01094
01095 if (s = mvcp_check(fname, dbc, dbh, fromdbdir, todbdir,
01096 dbfile, dmv.dbfile, flag))
01097 return s;
01098
01099 mvcp = (flag ? copyfile : renamefile);
01100
01101 if (strcmp(dbfile, dmv.dbfile)) {
01102 if (s = mvcp(dbfile, dmv.dbfile, fromdbdir, todbdir, 1))
01103 return statusMake(INVALID_DBFILES_COPY,
01104 "%s operation failed between "
01105 "'%s' and '%s': %s",
01106 XSTR(flag), dbfile, dmv.dbfile,
01107 s->err_msg);
01108 }
01109
01110 if ((fd = open(dmv.dbfile, O_RDWR)) >= 0) {
01111 if (read(fd, db_header._addr(), DbHeader_SIZE) != DbHeader_SIZE)
01112 return syserror("reading database file '%s'", dmv.dbfile);
01113 }
01114 else
01115 return statusMake(INVALID_DBFILE_ACCESS,
01116 "cannot open database file for writing: '%s'",
01117 dmv.dbfile);
01118
01119 if (s = mvcp_immediate(XSTR(flag),
01120 shmfileGet(dbfile), shmfileGet(dmv.dbfile),
01121 fromdbdir, todbdir, mvcp))
01122 return s;
01123
01124 if (s = mvcp_immediate(XSTR(flag),
01125 objmapfileGet(dbfile), objmapfileGet(dmv.dbfile),
01126 fromdbdir, todbdir, mvcp))
01127 return s;
01128
01129 if (s = mvcp_datafiles(dbc, dbh, &db_header, fd, fromdbdir, todbdir,
01130 dmv.dbfile, flag, mvcp))
01131 return s;
01132
01133 close(fd);
01134
01135 ESM_dbClose(dbh);
01136
01137 if (s = ESM_dbOpen(dmv.dbfile, VOLREAD, 0, 0, 0, 0, 0, 0, &dbh))
01138 return s;
01139
01140 ESM_dbClose(dbh);
01141 return Success;
01142 }
01143
01144 Status
01145 dbMove(const char *dbfile, const DbMoveDescription *dmv)
01146 {
01147 return mvcp_realize("dbMove", dbfile, dmv, 0);
01148 }
01149
01150 Status
01151 dbCopy(const char *dbfile, const DbCopyDescription *dcp)
01152 {
01153 return mvcp_realize("dbCopy", dbfile, dcp, 1);
01154 }
01155
01156 Status
01157 dbRelocate(const char *dbfile, const DbRelocateDescription *rel)
01158 {
01159 DbHeader xdbh;
01160 int fd, i;
01161 Status se;
01162
01163 #undef PR
01164 #define PR "dbRelocate: "
01165 if ( (fd = open(dbfile, O_RDWR)) < 0)
01166 return statusMake(INVALID_DBFILE_ACCESS, PR "cannot open database file for writing: '%s'", dbfile);
01167
01168 if (se = syscheckn(PR, read(fd, xdbh._addr(), DbHeader_SIZE), DbHeader_SIZE, ""))
01169 return se;
01170
01171 DbHeader dbh;
01172 x2h_dbHeader(&dbh, &xdbh);
01173 if (dbh.__magic() != MAGIC)
01174 return statusMake(INVALID_DBFILE, PR "database file '%s' is not a valid eyedbsm database file", dbfile);
01175
01176
01177
01178
01179
01180
01181
01182
01183 if (rel->ndat != dbh.__ndat()) {
01184 close(fd);
01185 return statusMake_s(INVALID_DATAFILE_CNT);
01186 }
01187
01188 for (i = 0; i < dbh.__ndat(); i++)
01189 strcpy(dbh.dat(i).file(), rel->file[i]);
01190
01191 if (se = syscheck(PR, lseek(fd, 0, 0), ""))
01192 return se;
01193
01194 h2x_dbHeader(&xdbh, &dbh);
01195 if (se = syscheckn(PR, write(fd, xdbh._addr(), DbHeader_SIZE), DbHeader_SIZE, ""))
01196 return se;
01197
01198 if (se = syscheck(PR, close(fd), ""))
01199 return se;
01200
01201 return Success;
01202 }
01203
01204
01205
01206
01207
01208
01209 static Status
01210 shmMap(const char *dbfile, size_t size, int shmfd, bool no_shm_access,
01211 void **pshm_addr, m_Map **pm_shm)
01212 {
01213 #undef PR
01214 #define PR "shmMap"
01215 int x;
01216 #ifndef MAP_NORESERVE
01217 #define MAP_NORESERVE 0
01218 #endif
01219 int flags = no_shm_access ? PROT_READ : PROT_READ|PROT_WRITE;
01220 for (x = 0; ; x++) {
01221 if (*pm_shm = m_mmap(0, size, flags,
01222 MAP_NORESERVE|MAP_SHARED, shmfd,
01223 0, (char **)pshm_addr, shmfileGet(dbfile), 0, 0)) {
01224 if (x)
01225 IDB_LOG(IDB_LOG_MMAP, ("m_mmap successfull in shmMap after %d attemps\n",
01226 x));
01227 break;
01228 }
01229
01230 if (x == MAXTRIES)
01231 return statusMake(MAP_ERROR, PR "shmfile '%s' cannot be mapped by eyedbsm server", shmfileGet(dbfile));
01232 IDB_LOG(IDB_LOG_MMAP, ("m_mmap failed in shmMap, tries again\n"));
01233 sleep(1);
01234 }
01235
01236 m_lock(*pm_shm);
01237
01238 return Success;
01239 }
01240
01241 static Status
01242 dbsUnmap(const char *dbfile, DbDescription *vd)
01243 {
01244 m_unlock(vd->m_dbs);
01245
01246 if (m_munmap(vd->m_dbs, (char *)vd->dbs_addr, DBS_DEFSIZE))
01247 return statusMake(MAP_ERROR, PR "database system file '%s' "
01248 "cannot be unmapped by eyedbsm server", dbfile);
01249
01250 return Success;
01251 }
01252
01253 static Status
01254 shmUnmap(const char *dbfile, DbDescription *vd, unsigned int size)
01255 {
01256 m_unlock(vd->m_shm);
01257
01258 if (m_munmap(vd->m_shm, (char *)vd->shm_addr_b, size))
01259 return statusMake(MAP_ERROR, PR "shmfile '%s' cannot be unmapped by eyedbsm server", shmfileGet(dbfile));
01260
01261 return Success;
01262 }
01263
01264 static Status
01265 shmMutexRelease(DbDescription *vd, DbShmHeader *shmh, unsigned int xid)
01266 {
01267 Status se;
01268
01269 if (xid && (se = DbMutexesRelease(vd, shmh, xid)))
01270 return se;
01271
01272 return Success;
01273 }
01274
01275 #define NO_BLOCK
01276 static void
01277 ESM_DbInitialize(DbDescription *vd, void *shm_addr, unsigned int shmsize)
01278 {
01279 DbMutexesInit(vd, (DbShmHeader *)shm_addr);
01280 ESM_transInit(vd, (char *)shm_addr, shmsize);
01281 }
01282
01283 static Status
01284 ESM_dbOpenPrologue(DbDescription *vd, DbShmHeader *shmh,
01285 unsigned int shmsize, const char *dbfile, int flags,
01286 unsigned int *pxid)
01287 {
01288 XMHandle *xmh;
01289 char hostname[256+1];
01290 bool no_shm_access = (vd->flags & NO_SHM_ACCESS) != 0;
01291
01292 #undef PR
01293 #define PR "dbOpenPrologue: "
01294
01295 if (shmh) {
01296 if (shmh->magic != MAGIC)
01297 return statusMake(INVALID_SHMFILE, PR "shm file is not a valid eyedbsm shm file: '%s'", shmfileGet(dbfile));
01298
01299 gethostname(hostname, sizeof(hostname)-1);
01300
01301 Mutex *mp = VD2MTX(vd, TRS);
01302
01303 DbMutexesLightInit(vd, shmh);
01304
01305
01306 xmh = XMOpen(((char *)shmh) + SHM_HEADSIZE, vd);
01307
01308 if (!xmh) {
01309
01310 return statusMake(INVALID_SHMFILE, PR "shm file is not a valid eyedbsm shm file: '%s'", shmfileGet(dbfile));
01311 }
01312
01313 Boolean mustUnlock = True;
01314 if (x2h_u32((unsigned int)shmh->hostid) != (unsigned int)gethostid() ||
01315 strncmp(shmh->arch, eyedblib::CompileBuiltin::getArch(), sizeof( shmh->arch))) {
01316 return statusMake(DATABASE_OPEN_FAILED,
01317 "cannot open database %s on "
01318 "computer %s (hostid=%d) [architecture %s]: "
01319 "database hold by computer %s (hostid=%d) [architecture %s]",
01320 dbfile, hostname, gethostid(), eyedblib::CompileBuiltin::getArch(), shmh->hostname, x2h_u32((unsigned int)shmh->hostid),
01321 shmh->arch);
01322 }
01323 }
01324
01325 if (backend) {
01326 *pxid = rpc_getpid();
01327
01328 if (!no_shm_access) {
01329 shmh->stat.total_db_access_cnt = h2x_u32(x2h_u32(shmh->stat.total_db_access_cnt)+1);
01330 shmh->stat.current_db_access_cnt = h2x_u32(x2h_u32(shmh->stat.current_db_access_cnt)+1);
01331 }
01332 }
01333 else {
01334 *pxid = import_xid;
01335 }
01336
01337
01338
01339
01340
01341
01342 IDB_LOG(IDB_LOG_DATABASE, ("dbOpenPrologue(%s) -> xid = %d [backend %d]\n", dbfile, *pxid,
01343 backend));
01344
01345 return Success;
01346 }
01347
01348 static void
01349 ESM_initHost(DbShmHeader *sm_shmh)
01350 {
01351 char hostname[256+1];
01352 gethostname(hostname, sizeof(hostname)-1);
01353 sm_shmh->hostid = x2h_u32(gethostid());
01354 strncpy(sm_shmh->hostname, hostname, sizeof(sm_shmh->hostname)-1);
01355 sm_shmh->hostname[sizeof(sm_shmh->hostname)-1] = 0;
01356 strncpy(sm_shmh->arch, eyedblib::CompileBuiltin::getArch(), sizeof( sm_shmh->arch));
01357 }
01358
01359 #define ESM_MMAP_WIDE_SEGMENT 2000
01360
01361 static OpenHints *
01362 get_default_hints()
01363 {
01364 static OpenHints hints = {SegmentMap, ESM_MMAP_WIDE_SEGMENT};
01365 return &hints;
01366 }
01367
01368 static bool TRACE_CLEANUP = (getenv("EYEDB_TRACE_CLEANUP") != 0);
01369 static bool SLEEP_CLEANUP = (getenv("EYEDB_SLEEP_CLEANUP") != 0);
01370
01371 static std::map<std::string, unsigned int> db_map;
01372
01373 static Status db_clean_shm(const char *dbfile, int *lkfd, int shmfd)
01374 {
01375 #undef PR
01376 #define PR "dbOpenPrologue: "
01377 errno = 0;
01378
01379 if (db_map.find(dbfile) != db_map.end()) {
01380 if (TRACE_CLEANUP) {
01381 fprintf(stderr, "eyedbsm: found database %s %d\n", dbfile, db_map[dbfile]);
01382 }
01383 db_map[dbfile]++;
01384 return Success;
01385 }
01386
01387 const char *lockfile = fileGet(dbfile, ".lck");
01388 if ((*lkfd = open(lockfile, O_RDWR)) < 0) {
01389 struct stat st;
01390 mode_t file_mode = DEFAULT_CREATION_MODE;
01391 if (stat(shmfileGet(dbfile), &st) >= 0) {
01392 file_mode = st.st_mode;
01393 }
01394
01395 int fd = fileCreate(lockfile, file_mode, (gid_t)-1);
01396 if (TRACE_CLEANUP) {
01397 fprintf(stderr, "eyedbsm: creating lockfile %s\n", lockfile);
01398 }
01399
01400 if (fd < 0) {
01401 return statusMake(INVALID_DBFILE,
01402 "%scannot create lock file: '%s' [%s]",
01403 PR, lockfile, strerror(errno));
01404 }
01405 close(fd);
01406
01407 if ((*lkfd = open(lockfile, O_RDWR)) < 0) {
01408 return statusMake(INVALID_DBFILE,
01409 "%scannot open lock file: '%s' [%s]",
01410 PR, lockfile, strerror(errno));
01411 }
01412 }
01413
01414 if (filelockX(*lkfd)) {
01415 if (TRACE_CLEANUP) {
01416 fprintf(stderr, "eyedbsm: cleaning up database %s %d %s\n", dbfile, errno, strerror(errno));
01417 }
01418
01419 dbCleanupRealize(shmfileGet(dbfile), shmfd);
01420
01421 if (SLEEP_CLEANUP) {
01422 int sl = atoi(getenv("EYEDB_SLEEP_CLEANUP"));
01423 if (TRACE_CLEANUP) {
01424 fprintf(stderr, "eyedbsm: waiting for %d seconds\n", sl);
01425 }
01426 sleep(sl);
01427 }
01428
01429 if (!filelockS(*lkfd)) {
01430 return statusMake(ERROR, PR "cannot open database '%s': cannot lock dbfile in share mode", dbfile);
01431 }
01432
01433 db_map[dbfile] = 1;
01434 return Success;
01435 }
01436
01437 if (TRACE_CLEANUP) {
01438 fprintf(stderr, "eyedbsm: does not clean up database %s %d %s\n", dbfile, errno, strerror(errno));
01439 }
01440
01441 for (int try_n = 0; !filelockS(*lkfd); try_n++) {
01442 #define MAX_TRY_LOCK_CNT 100
01443 if (try_n == MAX_TRY_LOCK_CNT) {
01444 return statusMake(ERROR, PR "cannot open database '%s': cannot lock dbfile in share mode", dbfile);
01445 }
01446 if (TRACE_CLEANUP) {
01447 fprintf(stderr, "eyedbsm: waiting before continuing...\n");
01448 }
01449 usleep(10000);
01450 }
01451
01452 if (TRACE_CLEANUP) {
01453 fprintf(stderr, "eyedbsm: continuing for database '%s'\n", dbfile);
01454 }
01455
01456 db_map[dbfile] = 1;
01457 return Success;
01458 }
01459
01460 Status
01461 ESM_dbOpen(const char *dbfile, int flags,
01462 const OpenHints *hints, int *id,
01463 void **pdblock, int create_mode, unsigned int xid,
01464 unsigned int *pversion, DbHandle **pdbh)
01465 {
01466 int hdfd, shmfd, ompfd, va, fop, i;
01467 int const opf = (flags & VOLREAD) ? O_RDONLY : O_RDWR;
01468 int const accflags = (flags & VOLREAD ? R_OK : R_OK|W_OK);
01469 bool no_shm_access = (flags & NO_SHM_ACCESS) != 0;
01470 size_t size;
01471 DbDescription *vd;
01472 DbHeader *dbh = NULL;
01473 Status se;
01474 Boolean suser = True;
01475 void *shm_addr;
01476 int x;
01477 size_t shmsize;
01478 unsigned int version;
01479
01480
01481
01482
01483
01484
01485
01486
01487 if (!hints)
01488 hints = get_default_hints();
01489
01490 if (hints->maph != WholeMap && hints->maph != SegmentMap)
01491 return statusMake(DATABASE_OPEN_FAILED, "invalid open hints %d",
01492 hints->maph);
01493 #undef PR
01494 #define PR "dbOpen: "
01495
01496 #ifdef TRACE
01497 utshm("ESM_dbOpen(%s)\n", dbfile);
01498 #endif
01499
01500 if (flags == (VOLRW|NO_SHM_ACCESS)) {
01501 return statusMake(INVALID_FLAG, PR "flag cannot be set to VOLRW|NO_SHM_ACCESS");
01502 }
01503
01504 if (flags != VOLREAD && flags != VOLRW && flags != (VOLREAD|NO_SHM_ACCESS)) {
01505 return statusMake(INVALID_FLAG, PR "flag is invalid: %u", flags);
01506 }
01507
01508 if (se = checkFileAccess(DATABASE_OPEN_FAILED, "shm file", shmfileGet(dbfile), accflags))
01509 return se;
01510
01511 vd = (DbDescription *)m_calloc(sizeof(DbDescription), 1);
01512
01513 #ifndef HAVE_EYEDBSMD
01514 smdcli_conn_t *conn = 0;
01515 #else
01516 smdcli_conn_t *conn = smdcli_open(smd_get_port());
01517 if (!conn) {
01518 free(vd);
01519 return statusMake(ERROR, "cannot connect to eyedbsmd on port "
01520 "%s", smd_get_port());
01521 }
01522 #ifdef HAVE_SEMAPHORE_POLICY_SYSV_IPC
01523 if (smdcli_init_getsems(conn, dbfile, vd->semkeys)) {
01524 free(vd);
01525 free(conn);
01526 return statusMake(ERROR, "protocol error with eyedbsmd on port "
01527 "%s", smd_get_port());
01528 }
01529 #else
01530 if (smdcli_init(conn, dbfile)) {
01531 free(vd);
01532 free(conn);
01533 return statusMake(ERROR, "protocol error with eyedbsmd on port "
01534 "%s", smd_get_port());
01535 }
01536 #endif
01537 #endif
01538
01539 if ((shmfd = shmfileOpen(dbfile, no_shm_access)) < 0) {
01540 free(vd);
01541 return statusMake(INVALID_SHMFILE_ACCESS, PR "shm file '%s'",
01542 shmfileGet(dbfile));
01543 }
01544
01545 vd->shmfd = shmfd;
01546 vd->conn = conn;
01547
01548 if ((ompfd = objmapfileOpen(dbfile, opf)) < 0) {
01549 free(vd);
01550 return statusMake(INVALID_OBJMAP_ACCESS, PR "objmap file '%s'",
01551 objmapfileGet(dbfile));
01552 }
01553
01554 shmsize = fdSizeGet(shmfd);
01555
01556 if ((se = shmMap(dbfile, shmsize, shmfd, no_shm_access, (void **)&vd->shm_addr_b,
01557 &vd->m_shm)) != Success) {
01558 free(vd);
01559 return se;
01560 }
01561
01562 vd->shm_addr = vd->shm_addr_b;
01563
01564 if (se = checkFileAccess(DATABASE_OPEN_FAILED, "database file", dbfile, accflags)) {
01565 free(vd);
01566 return se;
01567 }
01568
01569 if ((se = dopen(PR, dbfile, opf, &hdfd, &suser)) != Success) {
01570 free(vd);
01571 return se;
01572 }
01573
01574 DbHeader xdbh;
01575 if (se = syscheckn(PR, read(hdfd, xdbh._addr(), DbHeader_SIZE), DbHeader_SIZE, "")) {
01576 free(vd);
01577 free(dbh);
01578 return se;
01579 }
01580
01581 #ifndef HAVE_EYEDBSMD
01582 if (!no_shm_access) {
01583 if (se = db_clean_shm(dbfile, &vd->lkfd, shmfd)) {
01584 free(vd);
01585 free(dbh);
01586 return se;
01587 }
01588 }
01589 #endif
01590
01591 dbh = new DbHeader();
01592 x2h_dbHeader(dbh, &xdbh);
01593
01594 if (dbh->__magic() != MAGIC) {
01595 free(vd);
01596 delete dbh;
01597 return statusMake(INVALID_DBFILE, PR "database file '%s' is not a valid eyedbsm database file", dbfile);
01598 }
01599
01600 shm_addr = vd->shm_addr;
01601
01602 version = x2h_u32(((DbShmHeader *)shm_addr)->version);
01603
01604 if (pversion && *pversion && version > *pversion) {
01605 char str_version[32];
01606 char str_pversion[32];
01607 strcpy(str_version, string_version(version));
01608 strcpy(str_pversion, string_version(*pversion));
01609 free(vd);
01610 delete dbh;
01611 return statusMake(ERROR, "version of database '%s' (%s) is upper "
01612 "than the EyeDB version (%s): cannot be opened",
01613 dbfile,
01614 str_version, str_pversion);
01615 }
01616
01617 vd->version = version;
01618
01619 if (no_shm_access) {
01620 shm_addr = vd->shm_addr = 0;
01621 }
01622
01623
01624 fop = ((flags & VOLREAD) ? PROT_READ : PROT_READ|PROT_WRITE);
01625 vd->dbid = dbh->__dbid();
01626 vd->flags = flags;
01627 vd->rsuser = vd->suser = suser;
01628 vd->hints = *hints;
01629
01630 #ifdef ESM_DBG
01631 printf("FLAGS %d\n", flags);
01632 #endif
01633
01634 if (!(vd->m_dbs = m_mmap(0, DBS_DEFSIZE, fop, MAP_SHARED, hdfd, 0,
01635 (char **)&vd->dbs_addr, dbfile, 0, 0))) {
01636 shmUnmap(dbfile, vd, shmsize);
01637 free(vd);
01638 delete dbh;
01639 return statusMake(MAP_ERROR, "unexpected and unrecoverable mmap error in database opening process: '%s'", dbfile);
01640 }
01641
01642 m_lock(vd->m_dbs);
01643
01644 char pwd[DEFAULT_PWD_SIZE];
01645 se = push_dir(dbfile, pwd, sizeof pwd);
01646 if (se) return se;
01647
01648
01649 for (i = 0; i < dbh->__ndat(); i++) {
01650 if (!*dbh->dat(i).file()) {
01651 vd->m_dmp[i] = 0;
01652 vd->dmp_addr[i] = 0;
01653 continue;
01654 }
01655 const char *dmpfile = dmpfileGet(dbh->dat(i).file());
01656 int fd = open(dmpfile, opf);
01657 if (fd < 0) {
01658 pop_dir(pwd);
01659 return statusMake(DATABASE_OPEN_FAILED,
01660 PR "cannot open data map file '%s' for writing",
01661 dmpfile);
01662 }
01663
01664 size = DMP_SIZE(dbh->dat(i).mp()->mtype(), dbh->dat(i).mp()->nslots());
01665
01666 if (!(vd->m_dmp[i] = m_mmap(0, size, fop, MAP_SHARED, fd, 0,
01667 (char **)&vd->dmp_addr[i],
01668 dmpfileGet(dbh->dat(i).file()), 0, 0))) {
01669 shmUnmap(dbfile, vd, shmsize);
01670 dbsUnmap(dbfile, vd);
01671
01672 free(vd);
01673 delete dbh;
01674 pop_dir(pwd);
01675 perror("mmap");
01676 return statusMake(MAP_ERROR,
01677 "unexpected and unrecoverable mmap error in "
01678 "database opening process (dbfile='%s') for data map file: ", dbfile);
01679 }
01680
01681 m_lock(vd->m_dmp[i]);
01682 if (se = syscheck(PR, close(fd), "")) {
01683 delete dbh;
01684 free(vd);
01685 pop_dir(pwd);
01686 return se;
01687 }
01688 }
01689
01690
01691
01692
01693 size = OIDMAP_SIZE(dbh->__nbobjs());
01694
01695 if (!(vd->m_omp = m_mmap(0, size, fop, MAP_SHARED, ompfd, 0,
01696 (char **)&vd->omp_addr,
01697 objmapfileGet(dbfile), 0, 0))) {
01698 dbsUnmap(dbfile, vd);
01699 shmUnmap(dbfile, vd, shmsize);
01700
01701 free(vd);
01702 delete dbh;
01703 pop_dir(pwd);
01704 return statusMake(MAP_ERROR, "unexpected and unrecoverable mmap error in "
01705 "database opening process (dbfile: '%s') for object map file %s", dbfile,
01706 objmapfileGet(dbfile));
01707 }
01708
01709 m_lock(vd->m_omp);
01710
01711 if (se = syscheck(PR, close(hdfd), "")) {
01712 delete dbh;
01713 free(vd);
01714 pop_dir(pwd);
01715 return se;
01716 }
01717
01718 if (se = syscheck(PR, close(ompfd), "")) {
01719 delete dbh;
01720 free(vd);
01721 pop_dir(pwd);
01722 return se;
01723 }
01724
01725
01726 for (i = 0; i < dbh->__ndat(); i++) {
01727 vd->dmd[i].file = strdup(dbh->dat(i).file());
01728 if (!*dbh->dat(i).file()) {
01729 vd->dmd[i].fd = -1;
01730 continue;
01731 }
01732
01733 Status status;
01734 if (se = checkFileAccess(DATABASE_OPEN_FAILED, "datafile", dbh->dat(i).file(), accflags)) {
01735 delete dbh;
01736 free(vd);
01737 pop_dir(pwd);
01738 return se;
01739 }
01740
01741 if ((status = dopen(PR, dbh->dat(i).file(), opf, &vd->dmd[i].fd,
01742 &vd->suser)) != Success) {
01743 int j;
01744 for (j = 0; j < i; j++)
01745 if (vd->dmd[j].fd >= 0 &&
01746 (se = syscheck(PR, close(vd->dmd[j].fd), ""))) {
01747 delete dbh;
01748 free(vd);
01749 pop_dir(pwd);
01750 return se;
01751 }
01752
01753 delete dbh;
01754 free(vd);
01755 pop_dir(pwd);
01756 return status;
01757 }
01758
01759
01760
01761
01762
01763
01764 if (hints->maph == WholeMap) {
01765 if (!(vd->dmd[i].m_dat = m_mmap(0, (size_t)dbh->dat(i).__maxsize()*ONE_K,
01766 fop, MAP_SHARED, vd->dmd[i].fd, 0,
01767 (char **)&vd->dmd[i].addr,
01768 dbh->dat(i).file(), 0, 0))) {
01769 shmUnmap(dbfile, vd, shmsize);
01770 dbsUnmap(dbfile, vd);
01771 free(vd);
01772 delete dbh;
01773 pop_dir(pwd);
01774 return statusMake(MAP_ERROR,
01775 "unexpected and unrecoverable mmap error in "
01776 "database opening process (dbfile='%s') for data map file: ", dbfile,
01777 dbh->dat(i).file());
01778 }
01779
01780 m_lock(vd->dmd[i].m_dat);
01781 }
01782 else {
01783 vd->dmd[i].m_dat = 0;
01784 vd->dmd[i].addr = 0;
01785
01786 unsigned int mapwide = (hints->mapwide ? hints->mapwide : ESM_MMAP_WIDE_SEGMENT);
01787 vd->mapwide = mapwide * pgsize;
01788 vd->mapwide2 = vd->mapwide >> 1;
01789
01790 }
01791
01792 if (se = syscheck(PR, fcntl(vd->dmd[i].fd, F_SETFD, 1), "")) {
01793 delete dbh;
01794 free(vd);
01795 pop_dir(pwd);
01796 return se;
01797 }
01798 }
01799
01800 if (create_mode) {
01801 ESM_initHost((DbShmHeader *)shm_addr);
01802 ESM_DbInitialize(vd, shm_addr, shmsize);
01803 }
01804
01805 se = ESM_dbOpenPrologue(vd, (DbShmHeader *)shm_addr, shmsize, dbfile, flags,
01806 &xid);
01807
01808 if (se) {
01809 delete dbh;
01810 free(vd);
01811 pop_dir(pwd);
01812 return se;
01813 }
01814
01815 ALIGN4(vd->omp_addr);
01816
01817 *pdbh = (DbHandle *)m_calloc(sizeof(DbHandle), 1);
01818 (*pdbh)->vd = vd;
01819
01820 assert(!pdblock);
01821
01822 if (pdblock)
01823 *pdblock = &((DbShmHeader *)shm_addr)->dblock_W;
01824
01825 #if 1
01826 if (pversion)
01827 *pversion = version;
01828 #else
01829 if (pversion)
01830 *pversion = x2h_u32(((DbShmHeader *)shm_addr)->version);
01831 #endif
01832
01833 (*pdbh)->vd->xid = xid;
01834
01835 if (no_shm_access) {
01836 (*pdbh)->vd->trs_mh = 0;
01837 }
01838 else {
01839 (*pdbh)->vd->trs_mh = XMOpen(((char *)shm_addr) + SHM_HEADSIZE, vd);
01840 }
01841
01842
01843
01844
01845
01846
01847
01848
01849
01850
01851
01852
01853
01854
01855
01856 delete dbh;
01857
01858 (*pdbh)->dbfile = strdup(dbfile);
01859
01860 if (flags == VOLRW) {
01861 se = ESM_transactionsGarbage(*pdbh, True);
01862 if (se) {
01863 pop_dir(pwd);
01864 return se;
01865 }
01866 }
01867
01868
01869
01870 if (DbHeader((*pdbh)->vd->dbs_addr).state() == OPENING_STATE) {
01871 pop_dir(pwd);
01872 return Success;
01873 }
01874
01875 if (se = dbProtectionRunTimeUpdate(*pdbh)) {
01876 pop_dir(pwd);
01877 return se;
01878 }
01879
01880 pop_dir(pwd);
01881 return protectionRunTimeUpdate(*pdbh);
01882 }
01883
01884 int ESM_getOpenFlags(DbHandle const *dbh)
01885 {
01886 return dbh->vd->flags;
01887 }
01888
01889
01890
01891
01892
01893
01894 static Status
01895 ESM_dbCloseEpilogue(DbDescription *vd, DbShmHeader *shmh, unsigned int xid,
01896 int flags, const char *dbfile)
01897 {
01898 Status se;
01899 XMHandle *xmh;
01900 bool no_shm_access = (vd->flags & NO_SHM_ACCESS) != 0;
01901
01902 if (!no_shm_access) {
01903 xmh = XMOpen(((char *)shmh) + SHM_HEADSIZE, vd);
01904
01905 if (!xmh)
01906 return statusMake(INVALID_SHMFILE, PR "shm file is not a valid eyedbsm shm file: '%s'", shmfileGet(dbfile));
01907
01908 IDB_LOG(IDB_LOG_DATABASE, ("dbCloseEpilogue(%s) #1\n", dbfile));
01909
01910
01911 shmh->stat.current_db_access_cnt--;
01912
01913 if (se = ESM_transactionsRelease(vd, shmh, dbfile, xid, xmh, 0))
01914 return se;
01915
01916 if (se = shmMutexRelease(vd, shmh, xid))
01917 return se;
01918 }
01919
01920 IDB_LOG(IDB_LOG_DATABASE, ("dbCloseEpilogue(%s) #2\n", dbfile));
01921
01922 return Success;
01923 }
01924
01925 Status
01926 ESM_dbClose(const DbHandle *dbh)
01927 {
01928 Status se;
01929 int i;
01930
01931 #undef PR
01932 #define PR "dbClose: "
01933
01934 if (!check_dbh(dbh))
01935 return statusMake(INVALID_DB_HANDLE, PR IDBH);
01936
01937 DbHeader _dbh(DBSADDR(dbh));
01938 unsigned int ndat = x2h_u32(_dbh.__ndat());
01939 for (i = 0; i < ndat; i++) {
01940 MmapDesc *mmd, *mmend = &dbh->vd->dmd[i].mmd[MAX_MMAP_SEGMENTS];
01941
01942 if (dbh->vd->m_dmp[i]) {
01943 int mtype = x2h_u16(_dbh.dat(i).mp()->mtype());
01944 int nslots = x2h_u32(_dbh.dat(i).mp()->nslots());
01945 unsigned int size = DMP_SIZE(mtype, nslots);
01946 if (m_munmap(dbh->vd->m_dmp[i], dbh->vd->dmp_addr[i], size))
01947 return statusMake(MAP_ERROR, PR "cannot unmap dmp file");
01948 }
01949
01950 if (dbh->vd->dmd[i].fd >= 0 &&
01951 (se = syscheck(PR, close(dbh->vd->dmd[i].fd), "")))
01952 return se;
01953
01954 for (mmd = dbh->vd->dmd[i].mmd; mmd < mmend; mmd++) {
01955 if (mmd->ismapped)
01956 SEGMENT_UNMAP(mmd);
01957 }
01958 }
01959
01960 unsigned int nbobjs = x2h_u32(_dbh.__nbobjs());
01961 m_munmap(dbh->vd->m_omp, (char *)dbh->vd->omp_addr, OIDMAP_SIZE(nbobjs));
01962
01963
01964
01965
01966
01967 dbsUnmap(dbh->dbfile, dbh->vd);
01968
01969 if (backend)
01970 ESM_dbCloseEpilogue(dbh->vd, (DbShmHeader *)dbh->vd->shm_addr, dbh->vd->xid,
01971 dbh->vd->flags, dbh->dbfile);
01972
01973 if (se = shmUnmap(dbh->dbfile, dbh->vd, fdSizeGet(dbh->vd->shmfd))) {
01974 return se;
01975 }
01976
01977 if (se = syscheck(PR, close(dbh->vd->shmfd), "")) {
01978 return se;
01979 }
01980
01981 #ifndef HAVE_EYEDBSMD
01982 if (!--db_map[dbh->dbfile]) {
01983 if (TRACE_CLEANUP) {
01984 fprintf(stderr, "eyedbsm: closing lockfile map\n");
01985 }
01986
01987 if (se = syscheck(PR, close(dbh->vd->lkfd), "")) {
01988 return se;
01989 }
01990
01991 db_map.erase(dbh->dbfile);
01992 }
01993 #endif
01994
01995 if (dbh->vd->conn) {
01996 smdcli_close(dbh->vd->conn);
01997 }
01998
01999 XMClose(dbh->vd->trs_mh);
02000
02001 free(dbh->vd);
02002 free(dbh->dbfile);
02003 memset((char *)dbh, 0, sizeof(*dbh));
02004 free((char *)dbh);
02005
02006 return Success;
02007 }
02008
02009 int
02010 ESM_dataBaseIdGet(DbHandle const *dbh)
02011 {
02012 return dbh->vd->dbid;
02013 }
02014
02015 int
02016 dbidGet(const Oid *oid)
02017 {
02018 return OIDDBIDGET(oid);
02019 }
02020
02021 void
02022 dbidSet(Oid *oid, int dbid)
02023 {
02024 OIDDBIDMAKE(oid, dbid);
02025 }
02026
02027 Oid::NX
02028 getTotalObjectCount(DbHandle const *dbh)
02029 {
02030 DbHeader _dbh(DBSADDR(dbh));
02031 Oid::NX curobj_cnt = 0;
02032
02033 unsigned int ndat = x2h_u32(_dbh.__ndat());
02034 for (int datid = 0; datid < ndat; datid++) {
02035 if (isDatValid(dbh, datid)) {
02036 MapHeader mp = DAT2MP(dbh, datid);
02037 curobj_cnt += x2h_u32(mp.mstat_u_bmstat_obj_count());
02038 }
02039 }
02040
02041 return curobj_cnt;
02042 }
02043
02044 #define BLKIDXALLOC_INC 10000
02045
02046 Status
02047 nxFileSizeExtends(DbHandle const *dbh, Oid::NX cur_nx)
02048 {
02049 Oid::NX lastidxblkalloc = cur_nx + BLKIDXALLOC_INC;
02050 Oid::NX lastidxbusy = x2h_u32(LASTIDXBUSY(dbh));
02051
02052 char pwd[DEFAULT_PWD_SIZE];
02053 Status status = push_dir(dbh->dbfile, pwd, sizeof pwd);
02054 if (status) return status;
02055
02056 if (lastidxblkalloc < lastidxbusy)
02057 lastidxblkalloc = lastidxbusy + 1;
02058
02059 const char *file = objmapfileGet(dbh->dbfile);
02060 size_t size = OIDMAP_SIZE(lastidxblkalloc);
02061 size_t cursize = fileSizeGet(file);
02062
02063 if (cursize == ~0) {
02064 pop_dir(pwd);
02065 return statusMake(ERROR, "cannot stat file '%s'", file);
02066 }
02067
02068 if (cursize < size) {
02069 if (truncate(file, size) < 0) {
02070 pop_dir(pwd);
02071 return statusMake(ERROR, "nxFileSizeExtends: "
02072 "unexpected error reported by truncate "
02073 "on map file '%s': %s", file, strerror(errno));
02074 }
02075 }
02076
02077 LASTIDXBLKALLOC(dbh) = h2x_u32(lastidxblkalloc);
02078 return pop_dir(pwd);
02079 }
02080
02081 #define BLKNSALLOC_INC (40000/BITS_PER_BYTE)
02082
02083 Status
02084 nsFileSizeExtends(DbHandle const *dbh, short datid, NS curb)
02085 {
02086 NS lastnsblkalloc = curb + BLKNSALLOC_INC;
02087 DbHeader _dbh(DBSADDR(dbh));
02088 const char *file = dmpfileGet(_dbh.dat(datid).file());
02089 size_t size = lastnsblkalloc;
02090
02091 char pwd[DEFAULT_PWD_SIZE];
02092 Status status = push_dir(dbh->dbfile, pwd, sizeof pwd);
02093 if (status) return status;
02094
02095 size_t cursize = fileSizeGet(file);
02096
02097 if (cursize == ~0) {
02098 pop_dir(pwd);
02099 return statusMake(ERROR, "cannot stat file '%s'", file);
02100 }
02101
02102 if (cursize < size) {
02103 if (truncate(file, size) < 0) {
02104 pop_dir(pwd);
02105 return statusMake(ERROR, "nsFileSizeExtends: "
02106 "unexpected error reported by truncate "
02107 "on map file '%s': %s", file, strerror(errno));
02108 }
02109 }
02110
02111 LASTNSBLKALLOC(dbh, datid) = h2x_u32(lastnsblkalloc);
02112 return pop_dir(pwd);
02113 }
02114
02115 Status
02116 objectNumberSet(DbHandle const *dbh, Oid::NX maxobjs)
02117 {
02118 DbHeader _dbh(DBSADDR(dbh));
02119 DbShmHeader *shmh = dbh->vd->shm_addr;
02120
02121 Oid::NX curobj_cnt = getTotalObjectCount(dbh);
02122 if (maxobjs < curobj_cnt)
02123 return statusMake(ERROR,
02124 "objectNumberSet: cannot decrease object number "
02125 "to %d: current object number is %d", maxobjs,
02126 curobj_cnt);
02127
02128 #ifndef NO_FILE_LOCK
02129 #error "NO_FILE_LOCK not defined"
02130 if (!filelockX(dbh->vd->shmfd))
02131 return statusMake(ERROR,
02132 "objectNumberSet: cannot change object number "
02133 "when clients are connected.");
02134 #endif
02135
02136 _dbh.__nbobjs() = h2x_u32(maxobjs);
02137
02138 return Success;
02139 }
02140
02141 Status
02142 objectNumberGet(DbHandle const *dbh, Oid::NX *maxobjs)
02143 {
02144 DbHeader _dbh(DBSADDR(dbh));
02145
02146 *maxobjs = x2h_u32(_dbh.__nbobjs());
02147
02148 return Success;
02149 }
02150
02151 #define MINSHMSIZE 0x400000U
02152
02153
02154
02155 #undef HAVE_WIDE_MEMORY_MAPPED
02156
02157 #ifdef HAVE_WIDE_MEMORY_MAPPED
02158 #define MAXSHMSIZE 0x120000000U
02159 #else
02160 #define MAXSHMSIZE 0x40000000U
02161 #endif
02162
02163 Status
02164 shmSizeGet(DbHandle const *dbh, int *shmsize)
02165 {
02166 struct stat stat;
02167
02168 int shmfd = shmfileOpen(dbh->dbfile, true);
02169 if (shmfd < 0 || fstat(shmfd, &stat) < 0) {
02170 return statusMake(INVALID_DBFILE_ACCESS,
02171 "cannot open shm file for writing: '%s'",
02172 shmfileGet(dbh->dbfile));
02173 }
02174
02175 *shmsize = (int)(stat.st_size/ONE_K);
02176 return Success;
02177 }
02178
02179 Status
02180 shmSizeSet(DbHandle const *dbh, int shmsize)
02181 {
02182 shmsize *= ONE_K;
02183
02184 DbShmHeader dbhshm;
02185
02186 int shmfd = shmfileOpen(dbh->dbfile, false);
02187 #ifndef NO_FILE_LOCK
02188 if (!filelockX(shmfd)) {
02189 return statusMake(ERROR,
02190 "shmSizeSet: cannot change shm size "
02191 "when clients are connected.");
02192 }
02193 #endif
02194
02195 if (shmsize < MINSHMSIZE) {
02196 return statusMake(ERROR, "logsize %d MB is too small (minimum is %d MB)",
02197 shmsize/ONE_M, MINSHMSIZE/ONE_M);
02198 }
02199
02200 if (shmsize > MAXSHMSIZE) {
02201 return statusMake(ERROR, "logsize %d MB too large (maximum is %d MB)",
02202 shmsize/ONE_M, MAXSHMSIZE/ONE_M);
02203 }
02204
02205 if (read(shmfd, &dbhshm, sizeof(dbhshm)) < 0) {
02206 return statusMake(ERROR, "cannot read shmfile '%s'", shmfileGet(dbh->dbfile));
02207 }
02208
02209 if (dbhshm.magic != MAGIC)
02210 return statusMake(ERROR, "shmfile '%s' is not a valid eyedb shmfile\n",
02211 shmfileGet(dbh->dbfile));
02212
02213 if (dbhshm.trs_hdr.tr_cnt) {
02214
02215 return statusMake(ERROR, "shmfile %s is currently in use, cannot be resized", shmfileGet(dbh->dbfile));
02216 }
02217
02218 if (ftruncate(shmfd, shmsize)) {
02219 return statusMake(ERROR, "ftruncate(\"%s\", %u) returns: '%s'\n",
02220 shmfileGet(dbh->dbfile), shmsize, strerror(errno));
02221 }
02222
02223 ESM_DbInitialize(dbh->vd, dbh->vd->shm_addr_b, shmsize);
02224
02225 #ifndef NO_FILE_LOCK
02226 ut_file_unlock(shmfd);
02227 #endif
02228 return Success;
02229 }
02230
02231 Boolean
02232 isDatValid(DbHandle const *dbh, short datid)
02233 {
02234 DbHeader _dbh(DBSADDR(dbh));
02235 return (datid >= 0 && datid < x2h_u32(_dbh.__ndat()) &&
02236 dbh->vd->dmd[datid].fd >= 0) ?
02237 True : False;
02238 }
02239
02240 unsigned int
02241 getDbVersion(void *dbh)
02242 {
02243 #if 1
02244 return ((DbHandle *)dbh)->vd->version;
02245 #else
02246 return x2h_u32(((DbHandle *)dbh)->vd->shm_addr->version);
02247 #endif
02248 }
02249
02250 Boolean
02251 isWholeMapped(void *dbh)
02252 {
02253 return ((DbHandle *)dbh)->vd->hints.maph == WholeMap ? True : False;
02254 }
02255
02256 static Status
02257 dbCleanupRealize(const char *shmfile, int sm_fdshm)
02258 {
02259 caddr_t shm_addr;
02260 Status status;
02261 DbHandle *sm_dbh;
02262 DbHandle *dbh;
02263 DbShmHeader *sm_shmh;
02264 DbHeader *sm_h;
02265 XMHandle *sm_xmh;
02266 size_t sm_shmsize;
02267
02268 sm_shmsize = fdSizeGet(sm_fdshm);
02269
02270 shm_addr = (caddr_t)mmap(0, sm_shmsize, PROT_READ|PROT_WRITE,
02271 MAP_SHARED, sm_fdshm, 0);
02272
02273 if (shm_addr == MAP_FAILED)
02274 return statusMake(ERROR,
02275 "cannot map file '%s' for writing\n", shmfile);
02276
02277 sm_shmh = (DbShmHeader *)shm_addr;
02278 sm_xmh = XMOpen(shm_addr + SHM_HEADSIZE, 0);
02279
02280 unsigned int version = x2h_u32(sm_shmh->version);
02281
02282 DbStat stat = sm_shmh->stat;
02283 cleanup = True;
02284 memset(sm_shmh, 0, sizeof(DbShmHeader));
02285 sm_shmh->magic = MAGIC;
02286 sm_shmh->version = h2x_u32(version ? version : 20508);
02287
02288 sm_shmh->stat = stat;
02289 sm_shmh->stat.current_db_access_cnt = 0;
02290 Mutex mp;
02291 mutexInit(0, &mp, &sm_shmh->main_mp, "SHMMAIN");
02292 ESM_transInit(0, (char *)sm_shmh, sm_shmsize);
02293 DbMutexesInit(0, sm_shmh);
02294
02295 if (sm_xmh)
02296 XMInit(sm_xmh);
02297
02298 ESM_initHost(sm_shmh);
02299
02300 munmap(shm_addr, sm_shmsize);
02301
02302 cleanup = False;
02303
02304 return Success;
02305 }
02306
02307 Status
02308 dbCleanup(const char *dbfile)
02309 {
02310 extern Boolean cleanup;
02311 const char *shmfile = shmfileGet(dbfile);
02312 int fd;
02313
02314 if ((fd = open(dbfile, O_RDWR)) < 0)
02315 return statusMake(ERROR, "cannot open dbfile %s for writing",
02316 dbfile);
02317
02318 close(fd);
02319
02320 fd = open(shmfile, O_RDWR);
02321
02322 if (fd < 0)
02323 return statusMake(ERROR, "cannot open shmfile %s for writing",
02324 shmfile);
02325
02326 #ifndef NO_FILE_LOCK
02327 #error "NO_FILE_LOCK not defined"
02328 if (ut_file_lock(fd, ut_LOCKX, ut_NOBLOCK) < 0 &&
02329 !getenv("EYEDBFORCECLEANUP")) {
02330 close(fd);
02331 return statusMake(CANNOT_LOCK_SHMFILE,
02332 "cannot cleanup shmem file %s: currently used by"
02333 " other clients", shmfile);
02334 }
02335 #endif
02336
02337 Status s = dbCleanupRealize(shmfile, fd);
02338 close(fd);
02339 return s;
02340 }
02341 }