You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
77 lines
2.0 KiB
77 lines
2.0 KiB
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)
|
|
}
|
|
|