Replace per-file HEAD calls with a single ListBlobs metadata cache - #38
Merged
Conversation
Previously, every FileExists(string), FileLength(string), and OpenInput(string, IOContext) call issued an individual GetProperties (HEAD) request to Azure Blob Storage. For an index with N files, opening or refreshing a reader triggered N round-trips. This change introduces a BlobMetadata cache populated by a single GetBlobsByHierarchy call (which returns properties for all blobs in one page). The cache is: • refreshed by ListAll(), which Lucene always calls first when opening or re-checking an index • lazily populated on first access if ListAll() has not yet been called • updated in-place after AzureIndexOutput.Dispose() completes an upload, using the already-known local length — preventing an unnecessary re-download when Lucene reads a file it just wrote • invalidated per-entry on DeleteFile() AzureIndexInput now reads ContentLength from the cache instead of calling GetProperties on the blob before deciding whether to re-download. Net result: N HEAD calls per reader open/refresh replaced by 1 ListBlobs call.
There was a problem hiding this comment.
Pull request overview
This PR reduces Azure Blob Storage round-trips by replacing per-file property (HEAD) requests with a container listing–backed in-memory metadata cache, improving Lucene index open/refresh performance.
Changes:
- Add a blob metadata cache to
AzureDirectorypopulated viaGetBlobsByHierarchy()and used byListAll(),FileExists(),FileLength(), andOpenInput(). - Update
AzureIndexInputto use cachedContentLengthinstead of callingGetProperties(). - Update
AzureIndexOutputto update the metadata cache after successful upload; bump package/version numbers.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| source/Lucene.Net.Store.Azure/Lucene.Net.Store.Azure.csproj | Version bump for the new release containing the metadata-cache optimization. |
| source/Lucene.Net.Store.Azure/AzureIndexOutput.cs | Updates the metadata cache after upload to avoid immediate re-downloads. |
| source/Lucene.Net.Store.Azure/AzureIndexInput.cs | Uses cached blob length when deciding whether to download into the local cache. |
| source/Lucene.Net.Store.Azure/AzureDirectory.cs | Introduces and wires up the metadata cache; switches FileExists/FileLength to cache-backed lookups. |
Comments suppressed due to low confidence (1)
source/Lucene.Net.Store.Azure/AzureIndexInput.cs:61
- The
catch (RequestFailedException err)block in this length-comparison path no longer makes sense because the code inside thetryno longer performs any Azure SDK call that could throwRequestFailedException. This looks like leftover logic from the previousGetProperties()approach; consider removing the catch or replacing it with handling that matches the new cache-based flow.
{
try
{
long cachedLength = CacheDirectory.FileLength(name);
long blobLength = _azureDirectory.GetCachedMetadata(name)?.ContentLength ?? 0;
if (cachedLength != blobLength)
fileNeeded = true;
}
catch (RequestFailedException err)
{
// if blob not found
if (err.Status == 404)
{
// then we should remove from cache directory.
CacheDirectory.DeleteFile(name);
Debug.WriteLine($"{_azureDirectory.Name} {name} Does not exist");
throw new FileNotFoundException(name, err);
}
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Previously, every FileExists(string), FileLength(string), and OpenInput(string, IOContext) call issued an individual GetProperties (HEAD) request to Azure Blob Storage. For an index with N files, opening or refreshing a reader triggered N round-trips. This change introduces a BlobMetadata cache populated by a single GetBlobsByHierarchy call (which returns properties for all blobs in one page). The cache is:
AzureIndexInput now reads ContentLength from the cache instead of calling GetProperties on the blob before deciding whether to re-download. Net result: N HEAD calls per reader open/refresh replaced by 1 ListBlobs call.
Net result is that it's ~2X to 2.5X faster than old AzureDirctory code.