Class: Queris::Query::Op

Inherits:
Object
  • Object
show all
Defined in:
lib/queris/query/operations.rb

Overview

query operation

Direct Known Subclasses

IntersectOp, SortOp, UnionOp

Defined Under Namespace

Classes: Operand

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(fragile = false) ⇒ Op

Returns a new instance of Op.



129
130
131
132
133
134
135
# File 'lib/queris/query/operations.rb', line 129

def initialize(fragile=false)
  @operands = []
  @keys = []
  @weights = []
  @subqueries = []
  @fragile = fragile
end

Instance Attribute Details

#fragileObject

Returns the value of attribute fragile.



128
129
130
# File 'lib/queris/query/operations.rb', line 128

def fragile
  @fragile
end

#operandsObject

Returns the value of attribute operands.



128
129
130
# File 'lib/queris/query/operations.rb', line 128

def operands
  @operands
end

Instance Method Details

#commandObject



164
165
166
# File 'lib/queris/query/operations.rb', line 164

def command
  @command || self.class::COMMAND
end

#json_redis_dump(etc = {}) ⇒ Object



286
287
288
289
290
291
292
# File 'lib/queris/query/operations.rb', line 286

def json_redis_dump(etc={})
  all_ops = []
  operands.map do |op|
    all_ops.concat op.json_redis_dump(self.class::NAME)
  end
  all_ops
end

#keys(target_key = nil, first = nil) ⇒ Object



167
168
169
170
171
# File 'lib/queris/query/operations.rb', line 167

def keys(target_key=nil, first = nil)
  prepare
  @keys[0]=target_key unless target_key.nil?
  first ? @keys[1..-1] : @keys
end

#marshal_dumpObject



283
284
285
# File 'lib/queris/query/operations.rb', line 283

def marshal_dump
  [self.class::SYMBOL, operands.map {|op| op.marshal_dump}]
end

#notready!Object



152
153
154
155
# File 'lib/queris/query/operations.rb', line 152

def notready!
  @ready=nil
  self
end

#operand_key(op) ⇒ Object



244
245
246
# File 'lib/queris/query/operations.rb', line 244

def operand_key(op)
  op.index.key_for_query op.value
end

#operand_key_weight(op) ⇒ Object



179
180
181
# File 'lib/queris/query/operations.rb', line 179

def operand_key_weight(op)
  1
end

#optimize(smallkey, smallsize, page = nil) ⇒ Object



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/queris/query/operations.rb', line 195

def optimize(smallkey, smallsize, page=nil)
  #optimization walker. doesn't really do much unless given a decision block
  @optimized = nil
  operands.each do |op|
    key = op.key
    if Enumerable === key
      key.each do |k|
        yield k, op.key_size(k), op if block_given?
      end
    else
      yield key, op.key_size(key), op if block_given?
    end
    if op.optimized?
      @optimized = true
      notready!
    end
  end
  return smallkey, smallsize
end

#optimized?Boolean

Returns:

  • (Boolean)


214
215
216
# File 'lib/queris/query/operations.rb', line 214

def optimized?
  @optimized
end

#prepareObject



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/queris/query/operations.rb', line 221

def prepare
  return if @ready
  @keys, @weights, @subqueries = [:result_key], [target_key_weight], []
  operands.each do |op|
    k = block_given? ? yield(op) : op.optimized_key
    num_keys = @keys.length
    if Array === k
      @keys |= k
    else
      @keys << k
    end
    if (@keys.length - num_keys) < 0
      raise ArgumentError, "something really wrong here"
    end
    @weights += [ operand_key_weight(op) ] * (@keys.length - num_keys)
    @subqueries << op.index if Query === op.index
  end
  @ready = true
end

#push(index, val) ⇒ Object

push operand



156
157
158
159
160
# File 'lib/queris/query/operations.rb', line 156

def push(index, val) # push operand
  @ready = nil
  @operands << Operand.new(index,val)
  self
end

#query_run_stage_inspect(r, q) ⇒ Object



137
138
139
140
141
142
143
144
145
# File 'lib/queris/query/operations.rb', line 137

def query_run_stage_inspect(r, q)
  operands.each do |op|
    #this logic belongs elsewhere but is here for premature optimization
    if Queris::RangeIndex === op.index && op.index.rangehack?(op.value)
      op.index.ensure_rangehack_exists(r, op.value, q)
    end
    op.gather_key_sizes(r)
  end
end

#query_run_stage_release(r, q) ⇒ Object



146
147
148
149
150
# File 'lib/queris/query/operations.rb', line 146

def query_run_stage_release(r,q)
  operands.each do |op|
    op.index.clear_rangehack_keys if Queris::RangeIndex === op.index
  end
end

#run(redis, target, first = false, trace_callback = false) ⇒ Object



248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/queris/query/operations.rb', line 248

def run(redis, target, first=false, trace_callback=false)
  subqueries_on_slave = !subqueries.empty? && redis != Queris.redis(:master)
  
  redis.multi do |r| 
  r=redis
    if subqueries_on_slave || optimized?
      #prevent dummy result string on master from race-conditioning its way into the query

      Queris.run_script :delete_if_string, redis, subqueries.map{|s| s.key} if subqueries_on_slave
    end
    operands.each do |op| 
      op.run_optimization(redis)
      op.index.before_query_op(redis, target, op.value, op) if op.index.respond_to? :before_query_op 
      op.cleanup_optimization(redis)
    end
    unless trace_callback
      redis.send self.class::COMMAND, target, keys(target, first), :weights => weights(first)
    else
      operands.each do |operand|
        operand.split.each do |op| #ensure one key per operand
          keys = [ target, op.key ]
          weights = [target_key_weight, operand_key_weight(op)]
          if first
            keys.shift; weights.shift
            first = false
          end
          redis.send self.class::COMMAND, target, keys, :weights => weights
          trace_callback.call(self, op, target) if trace_callback
        end
      end
    end
  end
  operands.each { |op| op.index.after_query_op(redis, target, op.value, op) if op.index.respond_to? :after_query_op }
end

#subqueriesObject



191
192
193
194
# File 'lib/queris/query/operations.rb', line 191

def subqueries
  prepare
  @subqueries || []
end

#symbolObject



161
162
163
# File 'lib/queris/query/operations.rb', line 161

def symbol
  @symbol || self.class::SYMBOL
end

#target_key_weightObject



176
177
178
# File 'lib/queris/query/operations.rb', line 176

def target_key_weight
  1
end

#temp_keysObject



182
183
184
185
186
# File 'lib/queris/query/operations.rb', line 182

def temp_keys
  optimized = []
  operands.each { |op| optimized |= op.temp_keys }
  optimized
end

#temp_keys?Boolean

Returns:

  • (Boolean)


187
188
189
190
# File 'lib/queris/query/operations.rb', line 187

def temp_keys?
  operands.each { |op| return true unless op.temp_keys.empty? }
  nil
end

#to_sObject



293
294
295
# File 'lib/queris/query/operations.rb', line 293

def to_s
  "#{symbol} #{operands.map{|o| Query === o.index ? o.index : "#{o.index.name}<#{o.value}>"}.join(" #{symbol} ")}"
end

#weights(first = nil) ⇒ Object



172
173
174
175
# File 'lib/queris/query/operations.rb', line 172

def weights(first = nil)
  prepare
  first ? @weights[1..-1] : @weights
end