@@ -282,6 +282,12 @@ def __init__(self, my_fields: dict, strata_comm: MPI.Comm, field_order=None):
282282 # Gather layouts across ranks
283283 self .strata_buffer_layouts = strata_comm .allgather (self .buffer_layout )
284284
285+ # Keep one passive-target access epoch open for the lifetime of the
286+ # window. Individual operations complete at their target with Flush;
287+ # they do not repeatedly acquire and release target locks.
288+ self .window .Lock_all ()
289+ self ._epoch_open = True
290+
285291 def free (self ):
286292 if self .window is not None :
287293 guard_error = None
@@ -290,6 +296,9 @@ def free(self):
290296 self ._verify_window_guards (field , "free" , "before" )
291297 except RuntimeError as error :
292298 guard_error = error
299+ if self ._epoch_open :
300+ self .window .Unlock_all ()
301+ self ._epoch_open = False
293302 self .window .Free ()
294303 self .buff = None
295304 self .buffer_layout = None
@@ -465,18 +474,16 @@ def get(self, dest: nptyping.ArrayLike, strata_rank: int, field: Field,
465474 target_rank = strata_rank ,
466475 )
467476 window = self .window
468- # The shared epoch may overlap other readers, but it cannot overlap
469- # the publisher's exclusive self-target epoch below. Unlock provides
470- # completion for the Get before its destination and guards are read.
471- window .Lock (strata_rank , MPI .LOCK_SHARED )
472477 window .Get (
473478 (transfer , field_layout .transfer_nbytes , MPI .BYTE ),
474479 strata_rank ,
475480 (field_layout .transfer_offset_bytes ,
476481 field_layout .transfer_nbytes ,
477482 MPI .BYTE ),
478483 )
479- window .Unlock (strata_rank )
484+ # Flush provides local completion, so the destination and its
485+ # transmitted guards are safe to inspect below.
486+ window .Flush (strata_rank )
480487 self ._verify_transfer_guards (
481488 storage , field_layout , field , "get" , "after" ,
482489 target_rank = strata_rank ,
@@ -502,19 +509,18 @@ def put(self, values: nptyping.ArrayLike, field: Field):
502509 )
503510 self ._verify_window_guards (field , "put" , "before" )
504511 window = self .window
505- # Publishing through a self-target Put is intentional: unlike an
506- # ordinary local store, this exclusive epoch participates in the same
507- # MPI lock arbitration as remote readers and makes the field snapshot
508- # indivisible with respect to their shared epochs.
509- window .Lock (self .strata_rank , MPI .LOCK_EXCLUSIVE )
512+ # Publishing through a self-target Put is intentional: it keeps local
513+ # and remote publication on the same MPI-visible path. Phase 3 will
514+ # add the metadata protocol that lets readers reject an overlapping
515+ # publication; Phase 2 only changes epoch management.
510516 window .Put (
511517 (transfer , field_layout .transfer_nbytes , MPI .BYTE ),
512518 self .strata_rank ,
513519 (field_layout .transfer_offset_bytes ,
514520 field_layout .transfer_nbytes ,
515521 MPI .BYTE ),
516522 )
517- window .Unlock (self .strata_rank )
523+ window .Flush (self .strata_rank )
518524 self ._verify_transfer_guards (
519525 storage , field_layout , field , "put" , "after" ,
520526 target_rank = self .strata_rank ,
0 commit comments