/*

Copyright (c) 2002-2005, Yauheni Akhotnikau
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

- The name of the author may not be used to endorse or promote products derived
from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.

*/

/*!
	\since v.1.4.0
	\brief Класс %std_file_committer_t.
*/
#if !defined( _OESS_1__DB__STORAGE__TRX__STD_FILE_COMMITTER_HPP_ )
#define _OESS_1__DB__STORAGE__TRX__STD_FILE_COMMITTER_HPP_

#include <vector>

#include <oess_1/file/h/file.hpp>

#include <oess_1/db/storage/trx/h/types.hpp>

namespace oess_1 {

namespace db {

namespace storage {

namespace trx {

//
// std_file_committer_t
//

/*!
	\since v.1.4.0
	\brief Реализация %committer_t, которая записывает все
		восстановленые страницы БД в новый файл.

	В методе reduce_traces_set() вычеркивает из исходного можества
	trace-файлов те trace-файлы, которые вошли в актуальный snapshot.
	Если актуального snapshot-а нет, то оставляет исходное можество
	trace-файлов неизменным.

	В методе initialize() создает новый файл нужного размера
	с нулевым содержимым. Если существует актуальный snapshot, то
	первоначальное содержимое временного файла берется из актуального
	snapshot-а и только отсутствующие в snapshot-е страницы заполняются
	нулевыми значениями.

	В методе finalize() переименовывает получившийся файл под именем
	основного файла БД.

	Если вызова finalize() не было (т.е. восстановление завершилось
	неудачно), то удаляет временный файл в деструкторе.

	Метод is_insufficient_trace_info_allowed() возвращает true, если при
	восстановлении был задействован актуальный snapshot-файл.
*/
class	OESS_1__DB__TYPE	std_file_committer_t
	:	public committer_t
	{
	public :
		//! Инициализирующий конструктор.
		std_file_committer_t(
			//! Физическое имя восстанавливаемой БД.
			const std::string & physic_name );
		virtual ~std_file_committer_t();

	//! \name Реализация унаследованных методов.
	//! \{
		virtual void
		reduce_traces_set(
			const trace_file_number_set_t & all_traces,
			trace_file_number_set_t & actual_traces );

		virtual void
		initialize(
			oess_1::uint_t total_page_count,
			oess_1::uint_t page_size,
			oess_1::uint_t block_size );

		virtual void
		finalize();

		virtual void
		store_block(
			oess_1::uint_t ordinal,
			oess_1::uint_t block_index,
			const std::string & block_value );

		virtual bool
		is_insufficient_trace_info_allowed() const;
	//! \}

		//! Получить физической имя БД с которой ведется работа.
		const std::string &
		physic_name() const;

		//! Задать имя файла, в который нужно переименовать
		//! временный файл после успешного завершения процедуры
		//! обратного воспроизведения.
		void
		set_result_file_name(
			const std::string & file_name );

	private :
		//! Физическое имя восстанавливаемой БД.
		std::string	m_physic_name;

		//! Коллекция snapshot-ов, которая относиться к данной БД.
		std::auto_ptr< snapshot_collection_t >	m_snapshots;

		//! Файл для сохранения значения БД.
		oess_1::file::file_t	m_file;

		//! Признак того, что файл должен быть уничтожен в деструкторе.
		/*!
			Выставляется в initialize(), если файл был успешно открыт.

			Сбрасывается в finalize(), если файл был успешно переименован. 
		*/
		bool	m_is_file_exists;

		//! Размер одной страницы основного файла в байтах.
		/*!
			Выставляется в initialize().
		*/
		oess_1::uint_t	m_page_size;

		//! Буфер для ввода/вывода в методе store_block.
		std::vector< oess_1::char_t >	m_io_buf;

		//! Имя файла, которое должен получить временный файл после
		//! успешного завершения процедуры обратного воспроизведения.
		/*!
			По умолчанию имеет значение имени основного файла БД.
		*/
		std::string	m_result_file_name;

		//! Создать имя временного файла для сохранения
		//! восстанавливаемого значения.
		std::string
		make_tmp_file_name(
			//! Физическое имя восстанавливаемой БД.
			const std::string & physic_name );
	};

//
// unclear_file_committer_t
//

/*!
	\since v.1.4.0
	\brief Реализация %committer_t, которая расчитана на восстановление
		только последней транзакции.

	Данная реализация предназначения для режима сохранения восстановочной
	информации oess_1::db::storage::trace_last. Поэтому она работает
	с "грязным" файлом БД и восстанавливает его значение.

	В методе reduce_traces_set() копирует исходное можество trace-файлов
	в результирующие. Если в исходном можестве находится более одного
	элемента то порождается исключение, т.к. в этом режиме должен
	быть только один trace-файл.

	В методе initialize() доводит "грязный" файл до нужного размера.

	В методе finalize() переименовывает получившийся файл под именем
	основного файла БД.

	Если вызова finalize() не было (т.е. восстановление завершилось
	неудачно), то ничего не делает.

	Метод is_insufficient_trace_info_allowed() всегда возвращает true.
*/
class	OESS_1__DB__TYPE	unclear_file_committer_t
	:	public committer_t
	{
	public :
		//! Инициализирующий конструктор.
		unclear_file_committer_t(
			//! Физическое имя восстанавливаемой БД.
			const std::string & physic_name );
		virtual ~unclear_file_committer_t();

	//! \name Реализация унаследованных методов.
	//! \{
		virtual void
		reduce_traces_set(
			const trace_file_number_set_t & all_traces,
			trace_file_number_set_t & actual_traces );

		virtual void
		initialize(
			oess_1::uint_t total_page_count,
			oess_1::uint_t page_size,
			oess_1::uint_t block_size );

		virtual void
		finalize();

		virtual void
		store_block(
			oess_1::uint_t ordinal,
			oess_1::uint_t block_index,
			const std::string & block_value );

		virtual bool
		is_insufficient_trace_info_allowed() const;
	//! \}

	private :
		//! Физическое имя восстанавливаемой БД.
		std::string	m_physic_name;
		//! "Грязный" файл БД. Открывается в конструкторе.
		oess_1::file::file_t	m_file;

		//! Размер одной страницы основного файла в байтах.
		/*!
			Выставляется в initialize().
		*/
		oess_1::uint_t	m_page_size;

		//! Буфер для ввода/вывода в методе store_block.
		std::vector< oess_1::char_t >	m_io_buf;
	};

//
// snapshot_file_committer_t
//

/*!
	\since v.1.4.0
	\brief Реализация %committer_t, которая предназначена для
		формирования snapshot-ов.

	В методе reduce_traces_set() вычисляет множество trace-файлов,
	которые должны быть использованы для построения очередного
	snapshot-а и формирует имя результирующего snapshot-а.

	Вся остальная функциональность наследуется из std_file_committer_t.
*/
class	OESS_1__DB__TYPE	snapshot_file_committer_t
	:	public std_file_committer_t
	{
		//! Псевдоним для базового типа.
		typedef std_file_committer_t	base_type_t;

	public :
		//! Инициализирующий конструктор.
		snapshot_file_committer_t(
			//! Физическое имя восстанавливаемой БД.
			const std::string & physic_name );
		virtual ~snapshot_file_committer_t();

	//! \name Реализация унаследованных методов.
	//! \{
		virtual void
		reduce_traces_set(
			const trace_file_number_set_t & all_traces,
			trace_file_number_set_t & actual_traces );
	//! \}

		//! Получить множество trace-файлов, которые вошли в snapshot.
		/*!
			Эти файлы уже не актуальны и могут быть, при необходимости,
			уничтожены.

			Возвращает корректное значение только, если отработал метод
			reduce_traces_set().

			\attention Значение этого множества вычисляется в методе
				reduce_traces_set() и не как не зависит от успешности формирования
				snapshot-а. Поэтому доверять данному значению можно только, если
				формирование snapshot-а прошло успешно.
		*/
		trace_file_number_set_t
		outdated_traces() const;

	private :
		//! Множество trace-файлов, которые вошли в snapshot.	
		trace_file_number_set_t	m_outdated_traces;
	};

} /* namespace trx */

} /* namespace storage */

} /* namespace db */

} /* namespace oess */

#endif

