mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 20:42:30 +01:00
2291f932b2
Recovery of state.records (the count of records which is stored into the header of the index file). For that, state.is_of_lsn is introduced; logic is explained in ma_recovery.c (look for "Recovery of the state"). The net gain is that in case of crash, we now recover state.records, and it is idempotent (ma_test_recovery tests it). state.checksum is not recovered yet, mail sent for discussion. - WL#3071 Maria Checkpoint: preparation for it, by protecting all modifications of the state in memory or on disk with intern_lock (with the exception of the really-often-modified state.records, which is now protected with the log's lock, see ma_recovery.c (look for "Recovery of the state"). Also, if maria_close() sees that Checkpoint is looking at this table it will not my_free() the share. - don't compute row's checksum twice in case of UPDATE (correction to a bugfix I made yesterday). storage/maria/ha_maria.cc: protect state write with intern_lock (against Checkpoint) storage/maria/ma_blockrec.c: * don't reset trn->rec_lsn in _ma_unpin_all_pages(), because it should wait until we have corrected the allocation in the bitmap (as the REDO can serve to correct the allocation during Recovery); introducing _ma_finalize_row() for that. * In a changeset yesterday I moved computation of the checksum into write_block_record(), to fix a bug in UPDATE. Now I notice that maria_update() already computes the checksum, it's just that it puts it into info->cur_row while _ma_update_block_record() uses info->new_row; so, removing the checksum computation from write_block_record(), putting it back into allocate_and_write_block_record() (which is called only by INSERT and UNDO_DELETE), and copying cur_row->checksum into new_row->checksum in _ma_update_block_record(). storage/maria/ma_check.c: new prototypes, they will take intern_lock when writing the state; also take intern_lock when changing share->kfile. In both cases this is to protect against Checkpoint reading/writing the state or reading kfile at the same time. Not updating create_rename_lsn directly at end of write_log_record_for_repair() as it wouldn't have intern_lock. storage/maria/ma_close.c: Checkpoint builds a list of shares (under THR_LOCK_maria), then it handles each such share (under intern_lock) (doing flushing etc); if maria_close() freed this share between the two, Checkpoint would see a bad pointer. To avoid this, when building the list Checkpoint marks each share, so that maria_close() knows it should not free it and Checkpoint will free it itself. Extending the zone covered by intern_lock to protect against Checkpoint reading kfile, writing state. storage/maria/ma_create.c: When we update create_rename_lsn, we also update is_of_lsn to the same value: it is logical, and allows us to test in maria_open() that the former is not bigger than the latter (the contrary is a sign of index header corruption, or severe logging bug which hinders Recovery, table needs a repair). _ma_update_create_rename_lsn_on_disk() also writes is_of_lsn; it now operates under intern_lock (protect against Checkpoint), a shortcut function is available for cases where acquiring intern_lock is not needed (table's creation or first open). storage/maria/ma_delete.c: if table is transactional, "records" is already decremented when logging UNDO_ROW_DELETE. storage/maria/ma_delete_all.c: comments storage/maria/ma_extra.c: Protect modifications of the state, in memory and/or on disk, with intern_lock, against a concurrent Checkpoint. When state goes to disk, update it's is_of_lsn (by calling the new _ma_state_info_write()). In HA_EXTRA_FORCE_REOPEN, don't set share->changed to 0 (undoing a change I made a few days ago) and ASK_MONTY storage/maria/ma_locking.c: no real code change here. storage/maria/ma_loghandler.c: Log-write-hooks for updating "state.records" under log's mutex when writing/updating/deleting a row or deleting all rows. storage/maria/ma_loghandler_lsn.h: merge (make LSN_ERROR and LSN_REPAIRED_BY_MARIA_CHK different) storage/maria/ma_open.c: When opening a table verify that is_of_lsn >= create_rename_lsn; if false the header must be corrupted. _ma_state_info_write() is split in two: _ma_state_info_write_sub() which is the old _ma_state_info_write(), and _ma_state_info_write() which additionally takes intern_lock if requested (to protect against Checkpoint) and updates is_of_lsn. _ma_open_keyfile() should change kfile.file under intern_lock to protect Checkpoint from reading a wrong kfile.file. storage/maria/ma_recovery.c: Recovery of state.records: when the REDO phase sees UNDO_ROW_INSERT which has a LSN > state.is_of_lsn it increments state.records. Same for UNDO_ROW_DELETE and UNDO_ROW_PURGE. When closing a table during Recovery, we know its state is at least as new as the current log record we are looking at, so increase is_of_lsn to the LSN of the current log record. storage/maria/ma_rename.c: update for new behaviour of _ma_update_create_rename_lsn_on_disk(). storage/maria/ma_test1.c: update to new prototype storage/maria/ma_test2.c: update to new prototype (actually prototype was changed days ago, but compiler does not complain about the extra argument??) storage/maria/ma_test_recovery.expected: new result file of ma_test_recovery. Improvements: record count read from index's header is now always correct. storage/maria/ma_test_recovery: "rm" fails if file does not exist. Redirect stderr of script. storage/maria/ma_write.c: if table is transactional, "records" is already incremented when logging UNDO_ROW_INSERT. Comments. storage/maria/maria_chk.c: update is_of_lsn too storage/maria/maria_def.h: - MARIA_STATE_INFO::is_of_lsn which is used by Recovery. It is stored into the index file's header. - Checkpoint can now mark a table as "don't free this", and maria_close() can reply "ok then you will free it". - new functions storage/maria/maria_pack.c: update for new name
97 lines
3.1 KiB
C
97 lines
3.1 KiB
C
/* Copyright (C) 2007 MySQL AB & Sanja Belkin
|
|
|
|
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 */
|
|
|
|
#ifndef _ma_loghandler_lsn_h
|
|
#define _ma_loghandler_lsn_h
|
|
|
|
/*
|
|
Transaction log record address:
|
|
file_no << 32 | offset
|
|
file_no is only 3 bytes so we can use signed integer to make
|
|
comparison more simple.
|
|
*/
|
|
typedef int64 TRANSLOG_ADDRESS;
|
|
|
|
/*
|
|
Compare addresses
|
|
A1 > A2 -> result > 0
|
|
A1 == A2 -> 0
|
|
A1 < A2 -> result < 0
|
|
*/
|
|
#define cmp_translog_addr(A1,A2) ((A1) - (A2))
|
|
|
|
/* LSN type (address of certain log record chank */
|
|
typedef TRANSLOG_ADDRESS LSN;
|
|
|
|
/* Gets file number part of a LSN/log address */
|
|
#define LSN_FILE_NO(L) ((L) >> 32)
|
|
|
|
/* Gets raw file number part of a LSN/log address */
|
|
#define LSN_FILE_NO_PART(L) ((L) & ((int64)0xFFFFFF00000000LL))
|
|
|
|
/* Gets record offset of a LSN/log address */
|
|
#define LSN_OFFSET(L) ((L) & 0xFFFFFFFFL)
|
|
|
|
/* Makes lsn/log address from file number and record offset */
|
|
#define MAKE_LSN(F,S) ((LSN) ((((uint64)(F)) << 32) | (S)))
|
|
|
|
/* checks LSN */
|
|
#define LSN_VALID(L) \
|
|
((LSN_FILE_NO_PART(L) != FILENO_IMPOSSIBLE) && \
|
|
(LSN_OFFSET(L) != LOG_OFFSET_IMPOSSIBLE))
|
|
|
|
/* size of stored LSN on a disk, don't change it! */
|
|
#define LSN_STORE_SIZE 7
|
|
|
|
/* Puts LSN into buffer (dst) */
|
|
#define lsn_store(dst, lsn) \
|
|
do { \
|
|
int3store((dst), LSN_FILE_NO(lsn)); \
|
|
int4store((dst) + 3, LSN_OFFSET(lsn)); \
|
|
} while (0)
|
|
|
|
/* Unpacks LSN from the buffer (P) */
|
|
#define lsn_korr(P) MAKE_LSN(uint3korr(P), uint4korr((P) + 3))
|
|
|
|
/* what we need to add to LSN to increase it on one file */
|
|
#define LSN_ONE_FILE ((int64)0x100000000LL)
|
|
|
|
#define LSN_REPLACE_OFFSET(L, S) (LSN_FILE_NO_PART(L) | (S))
|
|
|
|
/*
|
|
an 8-byte type whose most significant uchar is used for "flags"; 7
|
|
other bytes are a LSN.
|
|
*/
|
|
typedef LSN LSN_WITH_FLAGS;
|
|
#define LSN_WITH_FLAGS_TO_LSN(x) (x & ULL(0x00FFFFFFFFFFFFFF))
|
|
#define LSN_WITH_FLAGS_TO_FLAGS(x) (x & ULL(0xFF00000000000000))
|
|
|
|
#define FILENO_IMPOSSIBLE 0 /**< log file's numbering starts at 1 */
|
|
#define LOG_OFFSET_IMPOSSIBLE 0 /**< log always has a header */
|
|
#define LSN_IMPOSSIBLE 0
|
|
/* following LSN also is impossible */
|
|
#define LSN_ERROR 1
|
|
|
|
/** @brief some impossible LSN serve as markers */
|
|
#define LSN_REPAIRED_BY_MARIA_CHK ((LSN)2)
|
|
|
|
/**
|
|
@brief the maximum valid LSN.
|
|
Unlike ULONGLONG_MAX, it can be safely used in comparison with valid LSNs
|
|
(ULONGLONG_MAX is too big for correctness of cmp_translog_address()).
|
|
*/
|
|
#define LSN_MAX (LSN)ULL(0x00FFFFFFFFFFFFFF)
|
|
|
|
#endif
|