Files
kopia/snapshot/policy/policy_tree.go
Prasad Ghangal 3bf947d746 feat(repository): Metadata compression config support for directory and indirect content (#4080)
* Configure compressor for k and x prefixed content

Adds metadata compression setting to policy
Add support to configure compressor for k and x prefixed content
Set zstd-fastest as the default compressor for metadata in the policy
Adds support to set and show metadata compression to kopia policy commands
Adds metadata compression config to dir writer

Signed-off-by: Prasad Ghangal <prasad.ganghal@veeam.com>

* Pass concatenate options with ConcatenateOptions struct

Signed-off-by: Prasad Ghangal <prasad.ganghal@veeam.com>

* Move content compression handling to caller

Signed-off-by: Prasad Ghangal <prasad.ganghal@veeam.com>

* Move handling manifests to manifest pkg

Signed-off-by: Prasad Ghangal <prasad.ganghal@veeam.com>

* Correct const in server_test

Signed-off-by: Prasad Ghangal <prasad.ganghal@veeam.com>

* Remove unnecessary whitespace

Signed-off-by: Prasad Ghangal <prasad.ganghal@veeam.com>

* Disable metadata compression for < V2 format

Signed-off-by: Prasad Ghangal <prasad.ganghal@veeam.com>

---------

Signed-off-by: Prasad Ghangal <prasad.ganghal@veeam.com>
2024-10-23 23:28:23 -07:00

208 lines
5.5 KiB
Go

package policy
import (
"strings"
)
//nolint:gochecknoglobals
var (
// defaultActionsPolicy is the default actions policy.
defaultActionsPolicy = ActionsPolicy{}
defaultCompressionPolicy = CompressionPolicy{
CompressorName: "none",
}
defaultMetadataCompressionPolicy = MetadataCompressionPolicy{
CompressorName: "zstd-fastest",
}
defaultSplitterPolicy = SplitterPolicy{}
// defaultErrorHandlingPolicy is the default error handling policy.
defaultErrorHandlingPolicy = ErrorHandlingPolicy{
IgnoreFileErrors: NewOptionalBool(false),
IgnoreDirectoryErrors: NewOptionalBool(false),
IgnoreUnknownTypes: NewOptionalBool(true),
}
// defaultFilesPolicy is the default file ignore policy.
defaultFilesPolicy = FilesPolicy{
DotIgnoreFiles: []string{".kopiaignore"},
}
// defaultLoggingPolicy is the default logs policy.
defaultLoggingPolicy = LoggingPolicy{
Directories: DirLoggingPolicy{
Snapshotted: NewLogDetail(LogDetailNormal),
Ignored: NewLogDetail(LogDetailNormal),
},
Entries: EntryLoggingPolicy{
Snapshotted: NewLogDetail(LogDetailNone),
Ignored: NewLogDetail(LogDetailNormal),
CacheHit: NewLogDetail(LogDetailNone),
CacheMiss: NewLogDetail(LogDetailNone),
},
}
defaultRetentionPolicy = RetentionPolicy{
KeepLatest: newOptionalInt(defaultKeepLatest),
KeepHourly: newOptionalInt(defaultKeepHourly),
KeepDaily: newOptionalInt(defaultKeepDaily),
KeepWeekly: newOptionalInt(defaultKeepWeekly),
KeepMonthly: newOptionalInt(defaultKeepMonthly),
KeepAnnual: newOptionalInt(defaultKeepAnnual),
IgnoreIdenticalSnapshots: NewOptionalBool(defaultIgnoreIdenticalSnapshots),
}
defaultSchedulingPolicy = SchedulingPolicy{
RunMissed: NewOptionalBool(defaultRunMissed),
}
defaultOSSnapshotPolicy = OSSnapshotPolicy{
VolumeShadowCopy: VolumeShadowCopyPolicy{
Enable: NewOSSnapshotMode(OSSnapshotNever),
},
}
defaultUploadPolicy = UploadPolicy{
MaxParallelSnapshots: newOptionalInt(1),
MaxParallelFileReads: nil, // defaults to runtime.NumCPUs()
// upload large files in chunks of 2 GiB
ParallelUploadAboveSize: newOptionalInt64(2 << 30), //nolint:mnd
}
// DefaultPolicy is a default policy returned by policy tree in absence of other policies.
DefaultPolicy = &Policy{
FilesPolicy: defaultFilesPolicy,
RetentionPolicy: defaultRetentionPolicy,
CompressionPolicy: defaultCompressionPolicy,
MetadataCompressionPolicy: defaultMetadataCompressionPolicy,
ErrorHandlingPolicy: defaultErrorHandlingPolicy,
SchedulingPolicy: defaultSchedulingPolicy,
LoggingPolicy: defaultLoggingPolicy,
Actions: defaultActionsPolicy,
OSSnapshotPolicy: defaultOSSnapshotPolicy,
UploadPolicy: defaultUploadPolicy,
}
// DefaultDefinition provides the Definition for the default policy.
DefaultDefinition = &Definition{}
)
// Tree represents a node in the policy tree, where a policy can be
// defined. A nil tree is a valid tree with default policy.
type Tree struct {
effective *Policy
inherited bool
children map[string]*Tree
}
// DefinedPolicy returns policy that's been explicitly defined for tree node or nil if no policy was defined.
func (t *Tree) DefinedPolicy() *Policy {
if t == nil || t.inherited {
return nil
}
return t.effective
}
// EffectivePolicy returns policy that's been defined for this tree node or inherited from its parent.
func (t *Tree) EffectivePolicy() *Policy {
if t == nil {
return DefaultPolicy
}
return t.effective
}
// IsInherited returns true if the policy inherited to the given tree hode has been inherited from its parent.
func (t *Tree) IsInherited() bool {
if t == nil {
return true
}
return t.inherited
}
// Child gets a subtree for an entry with a given name.
func (t *Tree) Child(name string) *Tree {
if t == nil {
return nil
}
parts := strings.Split(name, "/")
switch len(parts) {
case 1:
if name == "." || name == "" {
return t
}
ch := t.children[name]
if ch != nil {
return ch
}
// tree with no children, we can just reuse current node
if len(t.children) == 0 && t.inherited {
return t
}
return &Tree{effective: t.effective, inherited: true}
default:
ch := t
for _, p := range parts {
ch = ch.Child(p)
}
return ch
}
}
// BuildTree builds a policy tree from the given map of paths to policies.
// Each path must be relative and start with "." and be separated by slashes.
func BuildTree(defined map[string]*Policy, defaultPolicy *Policy) *Tree {
return buildTreeNode(defined, ".", defaultPolicy)
}
func buildTreeNode(defined map[string]*Policy, path string, defaultPolicy *Policy) *Tree {
n := &Tree{
effective: defined[path],
}
if n.effective == nil {
n.effective = defaultPolicy
n.inherited = true
}
children := childrenWithPrefix(defined, path+"/")
if len(children) > 0 {
n.children = map[string]*Tree{}
for childName, descendants := range children {
n.children[childName] = buildTreeNode(descendants, path+"/"+childName, n.effective)
}
}
return n
}
func childrenWithPrefix(m map[string]*Policy, path string) map[string]map[string]*Policy {
result := map[string]map[string]*Policy{}
for k, v := range m {
if !strings.HasPrefix(k, path) {
continue
}
childName := strings.Split(k[len(path):], "/")[0]
if result[childName] == nil {
result[childName] = map[string]*Policy{}
}
result[childName][k] = v
}
return result
}