/*
 * Copyright (C) 2008 Search Solution Corporation. All rights reserved by Search Solution.
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; version 2 of the License.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */


/*
 * file_io.h - I/O module at server
 *
 */

#ifndef _FILE_IO_H_
#define _FILE_IO_H_

#ident "$Id$"

#include "config.h"

#include <stdio.h>
#include <time.h>

#include "porting.h"
#include "storage_common.h"
#include "release_string.h"
#include "dbtype.h"
#include "memory_hash.h"
#if defined(SERVER_MODE)
#include "thread_impl.h"
#endif /* SERVER_MODE */
#include "lzoconf.h"
#include "lzo1x.h"
#include "thread_impl.h"

#define NULL_VOLDES   (-1)	/* Value of a null (invalid) vol descriptor */

#define FILEIO_INITIAL_BACKUP_UNITS    0

/* Note: this value must be at least as large as PATH_MAX */
#define FILEIO_MAX_USER_RESPONSE_SIZE 2000

#if defined(WINDOWS)
#define S_ISDIR(mode) ((mode) & _S_IFDIR)
#define S_ISREG(mode) ((mode) & _S_IFREG)
#endif /* WINDOWS */

#define FILEIO_FIRST_BACKUP_VOL_INFO      0
#define FILEIO_SECOND_BACKUP_VOL_INFO     1
#define FILEIO_NUM_THREADS_AUTO           0
#define FILEIO_MAX_BACKUP_PATH_LENGTH     PATH_MAX

typedef enum
{
  FILEIO_BACKUP_FULL_LEVEL,	/* Full backup */
  FILEIO_BACKUP_BIG_INCREMENT_LEVEL,	/* Backup since last full backup */
  FILEIO_BACKUP_SMALL_INCREMENT_LEVEL,	/* Backup since last INCRBIG */
  FILEIO_BACKUP_UNDEFINED_LEVEL	/* Undefined (must be highest ordinal value) */
} FILEIO_BACKUP_LEVEL;

typedef enum
{
  FILEIO_ZIP_NONE_METHOD,	/* None  */
  FILEIO_ZIP_LZO1X_METHOD,	/* LZO1X */
  FILEIO_ZIP_ZLIB_METHOD,	/* ZLIB  */
  FILEIO_ZIP_UNDEFINED_METHOD	/* Undefined (must be highest ordinal value) */
} FILEIO_ZIP_METHOD;

typedef enum
{
  FILEIO_ZIP_NONE_LEVEL,	/* None */
  FILEIO_ZIP_1_LEVEL,		/* best speed */
  FILEIO_ZIP_2_LEVEL,
  FILEIO_ZIP_3_LEVEL,
  FILEIO_ZIP_4_LEVEL,
  FILEIO_ZIP_5_LEVEL,
  FILEIO_ZIP_6_LEVEL,
  FILEIO_ZIP_7_LEVEL,
  FILEIO_ZIP_8_LEVEL,
  FILEIO_ZIP_9_LEVEL,		/* best compression */
  FILEIO_ZIP_UNDEFINED_LEVEL,	/* Undefined (must be highest ordinal value) */
  FILEIO_ZIP_LZO1X_999_LEVEL = FILEIO_ZIP_9_LEVEL,
  FILEIO_ZIP_LZO1X_DEFAULT_LEVEL = FILEIO_ZIP_1_LEVEL,
  FILEIO_ZIP_ZLIB_DEFAULT_LEVEL = FILEIO_ZIP_6_LEVEL
} FILEIO_ZIP_LEVEL;

typedef enum
{
  FILEIO_BACKUP_VOL_UNKNOWN,
  FILEIO_BACKUP_VOL_DIRECTORY,
  FILEIO_BACKUP_VOL_DEVICE
} FILEIO_BACKUP_VOL_TYPE;

typedef enum
{
  FILEIO_PROMPT_UNKNOWN,
  FILEIO_PROMPT_RANGE_TYPE,
  FILEIO_PROMPT_BOOLEAN_TYPE,
  FILEIO_PROMPT_STRING_TYPE,
  FILEIO_PROMPT_RANGE_WITH_SECONDARY_STRING_TYPE,
  FILEIO_PROMPT_DISPLAY_ONLY
} FILEIO_REMOTE_PROMPT_TYPE;

