Merge pull request #2 from rarf/windows-native-support
fix: native Windows support (msvcrt lock instead of fcntl)
This commit is contained in:
commit
e36da55815
2 changed files with 55 additions and 3 deletions
22
WINDOWS.md
Normal file
22
WINDOWS.md
Normal 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
34
memo
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue