def handle_cross_pop_link(link):
  """ Handle a situation where the two IPs on either end of a
  link should be in different PoPs.

  - Neither has a PoP assigned
    - Assign two new PoPs, and create links:inter
  - One side has a PoP assigned
    - Assign 1 new PoP and create links:inter
  -  Both sides have a PoP assigned
    - Add it to the links:inter
  """
  r = connection.Redis()

  ip1, ip2 = link.split(":")[2:]

  with r.pipeline() as pipe:
    try:
      pipe.watch(dbkeys.ip_key(ip1))
      pipe.watch(dbkeys.ip_key(ip2))
      pop1 = dbkeys.get_pop(ip1, pipe=pipe)
      pop2 = dbkeys.get_pop(ip2, pipe=pipe)
      pipe.multi()

      if pop1 is None and pop2 is None:
        pop1 = dbkeys.setpopnumber(dbkeys.mutex_popnum(), ip1, pipe=pipe)
        pop2 = dbkeys.setpopnumber(dbkeys.mutex_popnum(), ip2, pipe=pipe)

      elif pop1 is not None and pop2 is not None:
        pass
      else:
        if pop1 is None:
          pop1 = dbkeys.setpopnumber(dbkeys.mutex_popnum(), ip1, pipe=pipe)
        else:
          pop2 = dbkeys.setpopnumber(dbkeys.mutex_popnum(), ip2, pipe=pipe)
      store_link(r, (ip1, ip2), pop1, pop2, pipe=pipe)

      pipe.execute()
      return True
    except redis.WatchError:
      return False
    finally:
      pipe.reset()
def handle_same_pop_link(link):
  """ Handle links which should belong to the same PoP

  a. Neither has a PoP assigned
    - Assign both the same pop and set links:intra
  b. One side has a PoP assigned
    - Assign the other one the existing PoP and add links:intra
  c. Both sides have a PoP assigned
    - add to delayed_job:popjoins
  """
  r = connection.Redis()

  ip1, ip2 = link.split(":")[2:]

  with r.pipeline() as pipe:
    try:
      pipe.watch(dbkeys.ip_key(ip1))
      pipe.watch(dbkeys.ip_key(ip2))
      pop1 = dbkeys.get_pop(ip1, pipe=pipe)
      pop2 = dbkeys.get_pop(ip2, pipe=pipe)
      pipe.multi()

      if pop1 is None and pop2 is None:
        pop1 = dbkeys.setpopnumber(dbkeys.mutex_popnum(), ip1, pipe=pipe)
        pipe.hset(dbkeys.ip_key(ip2), 'pop', pop1)
        pipe.sadd(dbkeys.POP.members(pop1), ip2)

        store_link(r, (ip1, ip2), pop1, pipe=pipe)
      elif pop1 is not None and pop2 is not None:
        if not r.sismember('delayed_job:popjoins:known', (pop1, pop2)):
          pipe.lpush("delayed_job:popjoins", (pop1, pop2))
          pipe.sadd('delayed_job:popjoins:known', (pop1, pop2))
      else:
        if pop1 is None:
          knownpop = pop2
          pipe.hset(dbkeys.ip_key(ip1), 'pop', knownpop)
          pipe.sadd(dbkeys.POP.members(knownpop), ip1)
        else:
          knownpop = pop1
          pipe.hset(dbkeys.ip_key(ip2), 'pop', knownpop)
          pipe.sadd(dbkeys.POP.members(knownpop), ip2)
        store_link(r, (ip1, ip2), knownpop, pipe=pipe)

      pipe.execute()
      return True
    except redis.WatchError:
      return False
    finally:
      pipe.reset()