Socket Daemon
Last updated
The core/daemon package gives every process that opens the same data directory one shared unix socket, and this page explains how daemon.New decides whether a process becomes the server or a client.
Requirements It Satisfies
| # | Requirement | How |
|---|---|---|
| 1 | One shared socket per ToriiDB location | One Store is opened by the first process; everyone else talks to it over the socket |
| 2 | Different locations get different sockets | The socket name is a hash of the resolved absolute directory |
| 3 | Repeated New on one location shares the socket |
New dials first; a live socket means client mode |
| 4 | Callers never check their role | Get/Set/Del/... behave the same in both modes |
Transport is a unix socket with a custom length-prefixed JSON frame. There is no HTTP.
Mode Resolution
daemon.New(dir, apiKey...) runs:
- Reject an empty
dir. resolveDir:CheckDir(dir, true)→filepath.Abs→filepath.EvalSymlinks.resolveSocket:/tmp/toriidb-<uid>-<hex(sha256(realDir)[:8])>.sock.probeSocket:net.DialTimeout("unix", path, 500ms).
| Probe result | Mode | What New does |
|---|---|---|
| Dial succeeds | ModeClient |
Creates a pooled client; no store is opened |
ECONNREFUSED or ENOENT |
ModeServer |
Opens store.New(realDir, apiKey...) |
| Any other dial error | error | Returns probe socket <path>: ... |
| Design rule | Reason |
|---|---|
Socket directory is hard-coded /tmp |
os.TempDir() reads $TMPDIR, which would make the socket depend on environment instead of location |
Paths go through EvalSymlinks |
On macOS /tmp is a symlink to /private/tmp; relx, ./relx, /tmp/relx/, /private/tmp/relx, and symlinks must converge |
Liveness is decided by dialing, never by os.Stat |
kill -9 leaves the socket file behind; a stale file must not block a new server |
uid is part of the file name |
/tmp is shared between users |
New takes dir, not *store.Store |
Probing must happen before a store is opened; a client must not open a second store on the same directory |