1 /*
2    Copyright (c) 2011, 2021, Oracle and/or its affiliates.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include "ndb_event_data.h"
26 
27 #include <table.h>
28 
29 
Ndb_event_data(NDB_SHARE * the_share)30 Ndb_event_data::Ndb_event_data(NDB_SHARE *the_share) :
31   shadow_table(NULL),
32   share(the_share),
33   pk_bitmap(NULL)
34 {
35   ndb_value[0]= NULL;
36   ndb_value[1]= NULL;
37 }
38 
39 
~Ndb_event_data()40 Ndb_event_data::~Ndb_event_data()
41 {
42   if (shadow_table)
43     closefrm(shadow_table, 1);
44   shadow_table= NULL;
45 
46   delete pk_bitmap;
47   pk_bitmap = NULL;
48 
49   free_root(&mem_root, MYF(0));
50   share= NULL;
51   /*
52     ndbvalue[] allocated with my_multi_malloc -> only
53     first pointer need to be freed
54   */
55   my_free(ndb_value[0]);
56 }
57 
58 
print(const char * where,FILE * file) const59 void Ndb_event_data::print(const char* where, FILE* file) const
60 {
61   fprintf(file,
62           "%s shadow_table: %p '%s.%s'\n",
63           where,
64           shadow_table, shadow_table->s->db.str,
65           shadow_table->s->table_name.str);
66 
67   // Print stats for the MEM_ROOT where Ndb_event_data
68   // has allocated the shadow_table etc.
69   {
70     USED_MEM *mem_block;
71     size_t mem_root_used = 0;
72     size_t mem_root_size = 0;
73 
74     /* iterate through (partially) free blocks */
75     for (mem_block= mem_root.free; mem_block; mem_block= mem_block->next)
76     {
77       const size_t block_used =
78           mem_block->size - // Size of block
79           ALIGN_SIZE(sizeof(USED_MEM)) - // Size of header
80           mem_block->left; // What's unused in block
81       mem_root_used += block_used;
82       mem_root_size += mem_block->size;
83     }
84 
85     /* iterate through the used blocks */
86     for (mem_block= mem_root.used; mem_block; mem_block= mem_block->next)
87     {
88       const size_t block_used =
89           mem_block->size - // Size of block
90           ALIGN_SIZE(sizeof(USED_MEM)) - // Size of header
91           mem_block->left; // What's unused in block
92       mem_root_used += block_used;
93       mem_root_size += mem_block->size;
94     }
95     fprintf(file, "  - mem_root size: %lu\n", mem_root_size);
96     fprintf(file, "  - mem_root used: %lu\n", mem_root_used);
97   }
98 }
99 
100 /*
101  * While writing an UPDATE_ROW event to the binlog, a bitmap is
102  * used to indicate which columns should be written. An
103  * UPDATE_ROW event contains 2 versions of the row: a Before Image
104  * of the row before the update was done, and an After Image of
105  * the row after the update. Column bitmaps are used to decide
106  * which columns will be written to both images. The Before
107  * Image and After Image can contain different columns.
108  *
109  * For the binlog formats UPDATED_ONLY_USE_UPDATE_MINIMAL and
110  * FULL_USE_UPDATE_MINIMAL, it is necessary to write only primary
111  * key columns to the Before Image, and to remove all primary key
112  * columns from the After Image. A bitmap of primary key columns is
113  * created for this purpose.
114  */
init_pk_bitmap()115 void Ndb_event_data::init_pk_bitmap()
116 {
117   if (shadow_table->s->primary_key == MAX_KEY)
118   {
119     // Table without pk, no need for pk_bitmap since minimal is full
120     return;
121   }
122   pk_bitmap = new MY_BITMAP();
123   bitmap_init(pk_bitmap, pk_bitbuf, shadow_table->s->fields, FALSE);
124   KEY* key = shadow_table->key_info + shadow_table->s->primary_key;
125   KEY_PART_INFO* key_part_info = key->key_part;
126   const uint key_parts = key->user_defined_key_parts;
127   for (uint i = 0; i < key_parts; i++, key_part_info++)
128   {
129     bitmap_set_bit(pk_bitmap, key_part_info->fieldnr - 1);
130   }
131   assert(!bitmap_is_clear_all(pk_bitmap));
132 }
133 
134 /*
135  * Modify the column bitmaps generated for UPDATE_ROW as per
136  * the MINIMAL binlog format type. Expected arguments:
137  *
138  * @before: empty bitmap to be populated with PK columns
139  * @after: bitmap with updated cols, if ndb_log_updated_only=TRUE
140  *         bitmap with all cols, if ndb_log_updated_only=FALSE
141  *
142  * If no PK is defined, bitmaps revert to default behaviour:
143  *  - before and after bitmaps are identical
144  *  - bitmaps contain all/updated cols as per ndb_log_updated_only
145  */
generate_minimal_bitmap(MY_BITMAP * before,MY_BITMAP * after)146 void Ndb_event_data::generate_minimal_bitmap(MY_BITMAP *before, MY_BITMAP *after)
147 {
148   if (pk_bitmap)
149   {
150     assert(!bitmap_is_clear_all(pk_bitmap));
151     // set Before Image to contain only primary keys
152     bitmap_copy(before, pk_bitmap);
153     // remove primary keys from After Image
154     bitmap_subtract(after, pk_bitmap);
155   }
156   else
157   {
158     // no usable PK bitmap, set Before Image = After Image
159     bitmap_copy(before, after);
160   }
161 }
162