Skip to content

Commit 49f0964

Browse files
authored
Merge pull request #215 from roadrunner-server/chore/cleanup-modernize-deps
chore: simplify, modernize (Go 1.26), update deps
2 parents c3d4cbe + 5fde268 commit 49f0964

4 files changed

Lines changed: 94 additions & 70 deletions

File tree

boltjobs/driver.go

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,10 @@ type Driver struct {
5555
log *slog.Logger
5656
pq jobs.Queue
5757
pipeline atomic.Pointer[jobs.Pipeline]
58-
cond *sync.Cond
5958

6059
listeners atomic.Uint32
61-
active *uint64
62-
delayed *uint64
60+
active atomic.Uint64
61+
delayed atomic.Uint64
6362

6463
stopCh chan struct{}
6564
}
@@ -106,10 +105,6 @@ func FromConfig(_ context.Context, tracer *sdktrace.TracerProvider, configKey st
106105
return new(bytes.Buffer)
107106
},
108107
},
109-
cond: sync.NewCond(&sync.Mutex{}),
110-
111-
delayed: new(uint64),
112-
active: new(uint64),
113108

114109
db: db,
115110
log: log,
@@ -170,10 +165,6 @@ func FromPipeline(_ context.Context, tracer *sdktrace.TracerProvider, pipeline j
170165
bPool: sync.Pool{New: func() any {
171166
return new(bytes.Buffer)
172167
}},
173-
cond: sync.NewCond(&sync.Mutex{}),
174-
175-
delayed: new(uint64),
176-
active: new(uint64),
177168

178169
db: db,
179170
log: log,
@@ -216,7 +207,7 @@ func (d *Driver) Push(ctx context.Context, job jobs.Message) error {
216207
return errors.E(op, err)
217208
}
218209

219-
atomic.AddUint64(d.delayed, 1)
210+
d.delayed.Add(1)
220211

221212
return nil
222213
}
@@ -227,7 +218,7 @@ func (d *Driver) Push(ctx context.Context, job jobs.Message) error {
227218
return errors.E(op, err)
228219
}
229220

230-
atomic.AddUint64(d.active, 1)
221+
d.active.Add(1)
231222

232223
return nil
233224
})
@@ -297,7 +288,7 @@ func (d *Driver) Pause(ctx context.Context, p string) error {
297288
d.stopCh <- struct{}{}
298289
d.stopCh <- struct{}{}
299290

300-
d.listeners.Add(^uint32(0))
291+
d.listeners.Store(0)
301292

302293
d.log.Debug("pipeline was paused", "driver", pipe.Driver(), "pipeline", pipe.Name(), "start", start, "elapsed", time.Since(start))
303294

@@ -340,9 +331,9 @@ func (d *Driver) State(ctx context.Context) (*jobs.State, error) {
340331
Pipeline: pipe.Name(),
341332
Driver: pipe.Driver(),
342333
Queue: PushBucket,
343-
Priority: uint64(pipe.Priority()), //nolint:gosec
344-
Active: int64(atomic.LoadUint64(d.active)), //nolint:gosec
345-
Delayed: int64(atomic.LoadUint64(d.delayed)), //nolint:gosec
334+
Priority: uint64(pipe.Priority()), //nolint:gosec
335+
Active: int64(d.active.Load()), //nolint:gosec
336+
Delayed: int64(d.delayed.Load()), //nolint:gosec
346337
Ready: d.listeners.Load() > 0,
347338
}, nil
348339
}
@@ -368,12 +359,26 @@ func create(db *bolt.DB) error {
368359
}
369360

370361
inQb := tx.Bucket(strToBytes(InQueueBucket))
371-
cursor := inQb.Cursor()
372-
373362
pushB := tx.Bucket(strToBytes(PushBucket))
374363

