acde3f16d0
Given that every pin and block/put writes something to IPFS and thus increases the repo size, a while ago we added a check to let the IPFS connector directly trigger the sending of metrics every 10 of such requests. This was meant to update the metrics more often so that balancing happened more granularly (particularly the freespace one). In practice, on a cluster that receives several hundreds of pin/adds operations in a few seconds, this is just bad. So: * We disable by default the whole thing. * We add a new InformerTriggerInterval configuration option to enable the thing. * Fix a bug that made this always call the first informer, which may not have been the freespace one).
231 lines
6.2 KiB
Go
231 lines
6.2 KiB
Go
package ipfshttp
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/kelseyhightower/envconfig"
|
|
|
|
"github.com/ipfs/ipfs-cluster/config"
|
|
|
|
ma "github.com/multiformats/go-multiaddr"
|
|
)
|
|
|
|
const configKey = "ipfshttp"
|
|
const envConfigKey = "cluster_ipfshttp"
|
|
|
|
// Default values for Config.
|
|
const (
|
|
DefaultNodeAddr = "/ip4/127.0.0.1/tcp/5001"
|
|
DefaultConnectSwarmsDelay = 30 * time.Second
|
|
DefaultIPFSRequestTimeout = 5 * time.Minute
|
|
DefaultPinTimeout = 2 * time.Minute
|
|
DefaultUnpinTimeout = 3 * time.Hour
|
|
DefaultRepoGCTimeout = 24 * time.Hour
|
|
DefaultInformerTriggerInterval = 0 // disabled
|
|
DefaultUnpinDisable = false
|
|
)
|
|
|
|
// Config is used to initialize a Connector and allows to customize
|
|
// its behaviour. It implements the config.ComponentConfig interface.
|
|
type Config struct {
|
|
config.Saver
|
|
|
|
// Host/Port for the IPFS daemon.
|
|
NodeAddr ma.Multiaddr
|
|
|
|
// ConnectSwarmsDelay specifies how long to wait after startup before
|
|
// attempting to open connections from this peer's IPFS daemon to the
|
|
// IPFS daemons of other peers.
|
|
ConnectSwarmsDelay time.Duration
|
|
|
|
// IPFS Daemon HTTP Client POST timeout
|
|
IPFSRequestTimeout time.Duration
|
|
|
|
// Pin Operation timeout
|
|
PinTimeout time.Duration
|
|
|
|
// Unpin Operation timeout
|
|
UnpinTimeout time.Duration
|
|
|
|
// RepoGC Operation timeout
|
|
RepoGCTimeout time.Duration
|
|
|
|
// How many pin and block/put operations need to happen before we do a
|
|
// special broadcast informer metrics to the network. 0 to disable.
|
|
InformerTriggerInterval int
|
|
|
|
// Disables the unpin operation and returns an error.
|
|
UnpinDisable bool
|
|
|
|
// Tracing flag used to skip tracing specific paths when not enabled.
|
|
Tracing bool
|
|
}
|
|
|
|
type jsonConfig struct {
|
|
NodeMultiaddress string `json:"node_multiaddress"`
|
|
ConnectSwarmsDelay string `json:"connect_swarms_delay"`
|
|
IPFSRequestTimeout string `json:"ipfs_request_timeout"`
|
|
PinTimeout string `json:"pin_timeout"`
|
|
UnpinTimeout string `json:"unpin_timeout"`
|
|
RepoGCTimeout string `json:"repogc_timeout"`
|
|
InformerTriggerInterval int `json:"informer_trigger_interval"`
|
|
UnpinDisable bool `json:"unpin_disable,omitempty"`
|
|
}
|
|
|
|
// ConfigKey provides a human-friendly identifier for this type of Config.
|
|
func (cfg *Config) ConfigKey() string {
|
|
return configKey
|
|
}
|
|
|
|
// Default sets the fields of this Config to sensible default values.
|
|
func (cfg *Config) Default() error {
|
|
node, _ := ma.NewMultiaddr(DefaultNodeAddr)
|
|
cfg.NodeAddr = node
|
|
cfg.ConnectSwarmsDelay = DefaultConnectSwarmsDelay
|
|
cfg.IPFSRequestTimeout = DefaultIPFSRequestTimeout
|
|
cfg.PinTimeout = DefaultPinTimeout
|
|
cfg.UnpinTimeout = DefaultUnpinTimeout
|
|
cfg.RepoGCTimeout = DefaultRepoGCTimeout
|
|
cfg.InformerTriggerInterval = DefaultInformerTriggerInterval
|
|
cfg.UnpinDisable = DefaultUnpinDisable
|
|
|
|
return nil
|
|
}
|
|
|
|
// ApplyEnvVars fills in any Config fields found
|
|
// as environment variables.
|
|
func (cfg *Config) ApplyEnvVars() error {
|
|
jcfg, err := cfg.toJSONConfig()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = envconfig.Process(envConfigKey, jcfg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return cfg.applyJSONConfig(jcfg)
|
|
}
|
|
|
|
// Validate checks that the fields of this Config have sensible values,
|
|
// at least in appearance.
|
|
func (cfg *Config) Validate() error {
|
|
var err error
|
|
if cfg.NodeAddr == nil {
|
|
err = errors.New("ipfshttp.node_multiaddress not set")
|
|
}
|
|
|
|
if cfg.ConnectSwarmsDelay < 0 {
|
|
err = errors.New("ipfshttp.connect_swarms_delay is invalid")
|
|
}
|
|
|
|
if cfg.IPFSRequestTimeout < 0 {
|
|
err = errors.New("ipfshttp.ipfs_request_timeout invalid")
|
|
}
|
|
|
|
if cfg.PinTimeout < 0 {
|
|
err = errors.New("ipfshttp.pin_timeout invalid")
|
|
}
|
|
|
|
if cfg.UnpinTimeout < 0 {
|
|
err = errors.New("ipfshttp.unpin_timeout invalid")
|
|
}
|
|
|
|
if cfg.RepoGCTimeout < 0 {
|
|
err = errors.New("ipfshttp.repogc_timeout invalid")
|
|
}
|
|
if cfg.InformerTriggerInterval < 0 {
|
|
err = errors.New("ipfshttp.update_metrics_after")
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// LoadJSON parses a JSON representation of this Config as generated by ToJSON.
|
|
func (cfg *Config) LoadJSON(raw []byte) error {
|
|
jcfg := &jsonConfig{}
|
|
err := json.Unmarshal(raw, jcfg)
|
|
if err != nil {
|
|
logger.Error("Error unmarshaling ipfshttp config")
|
|
return err
|
|
}
|
|
|
|
cfg.Default()
|
|
|
|
return cfg.applyJSONConfig(jcfg)
|
|
}
|
|
|
|
func (cfg *Config) applyJSONConfig(jcfg *jsonConfig) error {
|
|
nodeAddr, err := ma.NewMultiaddr(jcfg.NodeMultiaddress)
|
|
if err != nil {
|
|
return fmt.Errorf("error parsing ipfs_node_multiaddress: %s", err)
|
|
}
|
|
|
|
cfg.NodeAddr = nodeAddr
|
|
cfg.UnpinDisable = jcfg.UnpinDisable
|
|
cfg.InformerTriggerInterval = jcfg.InformerTriggerInterval
|
|
|
|
err = config.ParseDurations(
|
|
"ipfshttp",
|
|
&config.DurationOpt{Duration: jcfg.ConnectSwarmsDelay, Dst: &cfg.ConnectSwarmsDelay, Name: "connect_swarms_delay"},
|
|
&config.DurationOpt{Duration: jcfg.IPFSRequestTimeout, Dst: &cfg.IPFSRequestTimeout, Name: "ipfs_request_timeout"},
|
|
&config.DurationOpt{Duration: jcfg.PinTimeout, Dst: &cfg.PinTimeout, Name: "pin_timeout"},
|
|
&config.DurationOpt{Duration: jcfg.UnpinTimeout, Dst: &cfg.UnpinTimeout, Name: "unpin_timeout"},
|
|
&config.DurationOpt{Duration: jcfg.RepoGCTimeout, Dst: &cfg.RepoGCTimeout, Name: "repogc_timeout"},
|
|
)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return cfg.Validate()
|
|
}
|
|
|
|
// ToJSON generates a human-friendly JSON representation of this Config.
|
|
func (cfg *Config) ToJSON() (raw []byte, err error) {
|
|
jcfg, err := cfg.toJSONConfig()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
raw, err = config.DefaultJSONMarshal(jcfg)
|
|
return
|
|
}
|
|
|
|
func (cfg *Config) toJSONConfig() (jcfg *jsonConfig, err error) {
|
|
// Multiaddress String() may panic
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
err = fmt.Errorf("%s", r)
|
|
}
|
|
}()
|
|
|
|
jcfg = &jsonConfig{}
|
|
|
|
// Set all configuration fields
|
|
jcfg.NodeMultiaddress = cfg.NodeAddr.String()
|
|
jcfg.ConnectSwarmsDelay = cfg.ConnectSwarmsDelay.String()
|
|
jcfg.IPFSRequestTimeout = cfg.IPFSRequestTimeout.String()
|
|
jcfg.PinTimeout = cfg.PinTimeout.String()
|
|
jcfg.UnpinTimeout = cfg.UnpinTimeout.String()
|
|
jcfg.RepoGCTimeout = cfg.RepoGCTimeout.String()
|
|
jcfg.InformerTriggerInterval = cfg.InformerTriggerInterval
|
|
jcfg.UnpinDisable = cfg.UnpinDisable
|
|
|
|
return
|
|
}
|
|
|
|
// ToDisplayJSON returns JSON config as a string.
|
|
func (cfg *Config) ToDisplayJSON() ([]byte, error) {
|
|
jcfg, err := cfg.toJSONConfig()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return config.DisplayJSON(jcfg)
|
|
}
|