typedef enum
{
  FILEIO_ERROR_INTERRUPT,	/* error/interrupt */
  FILEIO_READ,			/* access device for read */
  FILEIO_WRITE			/* access device for write */
} FILEIO_TYPE;

typedef enum
{
  FILEIO_BACKUP_WRITE,		/* access backup device for write */
  FILEIO_BACKUP_READ		/* access backup device for read */
} FILEIO_BACKUP_TYPE;

/* Reserved area of FILEIO_PAGE */
typedef struct fileio_page_reserved FILEIO_PAGE_RESERVED;
struct fileio_page_reserved
{
  LOG_LSA lsa;			/* Log Sequence number of page, Page recovery
				   stuff */
};

/* The FILEIO_PAGE */
typedef struct fileio_page FILEIO_PAGE;
struct fileio_page
{
  FILEIO_PAGE_RESERVED prv;	/* System page area. Reserved */
  char page[1];			/* The user page area               */
};


typedef struct fileio_backup_page FILEIO_BACKUP_PAGE;
struct fileio_backup_page
{
  PAGEID iopageid;		/* Identifier of page to buffer */
  FILEIO_PAGE iopage;		/* The content of the page */
  PAGEID iopageid_dup;		/* Copy of pageid for redundant checking during
				 * restore. Note: that the offset of this field
				 * cannot be used, because the size of an iopage
				 * is not know until run-time.  Take care when
				 * trying to access this value.
				 */
};

/*
 * During incremental restores, this structure helps keep track of
 * which pages have already been restored, so we do not overwrite newer
 * pages from an earlier backup.
 */
typedef struct fileio_restore_page_cache FILEIO_RESTORE_PAGE_CACHE;
struct fileio_restore_page_cache
{
  MHT_TABLE *ht;
  unsigned int heap_id;
};

typedef struct fileio_backup_record_info FILEIO_BACKUP_RECORD_INFO;
struct fileio_backup_record_info
{
  LOG_LSA lsa;
  time_t at_time;
};

/* Backup header */

typedef struct fileio_backup_header FILEIO_BACKUP_HEADER;
struct fileio_backup_header
{
  PAGEID iopageid;		/* Must be the same as start of an FILEIO_BACKUP_PAGE
				   NOTE: a union would be better. */
  char magic[CUBRID_MAGIC_MAX_LENGTH];	/* Magic value for file/magic
					   Unix utility */
  int bk_hdr_version;		/* For future compatibility checking */
  char db_release[REL_MAX_RELEASE_LENGTH];	/* CUBRID Release */
  char db_fullname[FILEIO_MAX_BACKUP_PATH_LENGTH];	/* Fullname of backed up database.
							   Really more than one byte */
  time_t db_creation;		/* Database creation time */
  PGLENGTH db_iopagesize;	/* Size of database pages */
  float db_compatibility;	/* Compatibility of the database against the
				   current release of CUBRID */
  FILEIO_BACKUP_LEVEL level;	/* Backup level: one of the following
				 * level 0: Full backup, every database page
				 *          that has been allocated.
				 * level 1: All database pages that have
				 *          changed since last level 0 backup
				 * level 2: All database pages that have
				 *          changed since last level 0 or 1.
				 */
  LOG_LSA start_lsa;		/* A page with a LSA greater than this value
				   is going to be backed up. */
  LOG_LSA chkpt_lsa;		/* LSA for next incremental backup */

  /* remember lsa's for every backup level */
  time_t at_time;		/* Time of backup */
  int unit_num;			/* Part # of removable backup vol, count
				   from 1 */
  int bkup_iosize;		/* Buffered io size when backup was taken */
  FILEIO_BACKUP_RECORD_INFO previnfo[FILEIO_BACKUP_UNDEFINED_LEVEL];

  /* Backward chain to preceding backup volume. */
  char db_prec_bkvolname[FILEIO_MAX_BACKUP_PATH_LENGTH];

  /* Forward chain to next backup volume. Note not implemented yet. */
  char db_next_bkvolname[FILEIO_MAX_BACKUP_PATH_LENGTH];

  FILE *verbose_file_p;		/* Backupdb/Restoredb status msg */
  int bkpagesize;		/* size of backup page */
  FILEIO_ZIP_METHOD zip_method;	/* compression method  */
  FILEIO_ZIP_LEVEL zip_level;	/* compression level   */
  int skip_activelog;
};

