+
    „WÝjâ#  ã            	      óX  a € 0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	H
t
HtHtHt ]P                  ! R4      tRt]^,           tRt^€t]P(                  R8X  d   RtRtR]R	&   ^ ;t;t;ttM‹ ^ RIt]! ]R
R^%R^Z/P;                  ]P<                  P?                  R4      4      4      t]P@                  ]PB                  ]PD                  uttt]PF                  t]$! ]! ]RR4      4      '       g	   ]%! R4      h ]P<                  R8X  g   R]P<                  9   d   RMRt'](])])3,          t*]+]*](])])3,          3,          t,]PZ                  ! 4       t./ t/R]R&   R R lt0R R lt1RR/R R llt2R R lt3R R lt4R  R! lt5R&R" R# llt6R$ R% lt7R#   ]%]&3 d    RtRt^ ;t;t;tt L¬i ; i)'u]  Hold a state.db writer's WAL-mode file locks in a form a stray ``close()`` cannot cancel.

SQLite protects a live WAL generation with two POSIX advisory locks: a SHARED lock on the main
file's lock range and a shared lock on the DMS byte of ``state.db-shm``. A sibling process may
checkpoint and unlink ``-wal``/``-shm`` at its close only after taking both EXCLUSIVE. POSIX locks
are per process, so any ``open()``/``close()`` of those two files inside the holder â€” a raw probe,
a plugin, a tool reading ``~/.hermes`` â€” cancels both (sqlite.org/howtocorrupt.html Â§2.2) and the
next foreign close strands the holder on a deleted generation (``DeletedWalGenerationError``).

This module adds the same two ranges as *open file description* locks (``F_OFD_SETLK``) on the
descriptors SQLite itself holds. OFD locks belong to the description, not the process: a stray
``close()`` elsewhere cannot cancel them, they die with the connection's own descriptor (nothing
extra to track or retire), and they conflict with a foreign EXCLUSIVE exactly like SQLite's own,
so the sibling's close-time unlink is refused while a guarded handle is open. The guard is
lifted before the handle's own close so a true last close still ends the generation normally;
lifting it first re-takes SQLite's own POSIX locks on the same ranges, so the handle is never
unlocked while its connection is still open. No-op on Windows and on runtimes without OFD locks.

Ownership model: the guard is a property of the *descriptor*, and a descriptor number is
reusable. Each ``hold()`` therefore locks every matching descriptor unconditionally (an OFD
re-lock on an already-locked description is idempotent) and ``release()`` unlocks only while
another handle in this process still needs the range â€” tracked by handle count per INODE, not
per fd, so a recycled fd number can never be mistaken for a surviving lock.
)ÚannotationsN)ÚDictÚOptionalÚSetÚTupleÚhermes_statei   @iþ  ÚntúOptional[int]Ú_F_OFD_SETLKÚF_OFD_SETLKÚlinuxÚdarwinÚ
0123456789Úfcntlz$fcntl module has no fcntl() callableÚbsdú@qqihhz@hhqqizdict[Identity, int]Ú_HANDLESc               ó   € V ^8„  d   QhRR/# )é   ÚreturnÚbool© )Úformats   "ÚJC:\Users\johnn\AppData\Local\hermes\hermes-agent\hermes_state_lockguard.pyÚ__annotate__r   U   s   € ÷ $ñ $�4ñ $ó    c                 ó   € \         R J# ©N)r
   r   r   r   Ú	supportedr   U   s   € Ü˜tÐ#Ð#r   c               ó(   € V ^8„  d   QhRRRRRRRR/# )r   Ú	lock_typeÚintÚstartÚlengthr   Úbytesr   )r   s   "r   r   r   Y   s.   € ÷ Nñ N�cð N #ð N¨sð N°uñ Nr   c                ó    € \         R 8X  d#   \        P                  ! \         W^ V \        4      # \        P                  ! \         V \        W^ 4      # )r   )Ú_FLOCK_FORMATÚstructÚpackÚ	_SEEK_SET)r    r"   r#   s   &&&r   Ú_flockr*   Y   s8   € Ü˜Ô Ü�{Š{œ=¨%¸¸IÄyÓQÐQÜ�;Š;”} i´¸EÈ1ÓMÐMr   Úcmdc               ó0   € V ^8„  d   QhRRRRRRRRRRRR	/# )
r   Úfdr!   r    r"   r#   r+   r	   r   r   r   )r   s   "r   r   r   _   s7   € ÷ ñ �#ð  #ð ¨cð ¸3ð Èð Ðaeñ r   c          	     ó¦   € \         e	   \        f   Q h \         P                   ! Yf   \        MT\        WV4      4       R#   \         d     R# i ; i)z‚Apply a non-blocking OFD lock (a process-owned POSIX one with ``cmd=_F_SETLK``); False when
the range is held EXCLUSIVE elsewhere.FT)r   r
   r*   ÚBlockingIOError)r-   r    r"   r#   r+   s   &&&&$r   Ú	_ofd_lockr0   _   sO   € ô Ò¤Ò!9Ð9Ð9ðÜ�Š�Bª�¸¼fÀYÐW]Ó>^Ô_ñ øô ô Úðús   ”+A ÁAÁAc               ó    € V ^8„  d   QhRRRR/# )r   ÚpathÚstrr   zOptional[Identity]r   )r   s   "r   r   r   j   s   € ÷ "ñ "�Cð "Ð.ñ "r   c                ó„   €  \         P                  ! V 4      pTP                  TP                  3#   \         d     R # i ; ir   )ÚosÚstatÚOSErrorÚst_devÚst_ino)r2   Ústs   & r   Ú	_identityr;   j   s=   € ðÜ�WŠW�T‹]ˆð �I‰I�r—y‘yÐ!Ð!øô ô Úðús   ‚0 °?¾?c               ó   € V ^8„  d   QhRR/# )r   Ú
identitieszset[Identity]r   )r   s   "r   r   r   r   s   € ÷ ñ ˜]ñ r   c              #  óh  "  € R Fƒ  p \         P                  ! V4      pT Fb  pTP                  4       '       g   K  \	        T4      p \         P
                  ! T4      pTP                  TP                  3pY`9   g   K]  YF3x € Kd  	   R# 	  R#   \         d     K—  i ; i  \         d     K�  i ; i5i)z¥Yield ``(fd, identity)`` for every descriptor of this process on one of *identities*
(SQLite's own connection descriptors; the cached header-probe fd too, harmless).N)z/proc/self/fdz/dev/fd)r5   Úlistdirr7   Úisdigitr!   Úfstatr8   r9   )r=   Úfd_dirÚnamesÚnamer-   r:   Úidents   &      r   Ú_own_fds_forrF   r   s¥   é € ó /ˆð	Ü—J’J˜vÓ&ˆEó ˆDØ—<‘<—>’>ÙÜ�T“ˆBðÜ—X’X˜b“\�ð —Y‘Y §	¡	Ð*ˆEØÖ"Ø�i”ñ ò 	ó! /øô ô 	Úð	ûô ô ÚðüsQ   ‚B2‰BŸ(B2ÁB ÁB2Á>B2ÂBÂB2ÂBÂB2Â B/Â+B2Â.B/Â/B2c               ó   € V ^8„  d   QhRR/# )r   r   ÚHeldr   )r   s   "r   r   r   ˆ   s   € ÷ ñ ˜dñ r   c                ó°   € \         P                  ! V 4      p/ pV\        \        33VR ,           \        ^333 F  w  r4\        V4      pVf   K  WBV&   K  	  V# )z-shm)r5   ÚfspathÚ_SHARED_FIRSTÚ_SHARED_SIZEÚ_SHM_DMS_BYTEr;   )Údb_pathÚbaseÚrangesr2   ÚrngrE   s   &     r   Ú_guard_rangesrR   ˆ   s]   € Ü�9Š9�WÓ€DØ€FØœm¬\Ð:Ð;¸dÀV½mÌmÐ]^ÐM_Ð=`Óa‰	ˆÜ˜$“ˆØÔØ�5‹Mñ bð €Mr   c               ó    € V ^8„  d   QhRRRR/# )r   ÚheldzOptional[Held]r   rH   r   )r   s   "r   r   r   ’   s   € ÷ ñ ˜ð °$ñ r   c           	     ó  € Vf   / MTp\        4       '       g   V# \        V 4      p \        ;_uu_ 4        \        \	        V4      4       F^  w  r4W$,          w  rV\        V\        WV4      '       g   K(  WA9  g   K0  W$,          W&   \        P                  V^ 4      ^,           \        V&   K`  	  RRR4       V#   + '       g   i     T# ; i  \         d1    \        P                  R\        P                  ! T 4      RR7        T# i ; i)ah  Lock the guard ranges on every descriptor this process has open on ``state.db`` and its
``-shm``. Returns the record :func:`release` needs; pass it back to extend an existing one
(a ``-shm`` minted after open, a reopened connection). Idempotent per handle: an inode already
in *held* is re-locked (cheap, covers a new descriptor) without a second handle count.Nz!WAL lock guard unavailable for %sT)Úexc_info)r   rR   Ú_LOCKrF   Úsetr0   Ú_F_RDLCKr   Úgetr7   ÚloggerÚdebugr5   rJ   )rN   rT   rP   r-   rE   r"   r#   s   &&     r   Úholdr]   ’   sÓ   € ð
 ’‰2 4€DÜ�;Š;ØˆÜ˜7Ó#€Fð]ßŽUÜ)¬#¨f«+Ö6‘	�Ø &¥‘�Ü˜R¤¨5×9Ô9¸eÖ>OØ"(¥-�D‘KÜ&.§l¡l°5¸!Ó&<¸qÕ&@”H˜U“Oñ	 7÷ ð €K÷ ŽUð €Kûô ô ]Ü�‰Ð8¼"¿)º)ÀGÓ:LÐW[ˆÕ\Ø€Kð]ús:   §C
 µ8B6Á2B6Á:2B6Â,C
 Â6C	ÃC
 ÃC
 Ã
7DÄDc               ó    € V ^8„  d   QhRRRR/# )r   rT   rH   r   ÚNoner   )r   s   "r   r   r   §   s   € ÷ ñ �$ð ˜4ñ r   c                ó`  € \        4       '       d	   V '       g   R# \        ;_uu_ 4        / pV P                  4        FN  w  r#\        P	                  V^4      ^,
          pV^ 8”  d   V\        V&   K4  \        P                  VR4       W1V&   KP  	  V P                  4        V'       g    RRR4       R#  \        \        V4      4       F7  w  rRW,          w  rg\        V\        Wg\        R7       \        V\        Wg4       K9  	  RRR4       R#   \         d     Li ; i  + '       g   i     R# ; i)aâ  Drop this handle's claim. The last handle on an inode unlocks the range on every descriptor
still referencing it. Call BEFORE the handle's own close so SQLite's close-time reset sees only
real holders: a sibling process's intact locks still refuse the unlink, and a true last close
ends the generation, so a later ``state.db`` replace never pairs with a stale WAL.

The OFD copy is swapped back for the POSIX lock SQLite believes it still holds (a stray close
cancelled the real one): unlocked outright, the still-open connection would let a sibling's
close take EXCLUSIVE and unlink ``-wal``/``-shm`` under it before its own close runs. SQLite's
close upgrades or drops that process-owned lock itself, so a true last close is unaffected.N)r+   )r   rW   Úitemsr   rZ   ÚpopÚclearrF   rX   r0   rY   Ú_F_SETLKÚ_F_UNLCKr7   )rT   Ú	to_unlockrE   rQ   Ú	remainingr-   r"   r#   s   &       r   Úreleaserh   §   sâ   € ô �;Š;ŸdÙß	ŽØˆ	ØŸ*™*ž,‰JˆEÜ Ÿ™ U¨AÓ.°Õ2ˆIØ˜1Œ}Ø"+”˜“ä—‘˜U DÔ)Ø#&˜%Ó ñ 'ð 	�
‰
ŒßØ÷ 
‰ð	Ü)¬#¨i«.Ö9‘	�Ø )Õ 0‘�Ü˜"œh¨¼8ÕDÜ˜"œh¨Ö6ñ :÷ 
‰øô" ô 	Ùð	ú÷# 
�ˆús1   ©A<DÂ&DÂ2ADÄDÄDÄDÄDÄD-	r   )8Ú__conditional_annotations__Ú__doc__Ú
__future__r   Úloggingr5   r'   ÚsysÚ	threadingÚtypingr   r   r   r   Ú	getLoggerr[   Ú_PENDING_BYTErK   rL   rM   rD   r   r
   Ú__annotations__rY   re   r)   rd   ÚgetattrrZ   ÚplatformÚrstripÚF_RDLCKÚF_UNLCKÚSEEK_SETÚF_SETLKÚcallableÚImportErrorÚAttributeErrorr&   Útupler!   ÚIdentityÚdictrH   ÚLockrW   r   r   r*   r0   r;   rF   rR   r]   rh   )ri   s   @r   Ú<module>r�      sÏ  øðôõ2 #ã Û 	Û Û 
Û ß -Ó -à	×	Ò	˜>Ó	*€ð €Ø Õ!€Ø€Ø€ð ‡7�7ˆd„?Ø€EØ"&€L�-Ó&Ø12Ð2€HÐ2ˆxÐ2˜)¡hð7Ûñ Ø�= 7¨B°¸"Ð"=×"AÑ"AÀ#Ç,Á,×BUÑBUÐVbÓBcÓ"dófˆà(-¯©°u·}±}ÀbÇkÁkÐ%ˆ�(˜IØ—=‘=ˆñ ™  w°Ó5×6Ò6ÙÐDÓEÐEð 7ð  ŸL™L¨HÔ4¸ÀÇÁÔ8M‘ÐS[€à��c��?€ØˆH�e˜C ˜H•oÐ%Õ&€ð 	�ŠÓ€Ø "€Ð
Ó "õ$õNðÐX\÷ õ"õõ,÷÷*øðG ˜Ð(ô 7ØˆØˆØ56Ð6ˆÐ6�8Ð6˜iª(ð7ús   Á2B	F ÆF)Æ(F)