Skip to content

Commit d5a9dcd

Browse files
committed
#9 Refactored async pages to use page fetch scheduler
1 parent 799b0f6 commit d5a9dcd

File tree

5 files changed

+63
-5
lines changed

5 files changed

+63
-5
lines changed

BFF.DataVirtualizingCollection/DataVirtualizingCollectionBuilderBase.cs

+16
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ internal abstract class DataVirtualizingCollectionBuilderBase<TItem, TVirtualiza
6363
private Func<int, int, CancellationToken, Task<TItem[]>>? _taskBasedPageFetcher;
6464
private Func<int, int, CancellationToken, IAsyncEnumerable<TItem>>? _asyncEnumerableBasedPageFetcher;
6565
protected Func<CancellationToken, int>? CountFetcher;
66+
private IAsyncPageFetchScheduler? _asyncPageFetchScheduler;
6667

6768
private Func<IObservable<(int PageKey, int PageIndex)>, IObservable<IReadOnlyList<int>>> _pageHoldingBehavior =
6869
HoardingPageNonRemoval.Create();
@@ -150,6 +151,7 @@ public TVirtualizationKind AsyncIndexAccess(
150151
{
151152
_indexAccessBehavior = IndexAccessBehavior.Asynchronous;
152153
_placeholderFactory = placeholderFactory;
154+
_asyncPageFetchScheduler = new ImmediateAsyncPageFetchScheduler();
153155
return GenerateCollection();
154156
}
155157

@@ -273,13 +275,15 @@ IPage<TItem> NonPreloadingPageFetcherFactory(
273275
{
274276
var taskBasedPageFetcher = _taskBasedPageFetcher ?? throw new NullReferenceException(UninitializedElementsExceptionMessage);
275277
var placeholderFactory = _placeholderFactory ?? throw new NullReferenceException(UninitializedElementsExceptionMessage);
278+
var asyncPageFetchScheduler = _asyncPageFetchScheduler ?? throw new NullReferenceException(UninitializedElementsExceptionMessage);
276279
return new AsyncTaskBasedPage<TItem>(
277280
pageKey,
278281
offset,
279282
pageSize,
280283
onDisposalAfterFetchCompleted,
281284
taskBasedPageFetcher,
282285
placeholderFactory,
286+
asyncPageFetchScheduler,
283287
_pageBackgroundScheduler,
284288
pageFetchEvents.AsObserver());
285289
}
@@ -293,13 +297,15 @@ IPage<TItem> PreloadingPageFetcherFactory(
293297
var taskBasedPageFetcher = _taskBasedPageFetcher ?? throw new NullReferenceException(UninitializedElementsExceptionMessage);
294298
var preloadingPlaceholderFactory = _preloadingPlaceholderFactory ??
295299
throw new NullReferenceException(UninitializedElementsExceptionMessage);
300+
var asyncPageFetchScheduler = _asyncPageFetchScheduler ?? throw new NullReferenceException(UninitializedElementsExceptionMessage);
296301
return new AsyncTaskBasedPage<TItem>(
297302
pageKey,
298303
offset,
299304
pageSize,
300305
onDisposalAfterFetchCompleted,
301306
taskBasedPageFetcher,
302307
preloadingPlaceholderFactory,
308+
asyncPageFetchScheduler,
303309
_preloadingBackgroundScheduler,
304310
pageFetchEvents.AsObserver());
305311
}
@@ -323,13 +329,15 @@ IPage<TItem> NonPreloadingPageFetcherFactory(
323329
{
324330
var asyncEnumerableBasedPageFetcher = _asyncEnumerableBasedPageFetcher ?? throw new NullReferenceException(UninitializedElementsExceptionMessage);
325331
var placeholderFactory = _placeholderFactory ?? throw new NullReferenceException(UninitializedElementsExceptionMessage);
332+
var asyncPageFetchScheduler = _asyncPageFetchScheduler ?? throw new NullReferenceException(UninitializedElementsExceptionMessage);
326333
return new AsyncEnumerableBasedPage<TItem>(
327334
pageKey,
328335
offset,
329336
pageSize,
330337
onDisposalAfterFetchCompleted,
331338
asyncEnumerableBasedPageFetcher,
332339
placeholderFactory,
340+
asyncPageFetchScheduler,
333341
_pageBackgroundScheduler,
334342
pageFetchEvents.AsObserver());
335343
}
@@ -343,13 +351,15 @@ IPage<TItem> PreloadingPageFetcherFactory(
343351
var asyncEnumerableBasedPageFetcher = _asyncEnumerableBasedPageFetcher ?? throw new NullReferenceException(UninitializedElementsExceptionMessage);
344352
var preloadingPlaceholderFactory = _preloadingPlaceholderFactory ??
345353
throw new NullReferenceException(UninitializedElementsExceptionMessage);
354+
var asyncPageFetchScheduler = _asyncPageFetchScheduler ?? throw new NullReferenceException(UninitializedElementsExceptionMessage);
346355
return new AsyncEnumerableBasedPage<TItem>(
347356
pageKey,
348357
offset,
349358
pageSize,
350359
onDisposalAfterFetchCompleted,
351360
asyncEnumerableBasedPageFetcher,
352361
preloadingPlaceholderFactory,
362+
asyncPageFetchScheduler,
353363
_preloadingBackgroundScheduler,
354364
pageFetchEvents.AsObserver());
355365
}
@@ -373,13 +383,15 @@ IPage<TItem> NonPreloadingPageFetcherFactory(
373383
{
374384
var pageFetcher = _pageFetcher ?? throw new NullReferenceException(UninitializedElementsExceptionMessage);
375385
var placeholderFactory = _placeholderFactory ?? throw new NullReferenceException(UninitializedElementsExceptionMessage);
386+
var asyncPageFetchScheduler = _asyncPageFetchScheduler ?? throw new NullReferenceException(UninitializedElementsExceptionMessage);
376387
return new AsyncNonTaskBasedPage<TItem>(
377388
pageKey,
378389
offset,
379390
pageSize,
380391
onDisposalAfterFetchCompleted,
381392
pageFetcher,
382393
placeholderFactory,
394+
asyncPageFetchScheduler,
383395
_pageBackgroundScheduler,
384396
pageFetchEvents.AsObserver());
385397
}
@@ -393,13 +405,15 @@ IPage<TItem> PreloadingPageFetcherFactory(
393405
var pageFetcher = _pageFetcher ?? throw new NullReferenceException(UninitializedElementsExceptionMessage);
394406
var preloadingPlaceholderFactory = _preloadingPlaceholderFactory ??
395407
throw new NullReferenceException(UninitializedElementsExceptionMessage);
408+
var asyncPageFetchScheduler = _asyncPageFetchScheduler ?? throw new NullReferenceException(UninitializedElementsExceptionMessage);
396409
return new AsyncNonTaskBasedPage<TItem>(
397410
pageKey,
398411
offset,
399412
pageSize,
400413
onDisposalAfterFetchCompleted,
401414
pageFetcher,
402415
preloadingPlaceholderFactory,
416+
asyncPageFetchScheduler,
403417
_preloadingBackgroundScheduler,
404418
pageFetchEvents.AsObserver());
405419
}
@@ -413,6 +427,7 @@ IPageStorage<TItem> PageStoreFactoryComposition(int count)
413427
internal Func<int, IPageStorage<TItem>> GenerateNonTaskBasedSynchronousPageStorage(
414428
Subject<(int Offset, int PageSize, TItem[] PreviousPage, TItem[] Page)> pageFetchEvents)
415429
{
430+
var immediateAsyncPageFetchScheduler = new ImmediateAsyncPageFetchScheduler();
416431
return PageStoreFactoryComposition;
417432

418433
IPage<TItem> NonPreloadingPageFetcherFactory(
@@ -447,6 +462,7 @@ IPage<TItem> PreloadingPageFetcherFactory(
447462
onDisposalAfterFetchCompleted,
448463
pageFetcher,
449464
preloadingPlaceholderFactory,
465+
immediateAsyncPageFetchScheduler,
450466
_preloadingBackgroundScheduler,
451467
pageFetchEvents.AsObserver());
452468
}

BFF.DataVirtualizingCollection/PageStorage/AsyncPageBase.cs

+19-5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ internal AsyncPageBase(
2929

3030
// dependencies
3131
Func<int, int, T> placeholderFactory,
32+
IAsyncPageFetchScheduler asyncPageFetchScheduler,
3233
IScheduler pageBackgroundScheduler,
3334
IObserver<(int Offset, int PageSize, T[] PreviousPage, T[] Page)> pageArrivalObservations)
3435
{
@@ -41,11 +42,17 @@ internal AsyncPageBase(
4142
.Select(pageIndex => placeholderFactory(pageKey, pageIndex))
4243
.ToArray();
4344
PageFetchCompletion = Observable
44-
.StartAsync(OnPageFetch, pageBackgroundScheduler)
45+
.StartAsync(FetchPage, pageBackgroundScheduler)
4546
.ToTask(_cancellationTokenSource.Token);
47+
48+
async Task FetchPage(CancellationToken ct)
49+
{
50+
await asyncPageFetchScheduler.Schedule(ct).ConfigureAwait(false);
51+
await FetchPageInner(ct).ConfigureAwait(false);
52+
}
4653
}
4754

48-
protected abstract Task OnPageFetch(CancellationToken ct);
55+
protected abstract Task FetchPageInner(CancellationToken ct);
4956

5057
public Task PageFetchCompletion { get; }
5158

@@ -98,6 +105,7 @@ internal AsyncNonTaskBasedPage(
98105
// dependencies
99106
Func<int, int, CancellationToken, T[]> pageFetcher,
100107
Func<int, int, T> placeholderFactory,
108+
IAsyncPageFetchScheduler asyncPageFetchScheduler,
101109
IScheduler pageBackgroundScheduler,
102110
IObserver<(int Offset, int PageSize, T[] PreviousPage, T[] Page)> pageArrivalObservations)
103111
: base(
@@ -106,11 +114,12 @@ internal AsyncNonTaskBasedPage(
106114
pageSize,
107115
onDisposalAfterFetchCompleted,
108116
placeholderFactory,
117+
asyncPageFetchScheduler,
109118
pageBackgroundScheduler,
110119
pageArrivalObservations) =>
111120
_pageFetcher = pageFetcher;
112121

113-
protected override async Task OnPageFetch(CancellationToken ct)
122+
protected override async Task FetchPageInner(CancellationToken ct)
114123
{
115124
var previousPage = Page;
116125
await Task.Delay(1, ct).ConfigureAwait(false);
@@ -137,6 +146,7 @@ internal AsyncTaskBasedPage(
137146
// dependencies
138147
Func<int, int, CancellationToken, Task<T[]>> pageFetcher,
139148
Func<int, int, T> placeholderFactory,
149+
IAsyncPageFetchScheduler asyncPageFetchScheduler,
140150
IScheduler pageBackgroundScheduler,
141151
IObserver<(int Offset, int PageSize, T[] PreviousPage, T[] Page)> pageArrivalObservations)
142152
: base(
@@ -145,11 +155,12 @@ internal AsyncTaskBasedPage(
145155
pageSize,
146156
onDisposalAfterFetchCompleted,
147157
placeholderFactory,
158+
asyncPageFetchScheduler,
148159
pageBackgroundScheduler,
149160
pageArrivalObservations) =>
150161
_pageFetcher = pageFetcher;
151162

152-
protected override async Task OnPageFetch(CancellationToken ct)
163+
protected override async Task FetchPageInner(CancellationToken ct)
153164
{
154165
var previousPage = Page;
155166
await Task.Delay(1, ct).ConfigureAwait(false);
@@ -176,6 +187,7 @@ internal AsyncEnumerableBasedPage(
176187
// dependencies
177188
Func<int, int, CancellationToken, IAsyncEnumerable<T>> pageFetcher,
178189
Func<int, int, T> placeholderFactory,
190+
IAsyncPageFetchScheduler asyncPageFetchScheduler,
179191
IScheduler pageBackgroundScheduler,
180192
IObserver<(int Offset, int PageSize, T[] PreviousPage, T[] Page)> pageArrivalObservations)
181193
: base(
@@ -184,12 +196,14 @@ internal AsyncEnumerableBasedPage(
184196
pageSize,
185197
onDisposalAfterFetchCompleted,
186198
placeholderFactory,
199+
asyncPageFetchScheduler,
187200
pageBackgroundScheduler,
188201
pageArrivalObservations) =>
189202
_pageFetcher = pageFetcher;
190203

191-
protected override async Task OnPageFetch(CancellationToken ct)
204+
protected override async Task FetchPageInner(CancellationToken ct)
192205
{
206+
await Task.Delay(1, ct).ConfigureAwait(false);
193207
var i = 0;
194208
await foreach (var item in _pageFetcher(Offset, PageSize, ct))
195209
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System.Threading;
2+
using System.Threading.Tasks;
3+
4+
namespace BFF.DataVirtualizingCollection.PageStorage
5+
{
6+
internal interface IAsyncPageFetchScheduler
7+
{
8+
Task Schedule(CancellationToken ct);
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System.Threading;
2+
using System.Threading.Tasks;
3+
4+
namespace BFF.DataVirtualizingCollection.PageStorage
5+
{
6+
internal class ImmediateAsyncPageFetchScheduler : IAsyncPageFetchScheduler
7+
{
8+
public Task Schedule(CancellationToken ct) => Task.CompletedTask;
9+
}
10+
}

Tests.Unit/PageStorage/AsyncPageBaseTests.cs

+8
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ public class AsyncNonTaskBasedPageTests : AsyncPageBaseTestsBase
9292
return new[] { 69 };
9393
},
9494
(_, __) => 23,
95+
new ImmediateAsyncPageFetchScheduler(),
9596
DefaultScheduler.Instance,
9697
Observer.Create<(int Offset, int PageSize, int[] PreviousPage, int[] Page)>(_ => { }));
9798

@@ -107,6 +108,7 @@ public class AsyncNonTaskBasedPageTests : AsyncPageBaseTestsBase
107108
return new[] {69};
108109
},
109110
(_, __) => 23,
111+
new ImmediateAsyncPageFetchScheduler(),
110112
DefaultScheduler.Instance,
111113
Observer.Create<(int Offset, int PageSize, int[] PreviousPage, int[] Page)>(_ => { }));
112114

@@ -124,6 +126,7 @@ internal override AsyncPageBase<IDisposable> PageWithDisposable(IDisposable disp
124126
return new[] { disposable };
125127
},
126128
(_, __) => Disposable.Empty,
129+
new ImmediateAsyncPageFetchScheduler(),
127130
DefaultScheduler.Instance,
128131
Observer.Create<(int Offset, int PageSize, IDisposable[] PreviousPage, IDisposable[] Page)>(_ => { }));
129132
}
@@ -142,6 +145,7 @@ internal override AsyncPageBase<IDisposable> PageWithDisposablePlaceholder(IDisp
142145
return new []{ Disposable.Empty };
143146
},
144147
(_, __) => disposable,
148+
new ImmediateAsyncPageFetchScheduler(),
145149
DefaultScheduler.Instance,
146150
Observer.Create<(int Offset, int PageSize, IDisposable[] PreviousPage, IDisposable[] Page)>(_ => { }));
147151
}
@@ -162,6 +166,7 @@ public class AsyncTaskBasedPageTests : AsyncPageBaseTestsBase
162166
return new[] { 69 };
163167
},
164168
(_, __) => 23,
169+
new ImmediateAsyncPageFetchScheduler(),
165170
DefaultScheduler.Instance,
166171
Observer.Create<(int Offset, int PageSize, int[] PreviousPage, int[] Page)>(_ => { }));
167172

@@ -177,6 +182,7 @@ public class AsyncTaskBasedPageTests : AsyncPageBaseTestsBase
177182
return new[] {69};
178183
},
179184
(_, __) => 23,
185+
new ImmediateAsyncPageFetchScheduler(),
180186
DefaultScheduler.Instance,
181187
Observer.Create<(int Offset, int PageSize, int[] PreviousPage, int[] Page)>(_ => { }));
182188

@@ -194,6 +200,7 @@ internal override AsyncPageBase<IDisposable> PageWithDisposable(IDisposable disp
194200
return new[] { disposable };
195201
},
196202
(_, __) => Disposable.Empty,
203+
new ImmediateAsyncPageFetchScheduler(),
197204
DefaultScheduler.Instance,
198205
Observer.Create<(int Offset, int PageSize, IDisposable[] PreviousPage, IDisposable[] Page)>(_ => { }));
199206
}
@@ -212,6 +219,7 @@ internal override AsyncPageBase<IDisposable> PageWithDisposablePlaceholder(IDisp
212219
return new[] { Disposable.Empty };
213220
},
214221
(_, __) => disposable,
222+
new ImmediateAsyncPageFetchScheduler(),
215223
DefaultScheduler.Instance,
216224
Observer.Create<(int Offset, int PageSize, IDisposable[] PreviousPage, IDisposable[] Page)>(_ => { }));
217225
}

0 commit comments

Comments
 (0)