/* Shouldn't this structure should use int and such? */
typedef struct fileio_backup_buffer FILEIO_BACKUP_BUFFER;
struct fileio_backup_buffer
{
  char loc_db_fullname[FILEIO_MAX_BACKUP_PATH_LENGTH];	/* Fullname specified in
							   the database-loc-file */
  char log_path[FILEIO_MAX_BACKUP_PATH_LENGTH];	/* for restore */
  LOG_LSA last_chkpt_lsa;	/* The chkpt_lsa of the highest level
				 * backup volume in the restore session. */
  int vdes;			/* Open descriptor of backup device */
  const char *vlabel;		/* Pointer to current backup device name */
  char name[PATH_MAX];		/* Name of the current backup volume:
				   either a file, or a raw device. */

  /* Original source location to backup (restore) volumes.  Can be a directory
     or raw device. Used for mult. volumes. */
  char current_path[PATH_MAX];

  int dtype;			/* Set to the type (dir, file, dev) */
  int iosize;			/* Optimal I/O pagesize for backup device */
  int count;			/* Number of current buffered bytes */
  int voltotalio;		/* Total number of bytes that have been
				   either read or written (current volume) */
  int alltotalio;		/* total for all volumes */
  char *buffer;			/* Pointer to the buffer */
  char *ptr;			/* Pointer to the first buffered byte when
				 * reading and pointer to the next byte to
				 * buffer when writting
				 */
  FILEIO_BACKUP_HEADER *bkuphdr;	/* pointer to header information */
};

typedef struct fileio_backup_db_buffer FILEIO_BACKUP_DB_BUFFER;
struct fileio_backup_db_buffer
{
  FILEIO_BACKUP_LEVEL level;	/* Backup level: one of the following
				 * level 0: Full backup, every database page
				 *          that has been allocated.
				 * level 1: All database pages that have
				 *          changed since last level 0 backup
				 * level 2: All database pages that have
				 *          changed since last level 0 or 1.
				 */
  LOG_LSA lsa;			/* A page with a LSA greater than this
				   value is going to be backed up. */
  int vdes;			/* Open file descriptor of device name for
				   writing purposes */
  VOLID volid;			/* Identifier of volume to backup/restore */
  int nbytes;			/* Number of bytes of file */
  const char *vlabel;		/* Pointer to file name to backup */
  FILEIO_BACKUP_PAGE *area;	/* Area to read/write the page */
};

typedef struct file_zip_page FILEIO_ZIP_PAGE;
struct file_zip_page
{
  lzo_uint buf_len;		/* compressed block size */
  lzo_byte buf[1];		/* data block */
};

typedef struct fileio_node FILEIO_NODE;
struct fileio_node
{
  struct fileio_node *prev;
  struct fileio_node *next;
  int pageid;
  bool writeable;
  int nread;
  FILEIO_BACKUP_PAGE *area;	/* Area to read/write the page */
  FILEIO_ZIP_PAGE *zip_page;	/* Area to compress/decompress the page */
  lzo_bytep wrkmem;
};

typedef struct fileio_queue FILEIO_QUEUE;
struct fileio_queue
{
  int size;
  FILEIO_NODE *head;
  FILEIO_NODE *tail;
  FILEIO_NODE *free_list;
};

typedef struct fileio_thread_info FILEIO_THREAD_INFO;
struct fileio_thread_info
{
#if defined(SERVER_MODE)
  MUTEX_T mtx;
  COND_T rcv;			/* condition variable of read_thread */
  COND_T wcv;			/* condition variable of write_thread */
#endif				/* SERVER_MODE */

  int tran_index;

  int num_threads;		/* number of read threads plus one write thread */
  int act_r_threads;		/* number of activated read threads */
  int end_r_threads;		/* number of ended read threads */

  int pageid;
  int from_npages;

  FILEIO_TYPE io_type;
  int errid;

  bool only_updated_pages;

  int check_ratio;
  int check_npages;

  FILEIO_QUEUE io_queue;
};

typedef struct io_backup_session FILEIO_BACKUP_SESSION;
struct io_backup_session
{
  FILEIO_BACKUP_TYPE type;
  FILEIO_BACKUP_BUFFER bkup;	/* Buffering area for backup device  */
  FILEIO_BACKUP_DB_BUFFER dbfile;	/* Buffer area for database files */
  FILEIO_THREAD_INFO read_thread_info;	/* read-threads info */
};

