package logstorage import ( "encoding/json" "errors" "os" "path/filepath" "tera-clone/services/tera-api/internal/storage/atomicfile" ) type linkClearState struct { Version int `json:"version"` Revision uint64 `json:"revision"` NextSequence uint64 `json:"next_sequence"` } func (s *Store) linkClearPath() string { return filepath.Join(s.root, "port", "cleared-link-v1.json") } func (s *Store) loadLinkClearLocked() error { info, err := os.Lstat(s.linkClearPath()) if os.IsNotExist(err) { return nil } if err != nil { return err } if !info.Mode().IsRegular() || info.Size() > 1024 { return errors.New("invalid link log deletion checkpoint") } data, err := os.ReadFile(s.linkClearPath()) if err != nil { return err } var state linkClearState if err := json.Unmarshal(data, &state); err != nil { return err } if state.Version != 1 || state.NextSequence == 0 || state.Revision == 0 { return errors.New("invalid link log deletion checkpoint") } s.linkClear = state return nil } func (s *Store) linkRecordCleared(event Envelope) bool { return event.Class == ClassLink && event.Sequence < s.linkClear.NextSequence } func (s *Store) LinkClearRevision() uint64 { s.mu.Lock() defer s.mu.Unlock() return s.linkClear.Revision } // ClearLink clears stored link-state events without altering live link state. func (s *Store) ClearLink() (int, error) { s.mu.Lock() defer s.mu.Unlock() deleted := 0 if err := s.walkClassLocked(ClassLink, false, func(Envelope) error { deleted++; return nil }); err != nil { return 0, err } next := linkClearState{Version: 1, Revision: s.linkClear.Revision + 1, NextSequence: s.classes[ClassLink].NextSequence} data, err := json.Marshal(next) if err != nil { return 0, err } if err := atomicfile.Write(s.linkClearPath(), append(data, '\n'), 0o600); err != nil { _ = s.loadLinkClearLocked() return 0, err } s.linkClear = next return deleted, s.compactClearedClassLocked(ClassLink, s.linkRecordCleared) }