[fix][broker] Clean up orphan ledger on concurrent initial schema creation in BookkeeperSchemaStorage - #25514
Conversation
…ation in BookkeeperSchemaStorage
…ation in BookkeeperSchemaStorage
2ffb279 to
1ba8b3c
Compare
|
/pulsarbot rerun-failure-checks |
|
@geniusjoe @dao-jun @codelipenghui @hanmz Seems like there are some issues?
|
|
@Denovo1998 However, the current approach could indeed introduce race condition issues in unit tests. I think your proposed solution makes sense. If you have time, you could go ahead and implement it as you suggested. Perhaps the cleanup semantics for both |
…ation in BookkeeperSchemaStorage (apache#25514)
…ation in BookkeeperSchemaStorage (#25514)
…ation in BookkeeperSchemaStorage (#25514)
…ation in BookkeeperSchemaStorage (apache#25514)
…ation in BookkeeperSchemaStorage (apache#25514) (cherry picked from commit 6d7a22b)
Fixes #18292
Related #18701
Motivation
When multiple requests concurrently create a schema for a brand-new topic (i.e., the schema locator z-node does not yet exist), each request first creates a BookKeeper ledger via
addNewSchemaEntryToStore, then attempts to create the schema locator z-node via CAS (createSchemaLocatorwithexpectedVersion = -1L).Only one request succeeds; the others fail with BadVersionException (because ZK MetadataStore translates NODEEXISTS to BadVersionException when expectedVersion == -1). However, the ledgers created by the failed requests were never cleaned up, resulting in orphan ledgers (dirty data) in BookKeeper.
Note that the existing
updateSchemaLocatormethod already has cleanup logic for this scenario (deleting the orphan ledger when CAS fails withBadVersionException) in #18701, but thecreateNewSchemamethod — which handles the initial schema creation path — was missing this cleanup.Modifications
BookkeeperSchemaStorage.createNewSchema: Added awhenCompletecallback aftercreateSchemaLocator. When the CAS operation fails due toAlreadyExistsExceptionorBadVersionException, the orphan BookKeeper ledger is asynchronously deleted, consistent with the existing cleanup logic inupdateSchemaLocator. The method is also refactored into three clearly commented steps for better readability.PulsarMockLedgerHandle: Added a new constructor that acceptsMap<String, byte[]> customMetadataand passes it toLedgerMetadataBuilder.withCustomMetadata(), so that mock ledgers can retain custom metadata set during creation.PulsarMockBookKeeper: UpdatedasyncCreateLedgerto forward thepropertiesparameter to the newPulsarMockLedgerHandleconstructor, enabling tests to inspect ledger custom metadata.SchemaTest: AddedtestConcurrentCreateSchemaNoOrphanLedgertest that verifies orphan ledgers are cleaned up when 16 producers concurrently create schema on a brand-new topic. The test inspects surviving BK ledgers viaPulsarMockBookKeeper.getLedgerMap()and asserts that only 1 ledger with matchingpulsar/schemaIdcustom metadata exists.Verifying this change
This change added tests and can be verified as follows:
testConcurrentCreateSchemaNoOrphanLedgerinSchemaTestthat concurrently creates 16 producers with the same AVRO schema on a brand-new topic, then verifies:admin.schemas().getAllSchemas()customMetadata["pulsar/schemaId"]matching the topic's schema name (orphan ledgers from failed concurrent creations were deleted)Does this pull request potentially affect one of the following parts: