Class: Puppet::Transaction::Relationship_graph_wrapper

Inherits:
Object
  • Object
show all
Defined in:
lib/vendor/puppet/transaction.rb

Overview

We want to monitor changes in the relationship graph of our catalog but this is complicated by the fact that the catalog both is_a graph and has_a graph, by the fact that changes to the structure of the object can have adverse serialization effects, by threading issues, by order-of-initialization issues, etc.

Since the proper lifetime/scope of the monitoring is a transaction and the transaction is already commiting a mild law-of-demeter transgression, we cut the Gordian knot here by simply wrapping the transaction’s view of the resource graph to capture and maintain the information we need. Nothing outside the transaction needs this information, and nothing outside the transaction can see it except via the Transaction#relationship_graph

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(real_graph, transaction) ⇒ Relationship_graph_wrapper

Returns a new instance of Relationship_graph_wrapper.



312
313
314
315
316
317
318
319
320
321
# File 'lib/vendor/puppet/transaction.rb', line 312

def initialize(real_graph,transaction)
  @real_graph = real_graph
  @transaction = transaction
  @ready = Puppet::RbTreeMap.new
  @generated = {}
  @done = {}
  @blockers = {}
  @unguessable_deterministic_key = Hash.new { |h,k| h[k] = Digest::SHA1.hexdigest("NaCl, MgSO4 (salts) and then #{k.ref}") }
  @providerless_types = []
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(*args, &block) ⇒ Object



322
323
324
# File 'lib/vendor/puppet/transaction.rb', line 322

def method_missing(*args,&block)
  real_graph.send(*args,&block)
end

Instance Attribute Details

#blockersObject (readonly)

Returns the value of attribute blockers.



311
312
313
# File 'lib/vendor/puppet/transaction.rb', line 311

def blockers
  @blockers
end

#doneObject (readonly)

Returns the value of attribute done.



311
312
313
# File 'lib/vendor/puppet/transaction.rb', line 311

def done
  @done
end

#generatedObject (readonly)

Returns the value of attribute generated.



311
312
313
# File 'lib/vendor/puppet/transaction.rb', line 311

def generated
  @generated
end

#readyObject (readonly)

Returns the value of attribute ready.



311
312
313
# File 'lib/vendor/puppet/transaction.rb', line 311

def ready
  @ready
end

#real_graphObject (readonly)

Returns the value of attribute real_graph.



311
312
313
# File 'lib/vendor/puppet/transaction.rb', line 311

def real_graph
  @real_graph
end

#transactionObject (readonly)

Returns the value of attribute transaction.



311
312
313
# File 'lib/vendor/puppet/transaction.rb', line 311

def transaction
  @transaction
end

#unguessable_deterministic_keyObject (readonly)

Returns the value of attribute unguessable_deterministic_key.



311
312
313
# File 'lib/vendor/puppet/transaction.rb', line 311

def unguessable_deterministic_key
  @unguessable_deterministic_key
end

Instance Method Details

#add_edge(f, t, label = nil) ⇒ Object



328
329
330
331
332
333
334
# File 'lib/vendor/puppet/transaction.rb', line 328

def add_edge(f,t,label=nil)
  key = unguessable_deterministic_key[t]

  ready.delete(key)

  real_graph.add_edge(f,t,label)
end

#add_vertex(v) ⇒ Object



325
326
327
# File 'lib/vendor/puppet/transaction.rb', line 325

def add_vertex(v)
  real_graph.add_vertex(v)
end

#enqueue(*resources) ⇒ Object



353
354
355
356
357
358
# File 'lib/vendor/puppet/transaction.rb', line 353

def enqueue(*resources)
  resources.each do |resource|
    key = unguessable_deterministic_key[resource]
    ready[key] = resource
  end
end

#enqueue_rootsObject

Enqueue the initial set of resources, those with no dependencies.



336
337
338
339
340
341
# File 'lib/vendor/puppet/transaction.rb', line 336

def enqueue_roots
  vertices.each do |v|
    blockers[v] = direct_dependencies_of(v).length
    enqueue(v) if blockers[v] == 0
  end
end

#fail_unsuitable_resources(resources) ⇒ Object



411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
# File 'lib/vendor/puppet/transaction.rb', line 411

def fail_unsuitable_resources(resources)
  resources.each do |resource|
    # We don't automatically assign unsuitable providers, so if there
    # is one, it must have been selected by the user.
    if resource.provider
      resource.err "Provider #{resource.provider.class.name} is not functional on this host"
    else
      @providerless_types << resource.type
    end

    transaction.resource_status(resource).failed = true

    finish(resource)
  end
end

#finish(resource) ⇒ Object



359
360
361
362
363
364
# File 'lib/vendor/puppet/transaction.rb', line 359

def finish(resource)
  direct_dependents_of(resource).each do |v|
    enqueue(v) if unblock(v)
  end
  done[resource] = true
end

#next_resourceObject



365
366
367
# File 'lib/vendor/puppet/transaction.rb', line 365

def next_resource
  ready.delete_min
end

#traverse(&block) ⇒ Object



368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
# File 'lib/vendor/puppet/transaction.rb', line 368

def traverse(&block)
  real_graph.report_cycles_in_graph

  enqueue_roots

  deferred_resources = []

  while (resource = next_resource) && !transaction.stop_processing?
    if resource.suitable?
      made_progress = true

      transaction.prefetch_if_necessary(resource)

      # If we generated resources, we don't know what they are now
      # blocking, so we opt to recompute it, rather than try to track every
      # change that would affect the number.
      blockers.clear if transaction.eval_generate(resource)

      yield resource

      finish(resource)
    else
      deferred_resources << resource
    end

    if ready.empty? and deferred_resources.any?
      if made_progress
        enqueue(*deferred_resources)
      else
        fail_unsuitable_resources(deferred_resources)
      end

      made_progress = false
      deferred_resources = []
    end
  end

  # Just once per type. No need to punish the user.
  @providerless_types.uniq.each do |type|
    Puppet.err "Could not find a suitable provider for #{type}"
  end
end

#unblock(resource) ⇒ Object

Decrement the blocker count for the resource by 1. If the number of blockers is unknown, count them and THEN decrement by 1.



344
345
346
347
348
349
350
351
352
# File 'lib/vendor/puppet/transaction.rb', line 344

def unblock(resource)
  blockers[resource] ||= direct_dependencies_of(resource).select { |r2| !done[r2] }.length
  if blockers[resource] > 0
    blockers[resource] -= 1
  else
    resource.warning "appears to have a negative number of dependencies"
  end
  blockers[resource] <= 0
end