Ejemplo n.º 1
0
/*{
** Name: DIwrite -  Writes  page(s) of a file to disk.
**
** Description:
**      The DIwrite routine is used to write pages of a direct access 
**      file.  This routine should be flexible enough to write multiple
**      contiguous pages.  The number of pages to write is indicated
**      as an input parameter,  This value is updated to indicate the
**      actual number of pages written.  A synchronous write is preferred
**      but not required.
**   
**	The buffer address from which the data is to be written is examined
**	to see if it is in shared memory. If so, we then instruct the slave
**	to write the page(s) directly from the target buffer. Otherwise, we
**	copy the page(s) from the buffer into the server segment, and then
**	instruct the slave to write the page(s) from the server segment.
**
** Inputs:
**      f                    Pointer to the DI file
**                           context needed to do I/O.
**      n                    Pointer to value indicating number of pages to 
**			     write.
**      page                 Value indicating page(s) to write.
**      buf                  Pointer to page(s) to write.
**      
** Outputs:
**      f                    Updates the file control block.
**      n                    Pointer to value indicating number of pages 
**			     written.
**      err_code             Pointer to a variable used
**                           to return operating system 
**                           errors.
**    Returns:
**          OK
**          DI_BADFILE          Bad file context.
**          DI_BADWRITE         Error writing.
**          DI_BADPARAM         Parameter(s) in error.
**          DI_ENDFILE          Write past end of file.
**	    DI_BADLRU_RELEASE	Error releasing open file.
**    Exceptions:
**        none
**
** Side Effects:
**        none
**
** History:
**    26-mar-87 (mmm)    
**          Created new for 6.0.
**    06-feb-89 (mikem)
**	    Return CL_ERR_DESC from DIlru_open().
**    23-mar-89 (mikem)
**	    update io_system_eof when necessary (bug 4854).
**    10-jul-89 (rogerk & mikem)
**	    When asked to write a page that is past our cached EOF marker, call
**	    DIsense to check the actual EOF before signalling an error.  The
**	    page may have been allocated by a different server and our copy of
**	    the EOF has just not been updated yet.
**
**	    This case can also come up in a single server case now, as we 
**	    continue to cache pages in the buffer manager even when the table 
**	    is closed.  This can result in a DIwrite() being performed on a
**	    newly opened file without ever doing a DIread() (where eof info
**	    was previously obtained).
**    10-jul-89 (mikem)
**	    Return DI_EXCEED_LIMIT if out of disk space, rather than
**	    BAD_WRITE.  Also add some debugging code to make it easier to
**	    test that the server handles out of disk space correctly (by
**	    returning out of disk space out of DIwrite based on a gloal set
**	    by DIalloc every N times called).
**    23-Jan-90 (anton)
**	    Call DI_sense instead of DIsense to prevent multiple DIlru_opens
**	    and use of two CSevcbs.
**	2-Feb-90 (anton)
**	    Don't always copy CL_ERR_DESC
**	6-Feb-90 (jkb)
**	    Change write to IIdio_write which combines the write and lseek
**	    commands and makes direct io available for Sequent
**	5-aug-1991 (bryanp)
**	    Added support for I/O directly from server shared memory,
**	    bypassing the copy through the server segment if possible.
**      03-mar-1992 (jnash)
**          Fix LG slave problem noted when Sun mmap() support
**          introduced, change slave logic to send to the slave the
**          segment id "key" rather than "segid" (segid value not
**          the same in the slave).
**	30-October-1992 (rmuth)
**	    Prototype and make sure we have opened the file before
**	    we close it.
**	30-nov-1992 (rmuth)
**	    - Include <cldio.h>
**	    - DIlru error checking, this was a major restructuring of the
**	      code. No Change in functionality.
**	10-dec-1993 (rmuth)
**	    If fail the past io_allocated_eof test then make sure that we
**	    unset the errno value in CL_ERR_DESC set by SETCLERR. This was
**	    causing confusion as we were logging random errno's to the
**	    errlog.log
**      31-jan-94 (mikem)
**          sir #57671
**          The transfer size of slave I/O is now stored in
**          Cs_srv_block.cs_size_io_buf, rather than a constant
**          DI_FILE_BUF_SIZE.
**	18-apr-1994 (jnash)
**	    fsync project.  Call DIforce() on systems where fsync() exists 
**	    but O_SYNC does not (hopefully never). 
**	20-jun-1995 (amo ICL)
**	    Added call on DI_async_write for async io
**	20-Apr-1998 (merja01)
**		Move "#" to column 1 to correct compile errors on axp_osf.
**	01-oct-1998 (somsa01)
**	    Return DI_NODISKSPACE when we are out of disk space.
**	29-Oct-1998 (schte01)
**		Move "#" to column 1 to correct compile errors on axp_osf.
**	14-Oct-2005 (jenjo02)
**	    Chris's file descriptor properties now cached in io_fprop
**	    (file properties) and established on the first open, 
**	    not every open.
*/
STATUS
DIwrite(
    DI_IO	   *f,
    i4             *n,
    i4        page,
    char           *buf,
    CL_ERR_DESC    *err_code)
{
    STATUS			big_status = OK, small_status = OK, r_status;
    i4			num_of_pages;
    i4			last_page_to_write;
    CL_ERR_DESC    		lerr_code;
    DI_OP			diop;

    /* default returns */

    CL_CLEAR_ERR( err_code );

    num_of_pages = *n;
    *n = 0;
    if (num_of_pages <= 0)
	return (DI_BADPARAM);

    last_page_to_write = page + num_of_pages - 1;

    diop.di_flags = 0;

    if (f->io_type != DI_IO_ASCII_ID)
        return(DI_BADFILE);

    if (f->io_mode != DI_IO_WRITE)
        return(DI_BADWRITE);

    /* Count another write */
    f->io_stat.write++;

    /* 
    ** get open file descriptor for the file
    */
    if (big_status = DIlru_open(f, FALSE, &diop, err_code))
	return(big_status);

    /* 
    ** now check for write within bounds of the file 
    */
    if (last_page_to_write > f->io_alloc_eof) 
    {
	i4	real_eof;

	/*
	** DI_sense updates f->io_alloc_eof with the protection
	** of io_sem (OS_THREADS), so there's no need to
	** duplicate that update here.
	*/
	big_status = DI_sense(f, &diop, &real_eof, err_code);

	if (big_status == OK)
	{
	    if (last_page_to_write > f->io_alloc_eof)
	    {
		small_status = DI_ENDFILE;
		SETCLERR(err_code, 0, ER_write);

		/*
		** The above sets errno as errno will be left over from
		** a previous call zero it out to avoid confusion.
		*/
		err_code->errnum = 0;
	     }
	 }
    }

    if (big_status == OK && small_status == OK)
    {
#ifdef xOUT_OF_DISK_SPACE_TEST
	if ((f->io_open_flags & DI_O_NODISKSPACE_DEBUG) &&
	    (last_page_to_write > f->io_logical_eof)    &&
	    (last_page_to_write <= f->io_alloc_eof))
	{
	    f->io_open_flags &= ~DI_O_NODISKSPACE_DEBUG;

	    small_status = DI_NODISKSPACE;
	    SETCLERR(err_code, 0, ER_write);
	    err_code->errnum = ENOSPC;

	    TRdisplay(
		"DIwrite(): Returning false DI_NODISKSPACE, page %d\n", page);
	}
	else
#endif /* xOUT_OF_DISK_SPACE_TEST */
	    
	{
	    if (Di_slave)
	    {
		big_status = DI_slave_write( f, &diop, buf, page, num_of_pages,
					     err_code );
	    }
	    else
# if defined(OS_THREADS_USED) || defined(xCL_ASYNC_IO)
	    if (Di_async_io)
	    {
		big_status = DI_async_write( f, &diop, buf, page, num_of_pages,
					      err_code );
	    }
	    else
# endif /* OS_THREADS_USED || xCL_ASYNC_IO */
	    {
		big_status = DI_inproc_write( f, &diop, buf, page, num_of_pages,
					      err_code );
	    }

	    if (big_status == OK && small_status == OK)

# if defined(xCL_010_FSYNC_EXISTS) && !defined(O_SYNC)
	    {
		/*
		** Due to lru activity, this code assumes that a force on any 
		** file descriptor forces pages for all open files.  If not 
		** the case, fsync() logic must be installed in the slave.
		*/
		big_status = DIforce( f, err_code );
	    }
	    if (big_status == OK && small_status == OK)
# endif

		*n = num_of_pages;
	}
    }

    r_status = DIlru_release(&diop, &lerr_code);

    if (big_status)
	return( big_status );
    else if (small_status)
	return( small_status );

    return(r_status);

}
Ejemplo n.º 2
0
/*
** Writes or erases a transaction log and displays a completion thermometer.
**
** 'context' must not be NULL, and defaults for element 0 & 1 of context
** must have been set.
*/
i4
write_transaction_log(bool create, PM_CONTEXT *context,
	char *log_dir[], char *log_file[],
	void (*message)(char *), void (*init_graph)(bool, i4), 
	i4 graph_size, void (*update_graph)())
{

# define LG_PAGE_SIZE		2048L
# define LG_NUMBER_OF_PAGES	32L	/* Number of pages to write at a time */

    DI_IO 		dio[LG_MAX_FILE];
    char 		buf[LG_PAGE_SIZE * LG_NUMBER_OF_PAGES];
    char		nodename[GL_MAXNAME];
    i4  		i, j, marker, count, num_logs;
    i4 		num_pages, page, part_size, remainder, loop;
    CL_ERR_DESC 	err;
    char		*string;
    LOCATION 		loc[LG_MAX_FILE];
    char 		locbuf[MAX_LOC + 1];
    char 		*path[LG_MAX_FILE];
    i4  		LOinfo_flag;
    LOINFORMATION 	loc_info;
    i8 		size;
    CS_SCB 		scb;
    bool		size_in_kbytes = FALSE;

    MEfill( sizeof( scb ), 0, ( PTR ) &scb ); 
    
    ++graph_size;

    /* Prepare transaction for log LOCATION(s) */
    for (num_logs = 0; num_logs < LG_MAX_FILE; num_logs++)
    {
	if (log_dir[num_logs] == 0)
	    break;
	STcopy( log_dir[num_logs], locbuf );
	LOfroms( PATH, locbuf, &loc[num_logs] );
	LOfstfile( log_file[num_logs], &loc[num_logs] );
	LOtos( &loc[num_logs], &path[num_logs] );
    }

    /* get size (in bytes) of log file to be created or erased */
    if( create )
    {
	STATUS status;
	char *value;
	bool havevalue = FALSE;

	status = PMmGet( context, ERx( "$.$.rcp.file.kbytes" ), &value );
	if ( status == OK )
	{
	    havevalue = TRUE;
	    size_in_kbytes = TRUE;
	}

	if ( havevalue == FALSE )
	{
	    status = PMmGet( context, ERx( "$.$.rcp.file.size" ), &value );
	    if ( status == OK )
		havevalue = TRUE;
	}

	if ( havevalue == FALSE )
	{
	    if ( message != NULL )
	    {
		char msg[ BIG_ENOUGH ];
		STprintf( msg, ERx( "%s %s" ),
			PMmExpandRequest( context,
			ERx( "$.$.rcp.file.kbytes" ) ),
			"not found." );
		message( msg );
	    }
	    return( 0 );	
	}
	CVal8( value, &size );
    }
    else
    {
	LOinfo_flag = LO_I_SIZE;
	size = 0;

	for (i = 0; i < num_logs; i++)
	{
	    if ( LOinfo( &loc[i], &LOinfo_flag, &loc_info ) != OK )
	    {
		if ( message != NULL )
		{
		    char msg[ BIG_ENOUGH ];

		    STprintf( msg,
			    "Unable to get size of transaction log:\n\n\t%s",
			    path[i] );	
		    (*message)( msg );
		}
		return( 0 );	
	    }
	    else
		size += loc_info.li_size;
	    if ((LOinfo_flag & LO_I_SIZE) == 0)
		break;
	}

	if ( (LOinfo_flag & LO_I_SIZE) == 0 || size == 0L)
	{
	    STATUS status;
	    char *value;
	    bool havevalue = FALSE;

	    status = PMmGet( context, ERx( "$.$.rcp.file.kbytes" ), &value );
	    if ( status == OK )
	    {
		havevalue = TRUE;
		size_in_kbytes = TRUE;
	    }

	    if ( havevalue == FALSE )
	    {
		status = PMmGet( context, ERx( "$.$.rcp.file.size" ), &value );
		if ( status == OK )
		    havevalue = TRUE;
	    }

	    if ( havevalue == FALSE  )
	    {
		if ( message != NULL )
		{
		    char msg[ BIG_ENOUGH ];

		    STprintf( msg, ERx( "%s %s." ),
			    PMmExpandRequest( context,
			    ERx( "$.$.rcp.file.kbytes" ) ),
			    "not found." );
		    message( msg );
		}
		return( 0 );	
	    }
	    CVal8( value, &size );
	}
    }

    for (i = 0; i < num_logs; i++)
    {
	if ( create && LOexist( &loc[i] ) == OK )
	{
		char msg[ BIG_ENOUGH ];

		if ( message != NULL )
		{
			STprintf( msg, "%s already exists.", path[i] ); 
			(*message)( msg ); 
			STprintf( msg, "To create a new transaction log, you must first delete all partitions of the old one." ); 
			(*message)( msg ); 
		}
		return( 0 );	
	}
    }

    if ( CSinitiate( (i4 *) NULL, (char ***) NULL, (CS_CB *) NULL )
	    != OK )
    {
	    if ( message != NULL )
		    message( "Unable to connect to shared memory" );
	    return( 0 );	
    }

    CSset_sid( &scb );

    /* create DI file */
    for (i = 0; i < num_logs; i++)
    {
	if ( create && DIcreate( &dio[i], 
		log_dir[i],  (u_i4)STlength(log_dir[i]), 
		log_file[i], (u_i4)STlength(log_file[i]),
		(i4)LG_PAGE_SIZE, &err) != OK )
	{
	    char msg[ BIG_ENOUGH ];

	    if ( message != NULL )
	    {
		STprintf( msg,
			"Unable to create transaction log:\n\n\t%s",
			path[i] );	
		(*message)( msg );
	    }
	    return( 0 );
	}

	/* open DI file */
	if ( DIopen( &dio[i],
		log_dir[i],  (u_i4)STlength(log_dir[i]), 
		log_file[i], (u_i4)STlength(log_file[i]),
		(i4)LG_PAGE_SIZE, DI_IO_WRITE, 0, &err) != OK )
	{
	    if ( message != NULL )
	    {
		char msg[ BIG_ENOUGH ];

		STprintf( msg,
			"Unable to open transaction log:\n\n\t%s",
			path[i] );	
		(*message)( msg );
	    }
	    return( 0 );
	}
    }

    if ( size_in_kbytes == FALSE )
	size = (size + 1023) / 1024;

    (*init_graph)( create, (i4) size );

    num_pages = size / (LG_PAGE_SIZE/1024);

    part_size = num_pages / num_logs;

    /* Readjust num_pages to be a multiple of num_logs */
    num_pages = part_size * num_logs;

    loop = part_size / LG_NUMBER_OF_PAGES;
    remainder = part_size % LG_NUMBER_OF_PAGES;

    marker = loop / graph_size;

    /* Fill buffer with zeroes */
    MEfill( sizeof( buf ), 0 , buf);

    for (i = 0; i < num_logs; i++)
    {
	if ( create &&
		DIalloc( &dio[i], part_size, &page, &err ) != OK )
	{
	    DIdelete( &dio[i], log_dir[i], (u_i4)STlength( log_dir[i] ),
		    log_file[i], (u_i4)STlength( log_file[i] ), &err );
	    if ( message != NULL )
		    (*message)( "Unable to allocate space in transaction log file." );
	    return( 0 );
	}
    }

    count = 0;
    for( j = 0; j < loop; j++ )
    {
	i4	n = LG_NUMBER_OF_PAGES;
	i4	page_no = j * n;

	for (i = 0; i < num_logs; i++)
	{
	    if ( DIwrite( &dio[i], &n, page_no, 
			buf, &err ) != OK )
	    {
		DIdelete( &dio[i], 
		    log_dir[i], (u_i4)STlength(log_dir[i]),
		    log_file[i], (u_i4)STlength(log_file[i]),
		    &err );
		if ( message != NULL )
			(*message)( "Unable to continue writing transaction log." );
		return( 0 );
	    }
	}

	if ( j >= marker && j % marker == 0 &&
		(f4) ((f4) j / (f4) loop) >= ((f4) count + 1) /
		graph_size )
	{
	    ++count;
	    (*update_graph)();
	    SIflush( stdout );
	}
    }

    if (remainder)
    {
	i4	page_no = loop * LG_NUMBER_OF_PAGES;

	for (i = 0; i < num_logs; i++)
	{
	    if ( DIwrite( &dio[i], &remainder, page_no,
			buf, &err ) != OK )
	    {
		DIdelete( &dio[i], 
		    log_dir[i], (u_i4)STlength(log_dir[i]),
		    log_file[i], (u_i4)STlength(log_file[i]),
		    &err );
		if ( message != NULL )
			(*message)( "Unable to continue writing transaction log." );
		return( 0 );
	    }
	}
    }

    for (i = 0; i < num_logs; i++)
    {
	if ( DIforce( &dio[i], &err ) != OK )
	{
	    DIdelete( &dio[i], log_dir[i], (u_i4)STlength(log_dir[i]),
		    log_file[i], (u_i4)STlength(log_file[i]), &err );
	    if ( message != NULL )
		(*message)( "Unable to force changes to transaction log." );
	    return( 0 );
	}

	if ( create && DIflush( &dio[i], &err ) != OK )
	{
	    DIdelete( &dio[i], log_dir[i], (u_i4)STlength(log_dir[i]),
		    log_file[i], (u_i4)STlength(log_file[i]), &err );
	    if ( message != NULL )
		(*message)( "Unable to flush transaction log to disk." );
	    return( 0 );
	}

	if( DIclose( &dio[i], &err ) != OK)
	{
	    DIdelete( &dio[i], log_dir[i], (u_i4)STlength(log_dir[i]),
		    log_file[i], (u_i4)STlength(log_file[i]), &err );
	    if ( message != NULL )
		(*message)( "Unable to finish writing transaction log." );
	    return( 0 );
	}
    }

    return( (i4) size );
}