/*
   Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License, version 2.0,
   as published by the Free Software Foundation.

   This program is also distributed with certain software (including
   but not limited to OpenSSL) that is licensed under separate terms,
   as designated in a particular file or component or in included license
   documentation.  The authors of MySQL hereby grant you an additional
   permission to link the program and your derivative works with the
   separately licensed software that they have included with MySQL.

   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, version 2.0, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
*/

#ifndef Restore_H
#define Restore_H

#include <SimulatedBlock.hpp>

#include <IntrusiveList.hpp>
#include <KeyTable.hpp>
#include <DLHashTable.hpp>
#include <DataBuffer.hpp>
#include <NodeBitmask.hpp>
#include <backup/BackupFormat.hpp>

#define JAM_FILE_ID 439


class Restore : public SimulatedBlock
{
  friend class RestoreProxy;

public:
  Restore(Block_context& ctx, Uint32 instanceNumber = 0);
  virtual ~Restore();
  BLOCK_DEFINES(Restore);
  
protected:
  
  void execSTTOR(Signal* signal);
  void sendSTTORRY(Signal*);
  void execREAD_CONFIG_REQ(Signal*);
  void execDUMP_STATE_ORD(Signal* signal);
  void execCONTINUEB(Signal* signal);
  void execRESTORE_LCP_REQ(Signal* signal);
  
  void execFSOPENREF(Signal*);
  void execFSOPENCONF(Signal*);
  void execFSREADREF(Signal*);
  void execFSREADCONF(Signal*);
  void execFSCLOSEREF(Signal*);
  void execFSCLOSECONF(Signal*);

  void execLQHKEYREF(Signal*);
  void execLQHKEYCONF(Signal*);
  
  typedef DataBuffer<15> List;

public:  
  struct Column
  {
    Uint16 m_id;
    Uint16 m_size;
    Uint16 m_unused;
    Uint16 m_flags; 

    enum Flags 
    { 
      COL_KEY  = 0x1,
      COL_VAR  = 0x2,
      COL_DISK = 0x4,
      COL_NULL = 0x8
    };
  };
private:

  struct File; // CC
  friend struct File;

  struct File 
  {
    File() {}
    Uint32 m_sender_ref;
    Uint32 m_sender_data;

    Uint32 m_fd;          // File pointer
    Uint32 m_file_type;   // File type
    Uint32 m_status;
    Uint32 m_lcp_version;

    enum StatusFlags 
    {
      FILE_EOF = 1,
      FILE_THREAD_RUNNING = 2,
      RESTORE_THREAD_RUNNING = 4,
      FIRST_READ = 8,
      READING_RECORDS = 16
    };
    
    Uint32 m_table_id;
    Uint32 m_table_version;
    Uint32 m_fragment_id;
    List::Head m_columns;
    
    Uint32 m_current_page_ptr_i;
    Uint32 m_current_page_pos; 
    Uint32 m_bytes_left; // Bytes read from FS
    Uint32 m_current_file_page;  // Where in file 
    Uint32 m_outstanding_reads;  // 
    Uint32 m_outstanding_operations;
    Uint64 m_rows_restored;
    Uint64 m_restore_start_time;
    
    Uint32 m_current_page_index; // Where in page list are we
    List::Head m_pages;
    
    Uint32 nextHash;
    Uint32 prevHash;
    Uint32 nextList;
    Uint32 prevList;
    Uint32 nextPool;
    Uint32 m_lcp_no;

    bool is_lcp() const { return m_file_type == BackupFormat::LCP_FILE;}
  };
  typedef Ptr<File> FilePtr;
  
  Uint32 init_file(const struct RestoreLcpReq*, FilePtr);
  void release_file(FilePtr);
  
  void open_file(Signal*, FilePtr);
  void read_file(Signal*, FilePtr);
  void restore_next(Signal*, FilePtr);
  void parse_file_header(Signal*, FilePtr, const Uint32*, Uint32 len);
  void parse_table_list(Signal*, FilePtr, const Uint32*, Uint32 len);
  void parse_table_description(Signal*, FilePtr, const Uint32*, Uint32 len);
  void parse_fragment_header(Signal*, FilePtr, const Uint32*, Uint32 len);
  void parse_record(Signal*, FilePtr, const Uint32*, Uint32 len);
  void parse_fragment_footer(Signal*, FilePtr, const Uint32*, Uint32 len);
  void parse_gcp_entry(Signal*, FilePtr, const Uint32*, Uint32 len);
  void close_file(Signal*, FilePtr);

  void reorder_key(const struct KeyDescriptor*, Uint32* data, Uint32 len);
  Uint32 calulate_hash(Uint32 tableId, const Uint32 *src);

  void parse_error(Signal*, FilePtr, Uint32 line, Uint32 extra);
  int check_file_version(Signal*, Uint32 file_version);
  void restore_lcp_conf(Signal* signal, FilePtr);
  void crash_during_restore(FilePtr, Uint32 line, Uint32 errCode);
public:
  
private:
  class Dblqh* c_lqh;
  class Dbtup* c_tup;
  DLList<File> m_file_list;
  KeyTable<File> m_file_hash;
  ArrayPool<File> m_file_pool;

  Uint64 m_rows_restored;
  Uint64 m_millis_spent;
  Uint32 m_frags_restored;
  
  List::DataBufferPool m_databuffer_pool;
  Uint32 m_table_buf[MAX_WORDS_META_FILE];
};

NdbOut& operator << (NdbOut&, const Restore::Column&);


#undef JAM_FILE_ID

#endif
