-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #430 from euanwm/fix/query_race_condition
fix/query race condition
- Loading branch information
Showing
4 changed files
with
87 additions
and
110 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,54 +1,68 @@ | ||
package dbtools | ||
|
||
import ( | ||
"backend/enum" | ||
"backend/structs" | ||
"sync" | ||
) | ||
|
||
type QueryState int | ||
|
||
const ( | ||
None QueryState = iota | ||
Working | ||
Completed | ||
) | ||
|
||
type QueryCache struct { | ||
Store []Query | ||
HashStore sync.Map // [structs.LeaderboardPayload]Query | ||
} | ||
|
||
type Query struct { | ||
Filter structs.LeaderboardPayload | ||
DataPositions []int | ||
Status QueryState | ||
} | ||
|
||
// AddQuery - Adds a query to the cache. | ||
func (q *QueryCache) AddQuery(query structs.LeaderboardPayload, dataPositions []int) { | ||
q.Store = append(q.Store, Query{Filter: query, DataPositions: dataPositions}) | ||
query.Start, query.Stop = 0, 0 | ||
q.HashStore.Store(query, Query{dataPositions, Completed}) | ||
} | ||
|
||
// CheckQuery - Checks if the query has been run before, if so, return the data positions. | ||
// A true value indicates that the query has been run before. | ||
// A false value indicates that the query has not been run before. | ||
// And a false value with a non-nil slice indicates that a similar query has been run before and the data positions are returned that should be used to filer from. | ||
// Hoping that the last case makes things a bit faster to reduce having to run multiple startup caching queries. | ||
func (q *QueryCache) CheckQuery(query structs.LeaderboardPayload) (bool, []int) { | ||
for _, cacheQuery := range q.Store { | ||
if cacheQuery.Filter == query { | ||
return true, cacheQuery.DataPositions | ||
} | ||
// checks for exact match | ||
if cacheQuery.Filter.SortBy == query.SortBy && cacheQuery.Filter.Federation == query.Federation && cacheQuery.Filter.WeightClass == query.WeightClass && cacheQuery.Filter.Year == query.Year { | ||
return true, cacheQuery.DataPositions | ||
func (q *QueryCache) InitQuery(query structs.LeaderboardPayload) { | ||
q.HashStore.Store(query, Query{ | ||
DataPositions: nil, | ||
Status: Working, | ||
}) | ||
} | ||
|
||
func (q *QueryCache) QueryStatus(query structs.LeaderboardPayload) QueryState { | ||
query.Start, query.Stop = 0, 0 | ||
queryStuff, ok := q.HashStore.Load(query) | ||
if !ok { | ||
return None | ||
} else { | ||
query, ok := queryStuff.(Query) | ||
if !ok { | ||
panic("how the fuck did you fuck this up?") | ||
} | ||
return query.Status | ||
} | ||
// if we get here, we haven't found a match, so we'll do some partial matching | ||
for _, cacheQuery := range q.Store { | ||
// all years for the same total/sinclair, federation and weight class | ||
if cacheQuery.Filter.SortBy == query.SortBy && cacheQuery.Filter.Federation == query.Federation && cacheQuery.Filter.WeightClass == query.WeightClass && cacheQuery.Filter.Year == enum.AllYearsStr { | ||
return false, cacheQuery.DataPositions | ||
} | ||
// all years for the same total/sinclair, federation, and all gendered weight classes | ||
if cacheQuery.Filter.SortBy == query.SortBy && cacheQuery.Filter.Federation == query.Federation && cacheQuery.Filter.Year == enum.AllYearsStr { | ||
if query.WeightClass[0] == 'M' && cacheQuery.Filter.WeightClass == "MALL" { | ||
return false, cacheQuery.DataPositions | ||
} | ||
if query.WeightClass[0] == 'F' && cacheQuery.Filter.WeightClass == "FALL" { | ||
return false, cacheQuery.DataPositions | ||
} | ||
} | ||
|
||
// CheckQuery - Checks if the query has been run before, if so, return the query state and data positions if they exist | ||
func (q *QueryCache) CheckQuery(query structs.LeaderboardPayload) (state QueryState, positions []int) { | ||
query.Start, query.Stop = 0, 0 | ||
loadedData, ok := q.HashStore.Load(query) | ||
if ok { | ||
storedQuery, ok := loadedData.(Query) | ||
if ok && (storedQuery.Status == Completed) || (storedQuery.Status == Working) { | ||
state = storedQuery.Status | ||
positions = storedQuery.DataPositions | ||
return | ||
} | ||
} | ||
return false, nil | ||
|
||
state = None | ||
positions = []int{} | ||
return state, positions | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters