Hey Abhishek,
Interesting. So I am going to assume this is the control flow where we hit a supposed duplicate, and then attempt to grab it instead. I think we need to widen the filter:
`internal async Task AddBlobAsync(NamespaceId namespaceId, BlobLocator locator, IReadOnlyCollection imports, List? exports = null, CancellationToken cancellationToken = default)
{
List importIds = await FindOrAddShadowBlobsAsync(namespaceId, imports, cancellationToken);
FilterDefinition insertFilter =
Builders.Filter.Eq(x => x.NamespaceId, namespaceId) &
Builders.Filter.Eq(x => x.Path, locator.ToString()) &
Builders.Filter.Eq(x => x.Shadow, true);
UpdateDefinition insertUpdate = Builders.Update
.Unset(x => x.Shadow);
if (importIds.Count > 0)
{
insertUpdate = insertUpdate.Set(x => x.Imports, importIds);
}
if (exports != null && exports.Count > 0)
{
insertUpdate = insertUpdate.Set(x => x.Aliases, exports);
}
// JULIAN_DIVERGENCE_START
BlobInfo? blobInfo;
try
{
blobInfo = await _blobCollection.FindOneAndUpdateAsync(insertFilter, insertUpdate, new FindOneAndUpdateOptions<BlobInfo, BlobInfo> { IsUpsert = true, ReturnDocument = ReturnDocument.After }, cancellationToken);
}
catch (Exception ex)
{
FilterDefinition existingFilter =
Builders.Filter.Eq(x => x.NamespaceId, namespaceId) &
Builders.Filter.Eq(x => x.Path, locator.ToString());
_logger.LogWarning(“Race condition on upsert for blob {Path}. Retrying as read-only lookup.”, locator.ToString());
blobInfo = await _blobCollection.Find(existingFilter).FirstOrDefaultAsync(cancellationToken);
if(blobInfo == null)
{
_logger.LogWarning(“We’ve hit the exception {Exception}, but have failed to obtain the duplicate entry.”, ex.Message);
}
}
_logger.LogDebug(“Created blob {BlobId} at {Path} ({NumImports} imports)”, blobInfo?.Id, blobInfo?.Path, imports?.Count);
// JULIAN_DIVERGENCE_END
return blobInfo;
}`I appreciate the collaboration on this by the way. And for posterity, the keys are constructed JIT when we initially setup the collection (StorageService.cs):
List<MongoIndex<BlobInfo>> blobIndexes = new List<MongoIndex<BlobInfo>>(); blobIndexes.Add(keys => keys.Ascending(x => x.Imports)); blobIndexes.Add(keys => keys.Ascending(x => x.NamespaceId).Ascending(s_blobAliasField)); blobIndexes.Add(keys => keys.Ascending(x => x.NamespaceId).Ascending(x => x.Path), unique: true); _blobCollection = mongoService.GetCollection<BlobInfo>("Storage.Blobs", blobIndexes);
Kind regards,
Julian