File: lob0first.h

package info (click to toggle)
mysql-8.0 8.0.44-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,272,892 kB
  • sloc: cpp: 4,685,345; ansic: 412,712; pascal: 108,395; java: 83,641; perl: 30,221; cs: 27,067; sql: 26,594; python: 21,816; sh: 17,285; yacc: 17,169; php: 11,522; xml: 7,388; javascript: 7,083; makefile: 1,793; lex: 1,075; awk: 670; asm: 520; objc: 183; ruby: 97; lisp: 86
file content (492 lines) | stat: -rw-r--r-- 18,240 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
/*****************************************************************************

Copyright (c) 2016, 2025, Oracle and/or its affiliates.

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

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

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
for more details.

You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA

*****************************************************************************/

#ifndef lob0first_h
#define lob0first_h

#include "btr0btr.h"
#include "buf0buf.h"
#include "dict0dict.h"
#include "fut0lst.h"
#include "lob0index.h"
#include "lob0lob.h"
#include "lob0util.h"
#include "mtr0log.h"

namespace lob {

/** The first page of an uncompressed LOB. */
struct first_page_t : public basic_page_t {
  /** Version information. One byte. */
  static const ulint OFFSET_VERSION = FIL_PAGE_DATA;

  /** One byte of flag bits.  Currently only one bit (the least
  significant bit) is used, other 7 bits are available for future use.*/
  static const ulint OFFSET_FLAGS = FIL_PAGE_DATA + 1;

  /** LOB version. 4 bytes.*/
  static const uint32_t OFFSET_LOB_VERSION = OFFSET_FLAGS + 1;

  /** The latest transaction that modified this LOB. */
  static const ulint OFFSET_LAST_TRX_ID = OFFSET_LOB_VERSION + 4;

  /** The latest transaction undo_no that modified this LOB. */
  static const ulint OFFSET_LAST_UNDO_NO = OFFSET_LAST_TRX_ID + 6;

  /** Length of data stored in this page.  4 bytes. */
  static const ulint OFFSET_DATA_LEN = OFFSET_LAST_UNDO_NO + 4;

  /** The trx that created the data stored in this page. */
  static const ulint OFFSET_TRX_ID = OFFSET_DATA_LEN + 4;

  /** The offset where the list base node is located.  This is the list
  of LOB pages. */
  static const ulint OFFSET_INDEX_LIST = OFFSET_TRX_ID + 6;

  /** The offset where the list base node is located.  This is the list
  of free nodes. */
  static const ulint OFFSET_INDEX_FREE_NODES =
      OFFSET_INDEX_LIST + FLST_BASE_NODE_SIZE;

  /** The offset where the contents of the first page begins. */
  static const ulint LOB_PAGE_DATA =
      OFFSET_INDEX_FREE_NODES + FLST_BASE_NODE_SIZE;

  static const ulint LOB_PAGE_TRAILER_LEN = FIL_PAGE_DATA_END;

  /** The default constructor. */
  first_page_t() = default;

  /** Constructor.
  @param[in]    block   Buffer block of the first page.
  @param[in]    mtr     Mini-transaction context. */
  first_page_t(buf_block_t *block, mtr_t *mtr) : basic_page_t(block, mtr) {}

  /** Constructor.
  @param[in]    block   the buffer block of the first page.*/
  first_page_t(buf_block_t *block) : basic_page_t(block, nullptr) {}

  /** Constructor.
  @param[in]    block   Buffer block of the first page.
  @param[in]    mtr     Mini-transaction context.
  @param[in]    index   Clustered index containing the LOB. */
  first_page_t(buf_block_t *block, mtr_t *mtr, dict_index_t *index)
      : basic_page_t(block, mtr, index) {}

  /** Constructor.
  @param[in]    mtr     Mini-transaction context.
  @param[in]    index   Clustered index containing the LOB. */
  first_page_t(mtr_t *mtr, dict_index_t *index)
      : basic_page_t(nullptr, mtr, index) {}

  /** Set the LOB format version number to 0. */
  void set_version_0() {
    mlog_write_ulint(frame() + OFFSET_VERSION, 0, MLOG_1BYTE, m_mtr);
  }

  /** Obtain the flags value. This has 8 bits of which only the first
  bit is used.
  @return one byte flag */
  uint8_t get_flags() { return (mach_read_from_1(frame() + OFFSET_FLAGS)); }

  /** When the bit is set, the LOB is not partially updatable anymore.
  @return true, if partially updatable.
  @return false, if partially NOT updatable. */
  bool can_be_partially_updated() {
    uint8_t flags = get_flags();
    return (!(flags & 0x01));
  }

  /** Do tablespace import. */
  void import(trx_id_t trx_id);