extern int fileio_format (THREAD_ENTRY * thread_p, const char *db_fullname,
			  const char *vlabel, VOLID volid, DKNPAGES npages,
			  bool sweep_clean, bool dolock, bool dosync);
extern DKNPAGES fileio_expand (VOLID volid, DKNPAGES npages_toadd);
extern DKNPAGES fileio_truncate (VOLID volid, DKNPAGES npages_to_resize);
extern void fileio_unformat (const char *vlabel);
extern int fileio_copy_volume (THREAD_ENTRY * thread_p, int from_vdes,
			       DKNPAGES npages, const char *to_vlabel,
			       VOLID to_volid, bool reset_recvinfo);
extern int fileio_reset_volume (int vdes, DKNPAGES npages,
				LOG_LSA * reset_lsa);
extern int fileio_mount (const char *db_fullname, const char *vlabel,
			 VOLID volid, int lockwait, bool dosync);
extern void fileio_dismount (int vdes);
extern void fileio_dismount_all (void);
extern void *fileio_read (int vdes, void *io_pgptr, PAGEID pageid);
extern void *fileio_write (int vdes, void *io_pgptr, PAGEID pageid);
extern void *fileio_writev (int vdes, void **arrayof_io_pgptr,
			    PAGEID start_pageid, DKNPAGES npages);
extern int fileio_synchronize (int vdes, bool force_flag);
extern int fileio_synchronize_all (bool force_flag, bool include_log);
extern void *fileio_read_user_area (int vdes, PAGEID pageid,
				    off_t start_offset, size_t nbytes,
				    void *area);
extern void *fileio_write_user_area (int vdes, PAGEID pageid,
				     off_t start_offset, ssize_t nbytes,
				     void *area);
extern bool fileio_is_volume_exist_and_file (const char *vlabel);
extern DKNPAGES fileio_get_number_of_volume_pages (int vdes);
extern const char *fileio_get_volume_label (VOLID volid);
extern VOLID fileio_find_volume_id_with_label (const char *vlabel);
extern int fileio_get_volume_descriptor (VOLID volid);
extern bool fileio_map_mounted (THREAD_ENTRY * thread_p,
				bool (*fun) (THREAD_ENTRY * thread_p,
					     VOLID volid, void *args),
				void *args);
extern int fileio_get_number_of_partition_free_pages (const char *path);
extern const char *fileio_rename (VOLID volid, const char *old_vlabel,
				  const char *new_vlabel);
extern bool fileio_is_volume_exist (const char *vlabel);
extern int fileio_get_max_name (const char *path,
				long int *filename_max,
				long int *pathname_max);
extern const char *fileio_get_base_file_name (const char *fullname);
extern char *fileio_get_directory_path (char *path, const char *fullname);
extern int fileio_get_volume_max_suffix (void);
extern void fileio_make_volume_info_name (char *volinfo_name,
					  const char *db_fullname);
extern void fileio_make_volume_ext_name (char *volext_fullname,
					 const char *ext_path,
					 const char *ext_name, VOLID volid);
extern void fileio_make_volume_ext_given_name (char *volext_fullname,
					       const char *ext_path,
					       const char *ext_name);
extern void fileio_make_volume_temp_name (char *voltmp_fullname,
					  const char *tmp_path,
					  const char *tmp_name, VOLID volid);
extern void fileio_make_log_active_name (char *logactive_name,
					 const char *log_path,
					 const char *dbname);
extern void fileio_make_log_active_temp_name (char *logactive_tmpname,
					      FILEIO_BACKUP_LEVEL level,
					      const char *active_name);
extern void fileio_make_log_archive_name (char *logarchive_name,
					  const char *log_path,
					  const char *dbname, int arvnum);
extern void fileio_make_log_info_name (char *loginfo_name,
				       const char *log_path,
				       const char *dbname);
extern void fileio_make_backup_volume_info_name (char *backup_volinfo_name,
						 const char *backinfo_path,
						 const char *dbname);
extern void fileio_make_backup_name (char *backup_name,
				     const char *nopath_volname,
				     const char *backup_path,
				     FILEIO_BACKUP_LEVEL level, int unit_num);
extern void fileio_remove_all_backup (int level);
extern FILEIO_BACKUP_SESSION *fileio_initialize_backup (const char
							*db_fullname,
							const char
							*backup_destination,
							FILEIO_BACKUP_SESSION
							* session,
							FILEIO_BACKUP_LEVEL
							level,
							const char
							*backup_verbose_file,
							int num_threads);
