Avoid archive lookup for known mapped FPs.

This commit is contained in:
beorn7 2015-05-08 16:36:46 +02:00
parent ed810b45bf
commit ac75dc2812
2 changed files with 28 additions and 25 deletions

View file

@ -72,7 +72,25 @@ func (r *fpMapper) mapFP(fp clientmodel.Fingerprint, m clientmodel.Metric) (clie
// Collision detected! // Collision detected!
return r.maybeAddMapping(fp, m) return r.maybeAddMapping(fp, m)
} }
// Metric is not in memory. Check the archive next. // Metric is not in memory. Before doing the expensive archive lookup,
// check if we have a mapping for this metric in place already.
r.mtx.RLock()
mappedFPs, fpAlreadyMapped := r.mappings[fp]
r.mtx.RUnlock()
if fpAlreadyMapped {
// We indeed have mapped fp historically.
ms := metricToUniqueString(m)
// fp is locked by the caller, so no further locking of
// 'collisions' required (it is specific to fp).
mappedFP, ok := mappedFPs[ms]
if ok {
// Historical mapping found, return the mapped FP.
return mappedFP, nil
}
}
// If we are here, FP does not exist in memory and is either not mapped
// at all, or existing mappings for FP are not for m. Check if we have
// something for FP in the archive.
archivedMetric, err := r.p.getArchivedMetric(fp) archivedMetric, err := r.p.getArchivedMetric(fp)
if err != nil { if err != nil {
return fp, err return fp, err
@ -86,24 +104,6 @@ func (r *fpMapper) mapFP(fp clientmodel.Fingerprint, m clientmodel.Metric) (clie
// Collision detected! // Collision detected!
return r.maybeAddMapping(fp, m) return r.maybeAddMapping(fp, m)
} }
// The fingerprint is genuinely new. We might have mapped it
// historically, though. so we need to check the collisions map.
r.mtx.RLock()
mappedFPs, ok := r.mappings[fp]
r.mtx.RUnlock()
if !ok {
// No historical mapping, we are good.
return fp, nil
}
// We indeed have mapped fp historically.
ms := metricToUniqueString(m)
// fp is locked by the caller, so no further locking of 'collisions'
// required (it is specific to fp).
mappedFP, ok := mappedFPs[ms]
if ok {
// Historical mapping found, return the mapped FP.
return mappedFP, nil
}
// As fp does not exist, neither in memory nor in archive, we can safely // As fp does not exist, neither in memory nor in archive, we can safely
// keep it unmapped. // keep it unmapped.
return fp, nil return fp, nil

View file

@ -367,28 +367,31 @@ func TestFPMapper(t *testing.T) {
} }
// To make sure that the mapping layer is not queried if the FP is found // To make sure that the mapping layer is not queried if the FP is found
// either in sm or in the archive, now put fp1 with cm12 in sm and fp2 // in sm but the mapping layer is queried before going to the archive,
// with cm22 into archive (which will never happen in practice as only // now put fp1 with cm12 in sm and fp2 with cm22 into archive (which
// mapped FPs are put into sm and the archive. // will never happen in practice as only mapped FPs are put into sm and
// the archive).
sm.put(fp1, &memorySeries{metric: cm12}) sm.put(fp1, &memorySeries{metric: cm12})
p.archiveMetric(fp2, cm22, 0, 0) p.archiveMetric(fp2, cm22, 0, 0)
gotFP, err = mapper.mapFP(fp1, cm12) gotFP, err = mapper.mapFP(fp1, cm12)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if wantFP := fp1; gotFP != wantFP { if wantFP := fp1; gotFP != wantFP { // No mapping happened.
t.Errorf("got fingerprint %v, want fingerprint %v", gotFP, wantFP) t.Errorf("got fingerprint %v, want fingerprint %v", gotFP, wantFP)
} }
gotFP, err = mapper.mapFP(fp2, cm22) gotFP, err = mapper.mapFP(fp2, cm22)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if wantFP := fp2; gotFP != wantFP { if wantFP := clientmodel.Fingerprint(3); gotFP != wantFP { // Old mapping still applied.
t.Errorf("got fingerprint %v, want fingerprint %v", gotFP, wantFP) t.Errorf("got fingerprint %v, want fingerprint %v", gotFP, wantFP)
} }
// If we now map cm21, we should get a mapping as the collision with the // If we now map cm21, we should get a mapping as the collision with the
// archived metric is detected. // archived metric is detected. Again, this is a pathological situation
// that must never happen in real operations. It's just staged here to
// test the expected behavior.
gotFP, err = mapper.mapFP(fp2, cm21) gotFP, err = mapper.mapFP(fp2, cm21)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)