/******************************************************
Recovery

(c) 1997 Innobase Oy

Created 9/20/1997 Heikki Tuuri
*******************************************************/

#ifndef log0recv_h
#define log0recv_h

#include "univ.i"
#include "ut0byte.h"
#include "page0types.h"
#include "hash0hash.h"
#include "log0log.h"

#ifdef UNIV_HOTBACKUP
extern ibool	recv_replay_file_ops;
#endif /* UNIV_HOTBACKUP */

/***********************************************************************
Reads the checkpoint info needed in hot backup. */

ibool
recv_read_cp_info_for_backup(
/*=========================*/
			/* out: TRUE if success */
	byte*	hdr,	/* in: buffer containing the log group header */
	dulint*	lsn,	/* out: checkpoint lsn */
	ulint*	offset,	/* out: checkpoint offset in the log group */
	ulint*	fsp_limit,/* out: fsp limit of space 0, 1000000000 if the
			database is running with < version 3.23.50 of InnoDB */
	dulint*	cp_no,	/* out: checkpoint number */
	dulint*	first_header_lsn);
			/* out: lsn of of the start of the first log file */
/***********************************************************************
Scans the log segment and n_bytes_scanned is set to the length of valid
log scanned. */

void
recv_scan_log_seg_for_backup(
/*=========================*/
	byte*		buf,		/* in: buffer containing log data */
	ulint		buf_len,	/* in: data length in that buffer */
	dulint*		scanned_lsn,	/* in/out: lsn of buffer start,
					we return scanned lsn */
	ulint*		scanned_checkpoint_no,
					/* in/out: 4 lowest bytes of the
					highest scanned checkpoint number so
					far */
	ulint*		n_bytes_scanned);/* out: how much we were able to
					scan, smaller than buf_len if log
					data ended here */
/***********************************************************************
Returns TRUE if recovery is currently running. */
UNIV_INLINE
ibool
recv_recovery_is_on(void);
/*=====================*/
/***********************************************************************
Returns TRUE if recovery from backup is currently running. */
UNIV_INLINE
ibool
recv_recovery_from_backup_is_on(void);
/*=================================*/
/****************************************************************************
Applies the hashed log records to the page, if the page lsn is less than the
lsn of a log record. This can be called when a buffer page has just been
read in, or also for a page already in the buffer pool. */

void
recv_recover_page(
/*==============*/
	ibool	recover_backup,	/* in: TRUE if we are recovering a backup
				page: then we do not acquire any latches
				since the page was read in outside the
				buffer pool */
	ibool	just_read_in,	/* in: TRUE if the i/o-handler calls this for
				a freshly read page */
	page_t*	page,		/* in: buffer page */
	ulint	space,		/* in: space id */
	ulint	page_no);	/* in: page number */
/************************************************************
Recovers from a checkpoint. When this function returns, the database is able
to start processing of new user transactions, but the function
recv_recovery_from_checkpoint_finish should be called later to complete
the recovery and free the resources used in it. */

ulint
recv_recovery_from_checkpoint_start(
/*================================*/
				/* out: error code or DB_SUCCESS */
	ulint	type,		/* in: LOG_CHECKPOINT or LOG_ARCHIVE */
	dulint	limit_lsn,	/* in: recover up to this lsn if possible */
	dulint	min_flushed_lsn,/* in: min flushed lsn from data files */
	dulint	max_flushed_lsn);/* in: max flushed lsn from data files */
/************************************************************
Completes recovery from a checkpoint. */

void
recv_recovery_from_checkpoint_finish(void);
/*======================================*/
/***********************************************************
Scans log from a buffer and stores new log data to the parsing buffer. Parses
and hashes the log records if new data found. */

ibool
recv_scan_log_recs(
/*===============*/
				/* out: TRUE if limit_lsn has been reached, or
				not able to scan any more in this log group */
	ibool	apply_automatically,/* in: TRUE if we want this function to
				apply log records automatically when the
				hash table becomes full; in the hot backup tool
				the tool does the applying, not this
				function */
	ulint	available_memory,/* in: we let the hash table of recs to grow
				to this size, at the maximum */
	ibool	store_to_hash,	/* in: TRUE if the records should be stored
				to the hash table; this is set to FALSE if just
				debug checking is needed */
	byte*	buf,		/* in: buffer containing a log segment or
				garbage */
	ulint	len,		/* in: buffer length */
	dulint	start_lsn,	/* in: buffer start lsn */
	dulint*	contiguous_lsn,	/* in/out: it is known that all log groups
				contain contiguous log data up to this lsn */
	dulint*	group_scanned_lsn);/* out: scanning succeeded up to this lsn */
/**********************************************************
Resets the logs. The contents of log files will be lost! */

void
recv_reset_logs(
/*============*/
	dulint	lsn,		/* in: reset to this lsn rounded up to
				be divisible by OS_FILE_LOG_BLOCK_SIZE,
				after which we add LOG_BLOCK_HDR_SIZE */
#ifdef UNIV_LOG_ARCHIVE
	ulint	arch_log_no,	/* in: next archived log file number */
#endif /* UNIV_LOG_ARCHIVE */
	ibool	new_logs_created);/* in: TRUE if resetting logs is done
				at the log creation; FALSE if it is done
				after archive recovery */
#ifdef UNIV_HOTBACKUP
/**********************************************************
Creates new log files after a backup has been restored. */

void
recv_reset_log_files_for_backup(
/*============================*/
	const char*	log_dir,	/* in: log file directory path */
	ulint		n_log_files,	/* in: number of log files */
	ulint		log_file_size,	/* in: log file size */
	dulint		lsn);		/* in: new start lsn, must be
					divisible by OS_FILE_LOG_BLOCK_SIZE */
#endif /* UNIV_HOTBACKUP */
/************************************************************
Creates the recovery system. */

void
recv_sys_create(void);
/*=================*/
/************************************************************
Inits the recovery system for a recovery operation. */

void
recv_sys_init(
/*==========*/
	ibool	recover_from_backup,	/* in: TRUE if this is called
					to recover from a hot backup */
	ulint	available_memory);	/* in: available memory in bytes */
/***********************************************************************
Empties the hash table of stored log records, applying them to appropriate
pages. */

void
recv_apply_hashed_log_recs(
/*=======================*/
	ibool	allow_ibuf);	/* in: if TRUE, also ibuf operations are
				allowed during the application; if FALSE,
				no ibuf operations are allowed, and after
				the application all file pages are flushed to
				disk and invalidated in buffer pool: this
				alternative means that no new log records
				can be generated during the application */
#ifdef UNIV_HOTBACKUP
/***********************************************************************
Applies log records in the hash table to a backup. */

void
recv_apply_log_recs_for_backup(void);
/*================================*/
#endif
#ifdef UNIV_LOG_ARCHIVE
/************************************************************
Recovers from archived log files, and also from log files, if they exist. */

ulint
recv_recovery_from_archive_start(
/*=============================*/
				/* out: error code or DB_SUCCESS */
	dulint	min_flushed_lsn,/* in: min flushed lsn field from the
				data files */
	dulint	limit_lsn,	/* in: recover up to this lsn if possible */
	ulint	first_log_no);	/* in: number of the first archived log file
				to use in the recovery; the file will be
				searched from INNOBASE_LOG_ARCH_DIR specified
				in server config file */
/************************************************************
Completes recovery from archive. */

void
recv_recovery_from_archive_finish(void);
/*===================================*/
#endif /* UNIV_LOG_ARCHIVE */

/* Block of log record data */
typedef struct recv_data_struct	recv_data_t;
struct recv_data_struct{
	recv_data_t*	next;	/* pointer to the next block or NULL */
				/* the log record data is stored physically
				immediately after this struct, max amount
				RECV_DATA_BLOCK_SIZE bytes of it */
};

