docs: publish Preview 19 dogfood evidence
Export the reviewed allowlisted snapshot from private source commit 05928cebd01b586cf9e9d4b8c8537a7605a6068c. This records the exact candidate, bounded capacity result, stateful migration scratch requirement, authenticated batch identity proof, and immediate live acceptance evidence. AI-Assisted: OpenAI Codex Signed-off-by: Cole Speelman <crspeelman@gmail.com>
This commit is contained in:
@@ -0,0 +1,317 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"gamertan.com/observatory/internal/model"
|
||||
"gamertan.com/observatory/internal/query"
|
||||
"gamertan.com/observatory/internal/schema"
|
||||
)
|
||||
|
||||
const maxRebuildSegments = 1_000_000
|
||||
|
||||
type RebuildReport struct {
|
||||
OrganizationID string `json:"organization_id"`
|
||||
Segments int `json:"segments"`
|
||||
Observations int64 `json:"observations"`
|
||||
ActiveVersion int `json:"active_projection_version"`
|
||||
IndexedRows int64 `json:"indexed_rows"`
|
||||
}
|
||||
|
||||
type rebuildSegment struct {
|
||||
digest string
|
||||
path string
|
||||
}
|
||||
|
||||
// RebuildOrganization reconstructs one disposable organization projection
|
||||
// from checksummed raw truth beside the live database, then atomically replaces
|
||||
// it. The caller must hold the data directory's exclusive process lock.
|
||||
func (s *Store) RebuildOrganization(ctx context.Context, organizationID string, now time.Time) (RebuildReport, error) {
|
||||
if err := model.ValidateSourceID(organizationID); err != nil || now.IsZero() {
|
||||
return RebuildReport{}, errors.New("projection rebuild input is invalid")
|
||||
}
|
||||
lock := s.namedLock("organization:" + organizationID)
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
dir := filepath.Join(s.root, "organizations", organizationID)
|
||||
if err := os.MkdirAll(dir, 0o700); err != nil {
|
||||
return RebuildReport{}, errors.New("create projection rebuild directory")
|
||||
}
|
||||
live := filepath.Join(dir, "projection.sqlite")
|
||||
if err := requireProjectionTarget(live); err != nil {
|
||||
return RebuildReport{}, err
|
||||
}
|
||||
exists, err := s.organizationHasSource(ctx, organizationID)
|
||||
if err != nil {
|
||||
return RebuildReport{}, err
|
||||
}
|
||||
if !exists {
|
||||
return RebuildReport{}, errors.New("projection rebuild organization has no enrolled sources")
|
||||
}
|
||||
segments, err := s.rebuildSegments(ctx, organizationID)
|
||||
if err != nil {
|
||||
return RebuildReport{}, err
|
||||
}
|
||||
temporary, err := os.CreateTemp(dir, ".projection-rebuild-*.sqlite")
|
||||
if err != nil {
|
||||
return RebuildReport{}, errors.New("create projection rebuild target")
|
||||
}
|
||||
stage := temporary.Name()
|
||||
if err = temporary.Close(); err != nil {
|
||||
_ = os.Remove(stage)
|
||||
return RebuildReport{}, errors.New("close projection rebuild target")
|
||||
}
|
||||
if err = os.Remove(stage); err != nil {
|
||||
return RebuildReport{}, errors.New("prepare projection rebuild target")
|
||||
}
|
||||
defer removeProjectionFiles(stage)
|
||||
|
||||
db, err := openProjection(ctx, stage)
|
||||
if err != nil {
|
||||
return RebuildReport{}, err
|
||||
}
|
||||
if err = db.Close(); err != nil {
|
||||
return RebuildReport{}, errors.New("close empty projection rebuild target")
|
||||
}
|
||||
report := RebuildReport{OrganizationID: organizationID, ActiveVersion: 1}
|
||||
for _, entry := range segments {
|
||||
if err = ctx.Err(); err != nil {
|
||||
return RebuildReport{}, err
|
||||
}
|
||||
batch, readErr := s.segments.Read(entry.path, entry.digest)
|
||||
if readErr != nil {
|
||||
return RebuildReport{}, fmt.Errorf("read projection rebuild segment: %w", readErr)
|
||||
}
|
||||
if err = batch.Validate(batch.ObservedAt); err != nil {
|
||||
return RebuildReport{}, errors.New("projection rebuild segment is invalid")
|
||||
}
|
||||
source, sourceErr := s.sourceByID(ctx, batch.SourceID)
|
||||
if sourceErr != nil {
|
||||
return RebuildReport{}, sourceErr
|
||||
}
|
||||
if source.Scope.OrganizationID != organizationID {
|
||||
return RebuildReport{}, errors.New("projection rebuild segment organization mismatch")
|
||||
}
|
||||
if err = projectAt(ctx, stage, source.Scope, batch, entry.digest); err != nil {
|
||||
return RebuildReport{}, err
|
||||
}
|
||||
if int64(len(batch.Records)) > math.MaxInt64-report.Observations {
|
||||
return RebuildReport{}, errors.New("projection rebuild observation count overflow")
|
||||
}
|
||||
report.Observations += int64(len(batch.Records))
|
||||
report.Segments++
|
||||
}
|
||||
descriptors, err := s.activatedDescriptors(ctx, organizationID)
|
||||
if err != nil {
|
||||
return RebuildReport{}, err
|
||||
}
|
||||
if len(descriptors) > 0 {
|
||||
report.ActiveVersion, report.IndexedRows, err = activateRebuiltDescriptors(ctx, stage, descriptors, now)
|
||||
if err != nil {
|
||||
return RebuildReport{}, err
|
||||
}
|
||||
}
|
||||
if err = finalizeProjection(stage); err != nil {
|
||||
return RebuildReport{}, err
|
||||
}
|
||||
if err = s.closeProjection(organizationID); err != nil {
|
||||
return RebuildReport{}, errors.New("close live projection before replacement")
|
||||
}
|
||||
if err = requireProjectionTarget(live); err != nil {
|
||||
return RebuildReport{}, err
|
||||
}
|
||||
if err = removeProjectionSidecars(live); err != nil {
|
||||
return RebuildReport{}, err
|
||||
}
|
||||
if err = os.Rename(stage, live); err != nil {
|
||||
return RebuildReport{}, errors.New("activate rebuilt projection")
|
||||
}
|
||||
if err = syncProjectionDirectory(dir); err != nil {
|
||||
return RebuildReport{}, errors.New("sync rebuilt projection directory")
|
||||
}
|
||||
return report, nil
|
||||
}
|
||||
|
||||
func (s *Store) organizationHasSource(ctx context.Context, organizationID string) (bool, error) {
|
||||
var exists int
|
||||
err := s.control.QueryRowContext(ctx, `SELECT EXISTS(SELECT 1 FROM sources WHERE organization_id=? LIMIT 1)`, organizationID).Scan(&exists)
|
||||
if err != nil {
|
||||
return false, errors.New("verify projection rebuild organization")
|
||||
}
|
||||
return exists == 1, nil
|
||||
}
|
||||
|
||||
func (s *Store) rebuildSegments(ctx context.Context, organizationID string) ([]rebuildSegment, error) {
|
||||
rows, err := s.control.QueryContext(ctx, `SELECT digest,path FROM segments WHERE organization_id=? AND tier='hot' AND retiring_at IS NULL ORDER BY source_id,stream_id,sequence`, organizationID)
|
||||
if err != nil {
|
||||
return nil, errors.New("list projection rebuild segments")
|
||||
}
|
||||
defer rows.Close()
|
||||
segments := make([]rebuildSegment, 0)
|
||||
for rows.Next() {
|
||||
if len(segments) >= maxRebuildSegments {
|
||||
return nil, errors.New("projection rebuild segment limit exceeded")
|
||||
}
|
||||
var entry rebuildSegment
|
||||
if err = rows.Scan(&entry.digest, &entry.path); err != nil {
|
||||
return nil, errors.New("read projection rebuild segment")
|
||||
}
|
||||
segments = append(segments, entry)
|
||||
}
|
||||
if err = rows.Err(); err != nil {
|
||||
return nil, errors.New("list projection rebuild segments")
|
||||
}
|
||||
return segments, nil
|
||||
}
|
||||
|
||||
func (s *Store) activatedDescriptors(ctx context.Context, organizationID string) ([]schema.Descriptor, error) {
|
||||
rows, err := s.control.QueryContext(ctx, `SELECT descriptor_json FROM descriptor_proposals WHERE organization_id=? AND status='activated' ORDER BY signal,field`, organizationID)
|
||||
if err != nil {
|
||||
return nil, errors.New("list activated descriptors for rebuild")
|
||||
}
|
||||
defer rows.Close()
|
||||
descriptors := make([]schema.Descriptor, 0)
|
||||
seen := map[string]bool{}
|
||||
for rows.Next() {
|
||||
if len(descriptors) >= model.MaxDistinctFields {
|
||||
return nil, errors.New("activated descriptor rebuild limit exceeded")
|
||||
}
|
||||
var encoded string
|
||||
var descriptor schema.Descriptor
|
||||
if err = rows.Scan(&encoded); err != nil || json.Unmarshal([]byte(encoded), &descriptor) != nil || descriptor.Validate() != nil {
|
||||
return nil, errors.New("activated descriptor rebuild data is invalid")
|
||||
}
|
||||
key := string(descriptor.Signal) + ":" + query.CanonicalField(descriptor.Field)
|
||||
if seen[key] {
|
||||
return nil, errors.New("activated descriptor rebuild data is duplicated")
|
||||
}
|
||||
seen[key] = true
|
||||
descriptor.ProjectionVersion = 2
|
||||
descriptors = append(descriptors, descriptor)
|
||||
}
|
||||
if err = rows.Err(); err != nil {
|
||||
return nil, errors.New("list activated descriptors for rebuild")
|
||||
}
|
||||
sort.Slice(descriptors, func(left, right int) bool {
|
||||
if descriptors[left].Signal == descriptors[right].Signal {
|
||||
return descriptors[left].Field < descriptors[right].Field
|
||||
}
|
||||
return descriptors[left].Signal < descriptors[right].Signal
|
||||
})
|
||||
return descriptors, nil
|
||||
}
|
||||
|
||||
func activateRebuiltDescriptors(ctx context.Context, path string, descriptors []schema.Descriptor, now time.Time) (int, int64, error) {
|
||||
db, err := openProjection(ctx, path)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
defer db.Close()
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return 0, 0, errors.New("begin rebuilt descriptor activation")
|
||||
}
|
||||
defer tx.Rollback()
|
||||
timestamp := now.UTC().Format(time.RFC3339Nano)
|
||||
if _, err = tx.ExecContext(ctx, `INSERT INTO projection_versions(version,created_at,activated_at) VALUES(2,?,?)`, timestamp, timestamp); err != nil {
|
||||
return 0, 0, errors.New("create rebuilt projection version")
|
||||
}
|
||||
for _, descriptor := range descriptors {
|
||||
encoded, marshalErr := json.Marshal(descriptor)
|
||||
if marshalErr != nil {
|
||||
return 0, 0, errors.New("encode rebuilt active descriptor")
|
||||
}
|
||||
if _, err = tx.ExecContext(ctx, `INSERT INTO projection_descriptors(version,signal,field,descriptor_json) VALUES(2,?,?,?)`, descriptor.Signal, descriptor.Field, string(encoded)); err != nil {
|
||||
return 0, 0, errors.New("store rebuilt active descriptor")
|
||||
}
|
||||
}
|
||||
indexed, err := buildProjectionIndex(ctx, tx, 2, descriptors)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
if _, err = tx.ExecContext(ctx, `UPDATE projection_state SET active_version=2 WHERE id=1 AND active_version=1`); err != nil {
|
||||
return 0, 0, errors.New("activate rebuilt projection version")
|
||||
}
|
||||
if err = tx.Commit(); err != nil {
|
||||
return 0, 0, errors.New("commit rebuilt descriptor activation")
|
||||
}
|
||||
return 2, indexed, nil
|
||||
}
|
||||
|
||||
func requireProjectionTarget(path string) error {
|
||||
if info, err := os.Lstat(path); err == nil {
|
||||
if !info.Mode().IsRegular() || info.Mode()&os.ModeSymlink != 0 {
|
||||
return errors.New("organization projection must be a regular non-symlink file")
|
||||
}
|
||||
} else if !errors.Is(err, os.ErrNotExist) {
|
||||
return errors.New("inspect organization projection")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeProjectionSidecars(path string) error {
|
||||
for _, suffix := range []string{"-wal", "-shm"} {
|
||||
sidecar := path + suffix
|
||||
info, err := os.Lstat(sidecar)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
continue
|
||||
}
|
||||
if err != nil || !info.Mode().IsRegular() || info.Mode()&os.ModeSymlink != 0 {
|
||||
return errors.New("projection sidecar is not a regular non-symlink file")
|
||||
}
|
||||
if err = os.Remove(sidecar); err != nil {
|
||||
return errors.New("remove inactive projection sidecar")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func finalizeProjection(path string) error {
|
||||
db, err := sql.Open("sqlite", path)
|
||||
if err != nil {
|
||||
return errors.New("open rebuilt projection for finalization")
|
||||
}
|
||||
if _, err = db.Exec(`PRAGMA wal_checkpoint(TRUNCATE)`); err == nil {
|
||||
_, err = db.Exec(`PRAGMA journal_mode=DELETE`)
|
||||
}
|
||||
closeErr := db.Close()
|
||||
if err != nil || closeErr != nil {
|
||||
return errors.New("finalize rebuilt projection")
|
||||
}
|
||||
if err = os.Chmod(path, 0o600); err != nil {
|
||||
return errors.New("set rebuilt projection mode")
|
||||
}
|
||||
for _, suffix := range []string{"-wal", "-shm"} {
|
||||
if _, err = os.Lstat(path + suffix); !errors.Is(err, os.ErrNotExist) {
|
||||
return errors.New("rebuilt projection retained a sidecar")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeProjectionFiles(path string) {
|
||||
_ = os.Remove(path)
|
||||
_ = os.Remove(path + "-wal")
|
||||
_ = os.Remove(path + "-shm")
|
||||
}
|
||||
|
||||
func syncProjectionDirectory(path string) error {
|
||||
directory, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer directory.Close()
|
||||
return directory.Sync()
|
||||
}
|
||||
Reference in New Issue
Block a user