@@ -442,7 +442,10 @@ func (db *BoltStore) DeleteReservedSessions(_ context.Context) error {
442442 return err
443443 }
444444
445- return sessionBucket .ForEach (func (k , v []byte ) error {
445+ // We create a copy of the sessions to delete so that we are
446+ // not iterating and modifying the bucket at the same time.
447+ var sessionsToDelete []* Session
448+ err = sessionBucket .ForEach (func (k , v []byte ) error {
446449 // We'll also get buckets here, skip those (identified
447450 // by nil value).
448451 if v == nil {
@@ -458,69 +461,120 @@ func (db *BoltStore) DeleteReservedSessions(_ context.Context) error {
458461 return nil
459462 }
460463
461- err = sessionBucket .Delete (k )
462- if err != nil {
463- return err
464- }
464+ sessionsToDelete = append (sessionsToDelete , session )
465465
466- idIndexBkt := sessionBucket .Bucket (idIndexKey )
467- if idIndexBkt == nil {
468- return ErrDBInitErr
469- }
466+ return nil
467+ })
468+ if err != nil {
469+ return err
470+ }
470471
471- // Delete the entire session ID bucket.
472- err = idIndexBkt . DeleteBucket ( session . ID [:])
473- if err != nil {
472+ for _ , session := range sessionsToDelete {
473+ if err := deleteSession ( sessionBucket ,
474+ session ); err != nil {
474475 return err
475476 }
477+ }
476478
477- groupIdIndexBkt := sessionBucket .Bucket (groupIDIndexKey )
478- if groupIdIndexBkt == nil {
479- return ErrDBInitErr
480- }
479+ return nil
480+ })
481+ }
481482
482- groupBkt := groupIdIndexBkt .Bucket (session .GroupID [:])
483- if groupBkt == nil {
484- return ErrDBInitErr
485- }
483+ // deleteSession deletes all the parts of a session from the database. This
484+ // assumes that the session has already been fetched from the db.
485+ func deleteSession (sessionBucket * bbolt.Bucket , session * Session ) error {
486+ sessionKey := getSessionKey (session )
487+ err := sessionBucket .Delete (sessionKey )
488+ if err != nil {
489+ return err
490+ }
486491
487- sessionIDsBkt := groupBkt .Bucket (sessionIDKey )
488- if sessionIDsBkt == nil {
489- return ErrDBInitErr
490- }
492+ idIndexBkt := sessionBucket .Bucket (idIndexKey )
493+ if idIndexBkt == nil {
494+ return ErrDBInitErr
495+ }
491496
492- var (
493- seqKey []byte
494- numSessions int
495- )
496- err = sessionIDsBkt .ForEach (func (k , v []byte ) error {
497- numSessions ++
497+ // Delete the entire session ID bucket.
498+ err = idIndexBkt .DeleteBucket (session .ID [:])
499+ if err != nil {
500+ return err
501+ }
498502
499- if ! bytes .Equal (v , session .ID [:]) {
500- return nil
501- }
503+ groupIdIndexBkt := sessionBucket .Bucket (groupIDIndexKey )
504+ if groupIdIndexBkt == nil {
505+ return ErrDBInitErr
506+ }
502507
503- seqKey = k
508+ groupBkt := groupIdIndexBkt .Bucket (session .GroupID [:])
509+ if groupBkt == nil {
510+ return ErrDBInitErr
511+ }
504512
505- return nil
506- })
507- if err != nil {
508- return err
509- }
513+ sessionIDsBkt := groupBkt .Bucket (sessionIDKey )
514+ if sessionIDsBkt == nil {
515+ return ErrDBInitErr
516+ }
510517
511- if numSessions == 0 {
512- return fmt .Errorf ("no sessions found for " +
513- "group ID %x" , session .GroupID )
514- }
518+ var (
519+ seqKey []byte
520+ numSessions int
521+ )
522+ err = sessionIDsBkt .ForEach (func (k , v []byte ) error {
523+ numSessions ++
515524
516- if numSessions == 1 {
517- // Delete the whole group bucket.
518- return groupBkt .DeleteBucket (sessionIDKey )
519- }
525+ if ! bytes .Equal (v , session .ID [:]) {
526+ return nil
527+ }
520528
521- // Else, delete just the session ID entry.
522- return sessionIDsBkt .Delete (seqKey )
523- })
529+ seqKey = k
530+
531+ return nil
532+ })
533+ if err != nil {
534+ return err
535+ }
536+
537+ if numSessions == 0 {
538+ return fmt .Errorf ("no sessions found for " +
539+ "group ID %x" , session .GroupID )
540+ }
541+
542+ if numSessions == 1 {
543+ // If this is the last session in the group, we can delete the
544+ // whole group bucket.
545+ return groupIdIndexBkt .DeleteBucket (session .GroupID [:])
546+ }
547+
548+ // Else, delete just the session ID entry from the group.
549+ return sessionIDsBkt .Delete (seqKey )
550+ }
551+
552+ // DeleteReservedSession removes a given session that is in the reserved state
553+ // from the database.
554+ //
555+ // NOTE: This is part of the Store interface.
556+ func (db * BoltStore ) DeleteReservedSession (_ context.Context , id ID ) error {
557+ return db .Update (func (tx * bbolt.Tx ) error {
558+ sessionBucket , err := getBucket (tx , sessionBucketKey )
559+ if err != nil {
560+ return err
561+ }
562+
563+ // We'll first get the session to make sure it's actually in the
564+ // reserved state before deleting. This gives us a slightly
565+ // better error message than just trying to delete and getting a
566+ // "not found" if the session was in another state.
567+ session , err := getSessionByID (sessionBucket , id )
568+ if err != nil {
569+ return err
570+ }
571+
572+ if session .State != StateReserved {
573+ return fmt .Errorf ("session not in reserved state, is " +
574+ "%v" , session .State )
575+ }
576+
577+ return deleteSession (sessionBucket , session )
524578 })
525579}
526580
0 commit comments