This file is indexed.

/usr/lib/ruby/vendor_ruby/moneta/adapters/activerecord.rb is in ruby-moneta 0.7.20-2.2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
require 'active_record'
require 'thread'

module Moneta
  module Adapters
    # ActiveRecord as key/value stores
    # @api public
    class ActiveRecord
      include Defaults

      supports :create, :increment
      attr_reader :table

      @table_mutex = ::Mutex.new
      @table_refcount = {}

      class << self
        def release(table)
          @table_mutex.synchronize do
            if (@table_refcount[table] -= 1) <= 0
              remove_const(table.name.sub(/^.*::/, ''))
              @table_refcount.delete(table)
            end
          end
        end

        def get(options)
          name = 'Table_' << options.inspect.gsub(/[^\w]+/) do
            $&.unpack('H2' * $&.bytesize).join.upcase
          end
          @table_mutex.synchronize do
            table =
              if const_defined?(name)
                const_get(name)
              else
                create(name, options)
              end
            @table_refcount[table] ||= 0
            @table_refcount[table] += 1
            table
          end
        end

        private

        def create(name, options)
          table = Class.new(::ActiveRecord::Base)
          const_set(name, table)
          table.table_name = options[:table] || 'moneta'
          table.primary_key = :k

          if options[:connection]
            begin
              table.establish_connection(options[:connection])
            rescue
              tries ||= 0
              (tries += 1) < 3 ? retry : raise
            end
          end

          table.connection_pool.with_connection do |conn|
            unless table.table_exists?
              conn.create_table(table.table_name, :id => false) do |t|
                # Do not use binary key (Issue #17)
                t.string :k, :null => false
                t.binary :v
              end
              conn.add_index(table.table_name, :k, :unique => true)
            end
          end

          table
        rescue
          remove_const(name)
          raise
        end
      end

      # @param [Hash] options
      # @option options [String] :table ('moneta') Table name
      # @option options [Hash]   :connection ActiveRecord connection configuration
      def initialize(options = {})
        @table = self.class.get(options)
      end

      # (see Proxy#key?)
      def key?(key, options = {})
        @table.connection_pool.with_connection do
          !@table.where(:k => key).empty?
        end
      end

      # (see Proxy#load)
      def load(key, options = {})
        @table.connection_pool.with_connection do
          record = @table.select(:v).where(:k => key).first
          record && record.v
        end
      end

      # (see Proxy#store)
      def store(key, value, options = {})
        @table.connection_pool.with_connection do
          record = @table.select(:k).where(:k => key).first_or_initialize
          record.v = value
          record.save
          value
        end
      rescue
        tries ||= 0
        (tries += 1) < 10 ? retry : raise
      end

      # (see Proxy#delete)
      def delete(key, options = {})
        @table.connection_pool.with_connection do
          if record = @table.where(:k => key).first
            record.destroy
            record.v
          end
        end
      end

      # (see Proxy#increment)
      def increment(key, amount = 1, options = {})
        @table.connection_pool.with_connection do
          @table.transaction do
            if record = @table.where(:k => key).lock.first
              value = Utils.to_int(record.v) + amount
              record.v = value.to_s
              record.save
              value
            elsif create(key, amount.to_s, options)
              amount
            else
              raise 'Concurrent modification'
            end
          end
        end
      rescue
        tries ||= 0
        (tries += 1) < 10 ? retry : raise
      end

      # (see Proxy#create)
      def create(key, value, options = {})
        @table.connection_pool.with_connection do
          record = @table.new
          record.k = key
          record.v = value
          record.save
          true
        end
      rescue
        # FIXME: This catches too many errors
        # it should only catch a not-unique-exception
        false
      end

      # (see Proxy#clear)
      def clear(options = {})
        @table.connection_pool.with_connection do
          @table.delete_all
        end
        self
      end

      # (see Proxy#close)
      def close
        self.class.release(@table)
        @table = nil
      end
    end
  end
end