/* PROGRAM: wrtmsg - do the correct type of write call depending on opsys * * RETURNS: DSMVOID */ LOCALF DSMVOID wrtmsg ( dsmContext_t *pcontext, int fd, TEXT *msgbuf, int msglen) { int ret=0; /* return code */ int retrycnt = 0; #if OPSYS==WIN32API /* Do STDOUT properly to allow redirection by parent process */ if (1 == fd) { WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msgbuf, msglen, &ret, NULL); return; } #endif /* OPSYS == WIN32API */ retry: errno = 0; ret = write(fd, (char *) msgbuf, msglen); if (ret != msglen) { switch (errno) { case EFBIG: MSGN_CALLBACK(pcontext, utMSG178, "wrtmsg"); break; case ENOSPC: MSGN_CALLBACK(pcontext, utMSG179); break; default: /* interrupted io to screen? */ if (errno!=EIO && fd==1 && ++retrycnt < 100 && ret >= 0) { msglen -= ret; msgbuf += ret; goto retry; } /* We get EINTR errno when we received a signal while doing a synchronous write. For some OSs the write fails once and subsequently succeeds, while on others it forever after returns -1 with errno set to EINTR, thus the retry count */ if( ++retrycnt < 100 && errno == EINTR && ret == -1 ) goto retry; } } return; } /* end wrtmsg */
/* * PROGRAM: rlaiCompare - compare the "on disk" size with the "as written" * size of the ai file * * This function compares the size of the ai file on disk with the size as * written that is stored in the header. The "on-disk" size is determined * using bkflen (passed in) which returns the number of blocks. The size * as stored in the header is the number of bytes. To do the comparison * we'll expand the "as stored" size to blocks and then round up by one * block. * * RETURNS; 0 if files compare, 1 if they do not */ LOCALF int rlaiCompare( dsmContext_t *pcontext, AIBLK *paiblk, /* ptr to 1st ai block in ai file or extent */ AICTL *paictl) /* pointer to ai control structure */ { dbcontext_t *pdbcontext = pcontext->pdbcontext; LONG onDiskBlocks; LONG asWrittenBlocks; onDiskBlocks = paictl->aisize / pdbcontext->pmstrblk->mb_aiblksize; if (paiblk->aifirst.aieof % pdbcontext->pmstrblk->mb_aiblksize) { asWrittenBlocks = paiblk->aifirst.aieof / pdbcontext->pmstrblk->mb_aiblksize + 1; } else { asWrittenBlocks = paiblk->aifirst.aieof / pdbcontext->pmstrblk->mb_aiblksize; } if ( onDiskBlocks < asWrittenBlocks ) { /* Issue a message indicating that we have an incomplete ai file */ MSGN_CALLBACK(pcontext, rlMSG145, asWrittenBlocks, onDiskBlocks); return -1; } return 0; }
/* * PROGRAM: rlaiblksize - validate ai file blocksize with ai subsystem * * This function compares the blocksize stored in the first ai block with * the blocksize stored in the ai control structure. If they do not match * then we cannot continue. This code does not issue a fatal exception, but * it is important that no I/O be done to the ai file or it will be damaged. * * RETURNS; 0 if blocksize matches, 1 if it does not match */ LOCALF int rlaiblksize( dsmContext_t *pcontext, AIBLK *paiblk, /* ptr to 1st ai block in ai file or extent */ AICTL *paictl) /* pointer to ai control structure */ { if (paiblk->aifirst.aiblksize == paictl->aiblksize) { /* blocksize matches should be ok */ return 0; } else { /* Invalid blocksize in ai file found %d, expected %l */ MSGN_CALLBACK(pcontext, rlMSG060, paiblk->aifirst.aiblksize, paictl->aiblksize); return 1; } } /* rlaiblksize */
LOCALF int rlaiVersion( dsmContext_t *pcontext, AIBLK *paiblk) /* Pointer to ai file header */ { LONG AiVersion; LONG rc = 1; /* Make sure that the header length is in the ball park */ if( paiblk->aihdr.aihdrlen > (COUNT)(sizeof(AIHDR) + sizeof(AIFIRST))) { /* This is not a Progress ai file */ MSGN_CALLBACK(pcontext, rlMSG104); return ( rc ); } /* Copy ai version to avoid alignment errors when testing the ai version in what is a bogus block. */ bufcop((TEXT *)&AiVersion, ((TEXT *)paiblk + paiblk->aihdr.aihdrlen - sizeof(LONG)), sizeof(LONG)); if( AiVersion != AIVERSION ) { /* Invalid after image version number found in ai file header */ MSGN_CALLBACK(pcontext, rlMSG100); if( paiblk->aihdr.aihdrlen != sizeof(AIHDR) + sizeof(AIFIRST)) { if ( paiblk->aihdr.aihdrlen == sizeof(AIHDRv0) + sizeof(AIFIRSTv0)) { /* This is a version 0 Progress ai file. */ MSGN_CALLBACK(pcontext, rlMSG101); /* The ai file must be truncated. */ MSGN_CALLBACK(pcontext, rlMSG102); /* See documentation for aimage truncate */ MSGN_CALLBACK(pcontext, rlMSG103); return ( rc ); } /* This is not a Progress ai file */ MSGN_CALLBACK(pcontext, rlMSG104); return ( rc ); } } rc = 0; return ( rc ); }
/* PROGRAM: rlaiopn - open the after-image (transaction-log) file * * Updates: allocates an aictl aictl.aibktbl will be setup. If the ai is opened for output, then that buffer will contain the current output block of the ai file (the last block containing valid data). If the ai is opened for input, then that buffer will contain the first blk of the ai file. aictl.aimode will be set appropriately aictl.aisize - physical EOF aictl.ailoc - input: start of file, output: logical EOF aictl.aiofst - offset of ailoc within current ai block Some of the updates is diffrent for an off-line Transaction-log file which doe not use the noral AI mechanism, but is very similar to it. * NOTE: rlaiopn can be called by normal progress to open the .ai file * * for input or output. * * * * When being called for output, The caller should check * * pmstrblk->mb_ai.ainew and should not call rlaiopn if it is 0. * * * RETURNS: 0 - on success * -1 - on failure * 1 - only a partial ai file was detected */ int rlaiopn( dsmContext_t *pcontext, int aimode, /* AIINPUT or AIOUTPUT */ TEXT *pname, /* name of the .ai file */ int execmode, /* non-zero => open for input with intent to rf */ int tmplog, /* 1 for off-line TL file. */ int retry) /* 1 - retry active, 0 - retry inactive */ { dbcontext_t *pdbcontext = pcontext->pdbcontext; MSTRBLK *pmstr = pdbcontext->pmstrblk; AICTL *paictl; AIBLK *paiblk; BKTBL *pbktbl; struct bkftbl *pbkftbl = (struct bkftbl *)NULL; COUNT buffmode; LONG ret; TEXT timeString[TIMESIZE]; UCOUNT returnCode = 0; if (aimode == AIOUTPUT && pmstr->mb_aisync==UNBUFFERED && !tmplog) buffmode = UNBUFFERED; else buffmode = BUFFERED; /* allocate all buffers and control structures */ rlaiseto (pcontext); /* get local pointer to global structure */ paictl = pdbcontext->paictl; /* get the ai file size in bytes */ if( pmstr->mb_aibusy_extent > (TEXT)0 ) { /* using an extent, get the length of busy extent */ paictl->aisize = rlaielen(pcontext, paictl->aiArea); } else { /* *** TODO: bkflen returns size in terms of database blocks */ /* using a named file get the length directly */ paictl->aisize = bkflen(pcontext, paictl->aiArea) * pdbcontext->pmstrblk->mb_aiblksize; } /* read the first ai block into current buffer */ pbktbl = &(XAIBUF(pdbcontext, paictl->aiqcurb)->aibk); pbktbl->bt_dbkey = 0L; bkRead(pcontext, pbktbl); paiblk = XAIBLK(pdbcontext, pbktbl->bt_qbuf); /* Make sure we have a compatible version */ if (rlaiVersion(pcontext, paiblk)) { /* AI file cannot be used with this database */ MSGN_CALLBACK(pcontext, rlMSG094); return -1; } /* make sure blocksize matches database */ if (rlaiblksize(pcontext, paiblk, paictl)) { /* AI file cannot be used with this database */ MSGN_CALLBACK(pcontext, rlMSG094); return -1; } /* Make sure the file is complete, BUG# 20000510-002 */ if ( rlaiCompare(pcontext, paiblk, paictl) ) { /* File lengths don't compare for whatever reason. Prohibit the ai seq num from being incremented so if the user happens to find the correct, full ai file they can retry. */ returnCode = 1; } /* setup for reading (rollforward) or writing (logging) to file */ if (aimode == AIINPUT) { if ( execmode ) { if ( retry ) { /* Retry is activate - check extent status */ if( paiblk->aifirst.aiextstate == AIEXTEMPTY ) { /* That's because this is an empty ai extent */ MSGN_CALLBACK(pcontext, rlMSG058); return -1; } /* Ensure ai in proper sequence. */ pmstr->mb_aiseq = pmstr->mb_aiseq ? pmstr->mb_aiseq : 1; if (paiblk->aifirst.aidates.aigennbr != pmstr->mb_aiseq) { /* This ai file is not in the proper sequence for rretry. */ /* Expected ai file number %l but file sepecified is %l in sequence. */ MSGN_CALLBACK(pcontext, rlMSG140, pmstr->mb_aiseq, paiblk->aifirst.aidates.aigennbr); return -1; } } else if (paiblk->aifirst.lstmod != pmstr->mb_lstmod ) { /* the time stamps dont match */ if( paiblk->aifirst.aiextstate == AIEXTEMPTY ) { /* That's because this is an empty ai extent */ MSGN_CALLBACK(pcontext, rlMSG058); } else { /* Ensure ai in proper sequence. */ pmstr->mb_aiseq = pmstr->mb_aiseq ? pmstr->mb_aiseq : 1; if (paiblk->aifirst.aidates.aigennbr != pmstr->mb_aiseq) { /* ai file is not in the proper sequence for rollf. */ /* "Expected ai file number %l but file sepecified is %l in sequence." */ MSGN_CALLBACK(pcontext, rlMSG140, pmstr->mb_aiseq, paiblk->aifirst.aidates.aigennbr); } MSGN_CALLBACK(pcontext, rlMSG001, uttime((time_t *)&pmstr->mb_lstmod, timeString, sizeof(timeString))); MSGN_CALLBACK(pcontext, rlMSG002, uttime((time_t *)&paiblk->aifirst.lstmod, timeString, sizeof(timeString))); MSGN_CALLBACK(pcontext, rlMSG003); } return -1; } } /* Init for reading from beginning of file */ paictl->aiofst = paiblk->aihdr.aihdrlen; paictl->ailoc = pbktbl->bt_dbkey; paictl->aimode = AIINPUT; } else { /* file is being opened for output (logging) check the dates */ if (paiblk->aifirst.aidates.aiopen != pmstr->mb_ai.aiopen) { /* time stamps dont match */ if( (pname == NULL) && (pdbcontext->pmstrblk->mb_aibusy_extent > (TEXT)0) ) { /* Means its an ai extent file */ ret = bkGetAreaFtbl(pcontext, paictl->aiArea,&pbkftbl); pbkftbl += pdbcontext->pmstrblk->mb_aibusy_extent - 1; pname = XTEXT(pdbcontext, pbkftbl->ft_qname); } MSGN_CALLBACK(pcontext, rlMSG045, pname); return -1; } /* get the current date/time and put into ai block */ time(&paiblk->aifirst.aidates.aiopen); /* put time into masterblock */ pmstr->mb_ai.aiopen = paiblk->aifirst.aidates.aiopen; /* write out both blocks */ bkWrite(pcontext, pbktbl, UNBUFFERED); bmFlushMasterblock(pcontext); /* initialize ai control structure for logging */ paictl->aiupdctr = paiblk->aifirst.aifirstctr; paictl->ailoc = pbktbl->bt_dbkey; paictl->aiofst = paiblk->aihdr.aihdrlen; paictl->aimode = AIOUTPUT; } /* done. ready to go */ if ( returnCode ) { /* detected partial ai file */ return (1); } else { /* success */ return (returnCode); } }
/* PROGRAM: dsmDatabaseProcessEvents - perform xxx processing * * NOTE: Quiet points and tmdelayed commit are supported here * * RETURNS: DSM_S_SUCCESS * DSM_S_INVALID_USER * DSM_S_SHUT_DOWN on EXBAD or EXGOOD */ dsmStatus_t dsmDatabaseProcessEvents( dsmContext_t *pcontext) { dbcontext_t *pdbcontext = pcontext->pdbcontext; dbshm_t *pdbshm = pdbcontext->pdbpub; usrctl_t *pusr = pcontext->pusrctl; mstrblk_t *pmstr; dsmStatus_t returnCode; #if OPSYS==WIN32API if (fWin95) return -1; #endif pdbcontext->inservice++; /* "post-pone" signal handling while in DSM API */ SETJMP_ERROREXIT(pcontext, returnCode) /* Ensure error exit address set */ if ((returnCode = dsmThreadSafeEntry(pcontext)) != DSM_S_SUCCESS) { returnCode = dsmEntryProcessError(pcontext, returnCode, (TEXT *)"dsmDatabaseProcessEvents"); goto done; } /* Check for quiet point command requests */ if (pdbshm->quietpoint == QUIET_POINT_REQUEST) { /* Shut off update activity for the quiet point */ rlTXElock(pcontext,RL_TXE_EXCL,RL_MISC_OP); MT_LOCK_MTX(); pmstr = pdbcontext->pmstrblk; /* Switch after imaging extent if there are ai extents */ if( rlaiqon(pcontext) && pmstr->mb_aibusy_extent > 0 ) { MT_LOCK_AIB(); if (rlaiswitch(pcontext, (int)RLAI_NEW, 1) ) { MT_UNLK_AIB(); /* Unable to switch to new ai extent */ MSGN_CALLBACK(pcontext, drMSG205); if ( MTHOLDING(MTL_MTX) ) MT_UNLK_MTX(); if ( pusr->uc_txelk ) rlTXEunlock(pcontext); goto done; } MT_UNLK_AIB(); } /* Flush the buffer pool and bi buffers */ rlbiflsh(pcontext,RL_FLUSH_ALL_BI_BUFFERS); /* At this point, the quiet point is in place */ MSGN_CALLBACK(pcontext, drMSG402); pdbshm->quietpoint = QUIET_POINT_ENABLED; while(pdbshm->quietpoint == QUIET_POINT_ENABLED && !pdbshm->shutdn) { utsleep(1); } MT_UNLK_MTX(); rlTXEunlock(pcontext); /* Release transaction end lock */ /* At this point, normal operations can return */ MSGN_CALLBACK(pcontext, drMSG403); pdbshm->quietpoint = QUIET_POINT_NORMAL; } /* Process delayed commit (-Mf) */ tmchkdelay(pcontext, 0); /* Check if table locking can be shut off */ lkTableLockCheck(pcontext); returnCode = DSM_S_SUCCESS; done: dsmThreadSafeExit(pcontext); pdbcontext->inservice--; /* re-allow signal handling */ return returnCode; } /* end dsmDatabaseProcessEvents */
/* PROGRAM: bkioCreateLkFile -- lock the database in desired mode. * * Create a .lk file holding the following information: * a.) The mode the db is in BKIO_LKSNGL | BKIO_LKMULT * b.) The process ID of the starter of the db * c.) The hostname of the machine where the db was started * * * RETURNS: * 0 database locked in requested mode. * BKIO_LKSNGL database currently locked in single-user mode, * request denied. * BKIO_LKMULT database currently locked in multi-user mode, * request denied. * BKIO_LKSTARTUP database is in the process of starting up * request denied. * */ int bkioCreateLkFile ( dsmContext_t *pcontext, int mode, /* desired usage mode, either BKIO_LKSNGL or BKIO_LKMULT */ TEXT *dbname, /* name of database */ int dispmsg) /* if true, then display a message */ { TEXT namebuf[MAXPATHN+1]; TEXT dbnamebuf[MAXPATHN+1]; TEXT nodebuf[BKIO_NODESZ]; int ret = 0; ULONG spid = 0; int errorStatus = 0; int bytesWritten; LONG retWrite; LONG retMakePath = 0; int lockret = 1; int wmode = mode; fileHandle_t lkhandle; int i; int local = 0; dbcontext_t *pdbcontext = pcontext->pdbcontext; /* see if the *.lk file already exists and is valid */ if(pdbcontext->pdatadir) utmypath(namebuf,pdbcontext->pdatadir,dbname, (TEXT *)".lk"); else retMakePath = utMakePathname(namebuf, sizeof(namebuf), dbname, (TEXT *)".lk"); if (retMakePath != DBUT_S_SUCCESS) { /* Report error */ dbUserError(pcontext, retMakePath, errno, 0, (DSMVOID *)NULL, (DSMVOID *)NULL); } if(pdbcontext->pdatadir) utmypath(dbnamebuf,pdbcontext->pdatadir,dbname, (TEXT *)".db"); else retMakePath = utMakePathname(dbnamebuf, sizeof(dbnamebuf), dbname, (TEXT *)".db"); if (retMakePath != DBUT_S_SUCCESS) { /* Report error */ dbUserError(pcontext, retMakePath, errno, 0, (DSMVOID *)NULL, (DSMVOID *)NULL); } ret = bkioTestLkFile(pcontext, dbname); if (ret) { switch(ret) { case BKIO_LKSNGL: if(dispmsg) MSGN_CALLBACK(pcontext, bkMSG005, dbname); break; /* db in use single-user */ case BKIO_LKMULT: case BKIO_LKSTARTUP: if(dispmsg) MSGN_CALLBACK(pcontext, bkMSG006, dbname); break; /* db in use multi-user */ case BKIO_LKNOHOST: MSGN_CALLBACK(pcontext, bkMSG007, namebuf); MSGN_CALLBACK(pcontext, bkMSG008); MSGN_CALLBACK(pcontext, bkMSG009); MSGN_CALLBACK(pcontext, bkMSG010); MSGN_CALLBACK(pcontext, bkMSG011, namebuf); break; case BKIO_LKTRUNC: break; /* message was put out by bkioTestLkFile */ default: FATAL_MSGN_CALLBACK(pcontext, bkFTL009, dbname); break; } } else { /* open failed, try to creat it */ /* 19990525-028 - small window of opportunity for two brokers */ /* to start on same database. Replace utOsCreat call with */ /* utOsOpen. */ /* lkhandle = utOsCreat((TEXT *)namebuf, 0444, 0, &errorStatus); */ /* 19990525-028 second try. Can only call utOsOpen if not on NFS */ /* See bug for details. */ local = bkioIsLocalFile(pcontext,dbnamebuf); /* if .lk file is on NFS drive */ if (local == 0) { lkhandle = utOsCreat((TEXT *)namebuf, 0444, 0, &errorStatus); } else { #if OPSYS == WIN32API lkhandle = utOsOpen((TEXT *)namebuf, (O_CREAT | O_EXCL | O_WRONLY), CREATE_DATA_FILE, 0, &errorStatus); #else lkhandle = utOsOpen((TEXT *)namebuf, (O_CREAT | O_EXCL | O_WRONLY), 0444, 0, &errorStatus); #endif } if (lkhandle == INVALID_FILE_HANDLE) { /* cant open */ MSGN_CALLBACK(pcontext, bkMSG002, namebuf, errorStatus); return -1; } /* Remove this conditional once file locking is implemented for UNIX */ #if OPSYS == WIN32API /* attempt to get a lock in the .lk file itself */ lockret = utLockLkFile(lkhandle); #endif /* if we got the lock, write out the mode, pid and nodename */ if (lockret) { if (mode == BKIO_LKMULT) { wmode = BKIO_LKSTARTUP; } /* write out the mode the database is in */ retWrite = utWriteToFile(lkhandle, 0, (TEXT *)&wmode, sizeof(int), &bytesWritten, &errorStatus); /* get the process id and put that into the file */ spid = utgetpid (); retWrite = utWriteToFile(lkhandle, sizeof(int), (TEXT *)&spid, sizeof(int), &bytesWritten, &errorStatus); stnclr(nodebuf,BKIO_NODESZ); /*fill with nulls*/ /* get the hostname and put it into the file */ ret = utgethostname((TEXT *)nodebuf,BKIO_NODESZ - 1); if (ret < 0) { /* if the utgethostname call failed, write out an ampty hostname, that will cause the .lk file checking to be more strict */ stnclr(nodebuf,BKIO_NODESZ); /*fill with nulls*/ } retWrite = utWriteToFile(lkhandle,2*(sizeof(int)),nodebuf, BKIO_NODESZ, &bytesWritten, &errorStatus); /* Save the handle in the lkstr structure */ for (i = 0; i < 240; i++) { if (lkstr[i].lkHandle == (fileHandle_t)0) { /* we found an empty slot, populate it */ lkstr[i].lkHandle = lkhandle; lkstr[i].nameCrc = calc_crc((UCOUNT)0, namebuf, (COUNT)stlen(namebuf)); break; } } } else { /* we did no succeed in locking the .lk file */ utOsClose(lkhandle,0); MSGN_CALLBACK(pcontext, bkMSG131, namebuf, errorStatus); return -1; } } return(ret); }
/* PROGRAM: bkioVerifyLkFile - verify that the .lk file is valid with the * passed in pid. * * * RETURNS: 0 - lk is valid * -1 - lk is invalid */ int bkioVerifyLkFile( dsmContext_t *pcontext, int pid, /* .lk creators pid */ TEXT *dbname) /* basename for the .lk file */ { LONG ret; /* return for utReadFromFile() */ int status =0; /* value returned */ int errorStatus = 0; TEXT namebuf[MAXPATHN+1]; TEXT nodebuf[BKIO_NODESZ]; TEXT snodebuf[BKIO_NODESZ]; int spid = 0; LONG retMakePath = 0; int bytesRead; int lockret = 0; int needopen = 0; UCOUNT nameCrc; fileHandle_t lkhandle = (fileHandle_t) -1; int i; dbcontext_t *pdbcontext = pcontext->pdbcontext; if(pdbcontext->pdatadir) utmypath(namebuf,pdbcontext->pdatadir,dbname, (TEXT *)".lk"); else retMakePath = utMakePathname(namebuf, sizeof(namebuf), dbname, (TEXT *)".lk"); if (retMakePath != DBUT_S_SUCCESS) { /* Report Error */ dbUserError(pcontext, retMakePath, errno, 0, (DSMVOID *)NULL, (DSMVOID *)NULL); } nameCrc = calc_crc((UCOUNT)0, namebuf, (COUNT)stlen(namebuf)); /* find the handle for the lkfile */ for (i = 0; i < 240; i++) { if ((lkstr[i].nameCrc == nameCrc) && (lkstr[i].lkHandle != (fileHandle_t)0)) { lkhandle = lkstr[i].lkHandle; break; } } /* if we don't have a valid file handle, open the lock file and get one */ if (lkhandle == (fileHandle_t) -1) { /* note that we needed to open the lock file */ needopen = 1; /* get the absolute path of the .lk file */ lkhandle = utOsOpen((TEXT *)namebuf, OPEN_R, DEFLT_PERM, OPEN_SEQL, &errorStatus); if (lkhandle == INVALID_FILE_HANDLE) { /* failed to open the .lk file, return the failure */ MSGN_CALLBACK(pcontext, bkMSG100,namebuf,errorStatus); return -1; } } /* Try to lock the lock file - if we get a lock, then the .lk file * is not valid. */ /* Remove this conditional once file locking is implemented for UNIX */ #if OPSYS == WIN32API lockret = utLockLkFile(lkhandle); #endif if (lockret) { /* we got the lock so the old .lk file must have been invalid */ MSGN_CALLBACK(pcontext, bkMSG132, namebuf, errorStatus); return -1; } /* now lets read the .lk file */ /* read the past the mode from the .lk file */ ret = utReadFromFile(lkhandle, 0, (TEXT *)&spid, sizeof(int), &bytesRead, &errorStatus); if (bytesRead != sizeof(int)) { /* read failed. Either the file is too short, or read gave an error. Regardless, we need to shutdown */ MSGN_CALLBACK(pcontext, bkMSG101,"MODE",namebuf,errorStatus); utOsClose(lkhandle,OPEN_SEQL); return -1; } /* read the pid from the .lk file */ ret = utReadFromFile(lkhandle, sizeof(int), (TEXT *)&spid,sizeof(int), &bytesRead, &errorStatus); if (bytesRead != sizeof(int)) { /* read failed. Either the file is too short, or read gave an error. Regardless, we need to shutdown */ MSGN_CALLBACK(pcontext, bkMSG101,"PID",namebuf,errorStatus); utOsClose(lkhandle,OPEN_SEQL); return -1; } /* read the hostname from the .lk file */ ret = utReadFromFile(lkhandle, 2 * sizeof(int), snodebuf,BKIO_NODESZ, &bytesRead, &errorStatus); if (bytesRead != BKIO_NODESZ) { /* read failed. Either the file is too short, or read gave an error. Regardless, we need to shutdown */ MSGN_CALLBACK(pcontext, bkMSG101,"HOSTNAME",namebuf,errorStatus); utOsClose(lkhandle,OPEN_SEQL); return -1; } /* get the systems hostname don't worry about failures, the stpcmp will verify the host for us later */ ret = utgethostname((TEXT *)nodebuf,BKIO_NODESZ - 1); /* now that we have read the .lk file, verify it's a valid one */ if (pid == spid) { /* pids match, now check the hostname */ if (stpcmp(nodebuf,snodebuf) != 0) { /* hostnames don't match. .lk file is invalid for this server */ MSGN_CALLBACK(pcontext, bkMSG102,namebuf,snodebuf,nodebuf); status = -1; } } else { /* pids don't match. .lk file is invalid for this server */ MSGN_CALLBACK(pcontext, bkMSG103,namebuf,spid,pid); status = -1; } if (needopen) { utOsClose (lkhandle, OPEN_SEQL); lkhandle = (fileHandle_t) -1; } return(status); }
/* PROGRAM: bkioUpdateLkFile - update the .lk file * * Update the .lk file with the NON-NULL parameters passed to the * routine. This is used to revalidate the .lk file incase it's * creator has disappeared. An example of this is during Emergency * Shutdown, the first thing that happens is that the broker dies * hence the .lk is now "stale". * * RETURNS: 0 - success * -1 - failure */ int bkioUpdateLkFile( dsmContext_t *pcontext, int mode, /* mode database is opened in */ int pid, /* pid of the owner */ TEXT *phost, /* hostname */ TEXT *dbname) /* name of database */ { LONG ret; LONG retMakePath = 0; int errorStatus = 0; int bytesWritten; TEXT namebuf[MAXPATHN+1]; int lockret; UCOUNT nameCrc; fileHandle_t lkhandle = (fileHandle_t) -1; int i; /* get the absolute path of the .lk file */ if(pcontext->pdbcontext->pdatadir) utmypath(namebuf,pcontext->pdbcontext->pdatadir, pcontext->pdbcontext->pdbname, (TEXT *)".lk"); else retMakePath = utMakePathname(namebuf, sizeof(namebuf), dbname, (TEXT *)".lk"); if (retMakePath != DBUT_S_SUCCESS) { /* Report error */ dbUserError(pcontext, retMakePath, errno, 0, (DSMVOID *)NULL, (DSMVOID *)NULL); } nameCrc = calc_crc((UCOUNT)0, namebuf, (COUNT)stlen(namebuf)); /* find the handle for the lkfile */ for (i = 0; i < 240; i++) { if ((lkstr[i].nameCrc == nameCrc) && (lkstr[i].lkHandle != (fileHandle_t)0)) { lkhandle = lkstr[i].lkHandle; break; } } /* If we were not called from a process that knew the lock file * handle, go get it. */ if (lkhandle == (fileHandle_t) -1) { lkhandle = utOsOpen((TEXT *)namebuf, OPEN_RW, DEFLT_PERM, OPEN_SEQL, &errorStatus); if (lkhandle == INVALID_FILE_HANDLE) { /* failed to open the .lk file, return the failure */ MSGN_CALLBACK(pcontext, bkMSG100, namebuf, errorStatus); return -1; } /* we are going to end up owning this lk file, save the handle for future use. */ for (i = 0; i < 240; i++) { if (lkstr[i].lkHandle == (fileHandle_t)0) { /* we found an empty slot, populate it */ lkstr[i].lkHandle = lkhandle; lkstr[i].nameCrc = calc_crc((UCOUNT)0, namebuf, (COUNT)stlen(namebuf)); break; } } } #if OPSYS==UNIX else { /* we are going to close this file at the end so we need to make sure every knows that */ lkstr[i].lkHandle = (fileHandle_t) -1; } #endif /* If we get the lock, then we were called by brkillall, watchdog, * or wdogLkFileCheck (after it was determined that the broker was gone). * If we don't get a lock, then we were called by nsaloop during startup * and we need to change the mode from DBLKSTARTUP to DBLKMULT. */ lockret = utLockLkFile(lkhandle); if (mode) { /* update the mode with the passed one */ ret = utWriteToFile(lkhandle, 0, (TEXT *)&mode,sizeof(int), &bytesWritten, &errorStatus); if (ret < 0) { /* failed to write mode to the .lk file, return the failure */ MSGN_CALLBACK(pcontext, bkMSG099,namebuf,errorStatus); return -1; } } if (pid) { /* update the pid with the passed one */ ret = utWriteToFile(lkhandle, sizeof(int), (TEXT *)&pid,sizeof(int), &bytesWritten, &errorStatus); if (ret < 0) { /* failed to seek to pid in the .lk file, return the failure */ MSGN_CALLBACK(pcontext, bkMSG099,namebuf,errorStatus); return -1; } } if (phost) { /* update the hostname with the passed one */ ret = utWriteToFile(lkhandle,2 * sizeof(int), phost,stlen(phost), &bytesWritten, &errorStatus); if (ret < 0) { /* failed to write hostname to the .lk file, return the failure */ MSGN_CALLBACK(pcontext, bkMSG099, namebuf, errorStatus); return -1; } } /* if we got here, time to close up shop and return success */ #if OPSYS == UNIX utOsClose (lkhandle, OPEN_SEQL); #endif return 0; }
/* PROGRAM: bkioTestLkFile -- examine the database to see if it is locked, and * if so return the mode, i.e. single-user or multi-user. * This version uses a special file, ".lk", instead of the * UNIX locking call. * * RETURNS: Returns 0 if the database is not locked, else returns * BKIO_LKSNGL or BKIO_LKMULT. */ int bkioTestLkFile ( dsmContext_t *pcontext, TEXT *dbname) /* path name for ".db" file */ { TEXT namebuf[MAXPATHN+1]; #if OPSYS == UNIX TEXT nodebuf[BKIO_NODESZ]; TEXT mynode[BKIO_NODESZ]; #endif LONG retRead; ULONG spid = 0; int lkmode = 0; int errorStatus = 0; int bytesRead; LONG retMakePath = 0; fileHandle_t lkhandle; int lockret = 0; /* form path name for *.lk file, see if it's there and current */ if(pcontext->pdbcontext->pdatadir) utmypath(namebuf,pcontext->pdbcontext->pdatadir, pcontext->pdbcontext->pdbname, (TEXT *)".lk"); else retMakePath = utMakePathname(namebuf, sizeof(namebuf), dbname, (TEXT *)".lk"); if (retMakePath != DBUT_S_SUCCESS) { /* Report Error */ dbUserError(pcontext, retMakePath, errno, 0, (DSMVOID *)NULL, (DSMVOID *)NULL); } #if OPSYS == WIN32API lkhandle = utOsOpen(namebuf, OPEN_RW, DEFLT_PERM, OPEN_SEQL, &errorStatus); #else lkhandle = utOsOpen(namebuf, OPEN_R, DEFLT_PERM, OPEN_SEQL, &errorStatus); #endif if (lkhandle == INVALID_FILE_HANDLE) { /* open failed, either db not in use, or permission screwed up */ if (errorStatus != ENOENT) FATAL_MSGN_CALLBACK(pcontext, svFTL013, namebuf, errorStatus); } else { /* read lock mode and server pid out of lock file */ /* the following loop takes care of a timing window that exists * when the server creates the .lk file, and the client attempts * to read the file before the server has written the lock mode * and its pid into the file. This loop should also handle interrupted * system call under Unix, and hence no special case for EINTR */ /* Remove this conditional once file locking is implemented for UNIX */ #if OPSYS == WIN32API /* Try to lock the .lk file */ lockret = utLockLkFile(lkhandle); #endif /* We got a lock, so the .lk file is invalid. Now unlock so it * can be overwritten. */ if (lockret) { lockret = utUnlockLkFile(&lkhandle); /* 19990525-028 - If we are going to change behavior such */ /* that the .lk file is only created if it does not already */ /* exist, then if the .lk file is invalid we must delete it */ bkioRemoveLkFile(pcontext, dbname); return (0); } else { /* The .lk file exists, we can't lock it, so it is valid */ retRead = utReadFromFile(lkhandle, 0, (TEXT *)&lkmode, sizeof (int), &bytesRead, &errorStatus); if ( bytesRead != sizeof(int)) { MSGN_CALLBACK(pcontext, svMSG005); return BKIO_LKTRUNC; } #if OPSYS == UNIX /* get PID and HOST name from file-- if its the same HOST as we are on, it is then safe to test the PID and erase .lk if its not a live process on this same machine and allow login. if the HOSTS are different, or gethostname() is not supported on this machine, the PID cannot be guaranteed to be valid because of NFS so return BKIO_LKNOHOST */ retRead = utReadFromFile(lkhandle, sizeof(int), (TEXT *)&spid, sizeof(int), &bytesRead, &errorStatus); if ( spid ) { stnclr(mynode,BKIO_NODESZ); utgethostname((TEXT *)mynode,BKIO_NODESZ -1); retRead = utReadFromFile(lkhandle, 2 * sizeof(int), (TEXT *)nodebuf, BKIO_NODESZ, &bytesRead, &errorStatus); if ( bytesRead == BKIO_NODESZ) { if (nodebuf[0] == '\0') /* No hostname in the .lk file */ { return BKIO_LKNOHOST; } if (stpcmp(nodebuf,mynode) == 0) /*see if nodes match*/ { if ( (kill ( spid, 0 ) == -1) && (errno == ESRCH) ) { lkmode= 0; } } } } #endif /* UNIX */ } } if (lkhandle != INVALID_FILE_HANDLE) { utOsClose(lkhandle, OPEN_SEQL); if (lkmode == 0) { bkioRemoveLkFile(pcontext, dbname); } } return(lkmode); }
/* PROGRAM: dbQuietPoint - evaluate the quiet request and * enable or disable the quiet point. * * RETURNS: 0 - success * non-zero - failure */ int dbQuietPoint(dsmContext_t *pcontext, UCOUNT quietRequest, ULONG quietArg) { int returnCode = 0; /* status of the quiet request */ dbcontext_t *pdbcontext = pcontext->pdbcontext; dbshm_t *pdbshm = pdbcontext->pdbpub; usrctl_t *pusrctl = pcontext->pusrctl; RLCTL *prl = pdbcontext->prlctl; LONG64 bithreshold = 0; DOUBLE bitholdBytes = 0; DOUBLE bitholdSize = 0; TEXT sizeId; DOUBLE fromBitholdBytes = 0; DOUBLE fromBitholdSize = 0; TEXT fromSizeId; DOUBLE toBitholdBytes = 0; DOUBLE toBitholdSize = 0; TEXT toSizeId; TEXT printBuffer[13]; TEXT fromPrintBuffer[13]; TEXT toPrintBuffer[13]; /* Before we attempt to enable or disable the quiescent point */ /* we need to check for the existence of the broker. */ if (!deadpid(pcontext, pdbshm->brokerpid)) { if (quietRequest == QUIET_POINT_REQUEST) { if (!pdbshm->quietpoint == QUIET_POINT_NORMAL) { if ((pdbshm->quietpoint == QUIET_POINT_REQUEST) || (pdbshm->quietpoint == QUIET_POINT_ENABLED)) { /* Quiet point has already been requested. */ MSGN_CALLBACK(pcontext, drMSG392); returnCode = 4; } else { /* Protect against a second user trying to quiet */ /* Enabling the quiet point is in effect. */ MSGN_CALLBACK(pcontext, drMSG393); returnCode = 6; } } else /* Database is in the Normal Processing State */ { /* Check if after imaging is enabled without */ /* the use of after image extents. */ if ( rlaiqon(pcontext) == 1 && pdbcontext->pmstrblk->mb_aibusy_extent == 0 ) { /* Cannot enable with single ai file */ MSGN_CALLBACK(pcontext, drMSG394); returnCode = 2; } else { /* Reset the shared memory variable to request */ /* the enabling of the quiet point by the broker. */ pdbshm->quietpoint = QUIET_POINT_REQUEST; /* Loop until the quietpoint state changes to */ /* QUIET_POINT_ENABLED */ for (;;) { /* Test for brokers existence and whether */ /* shutdown has already occurred. */ if (deadpid(pcontext, pdbshm->brokerpid)) { MSGN_CALLBACK(pcontext, drMSG395); returnCode = 16; break; } /* Check to see if a shutdown was received. */ if (pusrctl->usrtodie) { MSGN_CALLBACK(pcontext, drMSG396); returnCode = 16; break; } if (pdbshm->quietpoint == QUIET_POINT_ENABLED) { pdbcontext->usertype |= DBSHUT; returnCode = 0; break; } utsleep(1); } } } } /* Disable the Ouiet Point */ else if (quietRequest == QUIET_POINT_DISABLE) { /* Database is in the Normal Processing State */ if (pdbshm->quietpoint == QUIET_POINT_ENABLED) { /* Reset the shared memory variable to request */ /* the enabling of the quiet point by the broker. */ pdbshm->quietpoint = QUIET_POINT_DISABLE; /* Loop until the quietpoint state changes to */ /* QUIET_POINT_ENABLED */ for (;;) { /* Test for brokers existence */ if (deadpid(pcontext, pdbshm->brokerpid)) { MSGN_CALLBACK(pcontext, drMSG397); pdbcontext->usertype |= DBSHUT; returnCode = 16; break; } /* Check to see if a shutdown was received. */ if (pusrctl->usrtodie) { MSGN_CALLBACK(pcontext, drMSG398); pdbcontext->usertype |= DBSHUT; returnCode = 16; break; } if (pdbshm->quietpoint == QUIET_POINT_NORMAL) { pdbcontext->usertype |= DBSHUT; returnCode = 0; break; } utsleep(1); } } else if (pdbshm->quietpoint != QUIET_POINT_ENABLED) { /* Quiet point does not need to be disabled. */ MSGN_CALLBACK(pcontext, drMSG399); pdbcontext->usertype |= DBSHUT; returnCode = 3; } } else if (quietRequest == QUIET_POINT_BITHRESHOLD) { /* Round down bi threshold by a cluster if it is set */ bithreshold = ( (((LONG64)quietArg * 1048576) / prl->rlbiblksize) - (prl->rlclbytes / prl->rlbiblksize) ); if (bithreshold > 0 && bithreshold > prl->rlsize) { /* Validate the bi threshold value */ if (pdbshm->bithold == bithreshold) { /* bithold size same, request to change rejected */ bitholdBytes = (DOUBLE)bithreshold * prl->rlbiblksize; utConvertBytes(bitholdBytes, &bitholdSize, &sizeId); sprintf((char *)printBuffer, "%-5.1f %cBytes", bitholdSize, sizeId); MSGN_CALLBACK(pcontext, drMSG687, printBuffer); MSGN_CALLBACK(pcontext, drMSG451); returnCode = 3; } else if (pdbshm->bithold == 0 || pdbshm->bithold > (ULONG)prl->rlsize) { if (pdbshm->quietpoint != QUIET_POINT_ENABLED) { /* Quiet point not enabled and stall did not occur. Request to change bi threshold rejected */ MSGN_CALLBACK(pcontext, drMSG452); MSGN_CALLBACK(pcontext, drMSG451); returnCode = 3; } else { /* Make sure new bi threshold is larger than bi file size */ if (bithreshold >= prl->rlsize) { /* bi threshold changed from value to value */ fromBitholdBytes = (DOUBLE)pdbshm->bithold * prl->rlbiblksize; utConvertBytes(fromBitholdBytes, &fromBitholdSize, &fromSizeId); sprintf((char *)fromPrintBuffer, "%-5.1f %cBytes", fromBitholdSize, fromSizeId); toBitholdBytes = (DOUBLE)bithreshold * prl->rlbiblksize; utConvertBytes(toBitholdBytes, &toBitholdSize, &toSizeId); sprintf((char *)toPrintBuffer, "%-5.1f %cBytes", toBitholdSize, toSizeId); MSGN_CALLBACK(pcontext, drMSG686, fromPrintBuffer, toPrintBuffer); pdbshm->bithold = bithreshold; returnCode = 0; } else { /* Invalid value provided, request to change bi threshold rejected */ MSGN_CALLBACK(pcontext, drMSG454); MSGN_CALLBACK(pcontext, drMSG451); returnCode = 3; } } } else if ((pdbshm->bithold) <= (ULONG)prl->rlsize) { /* bi threshold reached */ /* bi threshold changed from value to value */ fromBitholdBytes = (DOUBLE)pdbshm->bithold * prl->rlbiblksize; utConvertBytes(fromBitholdBytes, &fromBitholdSize, &fromSizeId); sprintf((char *)fromPrintBuffer, "%-5.1f %cBytes", fromBitholdSize, fromSizeId); toBitholdBytes = (DOUBLE)bithreshold * prl->rlbiblksize; utConvertBytes(toBitholdBytes, &toBitholdSize, &toSizeId); sprintf((char *)toPrintBuffer, "%-5.1f %cBytes", toBitholdSize, toSizeId); MSGN_CALLBACK(pcontext, drMSG686, fromPrintBuffer, toPrintBuffer); pdbshm->bithold = bithreshold; pdbshm->quietpoint = QUIET_POINT_NORMAL; returnCode = 0; } else { /* Invalid value provided, request to change bi threshold rejected */ MSGN_CALLBACK(pcontext, drMSG454); MSGN_CALLBACK(pcontext, drMSG451); returnCode = 3; } } else { /* Invalid value provided, request to change bi threshold rejected */ MSGN_CALLBACK(pcontext, drMSG454); MSGN_CALLBACK(pcontext, drMSG451); returnCode = 3; } } } else /* The broker does not exist and shutdown may be in progress */ { /* Broker is dead - abnormal shutdown of the database */ MSGN_CALLBACK(pcontext, drMSG400); returnCode = 16; } return(returnCode); }
/* PROGRAM: dbLogOpen -- open the database log file (".lg"). * * RETURNS: 0 - OK * non-0 - Unable to open the .lg file */ int dbLogOpen( dsmContext_t *pcontext, TEXT *pname) /* name of the database */ { dbcontext_t *pdbcontext = pcontext->pdbcontext; TEXT namebuf[MAXPATHN+1]; fileHandle_t tmpfd; int errorStatus; LONG retMakePath; if (pdbcontext->logopen) return 0; /* setup the fd cache */ utInitFdCache(128); /* get name of log file, open it */ retMakePath = utMakePathname( namebuf, sizeof(namebuf), pname, (TEXT *) ".lg"); if (retMakePath != DBUT_S_SUCCESS) { /* Report error */ dbUserError(pcontext, retMakePath, errno, 0, (DSMVOID *)NULL, (DSMVOID *)NULL); } if ((tmpfd = utOsOpen (namebuf, OPEN_W_APPEND_TEXT, DEFLT_PERM, OPEN_SEQL,&errorStatus)) == INVALID_FILE_HANDLE) if ( (tmpfd = utOsCreat (namebuf, CREATMODE, CHG_OWNER|AUTOERR,&errorStatus)) != INVALID_FILE_HANDLE) { utOsClose(tmpfd,OPEN_SEQL); tmpfd = utOsOpen (namebuf, OPEN_W_APPEND_TEXT, DEFLT_PERM, OPEN_SEQL,&errorStatus); } if (tmpfd == INVALID_FILE_HANDLE) { MSGN_CALLBACK(pcontext, utMSG092, namebuf, errorStatus); return -1; } #if OPSYS == UNIX /* writing to the .lg file is *VERY* important, so it doesn't participate in the fd cache. To make this true we need to close the handle and do a regular open on it */ utOsClose(tmpfd, 0); pdbcontext->lgfd = open(namebuf, OPEN_W_APPEND_TEXT); if (pdbcontext->lgfd < 0) { MSGN_CALLBACK(pcontext, utMSG092, namebuf, errorStatus); return -1; } #else pdbcontext->lgfd = _open_osfhandle((LONG)tmpfd, O_APPEND | O_TEXT); #endif /* prevent child processes from inheriting this file */ utclex (tmpfd); pdbcontext->logopen = 1; return 0; } /* end dbLogOpen */
/* RETURNS: -1 = error; >=0 = the shmid of the segment */ int shmCreateSegment( dsmContext_t *pcontext, SHMDSC *pshmdsc, /*control blk for a series of shm segs */ int idchar _UNUSED_) /* Key value for multiple segments within db */ { int shmid; TEXT *pname = pshmdsc->pname;/*database name or other file name*/ pshmdsc->segsize = MIN(pshmdsc->segsize, mssize); #if ALPHAOSF /* -Mpte keeps VLM64 allocations in multiples of 8Mb for good performance */ if (pcontext->pdbcontext->argMpte) while (pshmdsc->segsize >= 0x00800000) { shmid = shmget(IPC_PRIVATE, /* ensure unique id */ (int)pshmdsc->segsize, /* segment size */ 0666+IPC_EXCL+IPC_CREAT); /* segment attributes */ if (shmid >= 0) return shmid; /* successful */ /* "vm: gh-fail-if-no-mem=1" in /etc/sysconfigtab can raise ENOMEM */ if (errno == EINVAL || errno == ENOMEM) { /* the size is invalid, decrease it by 8MB and try again */ pshmdsc->segsize -= 0x00800000; mssize = pshmdsc->segsize; continue; } else break; } /* if this didn't work, go on and try it the old fashioned way. */ mssize = pshmdsc->segsize = 0x00800000; #endif do { pshmdsc->segsize = (pshmdsc->segsize + 0xfff) & ~0xfff; shmid = shmget(IPC_PRIVATE, /* ensure unique id */ (int)pshmdsc->segsize, /* segment size */ 0666+IPC_EXCL+IPC_CREAT); /* segment attributes */ if (shmid >= 0) return shmid; /* successful */ if (errno == EINVAL) { /* the size is invalid, decrease it and try again */ pshmdsc->segsize = pshmdsc->segsize - 8192; if (pshmdsc->segsize < 8 * 1024) { /* The allowed shm segment size too small */ MSGN_CALLBACK(pcontext, utMSG024); return -1; } mssize = pshmdsc->segsize; } } while (errno == EINVAL); if (errno == ENOMEM || errno == EAGAIN) { MSGN_CALLBACK(pcontext, utMSG026); } else { /* print an error message */ shmmsg(pcontext, errno, (TEXT *)"create", pname, (key_t)shmid); } return -1; }
/* RETURNS: -1 = error; >=0 = the shmid of the segment */ int shmCreateSegment( dsmContext_t *pcontext, SHMDSC *pshmdsc,/* control blk for a series of shm segs */ int idchar) /*id for multiple segments for same db */ { LPVOID lpmem; HANDLE hmap; TEXT *pname = pshmdsc->pname; char szShareMem[MAXUTFLEN]; char szFile[MAXUTFLEN]; pshmdsc->segsize = MIN(pshmdsc->segsize, MAXSEGSIZE); utapath(szFile, MAXUTFLEN, pname, ""); utmkosnm("sharemem.", szFile, szShareMem, MAXUTFLEN, idchar); hmap = CreateFileMapping((HANDLE)0xFFFFFFFF, /* Use the swap file */ (SECURITY_ATTRIBUTES*)SecurityAttributes(0), /* Not inherited */ PAGE_READWRITE, /* Memory is Read/Write */ 0L, /* Size Upper 32 Bits */ (DWORD)pshmdsc->segsize,/* Size Lower 32 bits*/ szShareMem); if (!hmap) { DWORD dwRet = GetLastError(); switch (dwRet) { case ERROR_ALREADY_EXISTS: /* Right now this case will never */ /* be TRUE. hmap is not NULL */ /* if the mapping already existed */ default: /* Unable to create shared memory %s, error %d */ MSGN_CALLBACK(pcontext, utMSG062, szShareMem, dwRet); return -1; } } lpmem = MapViewOfFile(hmap, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, (DWORD)pshmdsc->segsize); #if 0 /* Your supposed to be able to do this */ CloseHandle(hmap); #endif if (lpmem == 0) { /* Unable to create shared memory %s, error %d */ MSGN_CALLBACK(pcontext, utMSG062, szShareMem, 0); return -1; } if (utshmAddNamedSegment(szShareMem, (int)lpmem, (ULONG)hmap)) { /* Failed, out of memory */ UnmapViewOfFile(lpmem); return -1; } return (int)lpmem; }