1 /*****************************************************************************
2 
3 Copyright (c) 2017, 2020, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License, version 2.0, as published by the
7 Free Software Foundation.
8 
9 This program is also distributed with certain software (including but not
10 limited to OpenSSL) that is licensed under separate terms, as designated in a
11 particular file or component or in included license documentation. The authors
12 of MySQL hereby grant you an additional permission to link the program and
13 your derivative works with the separately licensed software that they have
14 included with MySQL.
15 
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
19 for more details.
20 
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
24 
25 *****************************************************************************/
26 
27 /** @file include/arch0arch.h
28  Common interface for redo log and dirty page archiver system
29 
30  *******************************************************/
31 
32 #ifndef ARCH_ARCH_INCLUDE
33 #define ARCH_ARCH_INCLUDE
34 
35 #include <mysql/components/services/page_track_service.h>
36 #include "log0log.h"
37 #include "ut0mutex.h"
38 
39 #include <list>
40 
41 /** @name Archive file name prefix and constant length parameters. */
42 /* @{ */
43 /** Archive directory prefix */
44 const char ARCH_DIR[] = OS_FILE_PREFIX "ib_archive";
45 
46 /** Archive Log group directory prefix */
47 const char ARCH_LOG_DIR[] = "log_group_";
48 
49 /** Archive Page group directory prefix */
50 const char ARCH_PAGE_DIR[] = "page_group_";
51 
52 /** Archive log file prefix */
53 const char ARCH_LOG_FILE[] = "ib_log_";
54 
55 /** Archive page file prefix */
56 const char ARCH_PAGE_FILE[] = "ib_page_";
57 
58 /** //@} */
59 
60 /** File name for the durable file which indicates whether a group was made
61 durable or not. Required to differentiate durable group from group left over by
62 crash during clone operation. */
63 constexpr char ARCH_PAGE_GROUP_DURABLE_FILE_NAME[] = "durable";
64 
65 /** Byte length for printing LSN.
66 Each archive group name is appended with start LSN */
67 const uint MAX_LSN_DECIMAL_DIGIT = 32;
68 
69 /** Max string length for archive log file name */
70 const uint MAX_ARCH_LOG_FILE_NAME_LEN =
71     sizeof(ARCH_DIR) + 1 + sizeof(ARCH_LOG_DIR) + MAX_LSN_DECIMAL_DIGIT + 1 +
72     sizeof(ARCH_LOG_FILE) + MAX_LSN_DECIMAL_DIGIT + 1;
73 
74 /** Max string length for archive page file name */
75 const uint MAX_ARCH_PAGE_FILE_NAME_LEN =
76     sizeof(ARCH_DIR) + 1 + sizeof(ARCH_PAGE_DIR) + MAX_LSN_DECIMAL_DIGIT + 1 +
77     sizeof(ARCH_PAGE_FILE) + MAX_LSN_DECIMAL_DIGIT + 1;
78 
79 /** Max string length for archive group directory name */
80 const uint MAX_ARCH_DIR_NAME_LEN =
81     sizeof(ARCH_DIR) + 1 + sizeof(ARCH_PAGE_DIR) + MAX_LSN_DECIMAL_DIGIT + 1;
82 
83 /** Log archiver background thread */
84 void log_archiver_thread();
85 
86 /** Archiver thread event to signal that data is available */
87 extern os_event_t log_archiver_thread_event;
88 
89 /** Memory block size */
90 constexpr uint ARCH_PAGE_BLK_SIZE = UNIV_PAGE_SIZE_DEF;
91 
92 /** Archiver client state.
93 Archiver clients request archiving for specific interval using
94 the start and stop interfaces. During this time the client is
95 attached to global Archiver system. A client copies archived
96 data for the interval after calling stop. System keeps the data
97 till the time client object is destroyed.
98 
99 @startuml
100 
101   state ARCH_CLIENT_STATE_INIT
102   state ARCH_CLIENT_STATE_STARTED
103   state ARCH_CLIENT_STATE_STOPPED
104 
105   [*] -down-> ARCH_CLIENT_STATE_INIT
106   ARCH_CLIENT_STATE_INIT -down-> ARCH_CLIENT_STATE_STARTED : Attach and start \
107   archiving
108   ARCH_CLIENT_STATE_STARTED -right-> ARCH_CLIENT_STATE_STOPPED : Stop \
109   archiving
110   ARCH_CLIENT_STATE_STOPPED -down-> [*] : Detach client
111 
112 @enduml */
113 enum Arch_Client_State {
114   /** Client is initialized */
115   ARCH_CLIENT_STATE_INIT = 0,
116 
117   /** Archiving started by client */
118   ARCH_CLIENT_STATE_STARTED,
119 
120   /** Archiving stopped by client */
121   ARCH_CLIENT_STATE_STOPPED
122 };
123 
124 /** Remove files related to page and log archiving.
125 @param[in]	file_path	path to the file
126 @param[in]	file_name	name of the file */
127 void arch_remove_file(const char *file_path, const char *file_name);
128 
129 /** Remove group directory and the files related to page and log archiving.
130 @param[in]	dir_path	path to the directory
131 @param[in]	dir_name	directory name */
132 void arch_remove_dir(const char *dir_path, const char *dir_name);
133 
134 /** Archiver system state.
135 Archiver state changes are triggered by client request to start or
136 stop archiving and system wide events like shutdown fatal error etc.
137 Following diagram shows the state transfer.
138 
139 @startuml
140 
141   state ARCH_STATE_INIT
142   state ARCH_STATE_ACTIVE
143   state ARCH_STATE_PREPARE_IDLE
144   state ARCH_STATE_IDLE
145   state ARCH_STATE_ABORT
146 
147   [*] -down-> ARCH_STATE_INIT
148   ARCH_STATE_INIT -down-> ARCH_STATE_ACTIVE : Start archiving
149   ARCH_STATE_ACTIVE -right-> ARCH_STATE_PREPARE_IDLE : Stop archiving
150   ARCH_STATE_PREPARE_IDLE -right-> ARCH_STATE_IDLE : All data archived
151   ARCH_STATE_IDLE -down-> ARCH_STATE_ABORT : Shutdown or Fatal Error
152   ARCH_STATE_PREPARE_IDLE --> ARCH_STATE_ACTIVE : Resume archiving
153   ARCH_STATE_IDLE --> ARCH_STATE_ACTIVE : Start archiving
154   ARCH_STATE_ABORT -down-> [*]
155 
156 @enduml */
157 enum Arch_State {
158   /** Archiver is initialized */
159   ARCH_STATE_INIT = 0,
160 
161   /** Archiver is active and archiving data */
162   ARCH_STATE_ACTIVE,
163 
164   /** Archiver is processing last data chunks before idle state */
165   ARCH_STATE_PREPARE_IDLE,
166 
167   /** Archiver is idle */
168   ARCH_STATE_IDLE,
169 
170   /** Server is in read only mode, and hence the archiver */
171   ARCH_STATE_READ_ONLY,
172 
173   /** Archiver is aborted */
174   ARCH_STATE_ABORT
175 };
176 
177 /** Archived data block state.
178 A data block is a block in memory that holds dirty page IDs before persisting
179 into disk. Shown below is the state transfer diagram for a data block.
180 
181 @startuml
182 
183   state ARCH_BLOCK_INIT
184   state ARCH_BLOCK_ACTIVE
185   state ARCH_BLOCK_READY_TO_FLUSH
186   state ARCH_BLOCK_FLUSHED
187 
188   [*] -down-> ARCH_BLOCK_INIT
189   ARCH_BLOCK_INIT -> ARCH_BLOCK_ACTIVE : Writing page ID
190   ARCH_BLOCK_ACTIVE -> ARCH_BLOCK_READY_TO_FLUSH : Block is full
191   ARCH_BLOCK_READY_TO_FLUSH -> ARCH_BLOCK_FLUSHED : Block is flushed
192   ARCH_BLOCK_FLUSHED --> ARCH_BLOCK_ACTIVE : Writing page ID
193   ARCH_BLOCK_FLUSHED -down-> [*]
194 
195 @enduml */
196 enum Arch_Blk_State {
197   /** Data block is initialized */
198   ARCH_BLOCK_INIT = 0,
199 
200   /** Data block is active and having data */
201   ARCH_BLOCK_ACTIVE,
202 
203   /** Data block is full but not flushed to disk */
204   ARCH_BLOCK_READY_TO_FLUSH,
205 
206   /** Data block is flushed and can be reused */
207   ARCH_BLOCK_FLUSHED
208 };
209 
210 /** Archiver block type */
211 enum Arch_Blk_Type {
212   /* Block which holds reset information */
213   ARCH_RESET_BLOCK = 0,
214 
215   /* Block which holds archived page IDs */
216   ARCH_DATA_BLOCK
217 };
218 
219 /** Archiver block flush type */
220 enum Arch_Blk_Flush_Type {
221   /** Flush when block is full */
222   ARCH_FLUSH_NORMAL = 0,
223 
224   /** Flush partial block.
225   Needed for persistent page tracking. */
226   ARCH_FLUSH_PARTIAL
227 };
228 
229 /** Page Archive doublewrite buffer block offsets */
230 enum Arch_Page_Dblwr_Offset {
231   /** Archive doublewrite buffer page offset for RESET page. */
232   ARCH_PAGE_DBLWR_RESET_PAGE = 0,
233 
234   /* Archive doublewrite buffer page offset for FULL FLUSH page. */
235   ARCH_PAGE_DBLWR_FULL_FLUSH_PAGE,
236 
237   /* Archive doublewrite buffer page offset for PARTIAL FLUSH page. */
238   ARCH_PAGE_DBLWR_PARTIAL_FLUSH_PAGE
239 };
240 
241 /** Initialize Page and Log archiver system
242 @return error code */
243 dberr_t arch_init();
244 
245 /** Free Page and Log archiver system */
246 void arch_free();
247 
248 /** Start log archiver background thread.
249 @return error code */
250 int start_log_archiver_background();
251 
252 /** Start page archiver background thread.
253 @return error code */
254 int start_page_archiver_background();
255 
256 /** Archiver thread event to signal that data is available */
257 extern os_event_t page_archiver_thread_event;
258 
259 /** Page archiver background thread */
260 void page_archiver_thread();
261 
262 /** Wakes up archiver threads.
263 @return true iff any thread was still alive */
264 bool arch_wake_threads();
265 
266 /** Forward declarations */
267 class Arch_Group;
268 class Arch_Log_Sys;
269 class Arch_Dblwr_Ctx;
270 struct Arch_Recv_Group_Info;
271 
272 /** Position in page ID archiving system */
273 struct Arch_Page_Pos {
274   /** Initialize a position */
275   void init();
276 
277   /** Position in the beginning of next block */
278   void set_next();
279 
280   /** Unique block number */
281   uint64_t m_block_num;
282 
283   /** Offset within a block */
284   uint m_offset;
285 
286   bool operator<(Arch_Page_Pos pos) {
287     if (m_block_num < pos.m_block_num ||
288         (m_block_num == pos.m_block_num && m_offset <= pos.m_offset)) {
289       return (true);
290     }
291     return (false);
292   }
293 };
294 
295 /** Structure which represents a point in a file. */
296 struct Arch_Point {
297   /** LSN of the point */
298   lsn_t lsn{LSN_MAX};
299 
300   /** Position of the point */
301   Arch_Page_Pos pos;
302 };
303 
304 /* Structure which represents a file in a group and its reset points. */
305 struct Arch_Reset_File {
306   /* Initialize the structure. */
307   void init();
308 
309   /* Index of the file in the group */
310   uint m_file_index{0};
311 
312   /* LSN of the first reset point in the vector of reset points this
313   structure maintains. Treated as the file LSN. */
314   lsn_t m_lsn{LSN_MAX};
315 
316   /* Vector of reset points which belong to this file */
317   std::vector<Arch_Point> m_start_point;
318 };
319 
320 /* Structure representing list of archived files. */
321 using Arch_Reset = std::deque<Arch_Reset_File>;
322 
323 /** In memory data block in Page ID archiving system */
324 class Arch_Block {
325  public:
326   /** Constructor: Initialize elements
327   @param[in]	blk_buf	buffer for data block
328   @param[in]	size	buffer size
329   @param[in]	type	block type */
Arch_Block(byte * blk_buf,uint size,Arch_Blk_Type type)330   Arch_Block(byte *blk_buf, uint size, Arch_Blk_Type type)
331       : m_data(blk_buf), m_size(size), m_type(type) {}
332 
333   /** Do a deep copy of the members of the block passed as the parameter.
334   @note This member needs to be updated whenever a new data member is added to
335   this class. */
336   void copy_data(const Arch_Block *block);
337 
338   /** Set the block ready to begin writing page ID
339   @param[in]	pos		position to initiate block number */
340   void begin_write(Arch_Page_Pos pos);
341 
342   /** End writing to a block.
343   Change state to #ARCH_BLOCK_READY_TO_FLUSH */
344   void end_write();
345 
346   /** Check if block is initialised or not.
347   @return true if it has been initialised, else false  */
is_init()348   bool is_init() const { return (m_state == ARCH_BLOCK_INIT); }
349 
is_active()350   bool is_active() const { return (m_state == ARCH_BLOCK_ACTIVE); }
351   /** Check if the block can be flushed or not.
352   @return true, if the block cannot be flushed */
is_flushable()353   bool is_flushable() const { return (m_state != ARCH_BLOCK_READY_TO_FLUSH); }
354 
355   /** Set current block flushed.
356   Must hold page archiver sys operation mutex.  */
set_flushed()357   void set_flushed() { m_state = ARCH_BLOCK_FLUSHED; }
358 
359   /** Add page ID to current block
360   @param[in]	page	page from buffer pool
361   @param[in]	pos	Archiver current position
362   @return true, if successful
363           false, if no more space in current block */
364   bool add_page(buf_page_t *page, Arch_Page_Pos *pos);
365 
366   /* Add reset information to the current reset block.
367   @param[in]	reset_lsn	reset lsn info
368   @param[in]	reset_pos	reset pos info which needs to be added
369   to the current reset block */
370   void add_reset(lsn_t reset_lsn, Arch_Page_Pos reset_pos);
371 
372   /** Copy page Ids from this block at read position to a buffer.
373   @param[in]	read_pos	current read position
374   @param[in]	read_len	length of data to copy
375   @param[out]	read_buff	buffer to copy page IDs.
376                                   Caller must allocate the buffer.
377   @return true, if successful
378           false, if block is already overwritten */
379   bool get_data(Arch_Page_Pos *read_pos, uint read_len, byte *read_buff);
380 
381   /** Copy page Ids from a buffer to this block.
382   @param[in]	read_len	length of data to copy
383   @param[in]	read_buff	buffer to copy page IDs from
384   @param[in]	read_offset	offset from where to write
385   @return true if successful */
386   bool set_data(uint read_len, byte *read_buff, uint read_offset);
387 
388   /** Flush this block to the file group
389   @param[in]	file_group	current archive group
390   @param[in]	type		flush type
391   @return error code. */
392   dberr_t flush(Arch_Group *file_group, Arch_Blk_Flush_Type type);
393 
394   /* Update the block header with the given LSN
395   @param[in]	stop_lsn	stop LSN to update in the block header
396   @param[in]	reset_lsn	reset LSN to update in the blk header */
397   void update_block_header(lsn_t stop_lsn, lsn_t reset_lsn);
398 
399   void read(Arch_Group *group, uint64_t offset);
400 
401   /** Set the data length of the block.
402   @param[in]	data_len	data length */
set_data_len(uint data_len)403   void set_data_len(uint data_len) { m_data_len = data_len; }
404 
405   /** @return data length of the block. */
get_data_len()406   uint get_data_len() const { return (m_data_len); }
407 
408   /** @return block number of the block. */
get_number()409   uint64_t get_number() const { return (m_number); }
410 
411   /** @return stop lsn */
get_stop_lsn()412   lsn_t get_stop_lsn() const { return (m_stop_lsn); }
413 
414   /** Get oldest LSN among the pages that are added to this block
415   @return oldest LSN in block pages */
get_oldest_lsn()416   lsn_t get_oldest_lsn() const { return (m_oldest_lsn); }
417 
418   /** Get current state of the block
419   @return block state */
get_state()420   Arch_Blk_State get_state() const { return (m_state); }
421 
422   /** Check if the block contains only zeroes.
423   @param[in]  block   block data
424   @return true if block is filled with zeroes. */
425   static bool is_zeroes(const byte *block);
426 
427   /** Check if the block data is valid.
428   @param[in]  block   block to be validated
429   @return true if it's a valid block, else false */
430   static bool validate(byte *block);
431 
432   /** Get file index of the file the block belongs to.
433   @return file index */
434   static uint get_file_index(uint64_t block_num);
435 
436   /** Get block type from the block header.
437   @param[in]     block   block from where to get the type
438   @return block type */
439   static uint get_type(byte *block);
440 
441   /** Get block data length from the block header.
442   @param[in]     block   block from where to get the data length
443   @return block data length */
444   static uint get_data_len(byte *block);
445 
446   /** Get the stop lsn stored in the block header.
447   @param[in]     block   block from where to fetch the stop lsn
448   @return stop lsn */
449   static lsn_t get_stop_lsn(byte *block);
450 
451   /** Get the block number from the block header.
452   @param[in]     block   block from where to fetch the block number
453   @return block number */
454   static uint64_t get_block_number(byte *block);
455 
456   /** Get the reset lsn stored in the block header.
457   @param[in]     block   block from where to fetch the reset lsn
458   @return reset lsn */
459   static lsn_t get_reset_lsn(byte *block);
460 
461   /** Get the checksum stored in the block header.
462   @param[in]     block   block from where to fetch the checksum
463   @return checksum */
464   static uint32_t get_checksum(byte *block);
465 
466   /** Fetch the offset for a block in the archive file.
467   @param[in]	block_num	block number
468   @param[in]	type		type of block
469   @return file offset of the block */
470   static uint64_t get_file_offset(uint64_t block_num, Arch_Blk_Type type);
471 
472  private:
473   /* @note member function copy_data needs to be updated whenever a new data
474   member is added to this class. */
475 
476   /** Block data buffer */
477   byte *m_data;
478 
479   /** Block data length in bytes */
480   uint m_data_len{};
481 
482   /** Total block size in bytes */
483   uint m_size;
484 
485   /** State of the block. */
486   Arch_Blk_State m_state{ARCH_BLOCK_INIT};
487 
488   /** Unique block number */
489   uint64_t m_number{};
490 
491   /** Type of block. */
492   Arch_Blk_Type m_type;
493 
494   /** Checkpoint lsn at the time the last page ID was added to the
495   block. */
496   lsn_t m_stop_lsn{LSN_MAX};
497 
498   /** Oldest LSN of all the page IDs added to the block since the last
499    * checkpoint */
500   lsn_t m_oldest_lsn{LSN_MAX};
501 
502   /** Start LSN or the last reset LSN of the group */
503   lsn_t m_reset_lsn{LSN_MAX};
504 };
505 
506 /** Archiver file context.
507 Represents a set of fixed size files within a group */
508 class Arch_File_Ctx {
509  public:
510   /** Constructor: Initialize members */
Arch_File_Ctx()511   Arch_File_Ctx() { m_file.m_file = OS_FILE_CLOSED; }
512 
513   /** Destructor: Close open file and free resources */
~Arch_File_Ctx()514   ~Arch_File_Ctx() {
515     close();
516 
517     if (m_name_buf != nullptr) {
518       ut_free(m_name_buf);
519     }
520   }
521 
522   /** Initializes archiver file context.
523   @param[in]	path		path to the file
524   @param[in]	base_dir	directory name prefix
525   @param[in]	base_file	file name prefix
526   @param[in]	num_files	initial number of files
527   @param[in]	file_size	file size in bytes
528   @return error code. */
529   dberr_t init(const char *path, const char *base_dir, const char *base_file,
530                uint num_files, uint64_t file_size);
531 
532   /** Open a file at specific index
533   @param[in]	read_only	open in read only mode
534   @param[in]	start_lsn	start lsn for the group
535   @param[in]	file_index	index of the file within the group which needs
536   to be opened
537   @param[in]	file_offset	start offset
538   @return error code. */
539   dberr_t open(bool read_only, lsn_t start_lsn, uint file_index,
540                uint64_t file_offset);
541 
542   /** Add a new file and open
543   @param[in]	start_lsn	start lsn for the group
544   @param[in]	file_offset	start offset
545   @return error code. */
546   dberr_t open_new(lsn_t start_lsn, uint64_t file_offset);
547 
548   /** Open next file for read
549   @param[in]	start_lsn	start lsn for the group
550   @param[in]	file_offset	start offset
551   @return error code. */
552   dberr_t open_next(lsn_t start_lsn, uint64_t file_offset);
553 
554   /** Read data from the current file that is open.
555   Caller must ensure that the size is within the limits of current file
556   context.
557   @param[in,out]	to_buffer	read data into this buffer
558   @param[in]		offset		file offset from where to read
559   @param[in]		size		size of data to read in bytes
560   @return error code */
561   dberr_t read(byte *to_buffer, const uint64_t offset, const uint size);
562 
563   /** Write data to this file context from the given file offset.
564   Data source is another file context or buffer. If buffer is NULL, data is
565   copied from input file context. Caller must ensure that the size is within
566   the limits of current file for both source and destination file context.
567   @param[in]	from_file	file context to copy data from
568   @param[in]	from_buffer	buffer to copy data or NULL
569   @param[in]	offset		file offset from where to write
570   @param[in]	size		size of data to copy in bytes
571   @return error code */
572   dberr_t write(Arch_File_Ctx *from_file, byte *from_buffer, uint offset,
573                 uint size);
574 
575   /** Write data to this file context from the current offset.
576   Data source is another file context or buffer. If buffer is NULL, data is
577   copied from input file context. Caller must ensure that the size is within
578   the limits of current file for both source and destination file context.
579   @param[in]	from_file	file context to copy data from
580   @param[in]	from_buffer	buffer to copy data or NULL
581   @param[in]	size		size of data to copy in bytes
582   @return error code */
583   dberr_t write(Arch_File_Ctx *from_file, byte *from_buffer, uint size);
584 
585   /** Flush file. */
flush()586   void flush() {
587     if (m_file.m_file != OS_FILE_CLOSED) {
588       os_file_flush(m_file);
589     }
590   }
591 
592   /** Close file, if open */
close()593   void close() {
594     if (m_file.m_file != OS_FILE_CLOSED) {
595       os_file_close(m_file);
596       m_file.m_file = OS_FILE_CLOSED;
597     }
598   }
599 
600   /** Check if file is closed
601   @return true, if file is closed */
is_closed()602   bool is_closed() const { return (m_file.m_file == OS_FILE_CLOSED); }
603 
604   /** Check how much is left in current file
605   @return length left in bytes */
bytes_left()606   uint64_t bytes_left() const {
607     ut_ad(m_size >= m_offset);
608     return (m_size - m_offset);
609   }
610 
611   /** Construct file name at specific index
612   @param[in]	idx	file index
613   @param[in]	dir_lsn	lsn of the group
614   @param[out]	buffer	file name including path.
615                           The buffer is allocated by caller.
616   @param[in]	length	buffer length */
617   void build_name(uint idx, lsn_t dir_lsn, char *buffer, uint length);
618 
619   /** Construct group directory name
620   @param[in]	dir_lsn	lsn of the group
621   @param[out]	buffer	directory name.
622                           The buffer is allocated by caller.
623   @param[in]	length	buffer length */
624   void build_dir_name(lsn_t dir_lsn, char *buffer, uint length);
625 
626   /** Get the logical size of a file.
627   @return logical file size. */
get_size()628   uint64_t get_size() const { return (m_size); }
629 
630   /* Fetch offset of the file open in this context.
631   @return file offset */
get_offset()632   uint64_t get_offset() const { return (m_offset); }
633 
634   /** Get number of files
635   @return current file count */
get_count()636   uint get_count() const { return (m_count); }
637 
638   /** Get the physical size of a file that is open in this context.
639   @return physical file size */
get_phy_size()640   uint64_t get_phy_size() const {
641     ut_ad(m_name_buf != nullptr);
642     os_file_size_t file_size = os_file_get_size(m_name_buf);
643     return (file_size.m_total_size);
644   }
645 
646   /** Update stop lsn of a file in the group.
647   @param[in]	file_index	file_index the current write_pos belongs to
648   @param[in]	stop_lsn	stop point */
649   void update_stop_point(uint file_index, lsn_t stop_lsn);
650 
651 #ifdef UNIV_DEBUG
652   /** Print recovery related data.
653   @param[in]	file_start_index	file index from where to begin */
654   void recovery_reset_print(uint file_start_index);
655 
656   /** Check if the information maintained in the memory is the same
657   as the information maintained in the files.
658   @return true if both sets of information are the same
659   @param[in]	group	group whose file is being validated
660   @param[in]	file_index	index of the file which is being validated
661   @param[in]	start_lsn
662   @param[in,out]	reset_count	count of files which has been validated
663   @return true if both the sets of information are the same. */
664   bool validate(Arch_Group *group, uint file_index, lsn_t start_lsn,
665                 uint &reset_count);
666 #endif
667 
668   /** Update the reset information in the in-memory structure that we maintain
669   for faster access.
670   @param[in]	lsn     lsn at the time of reset
671   @param[in]	pos     pos at the time of reset
672   @retval true if the reset point was saved
673   @retval false if the reset point wasn't saved because it was already saved */
674   void save_reset_point_in_mem(lsn_t lsn, Arch_Page_Pos pos);
675 
676   /** Find the appropriate reset LSN that is less than or equal to the
677   given lsn and fetch the reset point.
678   @param[in]	check_lsn	LSN to be searched against
679   @param[out]	reset_point	reset position of the fetched reset point
680   @return true if the search was successful. */
681   bool find_reset_point(lsn_t check_lsn, Arch_Point &reset_point);
682 
683   /** Find the first stop LSN that is greater than the given LSN and fetch
684   the stop point.
685   @param[in]	group		the group whose stop_point we're interested in
686   @param[in]	check_lsn	LSN to be searched against
687   @param[out]	stop_point	stop point
688   @param[in]	last_pos	position of the last block in the group;
689   m_write_pos if group is active and m_stop_pos if not
690   @return true if the search was successful. */
691   bool find_stop_point(Arch_Group *group, lsn_t check_lsn,
692                        Arch_Point &stop_point, Arch_Page_Pos last_pos);
693 
694   /** Delete a single file belonging to the specified file index.
695   @param[in]	file_index	file index of the file which needs to be deleted
696   @param[in]	begin_lsn	group's start lsn
697   @return true if successful, else false. */
698   bool delete_file(uint file_index, lsn_t begin_lsn);
699 
700   /** Delete all files for this archive group
701   @param[in]	begin_lsn	group's start lsn */
702   void delete_files(lsn_t begin_lsn);
703 
704   /** Purge archived files until the specified purge LSN.
705   @param[in]	begin_lsn	start LSN of the group
706   @param[in]	end_lsn	end LSN of the group
707   @param[in]    purge_lsn   purge LSN until which files needs to be purged
708   @return LSN until which purging was successful
709   @retval LSN_MAX if there was no purging done. */
710   lsn_t purge(lsn_t begin_lsn, lsn_t end_lsn, lsn_t purge_lsn);
711 
712   /** Fetch the last reset file and last stop point info during recovery
713   @param[out]	reset_file	last reset file to be updated
714   @param[out]	stop_lsn	last stop lsn to be updated */
recovery_fetch_info(Arch_Reset_File & reset_file,lsn_t & stop_lsn)715   void recovery_fetch_info(Arch_Reset_File &reset_file, lsn_t &stop_lsn) {
716     if (m_reset.size() != 0) {
717       reset_file = m_reset.back();
718     }
719 
720     stop_lsn = get_last_stop_point();
721   }
722 
723   /** Fetch the status of the page tracking system.
724   @param[out]	status	vector of a pair of (ID, bool) where ID is the
725   start/stop point and bool is true if the ID is a start point else false */
get_status(std::vector<std::pair<lsn_t,bool>> & status)726   void get_status(std::vector<std::pair<lsn_t, bool>> &status) {
727     for (auto reset_file : m_reset) {
728       for (auto reset_point : reset_file.m_start_point) {
729         status.push_back(std::make_pair(reset_point.lsn, true));
730       }
731     }
732   }
733 
734   /** @return the stop_point which was stored last */
get_last_stop_point()735   lsn_t get_last_stop_point() const {
736     if (m_stop_points.size() == 0) {
737       return (LSN_MAX);
738     }
739 
740     return (m_stop_points.back());
741   }
742 
743   /** Fetch the reset points pertaining to a file.
744   @param[in]   file_index      file index of the file from which reset points
745   needs to be fetched
746   @param[in,out]	reset_pos	Update the reset_pos while fetching the
747   reset points
748   @return error code. */
749   dberr_t fetch_reset_points(uint file_index, Arch_Page_Pos &reset_pos);
750 
751   /** Fetch the stop lsn pertaining to a file.
752   @param[in]	last_file	true if the file for which the stop point is
753   being fetched for is the last file
754   @param[in,out]	write_pos	Update the write_pos while fetching the
755   stop points
756   @return error code. */
757   dberr_t fetch_stop_points(bool last_file, Arch_Page_Pos &write_pos);
758 
759  private:
760 #ifdef UNIV_DEBUG
761   /** Check if the reset information maintained in the memory is the same
762   as the information maintained in the given file.
763   @param[in]	file	file descriptor
764   @param[in]	file_index	index of the file
765   @param[in,out]	reset_count	number of files processed containing
766   reset data
767   @return true if both sets of information are the same */
768   bool validate_reset_block_in_file(pfs_os_file_t file, uint file_index,
769                                     uint &reset_count);
770 
771   /** Check if the stop LSN maintained in the memory is the same as the
772   information maintained in the files.
773   @param[in]	group	group whose file is being validated
774   @param[in]	file	file descriptor
775   @param[in]	file_index	index of the file for which the validation is
776   happening
777   @return true if both the sets of information are the same. */
778   bool validate_stop_point_in_file(Arch_Group *group, pfs_os_file_t file,
779                                    uint file_index);
780 #endif
781 
782   /** Fetch reset lsn of a particular reset point pertaining to a file.
783   @param[in]   block_num       block number where the reset occurred.
784   @return reset lsn */
785   lsn_t fetch_reset_lsn(uint64_t block_num);
786 
787  private:
788   /** File name buffer.
789   Used if caller doesn't allocate buffer. */
790   char *m_name_buf{nullptr};
791 
792   /** File name buffer length */
793   uint m_name_len{};
794 
795   /** Fixed length part of the file.
796   Path ended with directory separator. */
797   uint m_base_len{};
798 
799   /** Fixed part of the path to file */
800   const char *m_path_name{nullptr};
801 
802   /** Directory name prefix */
803   const char *m_dir_name{nullptr};
804 
805   /** File name prefix */
806   const char *m_file_name{nullptr};
807 
808   /** Current file descriptor */
809   pfs_os_file_t m_file;
810 
811   /** File index within the archive group */
812   uint m_index{};
813 
814   /** Current number of files in the archive group */
815   uint m_count{};
816 
817   /** Current file offset */
818   uint64_t m_offset{};
819 
820   /** File size limit in bytes */
821   uint64_t m_size{};
822 
823   /** Queue of file structure holding reset information pertaining to
824   their respective files in a group.
825   Protected by Arch_Page_Sys::m_mutex and Arch_Page_Sys::m_oper_mutex.
826   @note used only by the page archiver */
827   Arch_Reset m_reset;
828 
829   /** Vector of stop points corresponding to a file.
830   Stop point refers to the stop lsn (checkpoint lsn) until which the pages are
831   guaranteed to be tracked in a file. Each block in a file maintains this
832   information.
833   Protected by Arch_Page_Sys::m_oper_mutex.
834   @note used only by the page archiver */
835   std::vector<lsn_t> m_stop_points;
836 };
837 
838 /** Contiguous archived data for redo log or page tracking.
839 If there is a gap, that is if archiving is stopped and started, a new
840 group is created. */
841 class Arch_Group {
842  public:
843   /** Constructor: Initialize members
844   @param[in]	start_lsn	start LSN for the group
845   @param[in]	header_len	length of header for archived files
846   @param[in]	mutex		archive system mutex from caller */
Arch_Group(lsn_t start_lsn,uint header_len,ib_mutex_t * mutex)847   Arch_Group(lsn_t start_lsn, uint header_len, ib_mutex_t *mutex)
848       : m_begin_lsn(start_lsn),
849         m_header_len(header_len)
850 #ifdef UNIV_DEBUG
851         ,
852         m_arch_mutex(mutex)
853 #endif /* UNIV_DEBUG */
854   {
855     m_active_file.m_file = OS_FILE_CLOSED;
856     m_durable_file.m_file = OS_FILE_CLOSED;
857     m_stop_pos.init();
858   }
859 
860   /** Destructor: Delete all files for non-durable archiving. */
861   ~Arch_Group();
862 
863   /** Initialize the doublewrite buffer file context for the archive group.
864   @param[in]	path		path to the file
865   @param[in]	base_file	file name prefix
866   @param[in]	num_files	initial number of files
867   @param[in]	file_size	file size in bytes
868   @return error code. */
869   static dberr_t init_dblwr_file_ctx(const char *path, const char *base_file,
870                                      uint num_files, uint64_t file_size);
871 
872   /** Initialize the file context for the archive group.
873   File context keeps the archived data in files on disk. There
874   is one file context for a archive group.
875   @param[in]	path			path to the file
876   @param[in]	base_dir		directory name prefix
877   @param[in]	base_file		file name prefix
878   @param[in]	num_files		initial number of files
879   @param[in]	file_size		file size in bytes
880   @return error code. */
init_file_ctx(const char * path,const char * base_dir,const char * base_file,uint num_files,uint64_t file_size)881   dberr_t init_file_ctx(const char *path, const char *base_dir,
882                         const char *base_file, uint num_files,
883                         uint64_t file_size) {
884     return (m_file_ctx.init(path, base_dir, base_file, num_files, file_size));
885   }
886 
887   /* Close the file contexts when they're not required anymore. */
close_file_ctxs()888   void close_file_ctxs() {
889     m_file_ctx.close();
890 
891     if (m_durable_file.m_file != OS_FILE_CLOSED) {
892       os_file_close(m_durable_file);
893       m_durable_file.m_file = OS_FILE_CLOSED;
894     }
895   }
896 
897   /** Mark archive group inactive.
898   A group is marked inactive by archiver background before entering
899   into idle state ARCH_STATE_IDLE.
900   @param[in]	end_lsn	lsn where redo archiving is stopped */
disable(lsn_t end_lsn)901   void disable(lsn_t end_lsn) {
902     m_is_active = false;
903 
904     if (end_lsn != LSN_MAX) {
905       m_end_lsn = end_lsn;
906     }
907   }
908 
909   /** Attach a client to the archive group.
910   @param[in]	is_durable	true, if durable tracking is requested */
attach(bool is_durable)911   void attach(bool is_durable) {
912     ut_ad(mutex_own(m_arch_mutex));
913     ++m_num_active;
914 
915     if (is_durable) {
916       ++m_dur_ref_count;
917     } else {
918       ++m_ref_count;
919     }
920   }
921 
922   /** Detach a client when archiving is stopped by the client.
923   The client still has reference to the group so that the group
924   is not destroyed when it retrieves the archived data. The
925   reference is removed later by #Arch_Group::release.
926   @param[in]	stop_lsn	archive stop lsn for client
927   @param[in]	stop_pos	archive stop position for client. Used only by
928   the page_archiver.
929   @return number of active clients */
detach(lsn_t stop_lsn,Arch_Page_Pos * stop_pos)930   uint detach(lsn_t stop_lsn, Arch_Page_Pos *stop_pos) {
931     ut_ad(m_num_active > 0);
932     ut_ad(mutex_own(m_arch_mutex));
933     --m_num_active;
934 
935     if (m_num_active == 0) {
936       m_end_lsn = stop_lsn;
937       if (stop_pos != nullptr) {
938         m_stop_pos = *stop_pos;
939       }
940     }
941 
942     return (m_num_active);
943   }
944 
945   /** Release the archive group from a client.
946   Reduce the reference count. When all clients release the group,
947   the reference count falls down to zero. The function would then
948   return zero and the caller can remove the group.
949   @param[in]	is_durable	the client needs durable archiving */
release(bool is_durable)950   void release(bool is_durable) {
951     ut_ad(mutex_own(m_arch_mutex));
952     ut_a(!is_durable);
953 
954     ut_ad(m_ref_count > 0);
955     --m_ref_count;
956   }
957 
958   /** Construct file name for the active file which indicates whether a group
959   is active or not.
960   @note Used only by the page archiver.
961   @return error code. */
962   dberr_t build_active_file_name();
963 
964   /** Construct file name for the durable file which indicates whether a group
965   was made durable or not.
966   @note Used only by the page archiver.
967   @return error code. */
968   dberr_t build_durable_file_name();
969 
970   /** Mark the group active by creating a file in the respective group
971   directory. This is required at the time of recovery to know whether a group
972   was active or not in case of a crash.
973   @note Used only by the page archiver.
974   @return error code. */
975   int mark_active();
976 
977   /** Mark the group durable by creating a file in the respective group
978   directory. This is required at the time of recovery to differentiate durable
979   group from group left over by crash during clone operation.
980   @note Used only by the page archiver.
981   @return error code. */
982   int mark_durable();
983 
984   /** Mark the group inactive by deleting the 'active' file. This is required
985   at the time of crash recovery to know whether a group was active or not in
986   case of a crash.
987   @note Used only by the page archiver.
988   @return error code */
989   int mark_inactive();
990 
991   /** Check if archiving is going on for this group
992   @return true, if the group is active */
is_active()993   bool is_active() const { return (m_is_active); }
994 
995   /** Write the header (RESET page) to an archived file.
996   @note Used only by the Page Archiver and not by the Redo Log Archiver.
997   @param[in]	from_buffer	buffer to copy data
998   @param[in]	length		size of data to copy in bytes
999   @note Used only by the Page Archiver.
1000   @return error code */
1001   dberr_t write_file_header(byte *from_buffer, uint length);
1002 
1003   /** Write to the doublewrite buffer before writing archived data to a file.
1004   The source is either a file context or buffer. Caller must ensure that data
1005   is in single file in source file context.
1006   @param[in]	from_file	file context to copy data from
1007   @param[in]	from_buffer	buffer to copy data or NULL
1008   @param[in]	write_size	size of data to write in bytes
1009   @param[in]	offset		offset from where to write
1010   @note Used only by the Page Archiver.
1011   @return error code */
1012   static dberr_t write_to_doublewrite_file(Arch_File_Ctx *from_file,
1013                                            byte *from_buffer, uint write_size,
1014                                            Arch_Page_Dblwr_Offset offset);
1015 
1016   /** Archive data to one or more files.
1017   The source is either a file context or buffer. Caller must ensure that data
1018   is in single file in source file context.
1019   @param[in]	from_file	file context to copy data from
1020   @param[in]	from_buffer	buffer to copy data or NULL
1021   @param[in]	length		size of data to copy in bytes
1022   @param[in]	partial_write	true if the operation is part of partial flush
1023   @param[in]	do_persist	doublewrite to ensure persistence
1024   @return error code */
1025   dberr_t write_to_file(Arch_File_Ctx *from_file, byte *from_buffer,
1026                         uint length, bool partial_write, bool do_persist);
1027 
1028   /** Find the appropriate reset LSN that is less than or equal to the
1029   given lsn and fetch the reset point.
1030   @param[in]	check_lsn	LSN to be searched against
1031   @param[out]	reset_point	reset position of the fetched reset point
1032   @return true if the search was successful. */
find_reset_point(lsn_t check_lsn,Arch_Point & reset_point)1033   bool find_reset_point(lsn_t check_lsn, Arch_Point &reset_point) {
1034     return (m_file_ctx.find_reset_point(check_lsn, reset_point));
1035   }
1036 
1037   /** Find the first stop LSN that is greater than the given LSN and fetch
1038   the stop point.
1039   @param[in]	check_lsn	LSN to be searched against
1040   @param[out]	stop_point	stop point
1041   @param[in]	write_pos	latest write_pos
1042   @return true if the search was successful. */
find_stop_point(lsn_t check_lsn,Arch_Point & stop_point,Arch_Page_Pos write_pos)1043   bool find_stop_point(lsn_t check_lsn, Arch_Point &stop_point,
1044                        Arch_Page_Pos write_pos) {
1045     ut_ad(validate_info_in_files());
1046     Arch_Page_Pos last_pos = is_active() ? write_pos : m_stop_pos;
1047     return (m_file_ctx.find_stop_point(this, check_lsn, stop_point, last_pos));
1048   }
1049 
1050 #ifdef UNIV_DEBUG
1051   /** Adjust end LSN to end of file. This is used in debug
1052   mode to test the case when LSN is at file boundary.
1053   @param[in,out]        stop_lsn        stop lsn for client
1054   @param[out]   blk_len         last block length */
1055   void adjust_end_lsn(lsn_t &stop_lsn, uint32_t &blk_len);
1056 
1057   /** Adjust redo copy length to end of file. This is used
1058   in debug mode to archive only till end of file.
1059   @param[in,out]        length  data to copy in bytes */
1060   void adjust_copy_length(uint32_t &length);
1061 
1062   /** Check if the information maintained in the memory is the same
1063   as the information maintained in the files.
1064   @return true if both sets of information are the same */
1065   bool validate_info_in_files();
1066 #endif /* UNIV_DEBUG */
1067 
1068   /** Get the total number of archived files belonging to this group.
1069   @return number of archived files */
get_file_count()1070   uint get_file_count() const { return (m_file_ctx.get_count()); }
1071 
1072   /** Check if any client (durable or not) is attached to the archiver.
1073   @return true if any client is attached, else false */
is_referenced()1074   bool is_referenced() const {
1075     return (m_ref_count > 0) || (m_dur_ref_count > 0);
1076   }
1077 
1078   /** Check if any client requiring durable archiving is active.
1079   @return true if any durable client is still attached, else false */
is_durable_client_active()1080   bool is_durable_client_active() const {
1081     return (m_num_active != m_ref_count);
1082   }
1083 
1084   /** Check if any client requires durable archiving.
1085   @return true if there is at least 1 client that requires durable archiving*/
is_durable()1086   bool is_durable() const { return (m_dur_ref_count > 0); }
1087 
1088   /** Attach system client to the archiver during recovery if any group was
1089   active at the time of crash. */
attach_during_recovery()1090   void attach_during_recovery() { ++m_dur_ref_count; }
1091 
1092   /** Purge archived files until the specified purge LSN.
1093   @param[in]	purge_lsn	LSN until which archived files needs to be
1094   purged
1095   @param[out]	purged_lsn	LSN until which purging is successfule;
1096   LSN_MAX if there was no purging done
1097   @return error code */
1098   uint purge(lsn_t purge_lsn, lsn_t &purged_lsn);
1099 
1100   /** Operations to be done at the time of shutdown. */
shutdown()1101   static void shutdown() { s_dblwr_file_ctx.close(); }
1102 
1103   /** Update the reset information in the in-memory structure that we maintain
1104   for faster access.
1105   @param[in]	lsn     lsn at the time of reset
1106   @param[in]	pos     pos at the time of reset
1107   @retval true if the reset point was saved
1108   @retval false if the reset point wasn't saved because it was already saved */
save_reset_point_in_mem(lsn_t lsn,Arch_Page_Pos pos)1109   void save_reset_point_in_mem(lsn_t lsn, Arch_Page_Pos pos) {
1110     m_file_ctx.save_reset_point_in_mem(lsn, pos);
1111   }
1112 
1113   /** Update stop lsn of a file in the group.
1114   @param[in]	pos		stop position
1115   @param[in]	stop_lsn	stop point */
update_stop_point(Arch_Page_Pos pos,lsn_t stop_lsn)1116   void update_stop_point(Arch_Page_Pos pos, lsn_t stop_lsn) {
1117     m_file_ctx.update_stop_point(Arch_Block::get_file_index(pos.m_block_num),
1118                                  stop_lsn);
1119   }
1120 
1121   /** Recover the information belonging to this group from the archived files.
1122   @param[in,out]	group_info	structure containing information of a
1123   group obtained during recovery by scanning files
1124   @param[in,out]	new_empty_file	true if there is/was an empty archived
1125   file
1126   @param[in]		dblwr_ctx	file context related to doublewrite
1127   buffer
1128   @param[out]		write_pos	latest write position at the time of
1129   crash /shutdown that needs to be filled
1130   @param[out]		reset_pos   latest reset position at the time crash
1131   /shutdown that needs to be filled
1132   @return error code */
1133   dberr_t recover(Arch_Recv_Group_Info *group_info, bool &new_empty_file,
1134                   Arch_Dblwr_Ctx *dblwr_ctx, Arch_Page_Pos &write_pos,
1135                   Arch_Page_Pos &reset_pos);
1136 
1137   /** Reads the latest data block and reset block.
1138   This would be required in case of active group to start page archiving after
1139   recovery, and in case of inactive group to fetch stop lsn. So we perform this
1140   operation regardless of whether it's an active or inactive group.
1141   @param[in]	buf	buffer to read the blocks into
1142   @param[in]	offset	offset from where to read
1143   @param[in]	type	block type
1144   @return error code */
1145   dberr_t recovery_read_latest_blocks(byte *buf, uint64_t offset,
1146                                       Arch_Blk_Type type);
1147 
1148   /** Fetch the last reset file and last stop point info during recovery
1149   @param[out]   reset_file  last reset file to be updated
1150   @param[out]   stop_lsn    last stop lsn to be updated */
recovery_fetch_info(Arch_Reset_File & reset_file,lsn_t & stop_lsn)1151   void recovery_fetch_info(Arch_Reset_File &reset_file, lsn_t &stop_lsn) {
1152     m_file_ctx.recovery_fetch_info(reset_file, stop_lsn);
1153   }
1154 
1155 #ifdef UNIV_DEBUG
1156   /** Print recovery related data.
1157   @param[in]	file_start_index	file index from where to begin */
recovery_reset_print(uint file_start_index)1158   void recovery_reset_print(uint file_start_index) {
1159     DBUG_PRINT("page_archiver", ("Group : %" PRIu64 "", m_begin_lsn));
1160     m_file_ctx.recovery_reset_print(file_start_index);
1161     DBUG_PRINT("page_archiver", ("End lsn: %" PRIu64 "", m_end_lsn));
1162   }
1163 #endif
1164 
1165   /** Parse block for block info (header/data).
1166   @param[in]	cur_pos		position to read
1167   @param[in,out]	buff	buffer into which to write the parsed data
1168   @param[in]	buff_len	length of the buffer
1169   @return error code */
1170   int read_data(Arch_Page_Pos cur_pos, byte *buff, uint buff_len);
1171 
1172   /** Get archived file name at specific index in this group.
1173   Caller would use it to open and copy data from archived files.
1174   @param[in]	idx		file index in the group
1175   @param[out]	name_buf	file name and path. Caller must
1176                                   allocate the buffer.
1177   @param[in]	buf_len		allocated buffer length */
get_file_name(uint idx,char * name_buf,uint buf_len)1178   void get_file_name(uint idx, char *name_buf, uint buf_len) {
1179     ut_ad(name_buf != nullptr);
1180 
1181     /* Build name from the file context. */
1182     m_file_ctx.build_name(idx, m_begin_lsn, name_buf, buf_len);
1183   }
1184 
1185   /** Get file size for this group.
1186   Fixed size files are used for archiving data in a group.
1187   @return file size in bytes */
get_file_size()1188   uint64_t get_file_size() const { return (m_file_ctx.get_size()); }
1189 
1190   /** Get start LSN for this group
1191   @return start LSN */
get_begin_lsn()1192   lsn_t get_begin_lsn() const { return (m_begin_lsn); }
1193 
1194   /** @return stop LSN for this group */
get_end_lsn()1195   lsn_t get_end_lsn() const { return (m_end_lsn); }
1196 
1197   /** @return stop block position of the group. */
get_stop_pos()1198   Arch_Page_Pos get_stop_pos() const { return (m_stop_pos); }
1199 
1200   /** Fetch the status of the page tracking system.
1201   @param[out]	status	vector of a pair of (ID, bool) where ID is the
1202   start/stop point and bool is true if the ID is a start point else false */
get_status(std::vector<std::pair<lsn_t,bool>> & status)1203   void get_status(std::vector<std::pair<lsn_t, bool>> &status) {
1204     m_file_ctx.get_status(status);
1205 
1206     if (!is_active()) {
1207       status.push_back(std::make_pair(m_end_lsn, false));
1208     }
1209   }
1210 
1211   /** Disable copy construction */
1212   Arch_Group(Arch_Group const &) = delete;
1213 
1214   /** Disable assignment */
1215   Arch_Group &operator=(Arch_Group const &) = delete;
1216 
1217  private:
1218   /** Get page IDs from archived file
1219   @param[in]	read_pos	position to read from
1220   @param[in]	read_len	length of data to read
1221   @param[in]	read_buff	buffer to read page IDs
1222   @return error code */
1223   int read_from_file(Arch_Page_Pos *read_pos, uint read_len, byte *read_buff);
1224 
1225   /** Get the directory name for this archive group.
1226   It is used for cleaning up the archive directory.
1227   @param[out]	name_buf	directory name and path. Caller must
1228                                   allocate the buffer.
1229   @param[in]	buf_len		buffer length */
get_dir_name(char * name_buf,uint buf_len)1230   void get_dir_name(char *name_buf, uint buf_len) {
1231     m_file_ctx.build_dir_name(m_begin_lsn, name_buf, buf_len);
1232   }
1233 
1234   /** Check and replace blocks in archived files belonging to a group
1235   from the doublewrite buffer if required.
1236   @param[in]	dblwr_ctx	Doublewrite context which has the doublewrite
1237   buffer blocks
1238   @return error code */
1239   dberr_t recovery_replace_pages_from_dblwr(Arch_Dblwr_Ctx *dblwr_ctx);
1240 
1241   /** Delete the last file if there are no blocks flushed to it.
1242   @param[out]	num_files	number of files present in the group
1243   @param[in]	start_index	file index from where the files are present
1244   If this is not 0 then the files with file index less that this might have
1245   been purged.
1246   @param[in]	durable		true if the group is durable
1247   @param[out]	empty_file	true if there is/was an empty archived file
1248   @return error code. */
1249   dberr_t recovery_cleanup_if_required(uint &num_files, uint start_index,
1250                                        bool durable, bool &empty_file);
1251 
1252   /** Start parsing the archive file for archive group information.
1253   @param[out]		write_pos	latest write position at the time of
1254   crash /shutdown that needs to be filled
1255   @param[out]		reset_pos   latest reset position at the time crash
1256   /shutdown that needs to be filled
1257   @param[in]	start_index	file index from where the files are present
1258   If this is not 0 then the files with file index less that this might have
1259   been purged.
1260   @return error code */
1261   dberr_t recovery_parse(Arch_Page_Pos &write_pos, Arch_Page_Pos &reset_pos,
1262                          size_t start_index);
1263 
1264   /** Open the file which was open at the time of a crash, during crash
1265   recovery, and set the file offset to the last written offset.
1266   @param[in]	write_pos	block position from where page IDs will be
1267   tracked
1268   @param[in]	empty_file	true if an empty archived file was present at
1269   the time of crash. We delete this file as part of crash recovery process so
1270   this needs to be handled here.
1271   @return error code. */
1272   dberr_t open_file_during_recovery(Arch_Page_Pos write_pos, bool empty_file);
1273 
1274  private:
1275   /** If the group is active */
1276   bool m_is_active{true};
1277 
1278   /** To know which group was active at the time of a crash/shutdown during
1279   recovery we create an empty file in the group directory. This holds the name
1280   of the file. */
1281   char *m_active_file_name{nullptr};
1282 
1283   /** File descriptor for a file required to indicate that the group was
1284   active at the time of crash during recovery . */
1285   pfs_os_file_t m_active_file;
1286 
1287   /** File name for the durable file which indicates whether a group was made
1288   durable or not. Required to differentiate durable group from group left over
1289   by crash during clone operation. */
1290   char *m_durable_file_name{nullptr};
1291 
1292   /** File descriptor for a file to indicate that the group was made durable or
1293   not. Required to differentiate durable group from group left over by crash
1294   during clone operation. */
1295   pfs_os_file_t m_durable_file;
1296 
1297   /** Number of clients referencing the group */
1298   uint m_ref_count{};
1299 
1300   /** Number of clients referencing for durable archiving */
1301   uint m_dur_ref_count{};
1302 
1303   /** Number of clients for which archiving is in progress */
1304   uint m_num_active{};
1305 
1306   /** Start LSN for the archive group */
1307   lsn_t m_begin_lsn{LSN_MAX};
1308 
1309   /** End lsn for this archive group */
1310   lsn_t m_end_lsn{LSN_MAX};
1311 
1312   /** Stop position of the group, if it's not active. */
1313   Arch_Page_Pos m_stop_pos{};
1314 
1315   /** Header length for the archived files */
1316   uint m_header_len{};
1317 
1318   /** Archive file context */
1319   Arch_File_Ctx m_file_ctx;
1320 
1321   /** Doublewrite buffer file context.
1322   Note - Used only in the case of page archiver. */
1323   static Arch_File_Ctx s_dblwr_file_ctx;
1324 
1325 #ifdef UNIV_DEBUG
1326   /** Mutex protecting concurrent operations by multiple clients.
1327   This is either the redo log or page archive system mutex. Currently
1328   used for assert checks. */
1329   ib_mutex_t *m_arch_mutex;
1330 #endif /* UNIV_DEBUG */
1331 };
1332 
1333 /** A list of archive groups */
1334 using Arch_Grp_List = std::list<Arch_Group *, ut_allocator<Arch_Group *>>;
1335 
1336 /** An iterator for archive group */
1337 using Arch_Grp_List_Iter = Arch_Grp_List::iterator;
1338 
1339 /** Redo log archiving system */
1340 class Arch_Log_Sys {
1341  public:
1342   /** Constructor: Initialize members */
Arch_Log_Sys()1343   Arch_Log_Sys()
1344       : m_state(ARCH_STATE_INIT),
1345         m_archived_lsn(LSN_MAX),
1346         m_group_list(),
1347         m_current_group() {
1348     mutex_create(LATCH_ID_LOG_ARCH, &m_mutex);
1349   }
1350 
1351   /** Destructor: Free mutex */
~Arch_Log_Sys()1352   ~Arch_Log_Sys() {
1353     ut_ad(m_state == ARCH_STATE_INIT || m_state == ARCH_STATE_ABORT);
1354     ut_ad(m_current_group == nullptr);
1355     ut_ad(m_group_list.empty());
1356 
1357     mutex_free(&m_mutex);
1358   }
1359 
1360   /** Check if archiving is in progress.
1361   In #ARCH_STATE_PREPARE_IDLE state, all clients have already detached
1362   but archiver background task is yet to finish.
1363   @return true, if archiving is active */
is_active()1364   bool is_active() {
1365     return (m_state == ARCH_STATE_ACTIVE || m_state == ARCH_STATE_PREPARE_IDLE);
1366   }
1367 
1368   /** Check if archiver system is in initial state
1369   @return true, if redo log archiver state is #ARCH_STATE_INIT */
is_init()1370   bool is_init() { return (m_state == ARCH_STATE_INIT); }
1371 
1372   /** Get LSN up to which redo is archived
1373   @return last archived redo LSN */
get_archived_lsn()1374   lsn_t get_archived_lsn() { return (m_archived_lsn.load()); }
1375 
1376   /** Get current redo log archive group
1377   @return current archive group */
get_arch_group()1378   Arch_Group *get_arch_group() { return (m_current_group); }
1379 
1380   /** Start redo log archiving.
1381   If archiving is already in progress, the client
1382   is attached to current group.
1383   @param[out]	group		log archive group
1384   @param[out]	start_lsn	start lsn for client
1385   @param[out]	header		redo log header
1386   @param[in]	is_durable	if client needs durable archiving
1387   @return error code */
1388   int start(Arch_Group *&group, lsn_t &start_lsn, byte *header,
1389             bool is_durable);
1390 
1391   /** Stop redo log archiving.
1392   If other clients are there, the client is detached from
1393   the current group.
1394   @param[out]	group		log archive group
1395   @param[out]	stop_lsn	stop lsn for client
1396   @param[out]	log_blk		redo log trailer block
1397   @param[in,out]	blk_len		length in bytes
1398   @return error code */
1399   int stop(Arch_Group *group, lsn_t &stop_lsn, byte *log_blk,
1400            uint32_t &blk_len);
1401 
1402   /** Force to abort the archiver (state becomes ARCH_STATE_ABORT). */
1403   void force_abort();
1404 
1405   /** Release the current group from client.
1406   @param[in]	group		group the client is attached to
1407   @param[in]	is_durable	if client needs durable archiving */
1408   void release(Arch_Group *group, bool is_durable);
1409 
1410   /** Archive accumulated redo log in current group.
1411   This interface is for archiver background task to archive redo log
1412   data by calling it repeatedly over time.
1413   @param[in] init		true when called for first time; it will then
1414                                 be set to false
1415   @param[in]	curr_ctx	system redo logs to copy data from
1416   @param[out]	arch_lsn	LSN up to which archiving is completed
1417   @param[out]	wait		true, if no more redo to archive
1418   @return true, if archiving is aborted */
1419   bool archive(bool init, Arch_File_Ctx *curr_ctx, lsn_t *arch_lsn, bool *wait);
1420 
1421   /** Acquire redo log archiver mutex.
1422   It synchronizes concurrent start and stop operations by
1423   multiple clients. */
arch_mutex_enter()1424   void arch_mutex_enter() { mutex_enter(&m_mutex); }
1425 
1426   /** Release redo log archiver mutex */
arch_mutex_exit()1427   void arch_mutex_exit() { mutex_exit(&m_mutex); }
1428 
1429   /** Disable copy construction */
1430   Arch_Log_Sys(Arch_Log_Sys const &) = delete;
1431 
1432   /** Disable assignment */
1433   Arch_Log_Sys &operator=(Arch_Log_Sys const &) = delete;
1434 
1435  private:
1436   /** Wait for archive system to come out of #ARCH_STATE_PREPARE_IDLE.
1437   If the system is preparing to idle, #start needs to wait
1438   for it to come to idle state.
1439   @return true, if successful
1440           false, if needs to abort */
1441   bool wait_idle();
1442 
1443   /** Wait for redo log archive up to the target LSN.
1444   We need to wait till current log sys LSN during archive stop.
1445   @param[in]	target_lsn	target archive LSN to wait for
1446   @return error code */
1447   int wait_archive_complete(lsn_t target_lsn);
1448 
1449   /** Update checkpoint LSN and related information in redo
1450   log header block.
1451   @param[in,out]	header		redo log header buffer
1452   @param[in]	checkpoint_lsn	checkpoint LSN for recovery */
1453   void update_header(byte *header, lsn_t checkpoint_lsn);
1454 
1455   /** Check and set log archive system state and output the
1456   amount of redo log available for archiving.
1457   @param[in]	is_abort	need to abort
1458   @param[in,out]	archived_lsn	LSN up to which redo log is archived
1459   @param[out]	to_archive	amount of redo log to be archived */
1460   Arch_State check_set_state(bool is_abort, lsn_t *archived_lsn,
1461                              uint *to_archive);
1462 
1463   /** Copy redo log from file context to archiver files.
1464   @param[in]	file_ctx	file context for system redo logs
1465   @param[in]	length		data to copy in bytes
1466   @return error code */
1467   dberr_t copy_log(Arch_File_Ctx *file_ctx, uint length);
1468 
1469  private:
1470   /** Mutex to protect concurrent start, stop operations */
1471   ib_mutex_t m_mutex;
1472 
1473   /** Archiver system state.
1474   #m_state is protected by #m_mutex and #log_t::writer_mutex. For changing
1475   the state both needs to be acquired. For reading, hold any of the two
1476   mutexes. Same is true for #m_archived_lsn. */
1477   Arch_State m_state;
1478 
1479   /** System has archived log up to this LSN */
1480   atomic_lsn_t m_archived_lsn;
1481 
1482   /** List of log archive groups */
1483   Arch_Grp_List m_group_list;
1484 
1485   /** Current archive group */
1486   Arch_Group *m_current_group;
1487 
1488   /** Chunk size to copy redo data */
1489   uint m_chunk_size;
1490 
1491   /** System log file number where the archiving started */
1492   uint m_start_log_index;
1493 
1494   /** System log file offset where the archiving started */
1495   ib_uint64_t m_start_log_offset;
1496 };
1497 
1498 /** Vector of page archive in memory blocks */
1499 using Arch_Block_Vec = std::vector<Arch_Block *, ut_allocator<Arch_Block *>>;
1500 
1501 /** Page archiver in memory data */
1502 struct ArchPageData {
1503   /** Constructor */
ArchPageDataArchPageData1504   ArchPageData() {}
1505 
1506   /** Allocate buffer and initialize blocks
1507   @return true, if successful */
1508   bool init();
1509 
1510   /** Delete blocks and buffer */
1511   void clean();
1512 
1513   /** Get the block for a position
1514   @param[in]	pos	position in page archive sys
1515   @param[in]	type	block type
1516   @return page archive in memory block */
1517   Arch_Block *get_block(Arch_Page_Pos *pos, Arch_Blk_Type type);
1518 
1519   /** @return temporary block used to copy active block for partial flush. */
get_partial_flush_blockArchPageData1520   Arch_Block *get_partial_flush_block() const {
1521     return (m_partial_flush_block);
1522   }
1523 
1524   /** Vector of data blocks */
1525   Arch_Block_Vec m_data_blocks{};
1526 
1527   /** Reset block */
1528   Arch_Block *m_reset_block{nullptr};
1529 
1530   /** Temporary block used to copy active block for partial flush. */
1531   Arch_Block *m_partial_flush_block{nullptr};
1532 
1533   /** Block size in bytes */
1534   uint m_block_size{};
1535 
1536   /** Total number of blocks */
1537   uint m_num_data_blocks{};
1538 
1539   /** In memory buffer */
1540   byte *m_buffer{nullptr};
1541 };
1542 
1543 /** Forward declaration. */
1544 class Page_Arch_Client_Ctx;
1545 
1546 /** Dirty page archive system */
1547 class Arch_Page_Sys {
1548  public:
1549   /** Constructor: Initialize elements and create mutex */
1550   Arch_Page_Sys();
1551 
1552   /** Destructor: Free memory buffer and mutexes */
1553   ~Arch_Page_Sys();
1554 
1555   /** Start dirty page ID archiving.
1556   If archiving is already in progress, the client is attached to current group.
1557   @param[out]	group		page archive group the client gets attached to
1558   @param[out]	start_lsn	start lsn for client in archived data
1559   @param[out]	start_pos	start position for client in archived data
1560   @param[in]	is_durable	true if client needs durable archiving
1561   @param[in]	restart	true if client is already attached to current group
1562   @param[in]	recovery	true if archiving is being started during
1563   recovery
1564   @return error code */
1565   int start(Arch_Group **group, lsn_t *start_lsn, Arch_Page_Pos *start_pos,
1566             bool is_durable, bool restart, bool recovery);
1567 
1568   /** Stop dirty page ID archiving.
1569   If other clients are there, the client is detached from the current group.
1570   @param[in]	group		page archive group the client is attached to
1571   @param[out]	stop_lsn	stop lsn for client
1572   @param[out]	stop_pos	stop position in archived data
1573   @param[in]	is_durable	true if client needs durable archiving
1574   @return error code */
1575   int stop(Arch_Group *group, lsn_t *stop_lsn, Arch_Page_Pos *stop_pos,
1576            bool is_durable);
1577 
1578   /** Start dirty page ID archiving during recovery.
1579   @param[in]	group	Group which needs to be attached to the archiver
1580   @param[in]	new_empty_file  true if there was a empty file created
1581   @return error code */
1582   int start_during_recovery(Arch_Group *group, bool new_empty_file);
1583 
1584   /** Release the current group from client.
1585   @param[in]	group		group the client is attached to
1586   @param[in]	is_durable	if client needs durable archiving
1587   @param[in]	start_pos	start position when the client calling the
1588   release was started */
1589   void release(Arch_Group *group, bool is_durable, Arch_Page_Pos start_pos);
1590 
1591   /** Check and add page ID to archived data.
1592   Check for duplicate page.
1593   @param[in]	bpage		page to track
1594   @param[in]	track_lsn	LSN when tracking started
1595   @param[in]	frame_lsn	current LSN of the page
1596   @param[in]	force		if true, add page ID without check */
1597   void track_page(buf_page_t *bpage, lsn_t track_lsn, lsn_t frame_lsn,
1598                   bool force);
1599 
1600   /** Flush all the unflushed inactive blocks and flush the active block if
1601   required.
1602   @note Used only during the checkpointing process.
1603   @param[in]	checkpoint_lsn	next checkpoint LSN */
1604   void flush_at_checkpoint(lsn_t checkpoint_lsn);
1605 
1606   /** Archive dirty page IDs in current group.
1607   This interface is for archiver background task to flush page archive
1608   data to disk by calling it repeatedly over time.
1609   @param[out]	wait	true, if no more data to archive
1610   @return true, if archiving is aborted */
1611   bool archive(bool *wait);
1612 
1613   /** Acquire dirty page ID archiver mutex.
1614   It synchronizes concurrent start and stop operations by multiple clients. */
arch_mutex_enter()1615   void arch_mutex_enter() { mutex_enter(&m_mutex); }
1616 
1617   /** Release page ID archiver mutex */
arch_mutex_exit()1618   void arch_mutex_exit() { mutex_exit(&m_mutex); }
1619 
1620   /** Acquire dirty page ID archive operation mutex.
1621   It synchronizes concurrent page ID write to memory buffer. */
arch_oper_mutex_enter()1622   void arch_oper_mutex_enter() { mutex_enter(&m_oper_mutex); }
1623 
1624   /** Release page ID archiver operatiion  mutex */
arch_oper_mutex_exit()1625   void arch_oper_mutex_exit() { mutex_exit(&m_oper_mutex); }
1626 
1627   /* Save information at the time of a reset considered as the reset point.
1628   @param[in]  is_durable  true if it's durable page tracking
1629   @return true if the reset point information stored in the data block needs to
1630   be flushed to disk before returning to the caller, else false */
1631   bool save_reset_point(bool is_durable);
1632 
1633   /** Wait for reset info to be flushed to disk.
1634   @param[in]	request_block	block number until which blocks need to be
1635   flushed
1636   @return true if flushed, else false */
1637   bool wait_for_reset_info_flush(uint64_t request_block);
1638 
1639   /** Get the group which has tracked pages between the start_id and stop_id.
1640   @param[in,out]	start_id	start LSN from which tracked pages are
1641   required; updated to the actual start LSN used for the search
1642   @param[in,out]	stop_id     stop_lsn until when tracked pages are
1643   required; updated to the actual stop LSN used for the search
1644   @param[out]		group       group which has the required tracked
1645   pages, else nullptr.
1646   @return error */
1647   int fetch_group_within_lsn_range(lsn_t &start_id, lsn_t &stop_id,
1648                                    Arch_Group **group);
1649 
1650   /** Purge the archived files until the specified purge LSN.
1651   @param[in]	purge_lsn	purge lsn until where files needs to be purged
1652   @return error code
1653   @retval 0 if purge was successful */
1654   uint purge(lsn_t *purge_lsn);
1655 
1656   /** Update the stop point in all the required structures.
1657   @param[in]	cur_blk	block which needs to be updated with the stop info */
1658   void update_stop_info(Arch_Block *cur_blk);
1659 
1660   /** Fetch the status of the page tracking system.
1661   @param[out]	status	vector of a pair of (ID, bool) where ID is the
1662   start/stop point and bool is true if the ID is a start point else false */
get_status(std::vector<std::pair<lsn_t,bool>> & status)1663   void get_status(std::vector<std::pair<lsn_t, bool>> &status) {
1664     for (auto group : m_group_list) {
1665       group->get_status(status);
1666     }
1667   }
1668 
1669   /** Given start and stop position find number of pages tracked between them
1670   @param[in]	start_pos	start position
1671   @param[in]	stop_pos	stop position
1672   @param[out]	num_pages	number of pages tracked between start and stop
1673   position
1674   @return false if start_pos and stop_pos are invalid else true */
1675   bool get_num_pages(Arch_Page_Pos start_pos, Arch_Page_Pos stop_pos,
1676                      uint64_t &num_pages);
1677 
1678   /** Get approximate number of tracked pages between two given LSN values.
1679   @param[in,out]      start_id        fetch archived page Ids from this LSN
1680   @param[in,out]      stop_id         fetch archived page Ids until this LSN
1681   @param[out]         num_pages       number of pages tracked between specified
1682   LSN range
1683   @return error code */
1684   int get_num_pages(lsn_t &start_id, lsn_t &stop_id, uint64_t *num_pages);
1685 
1686   /** Get page IDs from a specific position.
1687   Caller must ensure that read_len doesn't exceed the block.
1688   @param[in]	group		group whose pages we're interested in
1689   @param[in]	read_pos	position in archived data
1690   @param[in]	read_len	amount of data to read
1691   @param[out]	read_buff	buffer to return the page IDs.
1692   @note Caller must allocate the buffer.
1693   @return true if we could successfully read the block. */
1694   bool get_pages(Arch_Group *group, Arch_Page_Pos *read_pos, uint read_len,
1695                  byte *read_buff);
1696 
1697   /** Get archived page Ids between two given LSN values.
1698   Attempt to read blocks directly from in memory buffer. If overwritten,
1699   copy from archived files.
1700   @param[in]	thd		thread handle
1701   @param[in]      cbk_func        called repeatedly with page ID buffer
1702   @param[in]      cbk_ctx         callback function context
1703   @param[in,out]  start_id        fetch archived page Ids from this LSN
1704   @param[in,out]  stop_id         fetch archived page Ids until this LSN
1705   @param[in]      buf             buffer to fill page IDs
1706   @param[in]      buf_len         buffer length in bytes
1707   @return error code */
1708   int get_pages(MYSQL_THD thd, Page_Track_Callback cbk_func, void *cbk_ctx,
1709                 lsn_t &start_id, lsn_t &stop_id, byte *buf, uint buf_len);
1710 
1711   /** Set the latest stop LSN to the checkpoint LSN at the time it's called. */
1712   void post_recovery_init();
1713 
1714   /** Recover the archiver system at the time of startup. Recover information
1715   related to all the durable groups and start archiving if any group was active
1716   at the time of crash/shutdown.
1717   @return error code */
1718   dberr_t recover();
1719 
1720 #ifdef UNIV_DEBUG
1721   /** Print information related to the archiver for debugging purposes. */
1722   void print();
1723 #endif
1724 
1725   /** Set the state of the archiver system to read only. */
set_read_only_mode()1726   void set_read_only_mode() { m_state = ARCH_STATE_READ_ONLY; }
1727 
1728   /** Check if archiver system is in initial state
1729   @return true, if page ID archiver state is #ARCH_STATE_INIT */
is_init()1730   bool is_init() const { return (m_state == ARCH_STATE_INIT); }
1731 
1732   /** Check if archiver system is active
1733   @return true, if page ID archiver state is #ARCH_STATE_ACTIVE or
1734   #ARCH_STATE_PREPARE_IDLE. */
is_active()1735   bool is_active() const {
1736     return (m_state == ARCH_STATE_ACTIVE || m_state == ARCH_STATE_PREPARE_IDLE);
1737   }
1738 
1739   /** @return true if in abort state */
is_abort()1740   bool is_abort() const { return (m_state == ARCH_STATE_ABORT); }
1741 
1742   /** Get the mutex protecting concurrent start, stop operations required
1743   for initialising group during recovery.
1744   @return mutex */
get_mutex()1745   ib_mutex_t *get_mutex() { return (&m_mutex); }
1746 
1747   /** @return operation mutex */
get_oper_mutex()1748   ib_mutex_t *get_oper_mutex() { return (&m_oper_mutex); }
1749 
1750   /** Fetch the system client context.
1751   @return system client context. */
get_sys_client()1752   Page_Arch_Client_Ctx *get_sys_client() const { return (m_ctx); }
1753 
1754   /** @return the latest stop LSN */
get_latest_stop_lsn()1755   lsn_t get_latest_stop_lsn() const { return (m_latest_stop_lsn); }
1756 
1757   /** Disable copy construction */
1758   Arch_Page_Sys(Arch_Page_Sys const &) = delete;
1759 
1760   /** Disable assignment */
1761   Arch_Page_Sys &operator=(Arch_Page_Sys const &) = delete;
1762 
1763   class Recv;
1764 
1765  private:
1766   /** Wait for archive system to come out of #ARCH_STATE_PREPARE_IDLE.
1767   If the system is preparing to idle, #start needs to wait
1768   for it to come to idle state.
1769   @return true, if successful
1770           false, if needs to abort */
1771   bool wait_idle();
1772 
1773   /** Check if the gap from last reset is short.
1774   If not many page IDs are added till last reset, we avoid
1775   taking a new reset point
1776   @return true, if the gap is small. */
1777   bool is_gap_small();
1778 
1779   /** Enable tracking pages in all buffer pools.
1780   @param[in]	tracking_lsn	track pages from this LSN */
1781   void set_tracking_buf_pool(lsn_t tracking_lsn);
1782 
1783   /** Track pages for which IO is already started. */
1784   void track_initial_pages();
1785 
1786   /** Flush the blocks to disk.
1787   @param[out]	wait	true, if no more data to archive
1788   @return error code */
1789   dberr_t flush_blocks(bool *wait);
1790 
1791   /** Flush all the blocks which are ready to be flushed but not flushed.
1792   @param[out]	cur_pos	position of block which needs to be flushed
1793   @param[in]	end_pos	position of block until which the blocks need to
1794   be flushed
1795   @return error code */
1796   dberr_t flush_inactive_blocks(Arch_Page_Pos &cur_pos, Arch_Page_Pos end_pos);
1797 
1798   /** Do a partial flush of the current active block
1799   @param[in]	cur_pos	position of block which needs to be flushed
1800   @param[in]	partial_reset_block_flush	true if reset block needs to be
1801   flushed
1802   @return error code */
1803   dberr_t flush_active_block(Arch_Page_Pos cur_pos,
1804                              bool partial_reset_block_flush);
1805 
1806  private:
1807   /** Mutex protecting concurrent start, stop operations */
1808   ib_mutex_t m_mutex;
1809 
1810   /** Archiver system state. */
1811   Arch_State m_state{ARCH_STATE_INIT};
1812 
1813   /** List of log archive groups */
1814   Arch_Grp_List m_group_list{};
1815 
1816   /** Position where last client started archiving */
1817   Arch_Page_Pos m_last_pos{};
1818 
1819   /** LSN when last client started archiving */
1820   lsn_t m_last_lsn{LSN_MAX};
1821 
1822   /** Latest LSN until where the tracked pages have been flushed. */
1823   lsn_t m_latest_stop_lsn{LSN_MAX};
1824 
1825   /** LSN until where the groups are purged. */
1826   lsn_t m_latest_purged_lsn{LSN_MAX};
1827 
1828   /** Mutex protecting concurrent operation on data */
1829   ib_mutex_t m_oper_mutex;
1830 
1831   /** Current archive group */
1832   Arch_Group *m_current_group{nullptr};
1833 
1834   /** In memory data buffer */
1835   ArchPageData m_data{};
1836 
1837   /** Position to add new page ID */
1838   Arch_Page_Pos m_write_pos{};
1839 
1840   /** Position to add new reset element */
1841   Arch_Page_Pos m_reset_pos{};
1842 
1843   /** Position set to explicitly request the flush archiver to flush until
1844   this position.
1845   @note this is always increasing and is only updated by the requester thread
1846   like checkpoint */
1847   Arch_Page_Pos m_request_flush_pos{};
1848 
1849   /** Block number set to explicitly request the flush archiver to partially
1850   flush the current active block with reset LSN.
1851   @note this is always increasing and is only updated by the requester thread
1852   like checkpoint */
1853   uint64_t m_request_blk_num_with_lsn{std::numeric_limits<uint64_t>::max()};
1854 
1855   /** Block number set once the flush archiver partially flushes the current
1856   active block with reset LSN.
1857   @note this is always increasing and is only updated by the requester thread
1858   like checkpoint */
1859   uint64_t m_flush_blk_num_with_lsn{std::numeric_limits<uint64_t>::max()};
1860 
1861   /** Position for start flushing
1862   @note this is always increasing and is only updated by the page archiver
1863   thread */
1864   Arch_Page_Pos m_flush_pos{};
1865 
1866   /** The index of the file the last reset belonged to.  */
1867   uint m_last_reset_file_index{0};
1868 
1869   /** System client. */
1870   Page_Arch_Client_Ctx *m_ctx;
1871 };
1872 
1873 /** Redo log archiver system global */
1874 extern Arch_Log_Sys *arch_log_sys;
1875 
1876 /** Dirty page ID archiver system global */
1877 extern Arch_Page_Sys *arch_page_sys;
1878 
1879 #endif /* ARCH_ARCH_INCLUDE */
1880