<commit_before># encoding utf-8

require_relative 'bolt.rb'

module Carto
  class GhostTablesManager
    MUTEX_REDIS_KEY = 'ghost_tables_working'.freeze
    MUTEX_TTL_MS = 600000
    MAX_TABLES_FOR_SYNC_RUN = 8

    def initialize(user_id)
      @user_id = user_id
    end

    def user
      @user ||= ::User[@user_id]
    end

    def link_ghost_tables
      return if user_tables_synced_with_db?

      if safe_sync?
        link_ghost_tables_synchronously
      else
        ::Resque.enqueue(::Resque::UserDBJobs::UserDBMaintenance::LinkGhostTables, @user_id)
      end
    end

    def link_ghost_tables_synchronously
      sync_user_tables_with_db unless user_tables_synced_with_db?
    end

    private

    # determine linked tables vs cartodbfied tables consistency; i.e.: needs to run sync
    def user_tables_synced_with_db?
      user_tables = fetch_user_tables
      cartodbfied_tables = fetch_cartodbfied_tables

      user_tables.length == cartodbfied_tables.length &&
        (user_tables - cartodbfied_tables).empty? &&
        (cartodbfied_tables - user_tables).empty?
    end

    # It's nice to run sync if any unsafe stale (dropped or renamed) tables will be shown to the user but we can't block
    # the workers for more that 180 seconds
    def safe_sync?
      cartodbfied_tables = fetch_cartodbfied_tables

      dropped_and_stale_table_count = find_dropped_tables(cartodbfied_tables).count +
                                      find_stale_tables(cartodbfied_tables).count

      dropped_and_stale_table_count < MAX_TABLES_FOR_SYNC_RUN
    end

    def sync_user_tables_with_db
      bolt = Carto::Bolt.new("#{user.username}:#{MUTEX_REDIS_KEY}", ttl_ms: MUTEX_TTL_MS)

      got_locked = bolt.run_locked { sync }

      CartoDB::Logger.info(message: 'Ghost table race condition avoided', user: user) unless got_locked
    end

    def sync
      CartoDB::Logger.debug(message: 'ghost tables', action: 'linkage start', user: user)

      cartodbfied_tables = fetch_cartodbfied_tables

      # Update table_id on UserTables with physical tables with changed oid. Should go first.
      find_regenerated_tables(cartodbfied_tables).each(&:regenerate_user_table)

      # Relink tables that have been renamed through the SQL API<commit_msg>rename method and change checks<commit_after># encoding utf-8

require_relative 'bolt.rb'

module Carto
  class GhostTablesManager
    MUTEX_REDIS_KEY = 'ghost_tables_working'.freeze
    MUTEX_TTL_MS = 600000
    MAX_TABLES_FOR_SYNC_RUN = 8

    def initialize(user_id)
      @user_id = user_id
    end

    def user
      @user ||= ::User[@user_id]
    end

    def link_ghost_tables
      return if user_tables_synced_with_db?

      if safe_sync?
        link_ghost_tables_synchronously
      else
        ::Resque.enqueue(::Resque::UserDBJobs::UserDBMaintenance::LinkGhostTables, @user_id)
      end
    end

    def link_ghost_tables_synchronously
      sync_user_tables_with_db unless user_tables_synced_with_db?
    end

    private

    # determine linked tables vs cartodbfied tables consistency; i.e.: needs to run sync
    def user_tables_synced_with_db?
      user_tables = fetch_user_tables
      cartodbfied_tables = fetch_cartodbfied_tables

      user_tables.length == cartodbfied_tables.length &&
        (user_tables - cartodbfied_tables).empty? &&
        (cartodbfied_tables - user_tables).empty?
    end

    # It's nice to run sync if any unsafe stale (dropped or renamed) tables will be shown to the user but we can't block
    # the workers for more that 180 seconds
    def should_run_synchronously?
      cartodbfied_tables = fetch_cartodbfied_tables

      dropped_and_stale_table_count = find_dropped_tables(cartodbfied_tables).count +
                                      find_stale_tables(cartodbfied_tables).count

      dropped_and_stale_table_count != 0 && dropped_and_stale_table_count < MAX_TABLES_FOR_SYNC_RUN
    end

    def sync_user_tables_with_db
      bolt = Carto::Bolt.new("#{user.username}:#{MUTEX_REDIS_KEY}", ttl_ms: MUTEX_TTL_MS)

      got_locked = bolt.run_locked { sync }

      CartoDB::Logger.info(message: 'Ghost table race condition avoided', user: user) unless got_locked
    end

    def sync
      CartoDB::Logger.debug(message: 'ghost tables', action: 'linkage start', user: user)

      cartodbfied_tables = fetch_cartodbfied_tables

      # Update table_id on UserTables with physical tables with changed oid. Should go first.
      find_regenerated_tables(cartodbfied_tables).each(&:regenerate_user_table)

      # Relink tables that have been renamed through the SQL API
{'fraction_non_alphanumeric': 0.06438981944746573, 'fraction_numerical': 0.005003262997607135, 'mean_word_length': 3.3915950334288443, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5429225', 'n_tokens_mistral': 1521, 'n_tokens_neox': 1462, 'n_words': 337}