// mapFP takes a raw fingerprint (as returned by Metrics.FastFingerprint) and // returns a truly unique fingerprint. The caller must have locked the raw // fingerprint. // // If an error is encountered, it is returned together with the unchanged raw // fingerprint. func (m *fpMapper) mapFP(fp clientmodel.Fingerprint, metric clientmodel.Metric) (clientmodel.Fingerprint, error) { // First check if we are in the reserved FP space, in which case this is // automatically a collision that has to be mapped. if fp <= maxMappedFP { return m.maybeAddMapping(fp, metric) } // Then check the most likely case: This fp belongs to a series that is // already in memory. s, ok := m.fpToSeries.get(fp) if ok { // FP exists in memory, but is it for the same metric? if metric.Equal(s.metric) { // Yupp. We are done. return fp, nil } // Collision detected! return m.maybeAddMapping(fp, metric) } // Metric is not in memory. Before doing the expensive archive lookup, // check if we have a mapping for this metric in place already. m.mtx.RLock() mappedFPs, fpAlreadyMapped := m.mappings[fp] m.mtx.RUnlock() if fpAlreadyMapped { // We indeed have mapped fp historically. ms := metricToUniqueString(metric) // 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 := m.p.archivedMetric(fp) if err != nil { return fp, err } if archivedMetric != nil { // FP exists in archive, but is it for the same metric? if metric.Equal(archivedMetric) { // Yupp. We are done. return fp, nil } // Collision detected! return m.maybeAddMapping(fp, metric) } // As fp does not exist, neither in memory nor in archive, we can safely // keep it unmapped. return fp, nil }