// Copyright 2020 The LevelDB-Go and Pebble Authors. All rights reserved. Use
// of this source code is governed by a BSD-style license that can be found in
// the LICENSE file.

//go:build (invariants && !race) || (tracing && !race)
// +build invariants,!race tracing,!race

package cache

import (
	"fmt"
	"os"

	"github.com/cockroachdb/pebble/v2/internal/invariants"
	"github.com/cockroachdb/pebble/v2/internal/manual"
)

// newValue creates a Value with a manually managed buffer of size n.
//
// This definition of newValue is used when either the "invariants" or
// "tracing" build tags are specified. It hooks up a finalizer to the returned
// Value that checks for memory leaks when the GC determines the Value is no
// longer reachable.
func newValue(n int) *Value {
	if n == 0 {
		return nil
	}
	b := manual.New(manual.BlockCacheData, n)
	v := &Value{buf: b}
	v.ref.init(1)
	// Note: this is a no-op if invariants and tracing are disabled or race is
	// enabled.
	invariants.SetFinalizer(v, func(obj interface{}) {
		v := obj.(*Value)
		if v.buf != nil {
			fmt.Fprintf(os.Stderr, "%p: cache value was not freed: refs=%d\n%s",
				v, v.refs(), v.ref.traces())
			os.Exit(1)
		}
	})
	return v
}

func (v *Value) free() {
	// When "invariants" are enabled set the value contents to 0xff in order to
	// cache use-after-free bugs.
	for i := range v.buf {
		v.buf[i] = 0xff
	}
	manual.Free(manual.BlockCacheData, v.buf)
	// Setting Value.buf to nil is needed for correctness of the leak checking
	// that is performed when the "invariants" or "tracing" build tags are
	// enabled.
	v.buf = nil
}
