Skip to content

Commit d23134b

Browse files
author
nimanikoo
committed
Optimized HashFieldExpireExecute - Reduce memory allocations and improve performance
- Replace List<RedisValue> with a fixed-size array. - Use ArrayPool for arrays larger than 16 elements to lower GC pressure. - Simplify the code without adding extra complexity.
1 parent fe04b9a commit d23134b

File tree

1 file changed

+38
-9
lines changed

1 file changed

+38
-9
lines changed

src/StackExchange.Redis/RedisDatabase.cs

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -414,18 +414,47 @@ public Task<ExpireResult[]> HashFieldExpireAsync(RedisKey key, RedisValue[] hash
414414
private T HashFieldExpireExecute<T, TProcessor>(RedisKey key, long milliseconds, ExpireWhen when, Func<bool, RedisCommand> getCmd, CustomExecutor<T, TProcessor> executor, TProcessor processor, CommandFlags flags, params RedisValue[] hashFields)
415415
{
416416
if (hashFields == null) throw new ArgumentNullException(nameof(hashFields));
417-
var useSeconds = milliseconds % 1000 == 0;
417+
418+
bool useSeconds = (milliseconds % 1000) == 0;
418419
var cmd = getCmd(useSeconds);
419-
long expiry = useSeconds ? (milliseconds / 1000) : milliseconds;
420+
long expiry = useSeconds ? milliseconds / 1000 : milliseconds;
421+
422+
int baseLength = (when == ExpireWhen.Always) ? 3 : 4;
423+
int totalLength = baseLength + hashFields.Length;
424+
425+
bool usePool = totalLength > 16;
426+
RedisValue[] values = usePool
427+
? ArrayPool<RedisValue>.Shared.Rent(totalLength)
428+
: new RedisValue[totalLength];
420429

421-
var values = when switch
430+
try
422431
{
423-
ExpireWhen.Always => new List<RedisValue> { expiry, RedisLiterals.FIELDS, hashFields.Length },
424-
_ => new List<RedisValue> { expiry, when.ToLiteral(), RedisLiterals.FIELDS, hashFields.Length },
425-
};
426-
values.AddRange(hashFields);
427-
var msg = Message.Create(Database, flags, cmd, key, values.ToArray());
428-
return executor(msg, processor);
432+
values[0] = expiry;
433+
if (when == ExpireWhen.Always)
434+
{
435+
values[1] = RedisLiterals.FIELDS;
436+
values[2] = hashFields.Length;
437+
}
438+
else
439+
{
440+
values[1] = when.ToLiteral();
441+
values[2] = RedisLiterals.FIELDS;
442+
values[3] = hashFields.Length;
443+
}
444+
Array.Copy(hashFields, 0, values, baseLength, hashFields.Length);
445+
446+
RedisValue[] finalValues = usePool ? new RedisValue[totalLength] : values;
447+
if (usePool)
448+
Array.Copy(values, finalValues, totalLength);
449+
450+
var msg = Message.Create(Database, flags, cmd, key, finalValues);
451+
return executor(msg, processor);
452+
}
453+
finally
454+
{
455+
if (usePool)
456+
ArrayPool<RedisValue>.Shared.Return(values);
457+
}
429458
}
430459

431460
private static RedisCommand PickExpireCommandByPrecision(bool useSeconds) => useSeconds ? RedisCommand.HEXPIRE : RedisCommand.HPEXPIRE;

0 commit comments

Comments
 (0)