  /** When the bit is set, the LOB is not partially updatable anymore.
  Enable the bit.
  @param[in]    trx     the current transaction. */
  void mark_cannot_be_partially_updated(trx_t *trx);

  /** Allocate the first page for uncompressed LOB.
  @param[in,out]        alloc_mtr       the allocation mtr.
  @param[in]    is_bulk         true if it is bulk operation.
                                  (OPCODE_INSERT_BULK)
  return the allocated buffer block.*/
  buf_block_t *alloc(mtr_t *alloc_mtr, bool is_bulk);

  /** Free all the index pages.  The list of index pages can be accessed
  by traversing via the FIL_PAGE_NEXT field.*/
  void free_all_index_pages();

  /** Free all the data pages. The data pages can be accessed through
  index entry. */
  void free_all_data_pages();

  /** Load the first page of LOB with s-latch.
  @param[in]   page_id    the page identifier of the first page.
  @param[in]   page_size  the page size information.
  @return the buffer block of the first page. */
  buf_block_t *load_s(page_id_t page_id, page_size_t page_size) {
    m_block =
        buf_page_get(page_id, page_size, RW_S_LATCH, UT_LOCATION_HERE, m_mtr);
    return (m_block);
  }

  /** Load the first page of LOB with x-latch.
  @param[in]   page_id    Page identifier of the first page.
  @param[in]   page_size  Page size information.
  @param[in]   mtr        Mini-transaction context for latch.
  @return the buffer block of the first page. */
  buf_block_t *load_x(const page_id_t &page_id, const page_size_t &page_size,
                      mtr_t *mtr);

  /** Load the first page of LOB with x-latch in the given mtr context.
  The first page must already be x-latched by the m_mtr.
  @param[in]   mtr        Mini-transaction context for latch.
  @return the buffer block of the first page. */
  buf_block_t *load_x(mtr_t *mtr) const {
    ut_ad(mtr_memo_contains(m_mtr, m_block, MTR_MEMO_PAGE_X_FIX));
    buf_block_t *tmp = buf_page_get(m_block->page.id, m_index->get_page_size(),
                                    RW_X_LATCH, UT_LOCATION_HERE, mtr);
    ut_ad(tmp == m_block);
    return (tmp);
  }

  /** Load the first page of LOB with x-latch.
  @param[in]   page_id    the page identifier of the first page.
  @param[in]   page_size  the page size information.
  @return the buffer block of the first page. */
  buf_block_t *load_x(const page_id_t &page_id, const page_size_t &page_size) {
    return (load_x(page_id, page_size, m_mtr));
  }

  /** Get the buffer block of the LOB first page.
  @return the buffer block. */
  buf_block_t *get_block() { return (m_block); }

  /** Load the file list node from the given location.  An x-latch is taken
  on the page containing the file list node.
  @param[in]    addr    Location of file list node.
  @param[in]    mtr   Mini-transaction context to be used.
  @return               the file list node.*/
  flst_node_t *addr2ptr_x(const fil_addr_t &addr, mtr_t *mtr) const;

  /** Load the file list node from the given location.  An x-latch is taken
  on the page containing the file list node.
  @param[in]    addr    the location of file list node.
  @return               the file list node.*/
  flst_node_t *addr2ptr_x(fil_addr_t &addr) const {
    return (addr2ptr_x(addr, m_mtr));
  }

  /** Load the file list node from the given location, assuming that it
  exists in the first page itself.
  @param[in]    addr    the location of file list node.
  @return               the file list node.*/
  flst_node_t *addr2ptr(const fil_addr_t &addr) {
    ut_ad(m_block->page.id.page_no() == addr.page);
    return (buf_block_get_frame(m_block) + addr.boffset);
  }

  /** Load the file list node from the given location.  An s-latch is taken
  on the page containing the file list node.
  @param[in]    addr    the location of file list node.
  @return               the file list node.*/
  flst_node_t *addr2ptr_s(fil_addr_t &addr) {
    space_id_t space = dict_index_get_space(m_index);
    const page_size_t page_size = dict_table_page_size(m_index->table);
    return (fut_get_ptr(space, page_size, addr, RW_S_LATCH, m_mtr));
  }

  /** Load the file list node from the given location.  An s-latch is taken
  on the page containing the file list node. The given cache is checked to
  see if the page is already loaded.
  @param[in]    cache   cache of loaded buffer blocks.
  @param[in]    addr    the location of file list node.
  @return               the file list node.*/
  flst_node_t *addr2ptr_s_cache(std::map<page_no_t, buf_block_t *> &cache,
                                fil_addr_t &addr) const {
    byte *result;
    space_id_t space = dict_index_get_space(m_index);
    const page_size_t page_size = dict_table_page_size(m_index->table);

    auto iter = cache.find(addr.page);

    if (iter == cache.end()) {
      /* Not there in cached blocks.  Add the loaded block to cache. */
      buf_block_t *block = nullptr;
      result = fut_get_ptr(space, page_size, addr, RW_S_LATCH, m_mtr, &block);
      cache.insert(std::make_pair(addr.page, block));
    } else {
      buf_block_t *block = iter->second;
      ut_ad(block->page.id.page_no() == addr.page);
      result = buf_block_get_frame(block) + addr.boffset;
    }
    return (result);
  }