375-
for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
376-
err = pushB.Put(k, v)
364+
// Collect all in-queue entries before any deletes: deleting the
365+
// current key mid-iteration shifts the underlying inode slice and
366+
// causes cursor.Next() to skip the next entry.
367+
type kv struct{ k, v []byte }
368+
var entries []kv
369+
cur := inQb.Cursor()
370+
for k, v := cur.First(); k != nil; k, v = cur.Next() {
371+
entries = append(entries, kv{
372+
k: append([]byte(nil), k...),
373+
v: append([]byte(nil), v...),
374+
})
375+
}
376+
for _, e := range entries {
377+
err = pushB.Put(e.k, e.v)
378+
if err != nil {
379+
return errors.E(upOp, err)
380+
}
381+
err = inQb.Delete(e.k)
377382
if err != nil {
378383
return errors.E(upOp, err)
379384
}

boltjobs/item.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ type Options struct {
4444

4545
// private
4646
db *bbolt.DB
47-
active *uint64
48-
delayed *uint64
47+
active *atomic.Uint64
48+
delayed *atomic.Uint64
4949
}
5050

5151
func (i *Item) ID() string {
@@ -96,9 +96,9 @@ func (i *Item) Context() ([]byte, error) {
9696
func (i *Item) Ack() error {
9797
defer func() {
9898
if i.Options.Delay > 0 {
99-
atomic.AddUint64(i.Options.delayed, ^uint64(0))
99+
i.Options.delayed.Add(^uint64(0))
100100
} else {
101-
atomic.AddUint64(i.Options.active, ^uint64(0))
101+
i.Options.active.Add(^uint64(0))
102102
}
103103
}()
104104

@@ -234,7 +234,7 @@ func (i *Item) Respond(_ []byte, _ string) error {
234234
return nil
235235
}
236236

237-
func (i *Item) attachDB(db *bbolt.DB, active, delayed *uint64) {
237+
func (i *Item) attachDB(db *bbolt.DB, active, delayed *atomic.Uint64) {
238238
i.Options.db = db
239239
i.Options.active = active
240240
i.Options.delayed = delayed

boltjobs/listener.go

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"bytes"
55
"context"
66
"encoding/gob"
7-
"sync/atomic"
7+
"slices"
88
"time"
99

1010
bolt "go.etcd.io/bbolt"
@@ -22,7 +22,7 @@ func (d *Driver) listener() {
2222
_ = d.pq.Remove((*d.pipeline.Load()).Name())
2323
return
2424
case <-tt.C:
25-
if atomic.LoadUint64(d.active) > uint64(d.prefetch) { //nolint:gosec
25+
if d.active.Load() > uint64(d.prefetch) { //nolint:gosec
2626
time.Sleep(time.Second)
2727
continue
2828
}
@@ -105,7 +105,7 @@ func (d *Driver) listener() {
105105
}
106106

107107
d.prop.Inject(ctx, propagation.HeaderCarrier(item.headers))
108-
item.attachDB(d.db, d.active, d.delayed)
108+
item.attachDB(d.db, &d.active, &d.delayed)
109109
d.pq.Insert(item)
110110
span.End()
111111
}
@@ -137,15 +137,21 @@ func (d *Driver) delayedJobsListener() {
137137
cursor := delayB.Cursor()
138138
endDate := strToBytes(time.Now().UTC().Format(time.RFC3339))
139139

140-
for k, v := cursor.Seek(startDate); k != nil && bytes.Compare(k, endDate) <= 0; k, v = cursor.Next() {
140+
// Collect items ready to be enqueued; defer pq.Insert until after
141+
// a successful commit so that a rollback does not leave ghost
142+
// items in the in-memory queue.
143+
var ready []*Item
144+
txOk := true
145+
for k, v := cursor.Seek(startDate); k != nil && slices.Compare(k, endDate) <= 0; k, v = cursor.Next() {
141146
buf := bytes.NewReader(v)
142147
dec := gob.NewDecoder(buf)
143148

144149
item := &Item{}
145150
err = dec.Decode(item)
146151
if err != nil {
147152
d.rollback(err, tx)
148-
continue
153+
txOk = false
154+
break
149155
}
150156

151157
if item.Options.Priority == 0 {
@@ -160,33 +166,43 @@ func (d *Driver) delayedJobsListener() {
160166
err = inQb.Put(strToBytes(item.ID()), v)
161167
if err != nil {
162168
d.rollback(err, tx)
163-
continue
169+
txOk = false
170+
break
164171
}
165172
}
166173

167174
err = delayB.Delete(k)
168175
if err != nil {
169176
d.rollback(err, tx)
170-
continue
177+
txOk = false
178+
break
171179
}
172180

173-
item.attachDB(d.db, d.active, d.delayed)
174-
d.pq.Insert(item)
181+
item.attachDB(d.db, &d.active, &d.delayed)
182+
ready = append(ready, item)
183+
}
184+
185+
if !txOk {
186+
continue
175187
}
176188

177189
err = tx.Commit()
178190
if err != nil {
179191
d.rollback(err, tx)
180192
continue
181193
}
194+
195+
for _, item := range ready {
196+
d.pq.Insert(item)
197+
}
182198
}
183199
}
184200
}
185201

186202
func (d *Driver) rollback(err error, tx *bolt.Tx) {
187203
errR := tx.Rollback()
188204
if errR != nil {
189-
d.log.Error("transaction commit error, rollback failed", "error", err, "error", errR)
205+
d.log.Error("transaction commit error, rollback failed", "error", err, "rollback_error", errR)
190206
return
191207
}
192208

boltkv/driver.go

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -159,13 +159,13 @@ func (d *Driver) Get(ctx context.Context, key string) ([]byte, error) {
159159
buf := bytes.NewReader(val)
160160
decoder := gob.NewDecoder(buf)
161161

162-
var i string
162+
var i []byte
163163
err := decoder.Decode(&i)
164164
if err != nil {
165165
return errors.E(op, err)
166166
}
167167

168-
val = strToBytes(i)
168+
val = i
169169
}
170170
return nil
171171
})
@@ -423,38 +423,7 @@ func (d *Driver) startGCLoop() {
423423
for {
424424
select {
425425
case <-t.C:
426-
d.clearMu.RLock()
427-
428-
now := time.Now().UTC()
429-
d.gc.Range(func(key, value any) bool {
430-
const op = errors.Op("boltdb_plugin_gc")
431-
k := key.(string)
432-
v, err := time.Parse(time.RFC3339, value.(string))
433-
if err != nil {
434-
d.log.Error("failed to parse TTL, removing entry", "key", k, "error", err)
435-
d.gc.Delete(k)
436-
return true
437-
}
438-
439-
if now.After(v) {
440-
d.gc.Delete(k)
441-
d.log.Debug("key deleted", "key", k)
442-
err := d.DB.Update(func(tx *bolt.Tx) error {
443-
b := tx.Bucket(d.bucket)
444-
if b == nil {
445-
return errors.E(op, errors.NoSuchBucket)
446-
}
447-
return b.Delete(strToBytes(k))
448-
})
449-
if err != nil {
450-
d.log.Error("error during the gc phase of update", "error", err)
451-
return false
452-
}
453-
}
454-
return true
455-
})
456-
457-
d.clearMu.RUnlock()
426+
d.gcRun()
458427
case <-d.stop:
459428
err := d.DB.Close()
460429
if err != nil {
@@ -465,6 +434,40 @@ func (d *Driver) startGCLoop() {
465434
}
466435
}
467436

437+
func (d *Driver) gcRun() {
438+
d.clearMu.RLock()
439+
defer d.clearMu.RUnlock()
440+
441+
now := time.Now().UTC()
442+
d.gc.Range(func(key, value any) bool {
443+
const op = errors.Op("boltdb_plugin_gc")
444+
k := key.(string)
445+
v, err := time.Parse(time.RFC3339, value.(string))
446+
if err != nil {
447+
d.log.Error("failed to parse TTL, removing entry", "key", k, "error", err)
448+
d.gc.Delete(k)
449+
return true
450+
}
451+
452+
if now.After(v) {
453+
d.gc.Delete(k)
454+
d.log.Debug("key deleted", "key", k)
455+
err := d.DB.Update(func(tx *bolt.Tx) error {
456+
b := tx.Bucket(d.bucket)
457+
if b == nil {
458+
return errors.E(op, errors.NoSuchBucket)
459+
}
460+
return b.Delete(strToBytes(k))
461+
})
462+
if err != nil {
463+
d.log.Error("error during the gc phase of update", "error", err)
464+
return false
465+
}
466+
}
467+
return true
468+
})
469+
}
470+
468471
func strToBytes(data string) []byte {
469472
if data == "" {
470473
return nil

0 commit comments

Comments
 (0)