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.

83 lines
2.2 KiB

package logstorage
import (
"encoding/json"
"errors"
"os"
"path/filepath"
"tera-clone/services/tera-api/internal/storage/atomicfile"
)
type systemClearState struct {
Version int `json:"version"`
Revision uint64 `json:"revision"`
NextSequence uint64 `json:"next_sequence"`
}
func (s *Store) systemClearPath() string {
return filepath.Join(s.root, "system", "cleared-system-v1.json")
}
func (s *Store) loadSystemClearLocked() error {
info, err := os.Lstat(s.systemClearPath())
if os.IsNotExist(err) {
return nil
}
if err != nil {
return err
}
if !info.Mode().IsRegular() || info.Size() > 1024 {
return errors.New("invalid system log deletion checkpoint")
}
data, err := os.ReadFile(s.systemClearPath())
if err != nil {
return err
}
var state systemClearState
if err := json.Unmarshal(data, &state); err != nil {
return err
}
if state.Version != 1 || state.NextSequence == 0 || state.Revision == 0 {
return errors.New("invalid system log deletion checkpoint")
}
s.systemClear = state
return nil
}
func (s *Store) systemRecordCleared(event Envelope) bool {
return event.Class == ClassSystem && event.Sequence < s.systemClear.NextSequence
}
func (s *Store) recordCleared(event Envelope) bool {
return s.portRecordCleared(event) || s.systemRecordCleared(event)
}
func (s *Store) SystemClearRevision() uint64 {
s.mu.Lock()
defer s.mu.Unlock()
return s.systemClear.Revision
}
// ClearSystem never accepts a caller-supplied class or filesystem path. Audit,
// port, and link records are outside this operation, even in the same bucket.
func (s *Store) ClearSystem() (int, error) {
s.mu.Lock()
defer s.mu.Unlock()
deleted := 0
if err := s.walkClassLocked(ClassSystem, false, func(Envelope) error { deleted++; return nil }); err != nil {
return 0, err
}
next := systemClearState{Version: 1, Revision: s.systemClear.Revision + 1, NextSequence: s.classes[ClassSystem].NextSequence}
data, err := json.Marshal(next)
if err != nil {
return 0, err
}
if err := atomicfile.Write(s.systemClearPath(), append(data, '\n'), 0o600); err != nil {
_ = s.loadSystemClearLocked()
return 0, err
}
s.systemClear = next
return deleted, s.compactClearedClassLocked(ClassSystem, s.systemRecordCleared)
}