parameters: (send=True, destroy=False)
return_statement: return work
docstring: Use the snapshot cache files to determine a work list for this particular
      node that will help bring the cluster into sync.   If this is run in series
      on all nodes, and nothing changes, then the cluster will be in sync.  If
      it run again, then all old data will also be deleted.
  
      # How to get the number of snaps that need to be sent to a given host.
      w = storage.work_to_sync()
      z = [(h,len([x for x in w if x['dest'] ==h])) for h in storage.all_hosts()]
docstring_summary: Use the snapshot cache files to determine a work list for this particular
      node that will help bring the cluster into sync.   If this is run in series
      on all nodes, and nothing changes, then the cluster will be in sync.  If
      it run again, then all old data will also be deleted.
docstring_tokens: Use the snapshot cache files to determine a work list for this particular node that will help bring the cluster into sync . If this is run in series on all nodes and nothing changes then the cluster will be in sync . If it run again then all old data will also be deleted .
function: def work_to_sync(send=True, destroy=False):
      """
      Use the snapshot cache files to determine a work list for this particular
      node that will help bring the cluster into sync.   If this is run in series
      on all nodes, and nothing changes, then the cluster will be in sync.  If
      it run again, then all old data will also be deleted.
  
      # How to get the number of snaps that need to be sent to a given host.
      w = storage.work_to_sync()
      z = [(h,len([x for x in w if x['dest'] ==h])) for h in storage.all_hosts()]
      """
      hashring  = multi_hash_ring()
      work      = []
      cache     = global_newest_snapshots_cache()
      n = len(cache)
      i = 0
      src = ip_address()
      datacenter = hashring.datacenter_of(src)
  
      for project_id, newest in cache.iteritems():
          i += 1
  
          newest_snap = ''
          best_host = ''
  
          # first figure out what the globally newest known snapshot is
          newest_snap = max([snap for _,snap in newest.iteritems()])
  
          if newest.get(src, '') != newest_snap:
              # we don't have the newest version on this node, so there's nothing further for us to do for this project.
              continue
  
          # make a list of (host, base_snap) pairs that definitely need to be updated
          stale_hosts = [(host, newest[host]) for host, snap in newest.iteritems() if snap < newest_snap]
  
          # also, add to the list each host (as determined by consistent hashing) with no snapshot at all
          for host in hashring.locations(project_id):
              if host not in newest:   # newest is a dictionary from hosts that *have* the project to their version (newest snapshot)
                  stale_hosts.append((host,''))
  
  
          # Now make the actual work items.
          if send:
              # We take all stale hosts in the same data center as us, and at most one from each of the other data centers
              available_dcs = set(hashring.topology.keys())   # we are still allowed to take a host from these data centers
              for dest, snap in stale_hosts:
                  dc = hashring.datacenter_of(dest)
                  if dc == datacenter or dc in available_dcs:
                      work.append({'action':'send', 'project_id':project_id, 'src':src, 'dest':dest, 'snap_src':newest_snap, 'snap_dest':snap})
                      if dc != datacenter:
                          available_dcs.remove(dc)   # remember not to take any more hosts from this datacenter
  
          if destroy and len(stale_hosts) == 0:
              # Never put in any destroy work items if the project hasn't been fully replicated out first,
              # since the actual work is run in parallel, not nec. in order!  The destroys will have to happen
              # in a later pass.
              locs = set(hashring.locations(project_id))
              for h in newest:
                  if h not in locs:
                      work.append({'action':'destroy', 'project_id':project_id,  'src':h})
  
      return work
function_tokens: def work_to_sync ( send = True , destroy = False ) : hashring = multi_hash_ring ( ) work = [ ] cache = global_newest_snapshots_cache ( ) n = len ( cache ) i = 0 src = ip_address ( ) datacenter = hashring . datacenter_of ( src ) for project_id , newest in cache . iteritems ( ) : i += 1 newest_snap = '' best_host = '' # first figure out what the globally newest known snapshot is newest_snap = max ( [ snap for _ , snap in newest . iteritems ( ) ] ) if newest . get ( src , '' ) != newest_snap : # we don't have the newest version on this node, so there's nothing further for us to do for this project. continue # make a list of (host, base_snap) pairs that definitely need to be updated stale_hosts = [ ( host , newest [ host ] ) for host , snap in newest . iteritems ( ) if snap < newest_snap ] # also, add to the list each host (as determined by consistent hashing) with no snapshot at all for host in hashring . locations ( project_id ) : if host not in newest : # newest is a dictionary from hosts that *have* the project to their version (newest snapshot) stale_hosts . append ( ( host , '' ) ) # Now make the actual work items. if send : # We take all stale hosts in the same data center as us, and at most one from each of the other data centers available_dcs = set ( hashring . topology . keys ( ) ) # we are still allowed to take a host from these data centers for dest , snap in stale_hosts : dc = hashring . datacenter_of ( dest ) if dc == datacenter or dc in available_dcs : work . append ( { 'action' : 'send' , 'project_id' : project_id , 'src' : src , 'dest' : dest , 'snap_src' : newest_snap , 'snap_dest' : snap } ) if dc != datacenter : available_dcs . remove ( dc ) # remember not to take any more hosts from this datacenter if destroy and len ( stale_hosts ) == 0 : # Never put in any destroy work items if the project hasn't been fully replicated out first, # since the actual work is run in parallel, not nec. in order!  The destroys will have to happen # in a later pass. locs = set ( hashring . locations ( project_id ) ) for h in newest : if h not in locs : work . append ( { 'action' : 'destroy' , 'project_id' : project_id , 'src' : h } ) return work