in hll/hll_4update.go [25:120]
func internalHll4Update(h *hll4ArrayImpl, slotNo int, newValue int) error {
var (
actualOldValue int
shiftedNewValue int //value - curMin
curMin = h.curMin
rawStoredOldNibble = h.getNibble(slotNo) // could be 0
lb0nOldValue = rawStoredOldNibble + h.curMin // provable lower bound, could be 0
err error
)
if newValue <= lb0nOldValue {
return nil
}
// Based on whether we have an AUX_TOKEN and whether the shiftedNewValue is greater than
// AUX_TOKEN, we have four cases for how to actually modify the data structure:
// 1. (shiftedNewValue >= AUX_TOKEN) && (rawStoredOldNibble = AUX_TOKEN) //881:
// The byte array already contains aux token
// This is the case where old and new values are both exceptions.
// Therefore, the 4-bit array already is AUX_TOKEN. Only need to update auxMap
// 2. (shiftedNewValue < AUX_TOKEN) && (rawStoredOldNibble = AUX_TOKEN) //885
// This is the (hypothetical) case where old value is an exception and the new one is not,
// which is impossible given that curMin has not changed here and the newValue > oldValue.
// 3. (shiftedNewValue >= AUX_TOKEN) && (rawStoredOldNibble < AUX_TOKEN) //892
// This is the case where the old value is not an exception and the new value is.
// Therefore, the AUX_TOKEN must be stored in the 4-bit array and the new value
// added to the exception table.
// 4. (shiftedNewValue < AUX_TOKEN) && (rawStoredOldNibble < AUX_TOKEN) //897
// This is the case where neither the old value nor the new value is an exception.
// Therefore, we just overwrite the 4-bit array with the shifted new value.
if rawStoredOldNibble == auxToken { //846 Note: This is rare and really hard to test!
if h.auxHashMap == nil {
return fmt.Errorf("auxHashMap must already exist")
}
actualOldValue, err = h.auxHashMap.mustFindValueFor(slotNo)
if newValue <= actualOldValue || err != nil {
return err
}
// We know that the array will be changed, but we haven't actually updated yet.
err := h.hipAndKxQIncrementalUpdate(actualOldValue, newValue)
if err != nil {
return err
}
shiftedNewValue = newValue - curMin
if shiftedNewValue < 0 {
return fmt.Errorf("shifedNewValue < 0")
}
if shiftedNewValue >= auxToken { //CASE 1:
err := h.auxHashMap.mustReplace(slotNo, newValue)
if err != nil {
return err
}
} //else //CASE 2: impossible
} else { //rawStoredOldNibble < AUX_TOKEN
actualOldValue = lb0nOldValue
// We know that the array will be changed, but we haven't actually updated yet.
err := h.hipAndKxQIncrementalUpdate(actualOldValue, newValue)
if err != nil {
return err
}
shiftedNewValue = newValue - curMin
if shiftedNewValue < 0 {
return fmt.Errorf("shifedNewValue < 0")
}
if shiftedNewValue >= auxToken { //CASE 3: //892
h.putNibble(slotNo, auxToken)
if h.auxHashMap == nil {
h.auxHashMap = h.getNewAuxHashMap()
}
err := h.auxHashMap.mustAdd(slotNo, newValue)
if err != nil {
return err
}
} else { // CASE 4: //897
h.putNibble(slotNo, byte(shiftedNewValue))
}
}
// We just changed the HLL array, so it might be time to change curMin.
if actualOldValue == curMin {
if h.numAtCurMin < 1 {
return fmt.Errorf("h.numAtCurMin < 1")
}
h.numAtCurMin--
for h.numAtCurMin == 0 {
// Increases curMin by 1, and builds a new aux table,
// shifts values in 4-bit table, and recounts curMin.
err := shiftToBiggerCurMin(h)
if err != nil {
return err
}
}
}
return nil
}