All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.netflix.spinnaker.keel.sql.SqlDiffFingerprintRepository.kt Maven / Gradle / Ivy

There is a newer version: 1.4.1
Show newest version
/*
 *
 * Copyright 2019 Netflix, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package com.netflix.spinnaker.keel.sql

import com.netflix.spinnaker.keel.api.ResourceDiff
import com.netflix.spinnaker.keel.persistence.DiffFingerprintRepository
import com.netflix.spinnaker.keel.persistence.metamodel.Tables.DIFF_FINGERPRINT
import com.netflix.spinnaker.keel.sql.RetryCategory.READ
import com.netflix.spinnaker.keel.sql.RetryCategory.WRITE
import org.jooq.DSLContext
import org.jooq.impl.DSL.selectFrom
import java.time.Clock

class SqlDiffFingerprintRepository(
  private val jooq: DSLContext,
  private val clock: Clock,
  private val sqlRetry: SqlRetry
) : DiffFingerprintRepository {
  override fun store(entityId: String, diff: ResourceDiff<*>) {
    val hash = diff.generateHash()
    val record = sqlRetry.withRetry(READ) {
      jooq
        .select(DIFF_FINGERPRINT.COUNT, DIFF_FINGERPRINT.FIRST_DETECTION_TIME, DIFF_FINGERPRINT.HASH, DIFF_FINGERPRINT.COUNT_ACTIONS_TAKEN)
        .from(DIFF_FINGERPRINT)
        .where(DIFF_FINGERPRINT.ENTITY_ID.eq(entityId))
        .fetchOne()
    }
    record?.let { (count, firstDetectionTime, existingHash, countActionsTaken) ->
      var newCount = 1
      var newTime = clock.instant()
      var newCountActionsTaken = 0
      if (hash == existingHash) {
        newCount = count + 1
        newTime = firstDetectionTime
        newCountActionsTaken = countActionsTaken
      }
      sqlRetry.withRetry(WRITE) {
        jooq.update(DIFF_FINGERPRINT)
          .set(DIFF_FINGERPRINT.HASH, hash)
          .set(DIFF_FINGERPRINT.COUNT, newCount)
          .set(DIFF_FINGERPRINT.COUNT_ACTIONS_TAKEN, newCountActionsTaken)
          .set(DIFF_FINGERPRINT.FIRST_DETECTION_TIME, newTime)
          .where(DIFF_FINGERPRINT.ENTITY_ID.eq(entityId))
          .execute()
      }
      return
    }

    // if there's a duplicate key here we have a bigger issue - either there's something wrong with our data,
    // or multiple instances are checking the resource at the same time
    sqlRetry.withRetry(WRITE) {
      jooq.insertInto(DIFF_FINGERPRINT)
        .set(DIFF_FINGERPRINT.ENTITY_ID, entityId)
        .set(DIFF_FINGERPRINT.HASH, hash)
        .set(DIFF_FINGERPRINT.COUNT, 1)
        .set(DIFF_FINGERPRINT.COUNT_ACTIONS_TAKEN, 0)
        .set(DIFF_FINGERPRINT.FIRST_DETECTION_TIME, clock.instant())
        .execute()
    }
  }

  override fun markActionTaken(entityId: String) {
    sqlRetry.withRetry(WRITE) {
      jooq.update(DIFF_FINGERPRINT)
        .set(DIFF_FINGERPRINT.COUNT_ACTIONS_TAKEN, DIFF_FINGERPRINT.COUNT_ACTIONS_TAKEN.plus(1))
        .where(DIFF_FINGERPRINT.ENTITY_ID.eq(entityId))
        .execute()
    }
  }

  override fun diffCount(entityId: String): Int {
    val count = sqlRetry.withRetry(READ) {
      jooq
        .select(DIFF_FINGERPRINT.COUNT)
        .from(DIFF_FINGERPRINT)
        .where(DIFF_FINGERPRINT.ENTITY_ID.eq(entityId))
        .fetchOne(DIFF_FINGERPRINT.COUNT)
    }
    return count ?: 0
  }

  override fun actionTakenCount(entityId: String): Int {
    val actionCount = sqlRetry.withRetry(READ) {
      jooq
        .select(DIFF_FINGERPRINT.COUNT_ACTIONS_TAKEN)
        .from(DIFF_FINGERPRINT)
        .where(DIFF_FINGERPRINT.ENTITY_ID.eq(entityId))
        .fetchOne(DIFF_FINGERPRINT.COUNT_ACTIONS_TAKEN)
    }
    return actionCount ?: 0
  }

  override fun seen(entityId: String, diff: ResourceDiff<*>): Boolean =
    sqlRetry.withRetry(READ) {
      jooq.fetchExists(
        selectFrom(DIFF_FINGERPRINT)
          .where(DIFF_FINGERPRINT.ENTITY_ID.eq(entityId))
          .and(DIFF_FINGERPRINT.HASH.eq(diff.generateHash()))
      )
    }

  override fun clear(entityId: String) {
    sqlRetry.withRetry(WRITE) {
      jooq.deleteFrom(DIFF_FINGERPRINT)
        .where(DIFF_FINGERPRINT.ENTITY_ID.eq(entityId))
        .execute()
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy