Skip to content

Commit 70bd4cf

Browse files
fix: make macOS CI pass for compact search and reranker tracing
Checkpoint libSQL WAL before Close so immutable search can see documents. Lock the Darwin exec-trace thread and detach with addr=1 to avoid SIGTRAP. Amp-Thread-ID: https://ampcode.com/threads/T-01a07399-82c4-76c8-b33d-34b2c89b219b Co-authored-by: Amp <amp@ampcode.com>
1 parent 5f57438 commit 70bd4cf

6 files changed

Lines changed: 87 additions & 10 deletions

File tree

‎pkg/index/index.go‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,9 @@ func (idx *Indexer) Index(ctx context.Context) error {
738738
if debugLevel >= util.DebugSummary {
739739
stats.PrintSummary()
740740
}
741+
if err := idx.Checkpoint(ctx); err != nil {
742+
return fmt.Errorf("checkpoint index: %w", err)
743+
}
741744
if err := writeRepoMetadata(idx.repoDir, idx.rootPath); err != nil {
742745
return fmt.Errorf("finalize index metadata: %w", err)
743746
}

‎pkg/rerank/supervisor.go‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,9 @@ func runConstrainedReranker(args []string) error {
288288
if len(args) < 3 || args[1] != "--" {
289289
return fmt.Errorf("invalid constrained reranker command")
290290
}
291+
// Darwin PT_TRACE_ME is thread-local. Stay on this OS thread through
292+
// syscall.Exec so the traced exec stop is delivered to the supervisor.
293+
runtime.LockOSThread()
291294
identity := os.NewFile(3, "reranker-identity")
292295
if identity == nil {
293296
return fmt.Errorf("reranker identity descriptor is unavailable")
@@ -947,10 +950,9 @@ func runRerankerSupervisor(cfg supervisorConfig) error {
947950
if err := armRunnerExec(identities.supervisor); err != nil {
948951
return abortBeforeHandle(err)
949952
}
950-
if err := authorizeRunnerExec(identities.supervisor); err != nil {
951-
return abortBeforeHandle(err)
952-
}
953-
state, releaseExec, reaped, err := waitForStoppedRerankerExec(cmd.Process.Pid, expectedDevice, expectedInode)
953+
state, releaseExec, reaped, err := waitForStoppedRerankerExec(cmd.Process.Pid, expectedDevice, expectedInode, func() error {
954+
return authorizeRunnerExec(identities.supervisor)
955+
})
954956
childReaped = reaped
955957
if err != nil {
956958
return abortBeforeHandle(err)

‎pkg/rerank/supervisor_peer_darwin.go‎

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ func enableRerankerExecTrace() error {
7070
// PT_TRACE_ME stops this process at each following exec before the new
7171
// image can execute user code. The supervisor refreshes the guardian's
7272
// audit-token handle while the configured image is stopped.
73+
// Darwin applies this to the calling thread; runConstrainedReranker
74+
// locks the OS thread before arming and keeps it through exec.
7375
//nolint:staticcheck // x/sys exposes Darwin ptrace constants but no trace-me wrapper.
7476
_, _, errno := unix.Syscall6(unix.SYS_PTRACE, unix.PT_TRACE_ME, 0, 0, 0, 0, 0)
7577
if errno != 0 {
@@ -78,8 +80,14 @@ func enableRerankerExecTrace() error {
7880
return nil
7981
}
8082

81-
func waitForStoppedRerankerExec(pid int, expectedDevice, expectedInode uint64) (rerankerPIDState, func() error, bool, error) {
83+
func waitForStoppedRerankerExec(pid int, expectedDevice, expectedInode uint64, authorize func() error) (rerankerPIDState, func() error, bool, error) {
8284
deadline := time.Now().Add(supervisorSetupTimeout)
85+
if authorize != nil {
86+
if err := authorize(); err != nil {
87+
_ = syscall.Kill(pid, syscall.SIGKILL)
88+
return rerankerPIDState{}, nil, false, err
89+
}
90+
}
8391
for {
8492
remaining := time.Until(deadline)
8593
if remaining <= 0 {
@@ -96,7 +104,7 @@ func waitForStoppedRerankerExec(pid int, expectedDevice, expectedInode uint64) (
96104
state, inspectErr := inspectRerankerProcess(pid)
97105
if inspectErr == nil && state.ExecutableDevice == expectedDevice && state.ExecutableInode == expectedInode {
98106
return state, func() error {
99-
if err := unix.PtraceDetach(pid); err != nil {
107+
if err := detachDarwinTrace(pid); err != nil {
100108
return fmt.Errorf("detach constrained reranker exec trace: %w", err)
101109
}
102110
return nil
@@ -151,8 +159,18 @@ func waitForDarwinTraceEvent(pid int, timeout time.Duration) (syscall.WaitStatus
151159
}
152160

153161
func continueDarwinTrace(pid int) error {
162+
return ptraceDarwin(unix.PT_CONTINUE, pid)
163+
}
164+
165+
func detachDarwinTrace(pid int) error {
166+
// x/sys's PtraceDetach passes addr=0. Darwin treats that like a null PC
167+
// on detach and delivers the exec-stop SIGTRAP as a fatal trace/BPT trap.
168+
return ptraceDarwin(unix.PT_DETACH, pid)
169+
}
170+
171+
func ptraceDarwin(request, pid int) error {
154172
//nolint:staticcheck // x/sys exposes attach/detach but no Darwin PT_CONTINUE wrapper.
155-
_, _, errno := unix.Syscall6(unix.SYS_PTRACE, unix.PT_CONTINUE, uintptr(pid), 1, 0, 0, 0)
173+
_, _, errno := unix.Syscall6(unix.SYS_PTRACE, uintptr(request), uintptr(pid), 1, 0, 0, 0)
156174
if errno != 0 {
157175
return errno
158176
}

‎pkg/rerank/supervisor_peer_linux.go‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,12 @@ func enableRerankerExecTrace() error {
4444
return nil
4545
}
4646

47-
func waitForStoppedRerankerExec(pid int, expectedDevice, expectedInode uint64) (rerankerPIDState, func() error, bool, error) {
47+
func waitForStoppedRerankerExec(pid int, expectedDevice, expectedInode uint64, authorize func() error) (rerankerPIDState, func() error, bool, error) {
48+
if authorize != nil {
49+
if err := authorize(); err != nil {
50+
return rerankerPIDState{}, nil, false, err
51+
}
52+
}
4853
state, err := waitForRerankerExec(pid, expectedDevice, expectedInode)
4954
return state, func() error { return nil }, false, err
5055
}

‎pkg/store/libsql.go‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,9 +1291,23 @@ func (s *LibSQLStore) ExportFileEmbeddings(ctx context.Context) ([]string, [][]f
12911291
return filePaths, vecs, nil
12921292
}
12931293

1294-
// Close closes the database.
1294+
// Close checkpoints WAL into the main DB, then closes the database.
1295+
//
1296+
// Search opens the same file with modernc sqlite and immutable=1, which does
1297+
// not read leftover WAL. Compact metadata writes must be visible after Close.
12951298
func (s *LibSQLStore) Close() error {
1296-
return s.db.Close()
1299+
var checkpointErr error
1300+
if !s.readOnly {
1301+
checkpointErr = s.Checkpoint(context.Background())
1302+
}
1303+
closeErr := s.db.Close()
1304+
if checkpointErr != nil {
1305+
if closeErr != nil {
1306+
return fmt.Errorf("%w; close: %v", checkpointErr, closeErr)
1307+
}
1308+
return checkpointErr
1309+
}
1310+
return closeErr
12971311
}
12981312

12991313
// Checkpoint flushes WAL data into the main DB and truncates sidecar growth.

‎pkg/store/libsql_test.go‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,41 @@ func TestLibSQLStore_FTSUpdateRemovesOldTerms(t *testing.T) {
699699
}
700700
}
701701

702+
func TestLibSQLStore_CloseMakesMetadataVisibleToImmutableSearch(t *testing.T) {
703+
dir := t.TempDir()
704+
dbPath := filepath.Join(dir, "index.db")
705+
s, err := OpenLibSQL(dbPath)
706+
if err != nil {
707+
t.Fatal(err)
708+
}
709+
710+
ctx := context.Background()
711+
doc := &Document{
712+
ID: "visible.go:chunk_1", FilePath: "visible.go", Content: "func visible() {}",
713+
StartLine: 1, EndLine: 1,
714+
}
715+
if err := s.StoreMetadataBatch(ctx, []*Document{doc}); err != nil {
716+
_ = s.Close()
717+
t.Fatal(err)
718+
}
719+
if err := s.Close(); err != nil {
720+
t.Fatal(err)
721+
}
722+
723+
metadata, err := OpenSQLiteMetadata(dbPath)
724+
if err != nil {
725+
t.Fatal(err)
726+
}
727+
defer func() { _ = metadata.Close() }()
728+
got, err := metadata.GetChunksByFilePath(ctx, doc.FilePath)
729+
if err != nil {
730+
t.Fatal(err)
731+
}
732+
if len(got) != 1 || got[0].ID != doc.ID || got[0].Content != doc.Content {
733+
t.Fatalf("immutable metadata after Close = %+v, want %s", got, doc.ID)
734+
}
735+
}
736+
702737
func TestLibSQLStore_GetChunksForColBERT_IncludesCompactMetadataRows(t *testing.T) {
703738
dir := t.TempDir()
704739
s, err := OpenLibSQL(filepath.Join(dir, "test.db"))

0 commit comments

Comments
 (0)