/* Stored log record struct */
typedef struct recv_struct	recv_t;
struct recv_struct{
	byte		type;	/* log record type */
	ulint		len;	/* log record body length in bytes */
	recv_data_t*	data;	/* chain of blocks containing the log record
				body */
	dulint		start_lsn;/* start lsn of the log segment written by
				the mtr which generated this log record: NOTE
				that this is not necessarily the start lsn of
				this log record */
	dulint		end_lsn;/* end lsn of the log segment written by
				the mtr which generated this log record: NOTE
				that this is not necessarily the end lsn of
				this log record */
	UT_LIST_NODE_T(recv_t)
			rec_list;/* list of log records for this page */
};

/* Hashed page file address struct */
typedef struct recv_addr_struct	recv_addr_t;
struct recv_addr_struct{
	ulint		state;	/* RECV_NOT_PROCESSED, RECV_BEING_PROCESSED,
				or RECV_PROCESSED */
	ulint		space;	/* space id */
	ulint		page_no;/* page number */
	UT_LIST_BASE_NODE_T(recv_t)
			rec_list;/* list of log records for this page */
	hash_node_t	addr_hash;
};

/* Recovery system data structure */
typedef struct recv_sys_struct	recv_sys_t;
struct recv_sys_struct{
	mutex_t		mutex;	/* mutex protecting the fields apply_log_recs,
				n_addrs, and the state field in each recv_addr
				struct */
	ibool		apply_log_recs;
				/* this is TRUE when log rec application to
				pages is allowed; this flag tells the
				i/o-handler if it should do log record
				application */
	ibool		apply_batch_on;
				/* this is TRUE when a log rec application
				batch is running */
	dulint		lsn;	/* log sequence number */
	ulint		last_log_buf_size;
				/* size of the log buffer when the database
				last time wrote to the log */
	byte*		last_block;
				/* possible incomplete last recovered log
				block */
	byte*		last_block_buf_start;
				/* the nonaligned start address of the
				preceding buffer */
	byte*		buf;	/* buffer for parsing log records */
	ulint		len;	/* amount of data in buf */
	dulint		parse_start_lsn;
				/* this is the lsn from which we were able to
				start parsing log records and adding them to
				the hash table; ut_dulint_zero if a suitable
				start point not found yet */
	dulint		scanned_lsn;
				/* the log data has been scanned up to this
				lsn */
	ulint		scanned_checkpoint_no;
				/* the log data has been scanned up to this
				checkpoint number (lowest 4 bytes) */
	ulint		recovered_offset;
				/* start offset of non-parsed log records in
				buf */
	dulint		recovered_lsn;
				/* the log records have been parsed up to
				this lsn */
	dulint		limit_lsn;/* recovery should be made at most up to this
				lsn */
	ibool		found_corrupt_log;
				/* this is set to TRUE if we during log
				scan find a corrupt log block, or a corrupt
				log record, or there is a log parsing
				buffer overflow */
	log_group_t*	archive_group;
				/* in archive recovery: the log group whose
				archive is read */
	mem_heap_t*	heap;	/* memory heap of log records and file
				addresses*/
	hash_table_t*	addr_hash;/* hash table of file addresses of pages */
	ulint		n_addrs;/* number of not processed hashed file
				addresses in the hash table */
};

extern recv_sys_t*	recv_sys;
extern ibool		recv_recovery_on;
extern ibool		recv_no_ibuf_operations;
extern ibool		recv_needed_recovery;

extern ibool		recv_lsn_checks_on;
#ifdef UNIV_HOTBACKUP
extern ibool		recv_is_making_a_backup;
#endif /* UNIV_HOTBACKUP */
extern ulint		recv_max_parsed_page_no;

/* Size of the parsing buffer; it must accommodate RECV_SCAN_SIZE many
times! */
#define RECV_PARSING_BUF_SIZE	(2 * 1024 * 1024)

/* Size of block reads when the log groups are scanned forward to do a
roll-forward */
#define RECV_SCAN_SIZE		(4 * UNIV_PAGE_SIZE)

/* States of recv_addr_struct */
#define RECV_NOT_PROCESSED	71
#define RECV_BEING_READ		72
#define RECV_BEING_PROCESSED	73
#define RECV_PROCESSED		74

extern ulint	recv_n_pool_free_frames;

#ifndef UNIV_NONINL
#include "log0recv.ic"
#endif

#endif
