private RegisterLocationAsync ( OperationContext context, IReadOnlyList contentHashes, BuildXL.Cache.ContentStore.Distributed.NuCache.MachineId machineId, string caller = null ) : Task |
||
context | OperationContext | |
contentHashes | IReadOnlyList | |
machineId | BuildXL.Cache.ContentStore.Distributed.NuCache.MachineId | |
caller | string | |
Результат | Task |
private Task<BoolResult> RegisterLocationAsync(
OperationContext context,
IReadOnlyList<ShortHashWithSize> contentHashes,
MachineId machineId,
[CallerMemberName] string caller = null)
{
const int operationsPerHash = 3;
var hashBatchSize = Math.Max(1, Configuration.RedisBatchPageSize / operationsPerHash);
return context.PerformOperationAsync(
Tracer,
async () =>
{
foreach (var page in contentHashes.GetPages(hashBatchSize))
{
var batchResult = await RaidedRedis.ExecuteRedisAsync(context, async (redisDb, token) =>
{
Counters[GlobalStoreCounters.RegisterLocalLocationHashCount].Add(page.Count);
int requiresSetBitCount;
ConcurrentBitArray requiresSetBit;
if (Configuration.UseOptimisticRegisterLocalLocation)
{
requiresSetBitCount = 0;
requiresSetBit = new ConcurrentBitArray(page.Count);
var redisBatch = redisDb.CreateBatch(RedisOperation.RegisterLocalSetNonExistentHashEntries);
// Perform initial pass to set redis entries in single operation. Fallback to more elaborate
// flow where we use SetBit + KeyExpire
foreach (var indexedHash in page.WithIndices())
{
var hash = indexedHash.value;
var key = GetRedisKey(hash.Hash);
redisBatch.AddOperationAndTraceIfFailure(context, key, async batch =>
{
bool set = await batch.StringSetAsync(key, ContentLocationEntry.ConvertSizeAndMachineIdToRedisValue(hash.Size, machineId), Configuration.LocationEntryExpiry, When.NotExists);
if (!set)
{
requiresSetBit[indexedHash.index] = true;
Interlocked.Increment(ref requiresSetBitCount);
}
return set;
}, operationName: "ConvertSizeAndMachineIdToRedisValue");
}
var result = await redisDb.ExecuteBatchOperationAsync(context, redisBatch, token);
if (!result || requiresSetBitCount == 0)
{
return result;
}
}
else
{
requiresSetBitCount = page.Count;
requiresSetBit = null;
}
// Some keys already exist and require that we set the bit and update the expiry on the existing entry
using (Counters[GlobalStoreCounters.RegisterLocalLocationUpdate].Start())
{
Counters[GlobalStoreCounters.RegisterLocalLocationUpdateHashCount].Add(requiresSetBitCount);
var updateRedisBatch = redisDb.CreateBatch(RedisOperation.RegisterLocalSetHashEntries);
foreach (var hash in page.Where((h, index) => requiresSetBit?[index] ?? true))
{
var key = GetRedisKey(hash.Hash);
updateRedisBatch.AddOperationAndTraceIfFailure(
context,
key,
batch => SetLocationBitAndExpireAsync(context, batch, key, hash, machineId),
operationName: "SetLocationBitAndExpireAsync");
}
return await redisDb.ExecuteBatchOperationAsync(context, updateRedisBatch, token);
}
}, Configuration.RetryWindow);
if (!batchResult)
{
return batchResult;
}
}
return BoolResult.Success;
},
Counters[GlobalStoreCounters.RegisterLocalLocation],
caller: caller,
traceErrorsOnly: true);
}
RedisGlobalStore::RegisterLocationAsync ( OperationContext context, BuildXL.Cache.ContentStore.Distributed.NuCache.MachineId machineId, IReadOnlyList contentHashes, bool touch ) : ValueTask |