262 lines
8.1 KiB
Go
262 lines
8.1 KiB
Go
|
// Copyright 2016 Apcera Inc. All rights reserved.
|
||
|
|
||
|
package stores
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"time"
|
||
|
|
||
|
"github.com/nats-io/gnatsd/server"
|
||
|
"github.com/nats-io/go-nats-streaming/pb"
|
||
|
"github.com/nats-io/nats-streaming-server/spb"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
// TypeMemory is the store type name for memory based stores
|
||
|
TypeMemory = "MEMORY"
|
||
|
// TypeFile is the store type name for file based stores
|
||
|
TypeFile = "FILE"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
// AllChannels allows to get state for all channels.
|
||
|
AllChannels = "*"
|
||
|
)
|
||
|
|
||
|
// Errors.
|
||
|
var (
|
||
|
ErrTooManyChannels = errors.New("too many channels")
|
||
|
ErrTooManySubs = errors.New("too many subscriptions per channel")
|
||
|
)
|
||
|
|
||
|
// Noticef logs a notice statement
|
||
|
func Noticef(format string, v ...interface{}) {
|
||
|
server.Noticef(format, v...)
|
||
|
}
|
||
|
|
||
|
// StoreLimits define limits for a store.
|
||
|
type StoreLimits struct {
|
||
|
// How many channels are allowed.
|
||
|
MaxChannels int
|
||
|
// Global limits. Any 0 value means that the limit is ignored (unlimited).
|
||
|
ChannelLimits
|
||
|
// Per-channel limits. If a limit for a channel in this map is 0,
|
||
|
// the corresponding global limit (specified above) is used.
|
||
|
PerChannel map[string]*ChannelLimits
|
||
|
}
|
||
|
|
||
|
// ChannelLimits defines limits for a given channel
|
||
|
type ChannelLimits struct {
|
||
|
// Limits for message stores
|
||
|
MsgStoreLimits
|
||
|
// Limits for subscriptions stores
|
||
|
SubStoreLimits
|
||
|
}
|
||
|
|
||
|
// MsgStoreLimits defines limits for a MsgStore.
|
||
|
// For global limits, a value of 0 means "unlimited".
|
||
|
// For per-channel limits, it means that the corresponding global
|
||
|
// limit is used.
|
||
|
type MsgStoreLimits struct {
|
||
|
// How many messages are allowed.
|
||
|
MaxMsgs int
|
||
|
// How many bytes are allowed.
|
||
|
MaxBytes int64
|
||
|
// How long messages are kept in the log (unit is seconds)
|
||
|
MaxAge time.Duration
|
||
|
}
|
||
|
|
||
|
// SubStoreLimits defines limits for a SubStore
|
||
|
type SubStoreLimits struct {
|
||
|
// How many subscriptions are allowed.
|
||
|
MaxSubscriptions int
|
||
|
}
|
||
|
|
||
|
// DefaultStoreLimits are the limits that a Store must
|
||
|
// use when none are specified to the Store constructor.
|
||
|
// Store limits can be changed with the Store.SetLimits() method.
|
||
|
var DefaultStoreLimits = StoreLimits{
|
||
|
100,
|
||
|
ChannelLimits{
|
||
|
MsgStoreLimits{
|
||
|
MaxMsgs: 1000000,
|
||
|
MaxBytes: 1000000 * 1024,
|
||
|
},
|
||
|
SubStoreLimits{
|
||
|
MaxSubscriptions: 1000,
|
||
|
},
|
||
|
},
|
||
|
nil,
|
||
|
}
|
||
|
|
||
|
// RecoveredState allows the server to reconstruct its state after a restart.
|
||
|
type RecoveredState struct {
|
||
|
Info *spb.ServerInfo
|
||
|
Clients []*Client
|
||
|
Subs RecoveredSubscriptions
|
||
|
}
|
||
|
|
||
|
// Client represents a client with ID, Heartbeat Inbox and user data sets
|
||
|
// when adding it to the store.
|
||
|
type Client struct {
|
||
|
spb.ClientInfo
|
||
|
UserData interface{}
|
||
|
}
|
||
|
|
||
|
// RecoveredSubscriptions is a map of recovered subscriptions, keyed by channel name.
|
||
|
type RecoveredSubscriptions map[string][]*RecoveredSubState
|
||
|
|
||
|
// PendingAcks is a set of message sequences waiting to be acknowledged.
|
||
|
type PendingAcks map[uint64]struct{}
|
||
|
|
||
|
// RecoveredSubState represents a recovered Subscription with a map
|
||
|
// of pending messages.
|
||
|
type RecoveredSubState struct {
|
||
|
Sub *spb.SubState
|
||
|
Pending PendingAcks
|
||
|
}
|
||
|
|
||
|
// ChannelStore contains a reference to both Subscription and Message stores.
|
||
|
type ChannelStore struct {
|
||
|
// UserData is set when the channel is created.
|
||
|
UserData interface{}
|
||
|
// Subs is the Subscriptions Store.
|
||
|
Subs SubStore
|
||
|
// Msgs is the Messages Store.
|
||
|
Msgs MsgStore
|
||
|
}
|
||
|
|
||
|
// Store is the storage interface for NATS Streaming servers.
|
||
|
//
|
||
|
// If an implementation has a Store constructor with StoreLimits, it should be
|
||
|
// noted that the limits don't apply to any state being recovered, for Store
|
||
|
// implementations supporting recovery.
|
||
|
//
|
||
|
type Store interface {
|
||
|
// Init can be used to initialize the store with server's information.
|
||
|
Init(info *spb.ServerInfo) error
|
||
|
|
||
|
// Name returns the name type of this store (e.g: MEMORY, FILESTORE, etc...).
|
||
|
Name() string
|
||
|
|
||
|
// SetLimits sets limits for this store. The action is not expected
|
||
|
// to be retroactive.
|
||
|
// The store implementation should make a deep copy as to not change
|
||
|
// the content of the structure passed by the caller.
|
||
|
// This call may return an error due to limits validation errors.
|
||
|
SetLimits(limits *StoreLimits) error
|
||
|
|
||
|
// CreateChannel creates a ChannelStore for the given channel, and returns
|
||
|
// `true` to indicate that the channel is new, false if it already exists.
|
||
|
// Limits defined for this channel in StoreLimits.PeChannel map, if present,
|
||
|
// will apply. Otherwise, the global limits in StoreLimits will apply.
|
||
|
CreateChannel(channel string, userData interface{}) (*ChannelStore, bool, error)
|
||
|
|
||
|
// LookupChannel returns a ChannelStore for the given channel, nil if channel
|
||
|
// does not exist.
|
||
|
LookupChannel(channel string) *ChannelStore
|
||
|
|
||
|
// HasChannel returns true if this store has any channel.
|
||
|
HasChannel() bool
|
||
|
|
||
|
// MsgsState returns message store statistics for a given channel, or all
|
||
|
// if 'channel' is AllChannels.
|
||
|
MsgsState(channel string) (numMessages int, byteSize uint64, err error)
|
||
|
|
||
|
// AddClient stores information about the client identified by `clientID`.
|
||
|
// If a Client is already registered, this call returns the currently
|
||
|
// registered Client object, and the boolean set to false to indicate
|
||
|
// that the client is not new.
|
||
|
AddClient(clientID, hbInbox string, userData interface{}) (*Client, bool, error)
|
||
|
|
||
|
// GetClient returns the stored Client, or nil if it does not exist.
|
||
|
GetClient(clientID string) *Client
|
||
|
|
||
|
// GetClients returns a map of all stored Client objects, keyed by client IDs.
|
||
|
// The returned map is a copy of the state maintained by the store so that
|
||
|
// it is safe for the caller to walk through the map while clients may be
|
||
|
// added/deleted from the store.
|
||
|
GetClients() map[string]*Client
|
||
|
|
||
|
// GetClientsCount returns the number of registered clients.
|
||
|
GetClientsCount() int
|
||
|
|
||
|
// DeleteClient removes the client identified by `clientID` from the store
|
||
|
// and returns it to the caller.
|
||
|
DeleteClient(clientID string) *Client
|
||
|
|
||
|
// Close closes all stores.
|
||
|
Close() error
|
||
|
}
|
||
|
|
||
|
// SubStore is the interface for storage of Subscriptions on a given channel.
|
||
|
//
|
||
|
// Implementations of this interface should not attempt to validate that
|
||
|
// a subscription is valid (that is, has not been deleted) when processing
|
||
|
// updates.
|
||
|
type SubStore interface {
|
||
|
// CreateSub records a new subscription represented by SubState. On success,
|
||
|
// it records the subscription's ID in SubState.ID. This ID is to be used
|
||
|
// by the other SubStore methods.
|
||
|
CreateSub(*spb.SubState) error
|
||
|
|
||
|
// UpdateSub updates a given subscription represented by SubState.
|
||
|
UpdateSub(*spb.SubState) error
|
||
|
|
||
|
// DeleteSub invalidates the subscription 'subid'.
|
||
|
DeleteSub(subid uint64)
|
||
|
|
||
|
// AddSeqPending adds the given message 'seqno' to the subscription 'subid'.
|
||
|
AddSeqPending(subid, seqno uint64) error
|
||
|
|
||
|
// AckSeqPending records that the given message 'seqno' has been acknowledged
|
||
|
// by the subscription 'subid'.
|
||
|
AckSeqPending(subid, seqno uint64) error
|
||
|
|
||
|
// Flush is for stores that may buffer operations and need them to be persisted.
|
||
|
Flush() error
|
||
|
|
||
|
// Close closes the subscriptions store.
|
||
|
Close() error
|
||
|
}
|
||
|
|
||
|
// MsgStore is the interface for storage of Messages on a given channel.
|
||
|
type MsgStore interface {
|
||
|
// State returns some statistics related to this store.
|
||
|
State() (numMessages int, byteSize uint64, err error)
|
||
|
|
||
|
// Store stores a message and returns the message sequence.
|
||
|
Store(data []byte) (uint64, error)
|
||
|
|
||
|
// Lookup returns the stored message with given sequence number.
|
||
|
Lookup(seq uint64) *pb.MsgProto
|
||
|
|
||
|
// FirstSequence returns sequence for first message stored, 0 if no
|
||
|
// message is stored.
|
||
|
FirstSequence() uint64
|
||
|
|
||
|
// LastSequence returns sequence for last message stored, 0 if no
|
||
|
// message is stored.
|
||
|
LastSequence() uint64
|
||
|
|
||
|
// FirstAndLastSequence returns sequences for the first and last messages stored,
|
||
|
// 0 if no message is stored.
|
||
|
FirstAndLastSequence() (uint64, uint64)
|
||
|
|
||
|
// GetSequenceFromTimestamp returns the sequence of the first message whose
|
||
|
// timestamp is greater or equal to given timestamp.
|
||
|
GetSequenceFromTimestamp(timestamp int64) uint64
|
||
|
|
||
|
// FirstMsg returns the first message stored.
|
||
|
FirstMsg() *pb.MsgProto
|
||
|
|
||
|
// LastMsg returns the last message stored.
|
||
|
LastMsg() *pb.MsgProto
|
||
|
|
||
|
// Flush is for stores that may buffer operations and need them to be persisted.
|
||
|
Flush() error
|
||
|
|
||
|
// Close closes the store.
|
||
|
Close() error
|
||
|
}
|