@@ -463,9 +463,13 @@ function poolset(@nospecialize(x), pid=myid(); size=approx_size(x),
463463
464464 id = atomic_add! (id_counter, 1 )
465465 sstate = if ! restore
466+ # Data is already in memory, so this state is born ready: share the
467+ # set `ALWAYS_READY` Event and the empty `NO_LEAVES` vector instead
468+ # of allocating fresh ones.
466469 StorageState (Some {Any} (x),
467- Vector {StorageLeaf} (),
468- device)
470+ NO_LEAVES,
471+ device,
472+ ALWAYS_READY)
469473 else
470474 @assert ! isa (leaf_device, CPURAMDevice) " Cannot use `CPURAMDevice()` as leaf device when `restore=true`"
471475 StorageState (nothing ,
562566
563567function _getlocal (f, id, remote, args... ; local_only:: Bool , from:: Int )
564568 state = with_lock (()-> datastore[id], datastore_lock)
565- lock_read (state. lock ) do
569+ lock_read (getlock! ( state) ) do
566570 if state. redirect != = nothing
567571 return RedirectTo (state. redirect)
568572 end
@@ -574,6 +578,13 @@ function _getlocal(f, id, remote, args...; local_only::Bool, from::Int)
574578 end
575579end
576580
581+ " Deferred device-deletion work item drained by the shared `SEND_QUEUE` task."
582+ function _delete_device_work (state:: RefState , id:: Int )
583+ device = storage_read (state). root
584+ device != = nothing && delete_from_device! (device, state, id)
585+ return
586+ end
587+
577588function datastore_delete (id)
578589 @safe_lock_spin datastore_counters_lock begin
579590 DEBUG_REFCOUNTING[] && _enqueue_work (Core. print, " -- (" , myid (), " , " , id, " ) with " , string (datastore_counters[(myid (), id)]), " \n " ; gc_context= true )
@@ -585,12 +596,13 @@ function datastore_delete(id)
585596 haskey (datastore, id) ? datastore[id] : nothing
586597 end
587598 (state === nothing ) && return
588- errormonitor (Threads. @spawn begin
589- device = storage_read (state). root
590- if device != = nothing
591- delete_from_device! (device, state, id)
592- end
593- end )
599+ # Defer device deletion onto the shared serial work queue rather than
600+ # spawning a fresh task per teardown. datastore_delete frequently runs from
601+ # a GC/finalizer context where task switches are illegal, so the device read
602+ # and `delete_from_device!` (which may wait on an in-flight storage
603+ # transition) must not run inline here. `_enqueue_work` is finalizer-safe and
604+ # reuses one long-lived task, avoiding a Task allocation per ref teardown.
605+ _enqueue_work (_delete_device_work, state, id; gc_context= true )
594606 @safe_lock_spin datastore_lock begin
595607 haskey (datastore, id) && delete! (datastore, id)
596608 end
@@ -621,7 +633,7 @@ function migrate!(ref::DRef, to::Integer; pre_migration=nothing, dest_post_migra
621633 # Lock the ref against further accesses
622634 # FIXME : Below is racey w.r.t data mutation
623635 local new_ref
624- @lock state. lock begin
636+ @lock getlock! ( state) begin
625637 # Read the current value of the ref
626638 data = read_from_device (state, ref, true )
627639
0 commit comments