restore: decide index replay from what the secondary backup carries - #1175
restore: decide index replay from what the secondary backup carries#1175czs007 wants to merge 1 commit into
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: czs007 The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
Codecov Report❌ Patch coverage is
❌ Your patch status has failed because the patch coverage (61.70%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #1175 +/- ##
==========================================
+ Coverage 42.69% 42.78% +0.08%
==========================================
Files 134 134
Lines 12415 12459 +44
==========================================
+ Hits 5301 5330 +29
- Misses 6710 6725 +15
Partials 404 404 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
field_id, type_params, index_params, create_time, is_auto_index and
min/max_index_version are read from etcd by the index-extra task; a backup
created without --backup_index_extra carries only what DescribeIndex returns
(field_name, index_name, index_type, params, index_id). Secondary restore
copied index.GetFieldId() straight into the CreateIndex message and broadcast
it anyway, so such a backup put an index on FieldID 0 (RowIDField, which is
never indexed) on the target: the import job stayed in IndexBuilding forever,
DataCoord index tasks failed with "parse magic number failed ... actual:
827474256" (PAR1), and DescribeIndex reported "failed to get collection
field: 0". Nothing forced that message to be sent - it was sent because the
loop over index infos never considered the attributes being absent.
Whether the indexes are part of a secondary restore is settled when the
backup is created, so decide it from the backup as a whole, once, before any
client is created or any DDL is broadcast:
- every index carries the extra attributes: replay create index as before;
- none does: the backup holds no index information a verbatim replay can
use, so restore the collections and their data without indexes and name
the left-out indexes up front;
- some do and some do not: the extra attributes are collected for every
index at once or for none, so the meta is inconsistent - fail before
anything is restored rather than replay half of it.
Nothing is reconstructed on the client side: the missing attributes are what
makes the replay match the source cluster.
Also state in `restore secondary --help` what --backup_index_extra buys.
Signed-off-by: zhenshan.cao <zhenshan.cao@zilliz.com>
b8c62cc to
0757304
Compare
|
Suggest failing the "none has extra" branch as well, rather than skipping indexes:
So |
issue: #1167
Follow-up to #1168.
Problem
IndexInfosplits into two groups by source:field_nameindex_nameindex_typeparamsindex_id--backup_index_extrafield_idcreate_timetype_paramsindex_paramsuser_index_paramsis_auto_indexmin_index_versionmax_index_versioncreateIndexesloops over the index infos and broadcasts each one unconditionally — it was written assuming the etcd half is always there, with no check and no fallback. So a backup taken without the flag broadcasts an index on FieldID 0 (RowIDField, which is never indexed), and the target ends up with an index entry that gates every future import of that collection:IndexBuilding; the client polls[state=Importing] [progress=80]and never stops, becausewaitBulkInsertStateonly returns onCompletedorFailed(_bulkInsertTimeoutlogs a warning and keeps going);parse magic number failed, expected: 16775868, actual: 827474256—PAR1, the index node reading the storage-v2 packed column file of field 0 as a v1 binlog;DescribeIndexon the restored collection fails withfailed to get collection field: 0, so the bogus entry is hard to even inspect.Nothing required that message to be sent. Not sending it is strictly better: with no index entry the import job has no index task to run and completes.
Change
Whether indexes are part of a secondary restore is settled when the backup is created, not at restore time. So decide it from the backup as a whole, once, in
Task.Executebefore any client is created or any DDL is broadcast:Nothing is reconstructed on the client side. The missing attributes are what makes the DDL replay match the source cluster, and
create_timein particular does not exist anywhere in a default backup; guessing them would silently put an index with different parameters on the replica, which is worse than not having one.restore secondary --helpnow states what--backup_index_extrabuys.Tests
TestReplayIndexcovers all three outcomes plus empty index list, empty collection list, andindex_paramsmissing on its own;TestIndexNamescovers the message formatting.Open question, deliberately not answered here
A collection restored without indexes still gets the
AlterLoadConfigbroadcast when the source was loaded. Whether the target can load a collection that has no index on its vector field is a server-side question I have not verified — if it cannot, the load stage needs the same treatment. Pointers welcome; I can follow up with a two-cluster test.Not in scope
restore secondaryis configured against the target (CI rewritesmilvus.grpc.portto the downstream before restoring), and--source_cluster_idis an identifier, not a connection — so this belongs on the source side, as its own command.--backup_index_extradefaults to false and is documented nowhere, so a defaultcreatesilently produces a backup that cannot replay indexes. Note it also gates the dynamic-field backup, which reuses the etcd client created only for it (core/backup/task.go:515) — the same silent gap, under a flag name that does not suggest it. @huanghaoyuanhhy's--use secondarypreset ([Bug]: restore secondary broadcasts CreateIndex with FieldID 0 when the backup was taken without --backup_index_extra #1167 (comment)) addresses this; happy to follow up once that issue is opened.Relation to the earlier review
@huanghaoyuanhhy proposed rejecting such backups outright (#1167 (comment)). This keeps his constraint — no client-side reconstruction, ever — but declines to make an existing backup unusable for secondary restore: it still restores the collections, the data and the CDC linkage, only without indexes, and says so up front. Rejecting outright would leave every backup taken before the contract was known with no path at all, and the data those backups hold is not the part that is missing.