Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,43 @@ type Repository struct {
// FileTombstones is a set of file paths that should be ignored across all branches
// in this shard.
FileTombstones map[string]struct{} `json:",omitempty"`

// DeltaStats contains advisory statistics used by experimental delta-index
// admission rules. Missing or stale stats must not affect correctness.
DeltaStats *RepositoryDeltaStats `json:",omitempty"`
}

// RepositoryDeltaStats records approximate live and physical index statistics
// for deciding whether a future delta build is likely to be cheap enough.
type RepositoryDeltaStats struct {
// LiveIndexedBytes approximates bytes that would contribute to shard sizing
// for the current live repository: file names plus indexed content bytes.
LiveIndexedBytes uint64

// LiveDocumentCount is the number of live, deduplicated indexed documents.
LiveDocumentCount uint64

// LivePathCount is the number of distinct live file paths.
LivePathCount uint64

// PhysicalIndexedBytes approximates bytes physically present across stacked
// shards, including stale documents hidden by tombstones.
PhysicalIndexedBytes uint64

// PhysicalDocumentCount is the number of physical documents across stacked
// shards, including stale documents hidden by tombstones.
PhysicalDocumentCount uint64

// TombstonePathCount is the number of paths currently tombstoned in old shards.
TombstonePathCount uint64

// DeltaLayerCount is the number of accepted delta generations since the last
// full rebuild.
DeltaLayerCount uint64

// LastFullIndexTimeUnix is the Unix timestamp of the last full rebuild when
// known. It is zero for old indexes where the value cannot be recovered.
LastFullIndexTimeUnix int64
}

func (r *Repository) UnmarshalJSON(data []byte) error {
Expand Down
34 changes: 34 additions & 0 deletions api_proto.go
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,38 @@ func (r *RepositoryBranch) ToProto() *webserverv1.RepositoryBranch {
}
}

func RepositoryDeltaStatsFromProto(p *webserverv1.RepositoryDeltaStats) *RepositoryDeltaStats {
if p == nil {
return nil
}

return &RepositoryDeltaStats{
LiveIndexedBytes: p.GetLiveIndexedBytes(),
LiveDocumentCount: p.GetLiveDocumentCount(),
LivePathCount: p.GetLivePathCount(),
PhysicalIndexedBytes: p.GetPhysicalIndexedBytes(),
PhysicalDocumentCount: p.GetPhysicalDocumentCount(),
TombstonePathCount: p.GetTombstonePathCount(),
DeltaLayerCount: p.GetDeltaLayerCount(),
}
}

func (s *RepositoryDeltaStats) ToProto() *webserverv1.RepositoryDeltaStats {
if s == nil {
return nil
}

return &webserverv1.RepositoryDeltaStats{
LiveIndexedBytes: s.LiveIndexedBytes,
LiveDocumentCount: s.LiveDocumentCount,
LivePathCount: s.LivePathCount,
PhysicalIndexedBytes: s.PhysicalIndexedBytes,
PhysicalDocumentCount: s.PhysicalDocumentCount,
TombstonePathCount: s.TombstonePathCount,
DeltaLayerCount: s.DeltaLayerCount,
}
}

func RepositoryFromProto(p *webserverv1.Repository) Repository {
branches := make([]RepositoryBranch, len(p.GetBranches()))
for i, branch := range p.GetBranches() {
Expand Down Expand Up @@ -454,6 +486,7 @@ func RepositoryFromProto(p *webserverv1.Repository) Repository {
LatestCommitDate: p.GetLatestCommitDate().AsTime(),
FileTombstones: fileTombstones,
Metadata: p.GetMetadata(),
DeltaStats: RepositoryDeltaStatsFromProto(p.GetDeltaStats()),
}
}

Expand Down Expand Up @@ -497,6 +530,7 @@ func (r *Repository) ToProto() *webserverv1.Repository {
LatestCommitDate: timestamppb.New(r.LatestCommitDate),
FileTombstones: fileTombstones,
Metadata: r.Metadata,
DeltaStats: r.DeltaStats.ToProto(),
}
}

Expand Down
69 changes: 69 additions & 0 deletions api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,37 @@ func TestRepositoryMergeMutable(t *testing.T) {
t.Fatalf("got different LineFragmentTemplate, %s vs %s", a.LineFragmentTemplate, b.LineFragmentTemplate)
}
})
t.Run("different DeltaStats", func(t *testing.T) {
a := a
a.DeltaStats = &RepositoryDeltaStats{
LiveIndexedBytes: 10,
LiveDocumentCount: 1,
LivePathCount: 1,
PhysicalIndexedBytes: 10,
PhysicalDocumentCount: 1,
}
b := a
b.DeltaStats = &RepositoryDeltaStats{
LiveIndexedBytes: 20,
LiveDocumentCount: 2,
LivePathCount: 2,
PhysicalIndexedBytes: 30,
PhysicalDocumentCount: 3,
TombstonePathCount: 1,
DeltaLayerCount: 1,
}

mutated, err := a.MergeMutable(&b)
if err != nil {
t.Fatalf("got err %v", err)
}
if mutated {
t.Fatalf("want mutated=false, got true")
}
if reflect.DeepEqual(a.DeltaStats, b.DeltaStats) {
t.Fatalf("MergeMutable should ignore advisory DeltaStats")
}
})
t.Run("all same", func(t *testing.T) {
b := a
mutated, err := a.MergeMutable(&b)
Expand All @@ -364,6 +395,44 @@ func TestRepositoryMergeMutable(t *testing.T) {
})
}

func TestRepositoryDeltaStatsJSON(t *testing.T) {
repo := Repository{
ID: 1,
Name: "repo",
DeltaStats: &RepositoryDeltaStats{
LiveIndexedBytes: 11,
LiveDocumentCount: 2,
LivePathCount: 2,
PhysicalIndexedBytes: 19,
PhysicalDocumentCount: 3,
TombstonePathCount: 1,
DeltaLayerCount: 2,
LastFullIndexTimeUnix: 123,
},
}

blob, err := json.Marshal(repo)
if err != nil {
t.Fatalf("Marshal: %v", err)
}

var round Repository
if err := json.Unmarshal(blob, &round); err != nil {
t.Fatalf("Unmarshal: %v", err)
}
if !reflect.DeepEqual(repo.DeltaStats, round.DeltaStats) {
t.Fatalf("DeltaStats round trip mismatch: got %+v, want %+v", round.DeltaStats, repo.DeltaStats)
}

var old Repository
if err := json.Unmarshal([]byte(`{"ID":1,"Name":"repo"}`), &old); err != nil {
t.Fatalf("Unmarshal old metadata: %v", err)
}
if old.DeltaStats != nil {
t.Fatalf("missing DeltaStats should decode as nil, got %+v", old.DeltaStats)
}
}

func TestMonthsSince1970(t *testing.T) {
tests := []struct {
name string
Expand Down
Loading
Loading