Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit db8e144

Browse files
committed
Change DeleteAll to use SSCAN to page through data instead of pulling all keys into memory all at once. This will reduce memory, but make the command chatty for very large typed sets.
1 parent b96308f commit db8e144

File tree

4 files changed

+55
-14
lines changed

4 files changed

+55
-14
lines changed

src/ServiceStack.Redis/Generic/RedisTypedClient.Async.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,24 @@ async Task IEntityStoreAsync<T>.DeleteByIdsAsync(IEnumerable ids, CancellationTo
131131

132132
async Task IEntityStoreAsync<T>.DeleteAllAsync(CancellationToken token)
133133
{
134-
var ids = await AsyncClient.GetAllItemsFromSetAsync(this.TypeIdsSetKey, token).ConfigureAwait(false);
134+
await DeleteAllAsync(0,1000, token).ConfigureAwait(false);
135+
}
136+
137+
private async Task DeleteAllAsync(ulong cursor, int pageSize, CancellationToken token)
138+
{
139+
var scanResult = await AsyncNative.SScanAsync(this.TypeIdsSetKey, cursor, pageSize, token: token).ConfigureAwait(false);
140+
var lastCursor = scanResult.Cursor;
141+
var ids = scanResult.Results.Select(x => Encoding.UTF8.GetString(x)).ToList();
135142
var urnKeys = ids.Map(t => client.UrnKey<T>(t));
136143
if (urnKeys.Count > 0)
137144
{
138145
await AsyncClient.RemoveEntryAsync(urnKeys.ToArray(), token).ConfigureAwait(false);
139-
await AsyncClient.RemoveEntryAsync(new[] { this.TypeIdsSetKey }, token).ConfigureAwait(false);
140146
}
147+
148+
if (lastCursor != 0)
149+
await DeleteAllAsync(lastCursor, pageSize, token).ConfigureAwait(false);
150+
else
151+
await AsyncClient.RemoveEntryAsync(new[] { this.TypeIdsSetKey }, token).ConfigureAwait(false);
141152
}
142153

143154
async ValueTask<List<T>> IRedisTypedClientAsync<T>.GetValuesAsync(List<string> keys, CancellationToken token)

src/ServiceStack.Redis/Generic/RedisTypedClient.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -466,16 +466,25 @@ public void DeleteByIds(IEnumerable ids)
466466
}
467467
}
468468

469-
public void DeleteAll()
469+
private void DeleteAll(ulong cursor, int pageSize)
470470
{
471-
var ids = client.GetAllItemsFromSet(this.TypeIdsSetKey);
471+
var scanResult = client.SScan(this.TypeIdsSetKey, cursor, pageSize);
472+
var resultCursor = scanResult.Cursor;
473+
var ids = scanResult.Results.Select(x => Encoding.UTF8.GetString(x)).ToList();
472474
var urnKeys = ids.Map(t => client.UrnKey<T>(t));
473475
if (urnKeys.Count > 0)
474476
{
475-
476477
this.RemoveEntry(urnKeys.ToArray());
477-
this.RemoveEntry(this.TypeIdsSetKey);
478478
}
479+
if(resultCursor != 0)
480+
DeleteAll(resultCursor,1000);
481+
else
482+
this.RemoveEntry(this.TypeIdsSetKey);
483+
}
484+
485+
public void DeleteAll()
486+
{
487+
DeleteAll(0,1000);
479488
}
480489

481490
#endregion

src/ServiceStack.Redis/RedisClient.Async.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -658,15 +658,26 @@ async Task IEntityStoreAsync.DeleteByIdsAsync<T>(ICollection ids, CancellationTo
658658
}
659659

660660
async Task IEntityStoreAsync.DeleteAllAsync<T>(CancellationToken token)
661+
{
662+
await DeleteAllAsync<T>(0, 1000, token).ConfigureAwait(false);
663+
}
664+
665+
private async Task DeleteAllAsync<T>(ulong cursor, int pageSize, CancellationToken token)
661666
{
662667
var typeIdsSetKey = this.GetTypeIdsSetKey<T>();
663-
var ids = await AsAsync().GetAllItemsFromSetAsync(typeIdsSetKey, token).ConfigureAwait(false);
664-
if (ids.Count > 0)
668+
var scanResult = await NativeAsync.SScanAsync(typeIdsSetKey, cursor, pageSize, token: token).ConfigureAwait(false);
669+
var lastCursor = scanResult.Cursor;
670+
var ids = scanResult.Results.Select(x => x.FromUtf8Bytes());
671+
var urnKeys = ids.Map(t => AsAsync().UrnKey<T>(t));
672+
if (urnKeys.Count > 0)
665673
{
666-
var urnKeys = ids.ToList().ConvertAll(UrnKey<T>);
667674
await AsAsync().RemoveEntryAsync(urnKeys.ToArray(), token).ConfigureAwait(false);
668-
await AsAsync().RemoveAsync(typeIdsSetKey, token).ConfigureAwait(false);
669675
}
676+
677+
if (lastCursor != 0)
678+
await DeleteAllAsync<T>(lastCursor, pageSize, token).ConfigureAwait(false);
679+
else
680+
await AsAsync().RemoveEntryAsync(new[] { typeIdsSetKey }, token).ConfigureAwait(false);
670681
}
671682

672683
ValueTask<List<string>> IRedisClientAsync.SearchSortedSetAsync(string setId, string start, string end, int? skip, int? take, CancellationToken token)

src/ServiceStack.Redis/RedisClient.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -830,15 +830,25 @@ public void DeleteByIds<T>(ICollection ids)
830830
}
831831

832832
public void DeleteAll<T>()
833+
{
834+
DeleteAll<T>(0,1000);
835+
}
836+
837+
private void DeleteAll<T>(ulong cursor, int pageSize)
833838
{
834839
var typeIdsSetKey = this.GetTypeIdsSetKey<T>();
835-
var ids = this.GetAllItemsFromSet(typeIdsSetKey);
836-
if (ids.Count > 0)
840+
var scanResult = this.SScan(typeIdsSetKey, cursor, pageSize);
841+
var resultCursor = scanResult.Cursor;
842+
var ids = scanResult.Results.Select(x => x.FromUtf8Bytes());
843+
var urnKeys = ids.Map(t => this.UrnKey(t));
844+
if (urnKeys.Count > 0)
837845
{
838-
var urnKeys = ids.ToList().ConvertAll(UrnKey<T>);
839846
this.RemoveEntry(urnKeys.ToArray());
840-
this.Remove(typeIdsSetKey);
841847
}
848+
if(resultCursor != 0)
849+
DeleteAll<T>(resultCursor, 1000);
850+
else
851+
this.RemoveEntry(typeIdsSetKey);
842852
}
843853

844854
public RedisClient CloneClient()

0 commit comments

Comments
 (0)