kern_db.cc

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

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