fis-gtm/sr_unix/mur_read_file_sp.c

183 lines
6.2 KiB
C

/****************************************************************
* *
* Copyright 2003, 2010 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
#include "mdef.h"
#include "min_max.h"
#include "gtm_fcntl.h"
#include "gtm_unistd.h"
#include "gtm_stat.h"
#include "gtm_string.h"
#include "eintr_wrappers.h"
#include "gtm_aio.h"
#include "gtmio.h"
#ifdef __MVS__
#include "gtm_zos_io.h"
#endif
#include "gdsroot.h"
#include "gdsbt.h"
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsfhead.h"
#include "filestruct.h"
#include "jnl.h"
#include "buddy_list.h"
#include "hashtab_mname.h" /* needed for muprec.h */
#include "hashtab_int4.h" /* needed for muprec.h */
#include "hashtab_int8.h" /* needed for muprec.h */
#include "muprec.h"
#include "mur_read_file.h"
#include "iosp.h"
#include "copy.h"
#include "gtmmsg.h"
#include "repl_sp.h" /* for F_CLOSE used by the JNL_FD_CLOSE macro */
GBLREF mur_opt_struct mur_options;
GBLREF mur_gbls_t murgbl;
#ifdef MUR_USE_AIO
/****************************************************************************************
* Function Name: mur_fread_start
* Input: struct mur_buffer_desc * buff
* Output : SS_NORMAL on successful
* error status on unsuccessful
* This function starts an asynchronous read in a given buffer
****************************************************************************************/
uint4 mur_fread_start(jnl_ctl_list *jctl, mur_buff_desc_t *buff)
{
buff->aiocbp->aio_offset = buff->dskaddr;
buff->aiocbp->aio_buf = (char *)buff->base;
buff->blen = MIN(MUR_BUFF_SIZE, jctl->eof_addr - buff->dskaddr);
buff->aiocbp->aio_nbytes = buff->blen;
buff->rip_channel = jctl->channel; /* store channel that issued the AIO in order to use later for aio_cancel() */
assert(!buff->read_in_progress);
buff->read_in_progress = TRUE;
AIO_READ(buff->rip_channel, buff->aiocbp, jctl->status, jctl->status2);
return jctl->status;
}
/************************************************************************************
* Function name: mur_fread_wait
* Input : struct mur_buffer_desc *buff
* Output: SS_NORMAL on success
* error status on unsuccessful
* Purpose: The purpose of this routine is to make sure that a previously issued asysnchronous read
* in a given buffer has completed
**************************************************************************************/
uint4 mur_fread_wait(jnl_ctl_list *jctl, mur_buff_desc_t *buff)
{
ssize_t nbytes;
error_def(ERR_PREMATEOF);
assert(buff->read_in_progress);
buff->read_in_progress = FALSE;
/* The aio_error function returns the error status associated with the specified aiocbp. If the aio_error function returns
* anything but EINPROGRESS, the asynchronous I/O operation has completed. Subsequently, we can fetch the status of the
* operation from a call to aio_return.
*/
AIO_ERROR(buff->aiocbp, jctl->status);
if (-1 != jctl->status)
{
AIO_RETURN(buff->aiocbp, nbytes); /* if successful jctl->status will contain number of bytes read */
if (-1 != nbytes)
{
if (buff->blen == nbytes)
return (jctl->status = SS_NORMAL);
/* AIO_READ didn't fetch the requested size chunk */
assert(buff->blen > nbytes);
DO_FILE_READ(buff->rip_channel, buff->dskaddr + nbytes, buff->base + nbytes, buff->blen - nbytes,
jctl->status, jctl->status2);
return jctl->status;
}
}
return (jctl->status = errno);
}
/* cancel asynchronous read */
uint4 mur_fread_cancel(jnl_ctl_list *jctl)
{
int status, index, save_err;
reg_ctl_list *rctl;
mur_read_desc_t *mur_desc;
mur_buff_desc_t *seq_buff;
rctl = jctl->reg_ctl;
mur_desc = rctl->mur_desc;
/* At most one buffer can have read_in_progress, not both */
assert(!(mur_desc->seq_buff[0].read_in_progress && mur_desc->seq_buff[1].read_in_progress));
for (index = 0, save_err = 0; index < ARRAYSIZE(mur_desc->seq_buff); index++)
{
seq_buff = &mur_desc->seq_buff[index];
if (seq_buff->read_in_progress)
{
AIO_CANCEL(seq_buff->rip_channel, NULL, status);
if (-1 == status)
save_err = errno;
else if (AIO_NOTCANCELED == status) /* the OS cannot cancel the aio once it has actually started */
jctl->status = mur_fread_wait(seq_buff); /* wait for it to finish. */
seq_buff->read_in_progress = FALSE;
}
}
/* Note that although the cancellation errored out for rip_channel, we are storing the status in jctl which need not
* actually be the jctl corresponding to rip_channel
*/
return (jctl->status = ((0 == save_err) ? SS_NORMAL : save_err));
}
#endif /* MUR_USE_AIO */
boolean_t mur_fopen_sp(jnl_ctl_list *jctl)
{
struct stat stat_buf;
int status, perms;
ZOS_ONLY(int realfiletag;)
error_def(ERR_JNLFILEOPNERR);
error_def(ERR_SYSCALL);
error_def(ERR_TEXT);
ZOS_ONLY(error_def(ERR_BADTAG);)
perms = O_RDONLY;
jctl->read_only = TRUE;
/* Both for recover and rollback open in read/write mode. We do not need to write in journal file
* for mupip journal extract/show/verify or recover -forward. So open it as read-only
*/
if (mur_options.update && !mur_options.forward)
{
perms = O_RDWR;
jctl->read_only = FALSE;
}
jctl->channel = OPEN((char *)jctl->jnl_fn, perms);
if (FD_INVALID != jctl->channel)
{
FSTAT_FILE(jctl->channel, &stat_buf, status);
if (-1 != status)
{
#ifdef __MVS__
if (-1 == gtm_zos_tag_to_policy(jctl->channel, TAG_BINARY, &realfiletag))
TAG_POLICY_GTM_PUTMSG((char *)jctl->jnl_fn, errno, realfiletag, TAG_BINARY);
#endif
jctl->os_filesize = (off_jnl_t)stat_buf.st_size;
return TRUE;
}
jctl->status = errno;
JNL_FD_CLOSE(jctl->channel, status); /* sets jctl->channel to NOJNL */
} else
jctl->status = errno;
assert(NOJNL == jctl->channel);
if (ENOENT == jctl->status) /* File Not Found is a common error, so no need for SYSCALL */
gtm_putmsg(VARLSTCNT(5) ERR_JNLFILEOPNERR, 2, jctl->jnl_fn_len, jctl->jnl_fn, jctl->status);
else
gtm_putmsg(VARLSTCNT(12) ERR_JNLFILEOPNERR, 2, jctl->jnl_fn_len, jctl->jnl_fn, ERR_SYSCALL, 5,
LEN_AND_STR((-1 == jctl->channel) ? "open" : "fstat"), CALLFROM, jctl->status);
return FALSE;
}