if (unlikely(pending_state.update_nolock(gtid)))
{
give_error("Out of memory processing GTID for binlog GTID index"); return1;
} /* Sparseindex;werecordonlyselectedGTIDs,andscanthebinlogforward fromtheretofindtheexactspot.
*/ if (offset - previous_offset < offset_min_threshold)
{
*out_gtid_list= nullptr;
*out_gtid_count= 0; return0;
}
count= pending_state.count_nolock();
DBUG_ASSERT(count > 0/* Since we just updated with a GTID. */);
gtid_list= (rpl_gtid *)
my_malloc(key_memory_binlog_gtid_index, count*sizeof(*gtid_list), MYF(0)); if (unlikely(!gtid_list))
{
give_error("Out of memory allocating GTID list for binlog GTID index"); return1;
} if (unlikely(pending_state.get_gtid_list_nolock(gtid_list, count)))
{ /* Shouldn't happen as we allocated the list with the correct length. */
DBUG_ASSERT(false);
give_error("Internal error allocating GTID list for binlog GTID index");
my_free(gtid_list); return1;
}
pending_state.reset_nolock();
previous_offset= offset;
*out_gtid_list= gtid_list;
*out_gtid_count= count; return0;
}
int
Gtid_index_writer::async_update(uint32 event_offset,
rpl_gtid *gtid_list,
uint32 gtid_count)
{
lock_gtid_index(); int res= write_record(event_offset, gtid_list, gtid_count);
unlock_gtid_index();
my_free(gtid_list); return res;
}
void
Gtid_index_writer::close()
{
lock_gtid_index(); if (!error_state)
{
for (Node_page *p= n->first_page; p ; p= p->next)
{ if (unlikely(is_root))
*(p->flag_ptr) |= PAGE_FLAG_ROOT; if (likely(!p->next))
*(p->flag_ptr) |= PAGE_FLAG_LAST;
int4store(p->page + page_size - CHECKSUM_LEN,
my_checksum(0, p->page, page_size - CHECKSUM_LEN)); if (mysql_file_write(index_file, p->page, page_size, MYF(MY_NABP)))
{
give_error("Error writing index page"); return0;
}
}
DBUG_ASSERT(node_pos % page_size == 0); /* Page numbers are +1 just so that zero can denote invalid page pointer. */ return1 + (node_pos / (uint32)page_size);
}
/* Makesurethereisrequestedspaceinthecurrentpage,byallocatinga newspillpageifnecessary.
*/ int
Gtid_index_writer::reserve_space(Index_node *n, size_t bytes)
{
DBUG_ASSERT(bytes <= page_size); if (likely(n->current_page) &&
likely(n->current_ptr - n->current_page->page + bytes <=
(page_size - CHECKSUM_LEN))) return0; /* Not enough room, allocate a spill page. */
Node_page *page= alloc_page();
n->force_spill_page= false; if (!page) return1;
n->current_ptr=
init_header(page, n->level==0, !n->current_page); if (n->current_page)
n->current_page->next= page; else
n->first_page= page;
n->current_page= page; return0;
}
int
Gtid_index_writer::do_write_record(uint32 level,
uint32 event_offset, const rpl_gtid *gtid_list,
uint32 gtid_count)
{
DBUG_ASSERT(level <= max_level);
Index_node *n= nodes[level]; if (reserve_space(n, 8)) return1; /* Store the count as +1, so that 0 can mean "no more records". */
int4store(n->current_ptr, gtid_count+1);
int4store(n->current_ptr+4, event_offset);
n->current_ptr+= 8; for (uint32 i= 0; i < gtid_count; ++i)
{ if (reserve_space(n, 16)) return1;
int4store(n->current_ptr, gtid_list[i].domain_id);
int4store(n->current_ptr+4, gtid_list[i].server_id);
int8store(n->current_ptr+8, gtid_list[i].seq_no);
n->current_ptr+= 16;
}
Inthegeneralcase,wemoveupthroughthepathtotheroot,writing lower-levelnodepagetodiskandaddingchildpointersinhigher-level nodes,untilwereachanodethathasroom.Thisfinalnodemaybea freshlyallocatednewrootnodeinthefewtimeswhentheheightofthe treeincreases.
*/ for (;;)
{
Index_node *n= nodes[level]; if (update_gtid_state(&n->state, gtid_list, gtid_count)) return give_error("Out of memory updating the local GTID state");
if (check_room(level, gtid_count))
{ /* There is room in the node, just add the index record. */ return do_write_record(level, event_offset, gtid_list, gtid_count);
}
bool
Gtid_index_writer::check_room(uint32 level, uint32 gtid_count)
{
Index_node *n= nodes[level]; /* There's always room in an empty (to-be-allocated) page. */ if (!n->current_page || n->num_records == 0) returntrue; /* Makesureweuseatleast1/2apageofroomaftertheinitialrecord, settingaflagtoallocateaspillpagelaterifneeded.
*/
size_t avail= page_size - CHECKSUM_LEN - (n->current_ptr - n->current_page->page); if (n->num_records==1 && avail < page_size/2)
{
n->force_spill_page= true; returntrue;
} if (n->force_spill_page) returntrue;
size_t needed= 8 + 16*gtid_count; /* Non-leaf pages need extra 4 bytes for a child pointer. */ if (level > 0)
needed+= 4; return needed <= avail;
}
int
Gtid_index_writer::alloc_level_if_missing(uint32 level)
{ if (likely(nodes))
{ if (likely(max_level >= level)) return0;
DBUG_ASSERT(level == max_level+1); // Alloc one at a time
}
Index_node *node= new Index_node(level); if (!node) return give_error("Out of memory allocating new node");
Index_node **new_nodes= (Index_node **)
my_realloc(key_memory_binlog_gtid_index, nodes, (level+1)*sizeof(*nodes),
MYF(MY_ALLOW_ZERO_PTR|MY_ZEROFILL)); if (!new_nodes)
{ delete node; return give_error("Out of memory allocating larger node list");
}
new_nodes[level]= node;
nodes= new_nodes;
max_level= level; return0;
}
int
Gtid_index_base::update_gtid_state(rpl_binlog_state_base *state, const rpl_gtid *gtid_list, uint32 gtid_count)
{ for (uint32 i= 0; i < gtid_count; ++i) if (state->update_nolock(>id_list[i])) return1; return0;
}
Gtid_index_base::Node_page *Gtid_index_base::alloc_page()
{
Node_page *new_node= (Node_page *)
my_malloc(key_memory_binlog_gtid_index, sizeof(Node_page) + page_size,
MYF(MY_ZEROFILL)); if (!new_node)
give_error("Out of memory for allocating index page"); return new_node;
}
int Gtid_index_writer::give_error(constchar *msg)
{ if (!error_state)
{
sql_print_information("Error during binlog GTID index creation, will " "fallback to slower sequential binlog scan. " "Error is: %s", msg);
error_state= true;
} return1;
}
int
Gtid_index_reader::search_cmp_offset(uint32 offset,
rpl_binlog_state_base *state)
{ if (offset <= in_search_offset) return0; else return -1;
}
int
Gtid_index_reader::search_cmp_gtid_pos(uint32 offset,
rpl_binlog_state_base *state)
{ if (state->is_before_pos(in_search_gtid_pos)) return0; else return -1;
}
int
Gtid_index_reader::next_page()
{ if (!read_page->next) return1;
read_page= read_page->next;
read_ptr= read_page->flag_ptr + 4; return0;
}
int
Gtid_index_reader::find_bytes(uint32 num_bytes)
{ if ((my_ptrdiff_t)(read_ptr - read_page->page + num_bytes) <=
(my_ptrdiff_t)(page_size - CHECKSUM_LEN)) return0; return next_page();
}
int
Gtid_index_reader::get_child_ptr(uint32 *out_child_ptr)
{ if (find_bytes(4)) return give_error("Corrupt index, short index node");
*out_child_ptr= (uint32)uint4korr(read_ptr);
read_ptr+= 4; return0;
}
/* Readthestartofanindexrecord(countofGTIDsinthedifferentialstate andoffset). Returns: 0ok 1EOF,nomoredatainthisnode
*/ int
Gtid_index_reader::get_offset_count(uint32 *out_offset, uint32 *out_gtid_count)
{ if (find_bytes(8)) return1;
uint32 gtid_count= uint4korr(read_ptr); if (gtid_count == 0)
{ /* 0 means invalid/no record (we store N+1 for N GTIDs in record). */ return1;
}
*out_gtid_count= gtid_count - 1;
*out_offset= uint4korr(read_ptr + 4);
read_ptr+= 8; return0;
}
int
Gtid_index_reader::get_gtid_list(rpl_gtid *out_gtid_list, uint32 count)
{ for (uint32 i= 0; i < count; ++i)
{ if (find_bytes(16)) return give_error("Corrupt index, short index node");
out_gtid_list[i].domain_id= uint4korr(read_ptr);
out_gtid_list[i].server_id= uint4korr(read_ptr + 4);
out_gtid_list[i].seq_no= uint8korr(read_ptr + 8);
read_ptr+= 16;
} return0;
}
int
Gtid_index_reader::open_index_file(constchar *binlog_filename)
{
close_index_file();
build_index_filename(binlog_filename); if ((index_file= mysql_file_open(key_file_gtid_index, index_file_name,
O_RDONLY|O_BINARY, MYF(0))) < 0) return1; // No error for missing index (eg. upgrade)
int
Gtid_index_reader::do_index_search(uint32 *out_offset, uint32 *out_gtid_count)
{ /* In cold index, we require a complete index with a valid root node. */ if (!has_root_node) return -1;
if (read_root_node()) return -1; for (;;)
{ if (*n->first_page->flag_ptr & PAGE_FLAG_IS_LEAF) break;
if (compare_state.load_nolock(¤t_state))
{
give_error("Out of memory allocating GTID list"); return -1;
}
uint32 child_ptr; if (get_child_ptr(&child_ptr)) return -1;
/* Scan over the keys in the node to find the child pointer to follow */ for (;;)
{
uint32 offset, gtid_count; int res= get_offset_count(&offset, >id_count); if (res == 1) // EOF?
{ /* Follow the right-most child pointer. */ if (read_node(child_ptr)) return -1; break;
}
rpl_gtid *gtid_list= gtid_list_buffer(gtid_count);
uint32 child2_ptr; if ((gtid_count > 0 && !gtid_list) ||
get_gtid_list(gtid_list, gtid_count) ||
get_child_ptr(&child2_ptr)) return -1; if (update_gtid_state(&compare_state, gtid_list, gtid_count)) return -1; int cmp= (this->*search_cmp_function)(offset, &compare_state); if (cmp < 0)
{ /* Follow the left child of this key. */ if (read_node(child_ptr)) return -1; break;
} /* Continue to scan the next key. */
update_gtid_state(¤t_state, gtid_list, gtid_count);
current_state_updated= true;
current_offset= offset;
child_ptr= child2_ptr;
}
} return do_index_search_leaf(current_state_updated,
out_offset, out_gtid_count);
}
int Gtid_index_reader::do_index_search_leaf(bool current_state_updated,
uint32 *out_offset,
uint32 *out_gtid_count)
{
uint32 offset, gtid_count; int res= get_offset_count(&offset, >id_count); if (res == 1)
{
DBUG_ASSERT(0);
give_error("Corrupt index; empty leaf node"); return -1;
}
rpl_gtid *gtid_list= gtid_list_buffer(gtid_count); if ((gtid_count > 0 && !gtid_list) ||
get_gtid_list(gtid_list, gtid_count)) return -1; /* Thefirstkeyisignored(alreadyincludedinthecurrentstate),unless itistheveryfirststateintheindex.
*/ if (!current_state_updated)
update_gtid_state(¤t_state, gtid_list, gtid_count);
current_offset= offset; if (compare_state.load_nolock(¤t_state))
{
give_error("Out of memory allocating GTID state"); return -1;
} int cmp= (this->*search_cmp_function)(offset, &compare_state); if (cmp < 0) return0; // Search position is before start of index.
/* Scan over the keys in the leaf node. */ for (;;)
{
uint32 offset, gtid_count; int res= get_offset_count(&offset, >id_count); if (res == 1) // EOF?
{ /* Reached end of leaf, last key is the one searched for. */ break;
}
gtid_list= gtid_list_buffer(gtid_count); if ((gtid_count > 0 && !gtid_list) ||
get_gtid_list(gtid_list, gtid_count)) return -1; if (update_gtid_state(&compare_state, gtid_list, gtid_count)) return -1;
cmp= (this->*search_cmp_function)(offset, &compare_state); if (cmp < 0)
{ /* Next key is larger, so current state is the one searched for. */ break;
}
update_gtid_state(¤t_state, gtid_list, gtid_count);
current_offset= offset;
}
*out_offset= current_offset;
*out_gtid_count= current_state.count_nolock(); /* Save the result in the shared gtid list buffer. */ if ((!(gtid_list= gtid_list_buffer(*out_gtid_count)) && *out_gtid_count > 0) ||
current_state.get_gtid_list_nolock(gtid_list, *out_gtid_count)) return -1;
return1;
}
/* Readthefileheaderandcheckthatit'svalidandthattheformatisnot toonewaversionforustobeabletoreadit.
*/ int
Gtid_index_reader::read_file_header()
{ if (!file_open) return1;
if (MY_FILEPOS_ERROR == mysql_file_seek(index_file, 0, MY_SEEK_SET, MYF(0)) ||
mysql_file_read(index_file, buf,
GTID_INDEX_FILE_HEADER_SIZE + GTID_INDEX_PAGE_HEADER_SIZE,
MYF(MY_NABP))) return give_error("Error reading page from index file"); if (memcmp(&buf[0], GTID_INDEX_MAGIC, sizeof(GTID_INDEX_MAGIC))) return give_error("Corrupt index file, magic not found in header");
version_major= buf[4];
version_minor= buf[5]; /* We cannot safely read a major version we don't know about. */ if (version_major > GTID_INDEX_VERSION_MAJOR) return give_error("Incompatible index file, version too high");
page_size= uint4korr(&buf[8]);
/* Verify checksum integrity of page_size and major/minor version. */
uint32 crc= my_checksum(0, buf, sizeof(buf));
uchar *buf3= (uchar *)
my_malloc(key_memory_binlog_gtid_index, page_size - sizeof(buf), MYF(0)); if (!buf3) return give_error("Error allocating memory for index page"); int res= 0; if (mysql_file_read(index_file, buf3, page_size - sizeof(buf), MYF(MY_NABP)))
res= give_error("Error reading page from index file"); else
{
crc= my_checksum(crc, buf3, page_size - sizeof(buf) - CHECKSUM_LEN); if (crc != uint4korr(buf3 + page_size - sizeof(buf) - CHECKSUM_LEN))
res= give_error("Corrupt page, invalid checksum");
}
my_free(buf3); if (res) return res;
/* Checkthatthereisavalidrootnodeattheendofthefile. Ifthereisnot,theindexmaybea"hotindex"thatiscurrentlybeing constructed.Oritwasonlypartiallywrittenbeforeservercrashandnot recoveredforsomereason.
*/
uchar flags= buf[GTID_INDEX_PAGE_HEADER_SIZE];
constexpr uchar needed_flags= PAGE_FLAG_ROOT|PAGE_FLAG_LAST; if ((flags & needed_flags) == needed_flags)
{ /* Special case: the index is a single page, which is the root node. */
has_root_node= true;
} else
{
uchar buf2[GTID_INDEX_PAGE_HEADER_SIZE]; if (MY_FILEPOS_ERROR == mysql_file_seek(index_file, -(int32)page_size,
MY_SEEK_END, MYF(0)) ||
mysql_file_read(index_file, buf2, GTID_INDEX_PAGE_HEADER_SIZE,
MYF(MY_NABP))) return give_error("Error reading root page from index file");
flags= buf2[0];
has_root_node= ((flags & needed_flags) == needed_flags); /* No need to verify checksum here, will be done by read_root_node(). */
}
index_valid= true; return0;
}
int
Gtid_index_reader::read_node(uint32 page_ptr)
{
DBUG_ASSERT(page_ptr != 0/* No zero child pointers in on-disk pages. */); if (!index_valid || !page_ptr) return1; return read_node_cold(page_ptr);
}
int
Gtid_index_reader::read_node_cold(uint32 page_ptr)
{ if (MY_FILEPOS_ERROR == mysql_file_seek(index_file, (page_ptr-1)*page_size,
MY_SEEK_SET, MYF(0))) return give_error("Error seeking index file");
bool file_header= (page_ptr == 1);
cold_node.reset();
n= &cold_node;
Node_page **next_ptr_ptr= &n->first_page; for (;;)
{
Node_page *page= alloc_and_read_page(); if (!page) return1;
page->flag_ptr= &page->page[file_header ? GTID_INDEX_FILE_HEADER_SIZE : 0];
file_header= false; /* Insert the page at the end of the list. */
page->next= nullptr;
*next_ptr_ptr= page;
next_ptr_ptr= &page->next;
uchar flags= *(page->flag_ptr); if (flags & PAGE_FLAG_LAST) break;
}
if (hot_writer)
{
hot_writer= nullptr;
Gtid_index_writer::unlock_gtid_index();
} return res;
}
int
Gtid_index_reader_hot::read_root_node()
{ if (!index_valid) return1;
if (hot_writer)
{
hot_level= hot_writer->max_level; return read_node_hot();
} if (has_root_node)
{ return Gtid_index_reader::read_root_node();
} return1;
}
int
Gtid_index_reader_hot::read_node(uint32 page_ptr)
{ if (!index_valid || (!page_ptr && !hot_writer)) return1;
if (hot_writer)
{ if (!page_ptr)
{ /* The"hot"indexisonlypartiallywritten.Notyetwrittenchildpages areindicatedbyzerochildpointers.Suchchildpagesarefoundfrom thelistofactivenodesinthewriter.
*/ if (hot_level <= 0)
{
DBUG_ASSERT(0/* Should be no child pointer to follow on leaf page. */); return give_error("Corrupt hot index (child pointer on leaf page");
}
DBUG_ASSERT(n == hot_writer->nodes[hot_level]);
--hot_level; return read_node_hot();
}
int
Gtid_index_reader_hot::read_node_hot()
{ if (hot_writer->error_state) return give_error("Cannot access hot index");
n= hot_writer->nodes[hot_level];
read_page= n->first_page; /* The writer should allocate pages for all nodes. */
DBUG_ASSERT(read_page != nullptr); if (!read_page) return give_error("Page not available in hot index");
read_ptr= read_page->flag_ptr + GTID_INDEX_PAGE_HEADER_SIZE; return0;
}
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.19Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-10-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.