Skip to content

Conversation

@shivam2680
Copy link
Contributor

@shivam2680 shivam2680 commented Oct 15, 2025

Problem

The flaky Iterator tests were failing with:
java.lang.IllegalStateException: Should not get result schema on an empty result handler

This occurred due to two related race conditions:

Root Cause 1: Missing Operation Readiness Check

The hasMoreRows() method was attempting to fetch result metadata before the operation finished executing. When tests used maxRows: null (disabling direct results), the operation had no cached
metadata and would try to fetch it while the server-side operation was still running, causing the result handler to be in an invalid state.

Unlike other methods (getSchema(), fetchChunk()), hasMoreRows() did NOT call waitUntilReady() before accessing metadata.

Root Cause 2: Concurrent Metadata Fetches

When multiple concurrent calls to fetchMetadata() occurred before the first completed:

  • Each would check if (!this.metadata) and find it undefined
  • Multiple requests would be sent to the server simultaneously
  • This could result in fetching metadata after the result handler was consumed

Fix

  1. Wait for Operation Readiness in hasMoreRows()

Added waitUntilReady() call to ensure the operation completes before fetching metadata:

public async hasMoreRows(): Promise {
if (this.closed || this.cancelled) {
return false;
}

  // Wait for operation to finish before checking for more rows
  if (this.operationHandle.hasResultSet) {
    await this.waitUntilReady();
  }

  const resultHandler = await this.getResultHandler();
  return resultHandler.hasMore();

}

  1. Async-Safe Metadata Fetching

Implemented promise-based locking using metadataPromise field:

  • First concurrent call creates and caches the promise
  • Subsequent concurrent calls wait for the same promise instead of creating new requests
  • Promise is cleared after completion (success or failure)

Tests Added

  1. Test for concurrent metadata fetch requests (verifies only 1 server call)
  2. Test for metadata caching after first fetch

Addresses race condition where concurrent calls to fetchMetadata() would
attempt multiple server requests before the first completed. This caused
failures when GetResultSetMetadata was called after result handler was
consumed.

The fix uses a promise-based locking pattern to ensure only one metadata
fetch occurs, with subsequent concurrent calls waiting for the same promise.

Also adds unit tests to verify async-safety of metadata fetching.

Signed-off-by: Shivam Raj <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants