Merge pull request #2 from rarf/windows-native-support

fix: native Windows support (msvcrt lock instead of fcntl)
This commit is contained in:
Victor Taelin 2026-07-27 18:51:42 -03:00 committed by GitHub
commit e36da55815
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 55 additions and 3 deletions

22
WINDOWS.md Normal file
View file

@ -0,0 +1,22 @@
# Windows support
OptMem now runs on native Windows (no WSL required).
## What changed
- `import fcntl` is guarded — falls back to `None` on platforms without it.
- `locked()` uses `msvcrt` advisory locking with spin/backoff when `fcntl`
is unavailable, so parallel sessions (the documented multi-process case)
queue instead of raising `Resource deadlock avoided`.
- The `.lock` file is opened in append mode (`"a"`) rather than `"w"`, which
would truncate and break locks held by other processes on Windows.
## Test (Windows native, no WSL)
```bat
python memo init
set MEMORY_DIR=C:\path\to\mem
python memo note "first memory"
python memo note "second memory"
python memo wake
```
Concurrency: 8 parallel `memo note` processes writing 1600 memories
resulted in 1600/1600 records persisted (lock verified).

34
memo
View file

@ -16,7 +16,10 @@ See github.com/VictorTaelin/OptMem.
""" """
import datetime import datetime
import fcntl try:
import fcntl
except ImportError:
fcntl = None # Windows has no fcntl; we fall back to msvcrt below
import os import os
import re import re
import sys import sys
@ -297,8 +300,35 @@ def pad(text, rec):
def locked(d): def locked(d):
lock = open(os.path.join(d, ".lock"), "w") # Open in append mode ("a"), NOT "w": reopening with "w" truncates the
# lock file and breaks advisory locks held by other processes on Windows.
lock = open(os.path.join(d, ".lock"), "a")
if fcntl is not None:
fcntl.flock(lock, fcntl.LOCK_EX) fcntl.flock(lock, fcntl.LOCK_EX)
else:
# Windows: no fcntl. Use msvcrt advisory lock with spin/backoff so
# parallel sessions (the documented multi-process case) queue instead
# of raising "Resource deadlock avoided" under contention.
import msvcrt as _ms
import time as _t
waited = 0.0
while True:
try:
_ms.locking(lock.fileno(), _ms.LK_NBLCK, 1)
break
except OSError:
if waited > 30.0:
raise
_t.sleep(min(0.01 + waited * 0.2, 0.25))
waited += 0.01
_orig_close = lock.close
def _close():
try:
_ms.locking(lock.fileno(), _ms.LK_UNLCK, 1)
except Exception:
pass
_orig_close()
lock.close = _close
return lock return lock