Skip to content

Commit 2eae5fb

Browse files
committed
* Index-Deletion now handled via Async/Task instead of its own thread (threads not supported on blazor-wasm)
1 parent a4807a2 commit 2eae5fb

2 files changed

Lines changed: 63 additions & 14 deletions

File tree

RELEASE_NOTES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
### 1.2.8
2+
* Index-Deletion now handled via Async/Task instead of its own thread (threads not supported on blazor-wasm)
3+
14
### 1.2.7
25
* several AList bugfixes
36
* added AList slicing utilities

src/FSharp.Data.Adaptive/Datastructures/Index.fs

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,57 @@ type IndexNode =
153153
end
154154

155155
#if !FABLE_COMPILER
156+
157+
type internal AsyncBlockingCollection<'a>() =
158+
let store = System.Collections.Generic.Queue<'a>()
159+
160+
let mutable next : option<Tasks.TaskCompletionSource<unit>> = None //Tasks.TaskCompletionSource<unit>()
161+
162+
member x.Add(value : 'a) =
163+
lock store (fun () ->
164+
store.Enqueue value
165+
match next with
166+
| Some n ->
167+
n.SetResult()
168+
next <- None
169+
| None ->
170+
()
171+
)
172+
173+
member x.Take() =
174+
Async.FromContinuations (fun (success, error, cancel) ->
175+
Monitor.Enter store
176+
try
177+
if store.Count > 0 then
178+
let value = store.Dequeue()
179+
Monitor.Exit store
180+
success value
181+
else
182+
let tcs =
183+
match next with
184+
| Some n -> n
185+
| None ->
186+
let n = Tasks.TaskCompletionSource<unit>()
187+
next <- Some n
188+
n
189+
Monitor.Exit store
190+
tcs.Task.ContinueWith (fun (_t : Tasks.Task<unit>) ->
191+
Async.StartWithContinuations(x.Take(), success, error, cancel)
192+
) |> ignore
193+
with
194+
| :? OperationCanceledException as e ->
195+
Monitor.Exit store
196+
cancel e
197+
| e ->
198+
Monitor.Exit store
199+
error e
200+
)
201+
202+
member x.Clear() =
203+
lock store (fun () ->
204+
store.Clear()
205+
)
206+
156207
/// datastructure representing an abstract index.
157208
/// supported operations are: Index.zero, Index.after(index), Index.before(index), Index.between(l, r).
158209
/// this is a 'simple' solution to the order-maintenance problem that has insert in O(log N), delete in O(1) and compare in O(1).
@@ -161,21 +212,16 @@ type IndexNode =
161212
type Index private(real : IndexNode) =
162213
do real.AddRef()
163214

164-
/// we create a thread for deleting the underlying values when Index goes out of scope.
165-
/// this way we avoid blocking the finalizer for Index.
166-
static let startThread (run : unit -> unit) =
167-
let start = System.Threading.ThreadStart(run)
168-
let thread = System.Threading.Thread(start, IsBackground = true, Name = "Index cleanup thread")
169-
thread.Start()
170-
thread
171-
172-
static let queue = new System.Collections.Concurrent.BlockingCollection<IndexNode>()
173-
static let runner =
174-
startThread (fun () ->
215+
216+
static let queue = new AsyncBlockingCollection<IndexNode>()
217+
218+
static do
219+
async {
175220
while true do
176-
try queue.Take().Delete()
177-
with e -> printfn "Index cleanup thread failed with: %A" e
178-
)
221+
let! v = queue.Take()
222+
do! Async.SwitchToThreadPool()
223+
v.Delete()
224+
} |> Async.Start
179225

180226
member private x.Value = real
181227

0 commit comments

Comments
 (0)