sort import values stably without using sort.Stable

sort.Stable has horrible runtime -- O(n*logn*logn) -- but if we
don't use sort.Stable, our logic for ensuring that we apply the
"last" value for a given column is actually completely wrong in
the first place.
This commit is contained in:
Seebs 2021-05-19 13:12:33 -05:00
parent 7572acb450
commit 4bad5defb6
2 changed files with 26 additions and 2 deletions

8
api.go
View file

@ -1568,7 +1568,15 @@ func (api *API) ImportValueWithTx(ctx context.Context, qcx *Qcx, req *ImportValu
}
if !options.Presorted {
// horrible hackery: we implement a secondary key so we can
// get a stable sort without using sort.Stable
req.scratch = make([]int, len(req.ColumnIDs))
for i := range req.scratch {
req.scratch[i] = i
}
sort.Sort(req)
// don't keep that list around since we don't need it anymore
req.scratch = nil
}
isLocalQcx := false
if qcx == nil {

View file

@ -123,6 +123,7 @@ type ImportValueRequest struct {
TimestampValues []time.Time
StringValues []string
Clear bool
scratch []int // scratch space to allow us to get a stable sort in reasonable time
}
// AtomicRecord applies all its Ivr and Ivr atomically, in a Tx.
@ -138,8 +139,20 @@ type AtomicRecord struct {
Ir []*ImportRequest // other field types, e.g. single bit
}
func (ivr *ImportValueRequest) Len() int { return len(ivr.ColumnIDs) }
func (ivr *ImportValueRequest) Less(i, j int) bool { return ivr.ColumnIDs[i] < ivr.ColumnIDs[j] }
func (ivr *ImportValueRequest) Len() int { return len(ivr.ColumnIDs) }
func (ivr *ImportValueRequest) Less(i, j int) bool {
if ivr.ColumnIDs[i] < ivr.ColumnIDs[j] {
return true
}
if ivr.ColumnIDs[i] > ivr.ColumnIDs[j] {
return false
}
if len(ivr.scratch) > 0 {
return ivr.scratch[i] < ivr.scratch[j]
}
return false
}
func (ivr *ImportValueRequest) Swap(i, j int) {
ivr.ColumnIDs[i], ivr.ColumnIDs[j] = ivr.ColumnIDs[j], ivr.ColumnIDs[i]
if len(ivr.Values) > 0 {
@ -151,6 +164,9 @@ func (ivr *ImportValueRequest) Swap(i, j int) {
} else if len(ivr.StringValues) > 0 {
ivr.StringValues[i], ivr.StringValues[j] = ivr.StringValues[j], ivr.StringValues[i]
}
if len(ivr.scratch) > 0 {
ivr.scratch[i], ivr.scratch[j] = ivr.scratch[j], ivr.scratch[i]
}
}
// Validate ensures that the payload of the request is valid.