2022-10-13 15:32:25 -06:00
|
|
|
// package memstore provides a driver that reads and writes events to memory.
|
2022-08-04 21:07:10 -06:00
|
|
|
package memstore
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
|
2023-02-26 22:33:01 -07:00
|
|
|
"go.sour.is/ev"
|
|
|
|
"go.sour.is/ev/internal/lg"
|
|
|
|
"go.sour.is/ev/pkg/es/driver"
|
|
|
|
"go.sour.is/ev/pkg/es/event"
|
|
|
|
"go.sour.is/ev/pkg/locker"
|
|
|
|
"go.sour.is/ev/pkg/math"
|
2022-08-04 21:07:10 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
type state struct {
|
2022-08-09 16:23:33 -06:00
|
|
|
streams map[string]*locker.Locked[event.Events]
|
|
|
|
}
|
|
|
|
type eventLog struct {
|
|
|
|
streamID string
|
|
|
|
events *locker.Locked[event.Events]
|
2022-08-04 21:07:10 -06:00
|
|
|
}
|
|
|
|
type memstore struct {
|
|
|
|
state *locker.Locked[state]
|
|
|
|
}
|
|
|
|
|
2023-01-09 11:30:02 -07:00
|
|
|
const AppendOnly = ev.AppendOnly
|
|
|
|
const AllEvents = ev.AllEvents
|
2022-08-04 21:07:10 -06:00
|
|
|
|
2022-09-06 10:35:14 -06:00
|
|
|
func Init(ctx context.Context) error {
|
|
|
|
ctx, span := lg.Span(ctx)
|
2022-08-13 18:59:15 -06:00
|
|
|
defer span.End()
|
|
|
|
|
2023-01-09 11:30:02 -07:00
|
|
|
return ev.Register(ctx, "mem", &memstore{})
|
2022-08-04 21:07:10 -06:00
|
|
|
}
|
|
|
|
|
2022-08-09 16:23:33 -06:00
|
|
|
var _ driver.Driver = (*memstore)(nil)
|
|
|
|
|
2022-08-13 18:59:15 -06:00
|
|
|
func (memstore) Open(ctx context.Context, name string) (driver.Driver, error) {
|
2022-09-06 10:35:14 -06:00
|
|
|
_, span := lg.Span(ctx)
|
2022-08-13 18:59:15 -06:00
|
|
|
defer span.End()
|
|
|
|
|
2022-08-09 16:23:33 -06:00
|
|
|
s := &state{streams: make(map[string]*locker.Locked[event.Events])}
|
2022-08-04 21:07:10 -06:00
|
|
|
return &memstore{locker.New(s)}, nil
|
|
|
|
}
|
2022-08-09 16:23:33 -06:00
|
|
|
func (m *memstore) EventLog(ctx context.Context, streamID string) (driver.EventLog, error) {
|
2022-09-06 10:35:14 -06:00
|
|
|
ctx, span := lg.Span(ctx)
|
2022-08-13 18:59:15 -06:00
|
|
|
defer span.End()
|
|
|
|
|
2022-08-09 16:23:33 -06:00
|
|
|
el := &eventLog{streamID: streamID}
|
|
|
|
|
2022-10-30 09:18:08 -06:00
|
|
|
err := m.state.Modify(ctx, func(ctx context.Context, state *state) error {
|
2022-09-06 10:35:14 -06:00
|
|
|
_, span := lg.Span(ctx)
|
2022-08-13 18:59:15 -06:00
|
|
|
defer span.End()
|
|
|
|
|
2022-08-09 16:23:33 -06:00
|
|
|
l, ok := state.streams[streamID]
|
|
|
|
if !ok {
|
|
|
|
l = locker.New(&event.Events{})
|
|
|
|
state.streams[streamID] = l
|
|
|
|
}
|
|
|
|
el.events = l
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return el, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ driver.EventLog = (*eventLog)(nil)
|
2022-08-04 21:07:10 -06:00
|
|
|
|
|
|
|
// Append implements driver.EventStore
|
2022-08-09 16:23:33 -06:00
|
|
|
func (m *eventLog) Append(ctx context.Context, events event.Events, version uint64) (uint64, error) {
|
2022-09-06 10:35:14 -06:00
|
|
|
ctx, span := lg.Span(ctx)
|
2022-08-13 18:59:15 -06:00
|
|
|
defer span.End()
|
|
|
|
|
2022-08-09 16:23:33 -06:00
|
|
|
event.SetStreamID(m.streamID, events...)
|
|
|
|
|
2022-10-30 09:18:08 -06:00
|
|
|
return uint64(len(events)), m.events.Modify(ctx, func(ctx context.Context, stream *event.Events) error {
|
2022-11-20 10:15:51 -07:00
|
|
|
ctx, span := lg.Span(ctx)
|
2022-08-13 18:59:15 -06:00
|
|
|
defer span.End()
|
|
|
|
|
2022-09-06 10:35:14 -06:00
|
|
|
span.AddEvent(fmt.Sprintf(" %s %d", m.streamID, len(*stream)))
|
2022-08-14 10:04:15 -06:00
|
|
|
|
2022-08-09 16:23:33 -06:00
|
|
|
last := uint64(len(*stream))
|
|
|
|
if version != AppendOnly && version != last {
|
2023-01-09 11:30:02 -07:00
|
|
|
return fmt.Errorf("%w: current version wrong %d != %d", ev.ErrWrongVersion, version, last)
|
2022-08-09 16:23:33 -06:00
|
|
|
}
|
2022-08-04 21:07:10 -06:00
|
|
|
|
|
|
|
for i := range events {
|
2022-08-13 18:59:15 -06:00
|
|
|
span.AddEvent(fmt.Sprintf("read event %d of %d", i, len(events)))
|
|
|
|
|
2022-09-06 15:31:48 -06:00
|
|
|
// --- clone event
|
|
|
|
e := events[i]
|
|
|
|
b, err := event.MarshalBinary(e)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
e, err = event.UnmarshalBinary(ctx, b, e.EventMeta().Position)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// ---
|
|
|
|
|
2022-08-04 21:07:10 -06:00
|
|
|
pos := last + uint64(i) + 1
|
2022-09-06 15:31:48 -06:00
|
|
|
event.SetPosition(e, pos)
|
|
|
|
*stream = append(*stream, e)
|
2022-08-04 21:07:10 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-10-30 09:18:08 -06:00
|
|
|
// ReadOne implements readone
|
|
|
|
func (m *eventLog) ReadN(ctx context.Context, index ...uint64) (event.Events, error) {
|
2022-11-20 10:15:51 -07:00
|
|
|
ctx, span := lg.Span(ctx)
|
2022-10-30 09:18:08 -06:00
|
|
|
defer span.End()
|
|
|
|
|
|
|
|
var events event.Events
|
|
|
|
err := m.events.Modify(ctx, func(ctx context.Context, stream *event.Events) error {
|
|
|
|
var err error
|
|
|
|
|
|
|
|
events, err = readStreamN(ctx, stream, index...)
|
|
|
|
|
|
|
|
return err
|
|
|
|
})
|
|
|
|
|
|
|
|
return events, err
|
|
|
|
}
|
|
|
|
|
2022-08-04 21:07:10 -06:00
|
|
|
// Read implements driver.EventStore
|
2022-10-25 20:15:57 -06:00
|
|
|
func (m *eventLog) Read(ctx context.Context, after int64, count int64) (event.Events, error) {
|
2022-09-06 10:35:14 -06:00
|
|
|
ctx, span := lg.Span(ctx)
|
2022-08-13 18:59:15 -06:00
|
|
|
defer span.End()
|
|
|
|
|
2022-08-09 16:23:33 -06:00
|
|
|
var events event.Events
|
2022-08-04 21:07:10 -06:00
|
|
|
|
2022-10-30 09:18:08 -06:00
|
|
|
err := m.events.Modify(ctx, func(ctx context.Context, stream *event.Events) error {
|
2022-11-20 10:15:51 -07:00
|
|
|
ctx, span := lg.Span(ctx)
|
2022-08-13 18:59:15 -06:00
|
|
|
defer span.End()
|
|
|
|
|
2022-09-06 10:35:14 -06:00
|
|
|
span.AddEvent(fmt.Sprintf("%s %d", m.streamID, len(*stream)))
|
2022-08-14 10:04:15 -06:00
|
|
|
|
2022-08-09 16:23:33 -06:00
|
|
|
first := stream.First().EventMeta().Position
|
|
|
|
last := stream.Last().EventMeta().Position
|
|
|
|
// ---
|
2022-08-04 21:07:10 -06:00
|
|
|
if first == 0 || last == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-10-25 20:15:57 -06:00
|
|
|
start, count := math.PagerBox(first, last, after, count)
|
2022-08-10 10:09:58 -06:00
|
|
|
if count == 0 {
|
|
|
|
return nil
|
2022-08-04 21:07:10 -06:00
|
|
|
}
|
2022-10-25 20:15:57 -06:00
|
|
|
span.AddEvent(fmt.Sprint("box", first, last, after, count))
|
2022-08-09 16:23:33 -06:00
|
|
|
events = make([]event.Event, math.Abs(count))
|
2022-08-04 21:07:10 -06:00
|
|
|
for i := range events {
|
2022-08-13 18:59:15 -06:00
|
|
|
span.AddEvent(fmt.Sprintf("read event %d of %d", i, math.Abs(count)))
|
2022-09-06 15:31:48 -06:00
|
|
|
|
|
|
|
// --- clone event
|
2022-10-30 09:18:08 -06:00
|
|
|
var err error
|
|
|
|
events[i], err = readStream(ctx, stream, start)
|
2022-09-06 15:31:48 -06:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-08-09 16:23:33 -06:00
|
|
|
// ---
|
2022-08-04 21:07:10 -06:00
|
|
|
|
|
|
|
if count > 0 {
|
|
|
|
start += 1
|
|
|
|
} else {
|
|
|
|
start -= 1
|
|
|
|
}
|
|
|
|
if start < first || start > last {
|
|
|
|
events = events[:i+1]
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2022-09-06 15:31:48 -06:00
|
|
|
event.SetStreamID(m.streamID, events...)
|
2022-08-04 21:07:10 -06:00
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-08-09 16:23:33 -06:00
|
|
|
return events, nil
|
2022-08-04 21:07:10 -06:00
|
|
|
}
|
2022-08-07 11:55:49 -06:00
|
|
|
|
2022-08-09 16:23:33 -06:00
|
|
|
// FirstIndex for the streamID
|
|
|
|
func (m *eventLog) FirstIndex(ctx context.Context) (uint64, error) {
|
2022-11-20 10:15:51 -07:00
|
|
|
ctx, span := lg.Span(ctx)
|
2022-08-13 18:59:15 -06:00
|
|
|
defer span.End()
|
|
|
|
|
2022-08-09 16:23:33 -06:00
|
|
|
events, err := m.events.Copy(ctx)
|
|
|
|
return events.First().EventMeta().Position, err
|
2022-08-07 11:55:49 -06:00
|
|
|
}
|
|
|
|
|
2022-08-09 16:23:33 -06:00
|
|
|
// LastIndex for the streamID
|
|
|
|
func (m *eventLog) LastIndex(ctx context.Context) (uint64, error) {
|
2022-11-20 10:15:51 -07:00
|
|
|
ctx, span := lg.Span(ctx)
|
2022-08-13 18:59:15 -06:00
|
|
|
defer span.End()
|
|
|
|
|
2022-08-09 16:23:33 -06:00
|
|
|
events, err := m.events.Copy(ctx)
|
|
|
|
return events.Last().EventMeta().Position, err
|
2022-08-07 11:55:49 -06:00
|
|
|
}
|
2022-08-14 10:04:15 -06:00
|
|
|
|
|
|
|
func (m *eventLog) LoadForUpdate(ctx context.Context, a event.Aggregate, fn func(context.Context, event.Aggregate) error) (uint64, error) {
|
|
|
|
panic("not implemented")
|
|
|
|
}
|
2022-10-30 09:18:08 -06:00
|
|
|
|
|
|
|
func readStream(ctx context.Context, stream *event.Events, index uint64) (event.Event, error) {
|
2022-11-20 10:15:51 -07:00
|
|
|
ctx, span := lg.Span(ctx)
|
2022-10-30 09:18:08 -06:00
|
|
|
defer span.End()
|
|
|
|
|
|
|
|
var b []byte
|
|
|
|
var err error
|
|
|
|
e := (*stream)[index-1]
|
|
|
|
b, err = event.MarshalBinary(e)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-11-20 10:15:51 -07:00
|
|
|
e, err = event.UnmarshalBinary(ctx, b, e.EventMeta().ActualPosition)
|
2022-10-30 09:18:08 -06:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return e, err
|
|
|
|
}
|
|
|
|
func readStreamN(ctx context.Context, stream *event.Events, index ...uint64) (event.Events, error) {
|
2022-11-20 10:15:51 -07:00
|
|
|
ctx, span := lg.Span(ctx)
|
2022-10-30 09:18:08 -06:00
|
|
|
defer span.End()
|
|
|
|
|
|
|
|
var b []byte
|
|
|
|
var err error
|
|
|
|
|
|
|
|
events := make(event.Events, len(index))
|
|
|
|
for i, index := range index {
|
|
|
|
e := (*stream)[index-1]
|
|
|
|
b, err = event.MarshalBinary(e)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
events[i], err = event.UnmarshalBinary(ctx, b, e.EventMeta().Position)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return events, err
|
|
|
|
}
|