extern FILEIO_BACKUP_SESSION *fileio_start_backup (THREAD_ENTRY * thread_p,
						   const char *db_fullname,
						   time_t * db_creation,
						   FILEIO_BACKUP_LEVEL
						   backup_level,
						   LOG_LSA * backup_start_lsa,
						   LOG_LSA * backup_ckpt_lsa,
						   FILEIO_BACKUP_RECORD_INFO *
						   all_levels_info,
						   FILEIO_BACKUP_SESSION *
						   session,
						   FILEIO_ZIP_METHOD
						   zip_method,
						   FILEIO_ZIP_LEVEL
						   zip_level);
extern FILEIO_BACKUP_SESSION *fileio_finish_backup (THREAD_ENTRY * thread_p,
						    FILEIO_BACKUP_SESSION *
						    session);
extern void fileio_abort_backup (FILEIO_BACKUP_SESSION * session,
				 bool does_unformat_bk);
extern int fileio_backup_volume (THREAD_ENTRY * thread_p,
				 FILEIO_BACKUP_SESSION * session,
				 const char *from_vlabel, VOLID from_volid,
				 PAGEID last_page, bool only_updated_pages);
extern FILEIO_BACKUP_SESSION *fileio_start_restore (THREAD_ENTRY * thread_p,
						    const char *db_fullname,
						    char *backup_source,
						    time_t match_dbcreation,
						    PGLENGTH * db_iopagesize,
						    float *db_compatibility,
						    FILEIO_BACKUP_SESSION *
						    session,
						    FILEIO_BACKUP_LEVEL level,
						    bool authenticate,
						    time_t match_bkupcreation,
						    const char
						    *restore_verbose_file,
						    bool newvolpath);
extern int fileio_finish_restore (FILEIO_BACKUP_SESSION * session);
extern void fileio_abort_restore (FILEIO_BACKUP_SESSION * session);
extern int fileio_list_restore (THREAD_ENTRY * thread_p,
				const char *db_fullname, char *backup_source,
				PGLENGTH * bkdb_iopagesize,
				float *bkdb_compatibility,
				FILEIO_BACKUP_LEVEL level, bool newvolpath);
extern int fileio_get_next_restore_file (THREAD_ENTRY * thread_p,
					 FILEIO_BACKUP_SESSION * session,
					 char *filename, VOLID * volid,
					 int *vol_nbytes);
extern int fileio_restore_volume (THREAD_ENTRY * thread_p,
				  FILEIO_BACKUP_SESSION * session,
				  char *to_vlabel, char *prev_vlabel,
				  FILEIO_RESTORE_PAGE_CACHE * pages_cache,
				  bool remember_pages);
extern int fileio_skip_restore_volume (THREAD_ENTRY * thread_p,
				       FILEIO_BACKUP_SESSION * session);
extern const char *fileio_get_zip_method_string (FILEIO_ZIP_METHOD
						 zip_method);
extern const char *fileio_get_zip_level_string (FILEIO_ZIP_LEVEL zip_level);


extern int fileio_read_backup_info_entries (FILE * fp, int which_bkvinf);
extern int fileio_write_backup_info_entries (FILE * fp, int which_bkvinf);
extern const char *fileio_get_backup_info_volume_name (FILEIO_BACKUP_LEVEL
						       level, int unit_num,
						       int which_bkvinf);
extern int fileio_add_volume_to_backup_info (const char *name,
					     FILEIO_BACKUP_LEVEL level,
					     int unit_num, int which_bkvinf);
extern int fileio_clear_backup_info_level (int level, bool dealloc,
					   int which_bkvinf);
extern void fileio_finalize_backup_info (int which_bkvinf);

extern int fileio_request_user_response (THREAD_ENTRY * thread_p,
					 FILEIO_REMOTE_PROMPT_TYPE prompt_id,
					 const char *prompt, char *response,
					 const char *failure_prompt,
					 int range_low, int range_high,
					 const char *secondary_prompt,
					 int reprompt_value);

#if !defined(WINDOWS)
extern int fileio_symlink (const char *src, const char *dest, int overwrite);
extern int fileio_set_permission (const char *vlabel);
#endif /* !WINDOWS */

#endif /* _FILE_IO_H_ */
