Skip to content

Commit

Permalink
Backport 1.14: Use our fork of bbolt to improve freelist performance (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
ncabatoff authored Jan 22, 2024
1 parent 0104fae commit cac9816
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 8 deletions.
3 changes: 3 additions & 0 deletions changelog/24010.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
storage/raft: Upgrade to bbolt 1.3.8, along with an extra patch to reduce time scanning large freelist maps.
```
2 changes: 1 addition & 1 deletion command/agentproxyshared/cache/cacheboltdb/bolt.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import (
"time"

"github.com/golang/protobuf/proto"
bolt "github.com/hashicorp-forge/bbolt"
"github.com/hashicorp/go-hclog"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"github.com/hashicorp/go-multierror"
bolt "go.etcd.io/bbolt"
)

const (
Expand Down
2 changes: 1 addition & 1 deletion command/agentproxyshared/cache/cacheboltdb/bolt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ import (
"time"

"github.com/golang/protobuf/proto"
bolt "github.com/hashicorp-forge/bbolt"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/vault/command/agentproxyshared/cache/keymanager"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
bolt "go.etcd.io/bbolt"
)

func getTestKeyManager(t *testing.T) keymanager.KeyManager {
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ require (
github.com/google/go-github v17.0.0+incompatible
github.com/google/go-metrics-stackdriver v0.2.0
github.com/google/tink/go v1.7.0
github.com/hashicorp-forge/bbolt v1.3.8-hc3
github.com/hashicorp/cap v0.3.0
github.com/hashicorp/consul-template v0.33.0
github.com/hashicorp/consul/api v1.23.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1993,6 +1993,8 @@ github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
github.com/hashicorp-forge/bbolt v1.3.8-hc3 h1:iTWR3RDPj0TGChAvJ8QjHFcNFWAUVgNQV73IE6gAX4E=
github.com/hashicorp-forge/bbolt v1.3.8-hc3/go.mod h1:sQBu5UIJ+rcUFU4Fo9rpTHNV935jwmGWS3dQ/MV8810=
github.com/hashicorp/cap v0.3.0 h1:zFzVxuWy78lO6QRLHu/ONkjx/Jh0lpfvPgmpDGri43E=
github.com/hashicorp/cap v0.3.0/go.mod h1:dHTmyMIVbzT981XxRoci5G//dfWmd/HhuNiCH6J5+IA=
github.com/hashicorp/consul-template v0.33.0 h1:UNyf7V/nFeh8edh5X6pP8f+9LZVn+DG9uNLLcTpLsFc=
Expand Down
2 changes: 1 addition & 1 deletion physical/raft/fsm.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

"github.com/armon/go-metrics"
"github.com/golang/protobuf/proto"
bolt "github.com/hashicorp-forge/bbolt"
log "github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-raftchunking"
Expand All @@ -28,7 +29,6 @@ import (
"github.com/hashicorp/vault/sdk/helper/jsonutil"
"github.com/hashicorp/vault/sdk/physical"
"github.com/hashicorp/vault/sdk/plugin/pb"
bolt "go.etcd.io/bbolt"
)

const (
Expand Down
66 changes: 63 additions & 3 deletions physical/raft/raft.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

"github.com/armon/go-metrics"
"github.com/golang/protobuf/proto"
bolt "github.com/hashicorp-forge/bbolt"
log "github.com/hashicorp/go-hclog"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
"github.com/hashicorp/go-raftchunking"
Expand All @@ -39,7 +40,7 @@ import (
"github.com/hashicorp/vault/vault/cluster"
"github.com/hashicorp/vault/vault/seal"
"github.com/hashicorp/vault/version"
bolt "go.etcd.io/bbolt"
etcdbolt "go.etcd.io/bbolt"
)

const (
Expand Down Expand Up @@ -402,7 +403,7 @@ func NewRaftBackend(conf map[string]string, logger log.Logger) (physical.Backend

// Create the backend raft store for logs and stable storage.
dbPath := filepath.Join(path, "raft.db")
opts := boltOptions(dbPath)
opts := etcdboltOptions(dbPath)
raftOptions := raftboltdb.Options{
Path: dbPath,
BoltOptions: opts,
Expand Down Expand Up @@ -633,7 +634,7 @@ func (b *RaftBackend) CollectMetrics(sink *metricsutil.ClusterMetricSink) {
stats = b.raft.Stats()
}
b.l.RUnlock()
b.collectMetricsWithStats(logstoreStats, sink, "logstore")
b.collectEtcdBoltMetricsWithStats(logstoreStats, sink, "logstore")
b.collectMetricsWithStats(fsmStats, sink, "fsm")
labels := []metrics.Label{
{
Expand Down Expand Up @@ -674,6 +675,29 @@ func (b *RaftBackend) collectMetricsWithStats(stats bolt.Stats, sink *metricsuti
sink.IncrCounterWithLabels([]string{"raft_storage", "bolt", "write", "time"}, float32(txstats.GetWriteTime().Milliseconds()), labels)
}

func (b *RaftBackend) collectEtcdBoltMetricsWithStats(stats etcdbolt.Stats, sink *metricsutil.ClusterMetricSink, database string) {
txstats := stats.TxStats
labels := []metricsutil.Label{{"database", database}}
sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "freelist", "free_pages"}, float32(stats.FreePageN), labels)
sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "freelist", "pending_pages"}, float32(stats.PendingPageN), labels)
sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "freelist", "allocated_bytes"}, float32(stats.FreeAlloc), labels)
sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "freelist", "used_bytes"}, float32(stats.FreelistInuse), labels)
sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "transaction", "started_read_transactions"}, float32(stats.TxN), labels)
sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "transaction", "currently_open_read_transactions"}, float32(stats.OpenTxN), labels)
sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "page", "count"}, float32(txstats.GetPageCount()), labels)
sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "page", "bytes_allocated"}, float32(txstats.GetPageAlloc()), labels)
sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "cursor", "count"}, float32(txstats.GetCursorCount()), labels)
sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "node", "count"}, float32(txstats.GetNodeCount()), labels)
sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "node", "dereferences"}, float32(txstats.GetNodeDeref()), labels)
sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "rebalance", "count"}, float32(txstats.GetRebalance()), labels)
sink.AddSampleWithLabels([]string{"raft_storage", "bolt", "rebalance", "time"}, float32(txstats.GetRebalanceTime().Milliseconds()), labels)
sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "split", "count"}, float32(txstats.GetSplit()), labels)
sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "spill", "count"}, float32(txstats.GetSpill()), labels)
sink.AddSampleWithLabels([]string{"raft_storage", "bolt", "spill", "time"}, float32(txstats.GetSpillTime().Milliseconds()), labels)
sink.SetGaugeWithLabels([]string{"raft_storage", "bolt", "write", "count"}, float32(txstats.GetWrite()), labels)
sink.IncrCounterWithLabels([]string{"raft_storage", "bolt", "write", "time"}, float32(txstats.GetWriteTime().Milliseconds()), labels)
}

// RaftServer has information about a server in the Raft configuration
type RaftServer struct {
// NodeID is the name of the server
Expand Down Expand Up @@ -1968,3 +1992,39 @@ func boltOptions(path string) *bolt.Options {

return o
}

func etcdboltOptions(path string) *etcdbolt.Options {
o := &etcdbolt.Options{
Timeout: 1 * time.Second,
FreelistType: etcdbolt.FreelistMapType,
NoFreelistSync: true,
MmapFlags: getMmapFlags(path),
}

if os.Getenv("VAULT_RAFT_FREELIST_TYPE") == "array" {
o.FreelistType = etcdbolt.FreelistArrayType
}

if os.Getenv("VAULT_RAFT_FREELIST_SYNC") != "" {
o.NoFreelistSync = false
}

// By default, we want to set InitialMmapSize to 100GB, but only on 64bit platforms.
// Otherwise, we set it to whatever the value of VAULT_RAFT_INITIAL_MMAP_SIZE
// is, assuming it can be parsed as an int. Bolt itself sets this to 0 by default,
// so if users are wanting to turn this off, they can also set it to 0. Setting it
// to a negative value is the same as not setting it at all.
if os.Getenv("VAULT_RAFT_INITIAL_MMAP_SIZE") == "" {
o.InitialMmapSize = initialMmapSize
} else {
imms, err := strconv.Atoi(os.Getenv("VAULT_RAFT_INITIAL_MMAP_SIZE"))

// If there's an error here, it means they passed something that's not convertible to
// a number. Rather than fail startup, just ignore it.
if err == nil && imms > 0 {
o.InitialMmapSize = imms
}
}

return o
}
2 changes: 1 addition & 1 deletion physical/raft/raft_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ import (

"github.com/go-test/deep"
"github.com/golang/protobuf/proto"
bolt "github.com/hashicorp-forge/bbolt"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-secure-stdlib/base62"
"github.com/hashicorp/go-uuid"
"github.com/hashicorp/raft"
"github.com/hashicorp/vault/sdk/helper/jsonutil"
"github.com/hashicorp/vault/sdk/physical"
bolt "go.etcd.io/bbolt"
)

func connectPeers(nodes ...*RaftBackend) {
Expand Down
2 changes: 1 addition & 1 deletion physical/raft/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ import (
"time"

"github.com/golang/protobuf/proto"
bolt "github.com/hashicorp-forge/bbolt"
log "github.com/hashicorp/go-hclog"
"github.com/hashicorp/vault/sdk/plugin/pb"
"github.com/rboyer/safeio"
bolt "go.etcd.io/bbolt"
"go.uber.org/atomic"

"github.com/hashicorp/raft"
Expand Down

0 comments on commit cac9816

Please sign in to comment.