Skip to content

Commit a204dca

Browse files
author
Ole John Aske
committed
Bug#35420131 NDB: Restore will not update 'equal' PK values changed during backup
If the same PK attr is specified twice in LE_UPDATE log entry, the second attr value will be an update of that attr value: We set up the backup triggers to only contain attrubutes having a change in their value. Currently restore will just ignore PK attribute values already seen when restoring log entries. Thus such changes will be lost. Note that an LE_UPDATE to a PK attribute will only be generated if we update the PK value to a 'compare-as-equal' value. E.g. update 'xyz' -> 'XYZ'. We still want such updates to be included in a restore though. If the PK update is to a 'not-compared-as-equal' value it will be represented as a LE_DELETE+LE_INSERT, which is not affected by this bug. Patch will detect that a PK-attr value is specified for the second time in a LE_UPDATE, and generate a setValue() operation for that. A few minor const-corrrectness fixes in addition, as well as reducing the size of the 'keys' Bitmask which was defined to use 4096 'words' -> 128k bits. Change-Id: I57e9b354f56bf47f19d54be98436112b2933b46c (cherry picked from commit 8f9b8a3a5d499359b531a85858d6d09703b6c001)
1 parent 2ecabd6 commit a204dca

File tree

4 files changed

+128
-14
lines changed

4 files changed

+128
-14
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use test;
2+
create table test.t1 (
3+
a varchar(20) not null,
4+
b varchar(20) not null,
5+
c varchar(20) not null,
6+
d varchar(20),
7+
primary key(a,b)
8+
) engine=ndb;
9+
insert into test.t1 values
10+
("1a","1b","1c","1d"),
11+
("2a","2b","2c","2d"),
12+
("3a","3b","3c","3d");
13+
Stall backup completion *after* table is scanned.
14+
... We will still collect log entries on table updates.
15+
Connected to Management Server at: localhost:13000
16+
17+
Run backup
18+
Starting backup
19+
Backup started
20+
Update 'a' to a 'compared as equal'-value
21+
update test.t1 set a="1A" where a="1a";
22+
Create log entries with insert and delete as well
23+
insert into test.t1 values("6a","6b","6c","6d");
24+
delete from test.t1 where a="2a";
25+
Now allow backup to complete...
26+
Connected to Management Server at: localhost:13000
27+
28+
Waiting for backup to complete
29+
Backup completed
30+
truncate t1;
31+
Run restore
32+
Restored table should show 'a=1a' updated to "1A"
33+
, as well as '2a' deleted and '6a' inserted .
34+
select * from test.t1 order by b;
35+
a b c d
36+
1A 1b 1c 1d
37+
3a 3b 3c 3d
38+
6a 6b 6c 6d
39+
drop table test.t1;
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
###################################
2+
# Test intended for testing different aspects of updating
3+
# PK columns during backup, and restore of these.
4+
#
5+
-- source include/have_ndb.inc
6+
-- source have_ndb_error_insert.inc
7+
-- source include/not_embedded.inc
8+
9+
####################################
10+
#
11+
# Bug#35420131
12+
# 'NDB: Restore will not update 'equal' PK values changed during backup'
13+
#
14+
use test;
15+
create table test.t1 (
16+
a varchar(20) not null,
17+
b varchar(20) not null,
18+
c varchar(20) not null,
19+
d varchar(20),
20+
primary key(a,b)
21+
) engine=ndb;
22+
23+
insert into test.t1 values
24+
("1a","1b","1c","1d"),
25+
("2a","2b","2c","2d"),
26+
("3a","3b","3c","3d");
27+
28+
--echo Stall backup completion *after* table is scanned.
29+
--echo ... We will still collect log entries on table updates.
30+
--exec $NDB_MGM -e "all error 10040"
31+
32+
--echo Run backup
33+
--source suite/ndb/t/ndb_backup_nowait_start.inc
34+
35+
--echo Update 'a' to a 'compared as equal'-value
36+
update test.t1 set a="1A" where a="1a";
37+
38+
--echo Create log entries with insert and delete as well
39+
insert into test.t1 values("6a","6b","6c","6d");
40+
delete from test.t1 where a="2a";
41+
42+
--echo Now allow backup to complete...
43+
--exec $NDB_MGM -e "all error 0"
44+
--source suite/ndb/t/ndb_backup_nowait_wait.inc
45+
46+
truncate t1;
47+
48+
--echo Run restore
49+
--exec $NDB_RESTORE -b $the_backup_id -n 1 -r $NDB_BACKUPS-$the_backup_id >> $NDB_TOOLS_OUTPUT 2>&1
50+
--exec $NDB_RESTORE -b $the_backup_id -n 2 -r $NDB_BACKUPS-$the_backup_id >> $NDB_TOOLS_OUTPUT 2>&1
51+
52+
--echo Restored table should show 'a=1a' updated to "1A"
53+
--echo , as well as '2a' deleted and '6a' inserted .
54+
select * from test.t1 order by b;
55+
56+
drop table test.t1;
57+
58+
--remove_file $NDB_TOOLS_OUTPUT

