{-# LANGUAGE OverloadedStrings #-}
{-|
Module      : Instana.SDK.Internal.Metrics.Compression
Description : Removes unchanged metrics from the sampled metrics to save
              bandwidth/CPU (JSON seralization/deserialization).
-}
module Instana.SDK.Internal.Metrics.Compression
  ( compressSample
  ) where


import           Data.HashMap.Strict                 (HashMap)
import qualified Data.HashMap.Strict                 as HashMap
import qualified Data.List                           as List
import           Data.Text                           (Text)

import           Instana.SDK.Internal.Metrics.Deltas (deltaKeyList)
import           Instana.SDK.Internal.Metrics.Sample (InstanaMetricValue (IntegralValue),
                                                      InstanaSample)


dummyMapWithKeysEligibleForDeltaComputation :: HashMap Text InstanaMetricValue
dummyMapWithKeysEligibleForDeltaComputation :: HashMap Text InstanaMetricValue
dummyMapWithKeysEligibleForDeltaComputation =
  (HashMap Text InstanaMetricValue
 -> Text -> HashMap Text InstanaMetricValue)
-> HashMap Text InstanaMetricValue
-> [Text]
-> HashMap Text InstanaMetricValue
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
List.foldl
    (\dummyMap :: HashMap Text InstanaMetricValue
dummyMap key :: Text
key -> Text
-> InstanaMetricValue
-> HashMap Text InstanaMetricValue
-> HashMap Text InstanaMetricValue
forall k v.
(Eq k, Hashable k) =>
k -> v -> HashMap k v -> HashMap k v
HashMap.insert Text
key InstanaMetricValue
dummyValue HashMap Text InstanaMetricValue
dummyMap)
    HashMap Text InstanaMetricValue
forall k v. HashMap k v
HashMap.empty
    [Text]
deltaKeyList
  where
     dummyValue :: InstanaMetricValue
dummyValue = Int -> InstanaMetricValue
IntegralValue 0


-- |Removes metric values that are identical in the both samples, also removes
-- original values for which deltas have been computed.
compressSample :: InstanaSample -> InstanaSample -> InstanaSample
compressSample :: HashMap Text InstanaMetricValue
-> HashMap Text InstanaMetricValue
-> HashMap Text InstanaMetricValue
compressSample previous :: HashMap Text InstanaMetricValue
previous next :: HashMap Text InstanaMetricValue
next =
  let
     -- step 1: remove the original metrics from which we have computed deltas,
     -- those are not used in the back end (we are only interested in the delta
     -- values of those metrics)
    deltaSourcesRemoved :: HashMap Text InstanaMetricValue
deltaSourcesRemoved =
      HashMap Text InstanaMetricValue
-> HashMap Text InstanaMetricValue
-> HashMap Text InstanaMetricValue
forall k v w.
(Eq k, Hashable k) =>
HashMap k v -> HashMap k w -> HashMap k v
HashMap.difference
        HashMap Text InstanaMetricValue
next
        HashMap Text InstanaMetricValue
dummyMapWithKeysEligibleForDeltaComputation
  in
  -- step 2: remove all values for which the value has not changed since the
  -- last sent metric payload
  (InstanaMetricValue
 -> InstanaMetricValue -> Maybe InstanaMetricValue)
-> HashMap Text InstanaMetricValue
-> HashMap Text InstanaMetricValue
-> HashMap Text InstanaMetricValue
forall k v w.
(Eq k, Hashable k) =>
(v -> w -> Maybe v) -> HashMap k v -> HashMap k w -> HashMap k v
HashMap.differenceWith InstanaMetricValue
-> InstanaMetricValue -> Maybe InstanaMetricValue
dropUnchanged HashMap Text InstanaMetricValue
deltaSourcesRemoved HashMap Text InstanaMetricValue
previous


dropUnchanged ::
  InstanaMetricValue
  -> InstanaMetricValue
  -> Maybe InstanaMetricValue
dropUnchanged :: InstanaMetricValue
-> InstanaMetricValue -> Maybe InstanaMetricValue
dropUnchanged nextValue :: InstanaMetricValue
nextValue previousValue :: InstanaMetricValue
previousValue =
  if InstanaMetricValue
nextValue InstanaMetricValue -> InstanaMetricValue -> Bool
forall a. Eq a => a -> a -> Bool
== InstanaMetricValue
previousValue then
    Maybe InstanaMetricValue
forall a. Maybe a
Nothing
  else
    InstanaMetricValue -> Maybe InstanaMetricValue
forall a. a -> Maybe a
Just InstanaMetricValue
nextValue