Describe the bug
In the RDS source's CDC/binlog stream mode, BinlogEventListener caches a tableId → TableMetadata mapping in memory (tableMetadataMap), populated from binlog TABLE_MAP events. This mapping is only ever populated for tables of interest (i.e., tables in the pipeline's tables.include), and stale entries are never invalidated.
MySQL's binlog table_id is not stable: it is assigned from the server's table-definition cache and can be reassigned across a server restart (and on table-cache eviction). When a table_id that was previously mapped to a synced table gets reassigned by the server to a non-synced table, the listener silently decodes the non-synced table's WRITE_ROWS/UPDATE_ROWS/DELETE_ROWS events using the stale synced-table schema.
The result is silent data corruption: rows from a table that is not part of the sync set get written into OpenSearch under the synced index, with mismatched/garbled column values.
To Reproduce
Steps to reproduce the behavior:
- Create two tables in the source DB:
- a synced table
synced_table (e.g., 21 columns) — listed in tables.include
- a non-synced table
other_table (e.g., 25 columns) — NOT listed in tables.include
- Start the pipeline in CDC stream mode and confirm
synced_table changes are synced to OpenSearch normally. At this point the listener has cached, say, tableId 140 → synced_table.
- Reboot the MySQL/Aurora server (binlog
table_id values are reset and re-assigned).
- After the reboot, drive DML so that the server reassigns the old
tableId (140) to other_table. (In practice, table_ids are assigned in the order tables are first touched by DML; inserting into padding tables to consume ids reliably steers the assignment.)
INSERT into other_table.
- Observe that OSIS processes
other_table's rows as synced_table and writes corrupted documents into OpenSearch.
Expected behavior
Row events for a table that is not in the sync set must never be processed. When a binlog table_id is reassigned (across a server restart, reconnect, or table-cache eviction), the cached tableId → metadata mapping for that id must be invalidated so that a non-synced table can never be decoded with a stale synced-table schema. No silent data corruption should occur.
Screenshots
N/A
Environment (please complete the following information):
- OS: [e.g. Ubuntu 20.04 LTS]
- Version [e.g. 22]
- Source: rds-source against Amazon Aurora MySQL
Additional context
Suggested fix direction:
- In
handleTableMapEvent, when a TABLE_MAP arrives whose (db, table) for a given tableId differs from the cached entry, evict/overwrite the stale entry instead of early-returning for non-interest tables.
- Clear (or invalidate)
tableMetadataMap on ROTATE / reconnect, since table_ids are not stable across restarts.
- In
isValidTableId, re-verify that the cached (db, table) for the tableId matches the most recent TABLE_MAP for that id before accepting the row event.
Describe the bug
In the RDS source's CDC/binlog stream mode,
BinlogEventListenercaches atableId → TableMetadatamapping in memory (tableMetadataMap), populated from binlogTABLE_MAPevents. This mapping is only ever populated for tables of interest (i.e., tables in the pipeline'stables.include), and stale entries are never invalidated.MySQL's binlog
table_idis not stable: it is assigned from the server's table-definition cache and can be reassigned across a server restart (and on table-cache eviction). When atable_idthat was previously mapped to a synced table gets reassigned by the server to a non-synced table, the listener silently decodes the non-synced table'sWRITE_ROWS/UPDATE_ROWS/DELETE_ROWSevents using the stale synced-table schema.The result is silent data corruption: rows from a table that is not part of the sync set get written into OpenSearch under the synced index, with mismatched/garbled column values.
To Reproduce
Steps to reproduce the behavior:
synced_table(e.g., 21 columns) — listed intables.includeother_table(e.g., 25 columns) — NOT listed intables.includesynced_tablechanges are synced to OpenSearch normally. At this point the listener has cached, say,tableId 140 → synced_table.table_idvalues are reset and re-assigned).tableId(140) toother_table. (In practice,table_ids are assigned in the order tables are first touched by DML; inserting into padding tables to consume ids reliably steers the assignment.)INSERTintoother_table.other_table's rows assynced_tableand writes corrupted documents into OpenSearch.Expected behavior
Row events for a table that is not in the sync set must never be processed. When a binlog
table_idis reassigned (across a server restart, reconnect, or table-cache eviction), the cachedtableId → metadatamapping for that id must be invalidated so that a non-synced table can never be decoded with a stale synced-table schema. No silent data corruption should occur.Screenshots
N/A
Environment (please complete the following information):
Additional context
Suggested fix direction:
handleTableMapEvent, when aTABLE_MAParrives whose(db, table)for a giventableIddiffers from the cached entry, evict/overwrite the stale entry instead of early-returning for non-interest tables.tableMetadataMaponROTATE/ reconnect, sincetable_ids are not stable across restarts.isValidTableId, re-verify that the cached(db, table)for thetableIdmatches the most recentTABLE_MAPfor that id before accepting the row event.