storage/ndb/src/kernel/blocks/backup/Backup.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5026,6 +5026,18 @@ Backup::execWAIT_GCP_CONF(Signal* signal){
50265026
return;
50275027
} else {
50285028
jam();
5029+
if (ERROR_INSERTED(10040))
5030+
{
5031+
jam();
5032+
conf->gci_hi = ptr.p->startGCP;
5033+
/* Pause */
5034+
sendSignalWithDelay(reference(),
5035+
GSN_WAIT_GCP_CONF,
5036+
signal,
5037+
300,
5038+
signal->getLength());
5039+
return;
5040+
}
50295041
if(gcp >= ptr.p->startGCP + 3)
50305042
{
50315043
CRASH_INSERTION((10009));

storage/ndb/tools/restore/consumer_restore.cpp

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2004, 2022, Oracle and/or its affiliates.
2+
Copyright (c) 2004, 2023, Oracle and/or its affiliates.
33
44
This program is free software; you can redistribute it and/or modify
55
it under the terms of the GNU General Public License, version 2.0,
@@ -4576,7 +4576,6 @@ BackupRestore::logEntry_a(restore_callback_t *cb)
45764576
}
45774577

45784578
retry:
4579-
Uint32 mapping_idx_key_count = 0;
45804579
if (cb->retries == MAX_RETRIES)
45814580
{
45824581
restoreLogger.log_error("execute failed");
@@ -4659,25 +4658,25 @@ BackupRestore::logEntry_a(restore_callback_t *cb)
46594658
op->setPartitionId(tup.m_frag_id);
46604659
}
46614660

4662-
Bitmask<4096> keys;
4663-
Uint32 n_bytes= 0;
4661+
Bitmask<MAXNROFATTRIBUTESINWORDS> keys;
46644662
for (Uint32 pass= 0; pass < 2; pass++) // Keys then Values
46654663
{
4664+
Uint32 mapping_idx_key_count = 0;
46664665
for (Uint32 i= 0; i < tup.size(); i++)
46674666
{
46684667
const AttributeS * attr = tup[i];
4669-
int size = attr->Desc->size;
4670-
int arraySize = attr->Desc->arraySize;
4668+
const int size = attr->Desc->size;
4669+
const int arraySize = attr->Desc->arraySize;
46714670
const char * dataPtr = attr->Data.string_value;
46724671
const bool col_pk_in_backup = attr->Desc->m_column->getPrimaryKey();
46734672

46744673
if (attr->Desc->m_exclude)
46754674
continue;
46764675

4677-
const bool col_pk_in_kernel =
4678-
table->getColumn(attr->Desc->attrId)->getPrimaryKey();
4676+
const Uint32 attrId = attr->Desc->attrId;
4677+
const bool col_pk_in_kernel = table->getColumn(attrId)->getPrimaryKey();
46794678
bool col_is_key = col_pk_in_kernel;
4680-
Uint32 keyAttrId = attr->Desc->attrId;
4679+
Uint32 keyAttrId = attrId;
46814680

46824681
if (unlikely(use_mapping_idx))
46834682
{
@@ -4735,7 +4734,7 @@ BackupRestore::logEntry_a(restore_callback_t *cb)
47354734
}
47364735
}
47374736

4738-
if (tup.m_table->have_auto_inc(attr->Desc->attrId))
4737+
if (tup.m_table->have_auto_inc(attrId))
47394738
{
47404739
Uint64 usedAutoVal = extract_auto_val(dataPtr,
47414740
size * arraySize,
@@ -4745,7 +4744,6 @@ BackupRestore::logEntry_a(restore_callback_t *cb)
47454744
}
47464745

47474746
const Uint32 length = (size / 8) * arraySize;
4748-
n_bytes+= length;
47494747

47504748
if (attr->Desc->convertFunc &&
47514749
dataPtr != NULL) // NULL will not be converted
@@ -4775,18 +4773,25 @@ BackupRestore::logEntry_a(restore_callback_t *cb)
47754773
{
47764774
assert(pass == 0);
47774775

4778-
if(!keys.get(keyAttrId))
4776+
if (!keys.get(attrId))
47794777
{
4780-
keys.set(keyAttrId);
4778+
keys.set(attrId);
47814779
check= op->equal(keyAttrId, dataPtr, length);
47824780
}
4781+
else if (tup.m_type == LogEntry::LE_UPDATE)
4782+
{
4783+
// If an LE_UPDATE entry contains the same 'key' twice,
4784+
// the second log entry is an update of the value.
4785+
// (As we request only changed values in the triggers)
4786+
check= op->setValue(attrId, dataPtr);
4787+
}
47834788
}
47844789
else
47854790
{
47864791
assert(pass == 1);
47874792
if (tup.m_type != LogEntry::LE_DELETE)
47884793
{
4789-
check= op->setValue(attr->Desc->attrId, dataPtr, length);
4794+
check= op->setValue(attrId, dataPtr, length);
47904795
}
47914796
}
47924797

0 commit comments

Comments
 (0)