Skip to content

Commit

Permalink
use a mutex to control access to the QSOList
Browse files Browse the repository at this point in the history
  • Loading branch information
ftl committed May 21, 2024
1 parent 468ba2c commit 1962afe
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 54 deletions.
2 changes: 1 addition & 1 deletion core/bandmap/bandmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func NewBandmap(clock core.Clock, settings core.Settings, dupeChecker DupeChecke
maximumAge: maximumAge,
weights: defaultWeights,

do: make(chan func()),
do: make(chan func(), 1),
closed: make(chan struct{}),
}
result.entries = NewEntries(result.countEntryValue)
Expand Down
168 changes: 115 additions & 53 deletions core/logbook/qsolist.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package logbook

import (
"log"
"sync"

"github.com/ftl/conval"
"github.com/ftl/hamradio/callsign"
Expand Down Expand Up @@ -69,11 +70,12 @@ type QSOList struct {
theirExchangeFields []core.ExchangeField
bandRule conval.BandRule

list []core.QSO
scorer QSOScorer
dupes dupeIndex
worked dupeIndex
invalid bool
dataLock *sync.RWMutex
list []core.QSO
scorer QSOScorer
dupes dupeIndex
worked dupeIndex
invalid bool

listeners []interface{}
}
Expand All @@ -83,6 +85,7 @@ func NewQSOList(settings core.Settings, scorer QSOScorer) *QSOList {
return &QSOList{
myExchangeFields: contest.MyExchangeFields,
theirExchangeFields: contest.TheirExchangeFields,
dataLock: &sync.RWMutex{},
list: make([]core.QSO, 0),
scorer: scorer,
dupes: make(dupeIndex),
Expand Down Expand Up @@ -111,50 +114,77 @@ func (l *QSOList) Valid() bool {
}

func (l *QSOList) Clear() {
l.dataLock.Lock()
l.clear()
l.dataLock.Unlock()

l.emitQSOsCleared()
}

func (l *QSOList) clear() {
l.list = make([]core.QSO, 0)
l.dupes = make(dupeIndex)
l.worked = make(dupeIndex)
l.invalid = false

l.emitQSOsCleared()
}

func (l *QSOList) Fill(qsos []core.QSO) {
l.dataLock.Lock()

l.scorer.Clear()
if len(l.list) > 0 {
l.Clear()
l.clear()
}

for _, qso := range qsos {
l.put(qso, true)
l.put(qso)
}

l.refreshScore()
for _, qso := range l.list {
allQSOs := l.all()

l.dataLock.Unlock()

l.emitQSOsCleared()
for _, qso := range allQSOs {
l.emitQSOAdded(qso)
}
}

func (l *QSOList) Put(qso core.QSO) {
l.put(qso, false)
l.dataLock.Lock()

emitNotifications := l.put(qso)

l.dataLock.Unlock()

emitNotifications()
}

func (l *QSOList) put(qso core.QSO, silent bool) {
func (l *QSOList) put(qso core.QSO) func() {
if len(l.list) == 0 {
l.append(qso, silent)
return
return l.append(qso)
}

lastNumber := l.list[len(l.list)-1].MyNumber
if qso.MyNumber > lastNumber {
l.append(qso, silent)
return
return l.append(qso)
}

index, found := l.findIndex(qso.MyNumber)
if !found {
l.insert(index, qso, silent)
return
l.insert(index, qso)
} else {
l.update(index, qso)
}
l.refreshScore()
qsos := l.all()

return func() {
l.emitQSOsCleared()
for _, qso := range qsos {
l.emitQSOAdded(qso)
}
}
l.update(index, qso, silent)
}

func (l *QSOList) findIndex(number core.QSONumber) (int, bool) {
Expand Down Expand Up @@ -182,7 +212,7 @@ func findIndex(list []core.QSO, number core.QSONumber) (int, bool) {
return low, true
}

func (l *QSOList) append(qso core.QSO, silent bool) {
func (l *QSOList) append(qso core.QSO) func() {
score := l.scorer.Add(qso)
qso.Points = score.Points
qso.Multis = score.Multis
Expand All @@ -194,34 +224,18 @@ func (l *QSOList) append(qso core.QSO, silent bool) {

l.list = append(l.list, qso)

if silent {
return
return func() {
l.emitQSOAdded(qso)
}

l.emitQSOAdded(qso)
}

func (l *QSOList) insert(index int, qso core.QSO, silent bool) {
func (l *QSOList) insert(index int, qso core.QSO) {
l.list = append(l.list[:index+1], l.list[index:]...)
l.list[index] = qso

if silent {
return
}

l.refreshScore()
l.refreshAfterUpdate()
}

func (l *QSOList) update(index int, qso core.QSO, silent bool) {
func (l *QSOList) update(index int, qso core.QSO) {
l.list[index] = qso

if silent {
return
}

l.refreshScore()
l.refreshAfterUpdate()
}

func (l *QSOList) refreshScore() {
Expand All @@ -242,13 +256,6 @@ func (l *QSOList) refreshScore() {
}
}

func (l *QSOList) refreshAfterUpdate() {
l.emitQSOsCleared()
for _, qso := range l.list {
l.emitQSOAdded(qso)
}
}

func (l *QSOList) dupeBandAndMode(band core.Band, mode core.Mode) (core.Band, core.Mode) {
switch l.bandRule {
case conval.Once:
Expand All @@ -263,22 +270,39 @@ func (l *QSOList) dupeBandAndMode(band core.Band, mode core.Mode) (core.Band, co
}

func (l *QSOList) All() []core.QSO {
return l.list
l.dataLock.RLock()
defer l.dataLock.RUnlock()

return l.all()
}

func (l *QSOList) all() []core.QSO {
result := make([]core.QSO, len(l.list))
copy(result, l.list)
return result
}

func (l *QSOList) SelectRow(index int) {
l.dataLock.RLock()

if index < 0 || index >= len(l.list) {
log.Printf("invalid QSO index %d", index)
l.dataLock.RUnlock()
return
}

qso := l.list[index]

l.dataLock.RUnlock()

l.emitQSOSelected(qso)
l.emitRowSelected(index)
}

func (l *QSOList) SelectQSO(qso core.QSO) {
l.dataLock.RLock()
index, ok := l.findIndex(qso.MyNumber)
l.dataLock.RUnlock()

if !ok {
log.Print("qso not found")
return
Expand All @@ -289,28 +313,45 @@ func (l *QSOList) SelectQSO(qso core.QSO) {
}

func (l *QSOList) SelectLastQSO() {
l.dataLock.RLock()

if len(l.list) == 0 {
l.dataLock.RUnlock()
return
}

index := len(l.list) - 1
qso := l.list[index]

l.dataLock.RUnlock()

l.emitQSOSelected(qso)
l.emitRowSelected(index)
}

func (l *QSOList) LastBandAndMode() (core.Band, core.Mode) {
l.dataLock.RLock()

if len(l.list) == 0 {
l.dataLock.RUnlock()
return core.NoBand, core.NoMode
}

index := len(l.list) - 1
qso := l.list[index]

l.dataLock.RUnlock()

return qso.Band, qso.Mode
}

func (l *QSOList) Find(callsign callsign.Callsign, band core.Band, mode core.Mode) []core.QSO {
l.dataLock.RLock()
qsos := l.all()
l.dataLock.RUnlock()

result := make([]core.QSO, 0)
for _, qso := range l.list {
for _, qso := range qsos {
if callsign != qso.Callsign {
continue
}
Expand All @@ -326,12 +367,23 @@ func (l *QSOList) Find(callsign callsign.Callsign, band core.Band, mode core.Mod
}

func (l *QSOList) FindDuplicateQSOs(callsign callsign.Callsign, band core.Band, mode core.Mode) []core.QSO {
l.dataLock.RLock()
defer l.dataLock.RUnlock()

band, mode = l.dupeBandAndMode(band, mode)
numbers := l.dupes.Get(callsign, band, mode)
return l.GetQSOs(numbers)

return l.getQSOs(numbers)
}

func (l *QSOList) GetQSOs(numbers []core.QSONumber) []core.QSO {
l.dataLock.RLock()
defer l.dataLock.RUnlock()

return l.getQSOs(numbers)
}

func (l *QSOList) getQSOs(numbers []core.QSONumber) []core.QSO {
result := make([]core.QSO, 0, len(numbers))
for _, n := range numbers {
listIndex, found := l.findIndex(n)
Expand All @@ -354,8 +406,13 @@ func (l *QSOList) GetQSOs(numbers []core.QSONumber) []core.QSO {
}

func (l *QSOList) FindWorkedQSOs(callsign callsign.Callsign, band core.Band, mode core.Mode) ([]core.QSO, bool) {
l.dataLock.RLock()

numbers := l.worked.Get(callsign, core.NoBand, core.NoMode)
qsos := l.GetQSOs(numbers)
qsos := l.getQSOs(numbers)

l.dataLock.RUnlock()

if len(qsos) == 0 {
return qsos, false
}
Expand Down Expand Up @@ -384,6 +441,7 @@ func (l *QSOList) Notify(listener interface{}) {
}

func (l *QSOList) emitQSOsCleared() {
log.Printf("QSOs cleared")
for _, listener := range l.listeners {
if qsosClearedListener, ok := listener.(QSOsClearedListener); ok {
qsosClearedListener.QSOsCleared()
Expand All @@ -392,6 +450,7 @@ func (l *QSOList) emitQSOsCleared() {
}

func (l *QSOList) emitQSOAdded(qso core.QSO) {
log.Printf("QSO added")
for _, listener := range l.listeners {
if qsoAddedListener, ok := listener.(QSOAddedListener); ok {
qsoAddedListener.QSOAdded(qso)
Expand All @@ -400,6 +459,7 @@ func (l *QSOList) emitQSOAdded(qso core.QSO) {
}

func (l *QSOList) emitQSOSelected(qso core.QSO) {
log.Printf("QSO selected")
for _, listener := range l.listeners {
if qsoSelectedListener, ok := listener.(QSOSelectedListener); ok {
qsoSelectedListener.QSOSelected(qso)
Expand All @@ -408,6 +468,7 @@ func (l *QSOList) emitQSOSelected(qso core.QSO) {
}

func (l *QSOList) emitRowSelected(index int) {
log.Printf("Row selected")
for _, listener := range l.listeners {
if rowSelectedListener, ok := listener.(RowSelectedListener); ok {
rowSelectedListener.RowSelected(index)
Expand All @@ -416,6 +477,7 @@ func (l *QSOList) emitRowSelected(index int) {
}

func (l *QSOList) emitExchangeFieldsChanged(myExchangeFields []core.ExchangeField, theirExchangeFields []core.ExchangeField) {
log.Printf("Exchange Fields changed")
for _, listener := range l.listeners {
if exchangeFieldsChangedListener, ok := listener.(ExchangeFieldsChangedListener); ok {
exchangeFieldsChangedListener.ExchangeFieldsChanged(myExchangeFields, theirExchangeFields)
Expand Down

0 comments on commit 1962afe

Please sign in to comment.