  /** Free the first page.  This is done when all other LOB pages have
  been freed. */
  void dealloc();

  /** Free all the pages associated with this LOB. */
  void destroy();

  /** Free all the pages associated with this LOB, except the first page. */
  void make_empty();

  /** Check if the index list is empty or not.
  @return true if empty, false otherwise. */
  bool is_empty() const {
    flst_base_node_t *base = index_list();
    ut_ad(base != nullptr);
    return (flst_get_len(base) == 0);
  }

  /** Allocate one index entry.  If required an index page (of type
  FIL_PAGE_TYPE_LOB_INDEX) will be allocated.
  @param[in]    bulk    true if it is a bulk operation
                          (OPCODE_INSERT_BULK), false otherwise.
  @return the file list node of the index entry. */
  flst_node_t *alloc_index_entry(bool bulk);

  /** Get a pointer to the beginning of the index entry nodes in the
  first part of the page.
  @return       the first index entry node. */
  byte *nodes_begin() const { return (frame() + LOB_PAGE_DATA); }

  /** Calculate and return the payload.
  @return the payload possible in this page. */
  static ulint payload() {
    return (UNIV_PAGE_SIZE - LOB_PAGE_DATA - LOB_PAGE_TRAILER_LEN);
  }

  /** Set the transaction identifier in the first page header without
  generating redo logs.
  @param[in]    id      the transaction identifier. */
  void set_trx_id_no_redo(trx_id_t id) {
    byte *ptr = frame() + OFFSET_TRX_ID;
    mach_write_to_6(ptr, id);
  }

  /** Set the transaction identifier in the first page header.
  @param[in]    id      the transaction identifier. */
  void set_trx_id(trx_id_t id) {
    byte *ptr = frame() + OFFSET_TRX_ID;
    mach_write_to_6(ptr, id);
    mlog_log_string(ptr, 6, m_mtr);
  }

  /** Initialize the LOB version to 1. */
  void init_lob_version() {
    ut_ad(m_mtr != nullptr);

    mlog_write_ulint(frame() + OFFSET_LOB_VERSION, 1, MLOG_4BYTES, m_mtr);
  }

  /** Get the lob version number.
  @return the lob version. */
  uint32_t get_lob_version() {
    return (mach_read_from_4(frame() + OFFSET_LOB_VERSION));
  }

  /** Increment the lob version by 1. */
  uint32_t incr_lob_version();

  /** Set the last transaction identifier, without generating redo log
  records.
  @param[in]    id      the trx identifier. */
  void set_last_trx_id_no_redo(trx_id_t id) {
    byte *ptr = frame() + OFFSET_LAST_TRX_ID;
    mach_write_to_6(ptr, id);
  }

  /** Set the last transaction identifier.
  @param[in]    id      the trx identifier. */
  void set_last_trx_id(trx_id_t id) {
    byte *ptr = frame() + OFFSET_LAST_TRX_ID;
    mach_write_to_6(ptr, id);
    mlog_log_string(ptr, 6, m_mtr);
  }

  /** Set the last transaction undo number.
  @param[in]    undo_no the trx undo number. */
  void set_last_trx_undo_no(undo_no_t undo_no) {
    ut_ad(m_mtr != nullptr);

    byte *ptr = frame() + OFFSET_LAST_UNDO_NO;
    mlog_write_ulint(ptr, undo_no, MLOG_4BYTES, m_mtr);
  }

  /** Get the last transaction identifier.
  @return the transaction identifier. */
  trx_id_t get_last_trx_id() const {
    byte *ptr = frame() + OFFSET_LAST_TRX_ID;
    return (mach_read_from_6(ptr));
  }

  /** Get the last transaction undo number.
  @return the transaction undo number. */
  undo_no_t get_last_trx_undo_no() const {
    byte *ptr = frame() + OFFSET_LAST_UNDO_NO;
    return (mach_read_from_4(ptr));
  }

  /** Set the length of data stored in bytes.
  @param[in]    len     amount of data stored in bytes. */
  void set_data_len(ulint len) {
    ut_ad(m_mtr != nullptr);

    mlog_write_ulint(frame() + OFFSET_DATA_LEN, len, MLOG_4BYTES, m_mtr);
  }

  /** Write as much as possible of the given data into the page.
  @param[in]    trxid   the current transaction.
  @param[in]    data    the data to be written.
  @param[in]    len     the length of the given data.
  @return number of bytes actually written. */
  ulint write(trx_id_t trxid, const byte *&data, ulint &len);

  /** Replace data in the page by making a copy-on-write.
  @param[in]      trx     Current transaction.
  @param[in]      offset  Location where replace operation starts.
  @param[in,out]  ptr     Buffer containing new data. after the call it will
  point to remaining data.
  @param[in,out]  want    Requested amount of data to be replaced. After the
  call it will contain amount of data yet to be replaced.
  @param[in]      mtr     Mini-transaction context.
  @return  the newly allocated buffer block.
  @return  nullptr if new page could not be allocated
  (DB_OUT_OF_FILE_SPACE). */
  buf_block_t *replace(trx_t *trx, ulint offset, const byte *&ptr, ulint &want,
                       mtr_t *mtr);

  /** Replace data in the page inline.
  @param[in]    offset  Location where replace operation starts.
  @param[in,out]        ptr     Buffer containing new data. after the
                          call it will point to remaining data.
  @param[in,out]        want    Requested amount of data to be replaced.
                          after the call it will contain amount of
                          data yet to be replaced.
  @param[in]    mtr     Mini-transaction context.*/
  void replace_inline(ulint offset, const byte *&ptr, ulint &want, mtr_t *mtr);

  ulint get_data_len() const {
    return (mach_read_from_4(frame() + OFFSET_DATA_LEN));
  }

  /** Read data from the first page.
  @param[in]    offset  the offset from where read starts.
  @param[out]   ptr     the output buffer
  @param[in]    want    number of bytes to read.
  @return number of bytes read. */
  ulint read(ulint offset, byte *ptr, ulint want);

  void set_page_type() {
    ut_ad(m_mtr != nullptr);

    mlog_write_ulint(frame() + FIL_PAGE_TYPE, FIL_PAGE_TYPE_LOB_FIRST,
                     MLOG_2BYTES, m_mtr);
  }

  flst_base_node_t *index_list() const { return (frame() + OFFSET_INDEX_LIST); }

  flst_base_node_t *free_list() const {
    return (frame() + OFFSET_INDEX_FREE_NODES);
  }

  /** Get the number of bytes used to store LOB data in the first page
  of uncompressed LOB.
  @return Number of bytes available for LOB data. */
  static ulint max_space_available() {
    const ulint index_array_size = node_count() * index_entry_t::SIZE;

    return (payload() - index_array_size);
  }

  /** Get the number of index entries this page can hold.
  @return Number of index entries this page can hold. */
  constexpr static ulint node_count() {
    /* Each index entry is of size 60 bytes.  We store only 10
    index entries in the first page of the LOB.  This means that
    only 600 bytes are used for index data in the first page of
    LOB. This will help to reserve more space in the first page
    for the LOB data.*/
    return (10);
  }

  std::ostream &print_index_entries(std::ostream &out) const;

  std::ostream &print_index_entries_cache_s(std::ostream &out,
                                            BlockCache &cache) const;

  /** Obtain the location where the data begins.
  @return pointer to location within page where data begins. */
  byte *data_begin() const {
    ut_ad(buf_block_get_page_zip(m_block) == nullptr);

    constexpr ulint index_array_size = node_count() * index_entry_t::SIZE;

    return (frame() + LOB_PAGE_DATA + index_array_size);
  }

  /** Append data into a LOB first page. */
  ulint append(trx_id_t trxid, byte *&data, ulint &len);

#ifdef UNIV_DEBUG
  /** Validate the first page. */
  bool validate() const;
#endif /* UNIV_DEBUG */

  page_type_t get_page_type() { return (basic_page_t::get_page_type()); }

  static page_type_t get_page_type(dict_index_t *index,
                                   const page_id_t &page_id,
                                   const page_size_t &page_size) {
    mtr_t local_mtr;
    mtr_start(&local_mtr);
    first_page_t first(&local_mtr, index);
    first.load_x(page_id, page_size);
    page_type_t page_type = first.get_page_type();
    mtr_commit(&local_mtr);
    return (page_type);
  }

 public:
  /** Restart the given mtr. The first page must already be x-latched by
  the m_mtr.
  @param[in]   mtr   Mini-transaction context which is to be restarted. */
  void restart_mtr(mtr_t *mtr) {
    ut_ad(mtr != m_mtr);
    mtr_commit(mtr);
    mtr_start(mtr);
    mtr->set_log_mode(m_mtr->get_log_mode());
    load_x(mtr);
  }
};

} /* namespace lob */

#endif /* lob0first_h */