Exemplo n.º 1
0
 def capture_unique_violation(self):
     """Trigger a unique violation, return its ``exc_info`` tuple."""
     try:
         self.cause_unique_violation()
     except IntegrityError as e:
         if is_unique_violation(e):
             return sys.exc_info()
         else:
             raise
Exemplo n.º 2
0
    def _attempt_allocation_of_free_address(self,
                                            requested_address,
                                            alloc_type,
                                            user=None,
                                            subnet=None):
        """Attempt to allocate `requested_address`, which is known to be free.

        It is known to be free *in this transaction*, so this could still
        fail. If it does fail because of a `UNIQUE_VIOLATION` it will request
        a retry, except while holding an addition lock. This is not perfect:
        other threads could jump in before acquiring the lock and steal an
        apparently free address. However, in stampede situations this appears
        to be effective enough. Experiment by increasing the `count` parameter
        in `test_allocate_new_works_under_extreme_concurrency`.

        This method shares a lot in common with `_attempt_allocation` so check
        out its documentation for more details.

        :param requested_address: The address to be allocated.
        :typr requested_address: IPAddress
        :param alloc_type: Allocation type.
        :param user: Optional user.
        :return: `StaticIPAddress` if successful.
        :raise RetryTransaction: if the address was already taken.
        """
        ipaddress = StaticIPAddress(alloc_type=alloc_type, subnet=subnet)
        try:
            # Try to save this address to the database. Do this in a nested
            # transaction so that we can continue using the outer transaction
            # even if this breaks.
            with orm.savepoint():
                ipaddress.set_ip_address(requested_address.format())
                ipaddress.save()
        except IntegrityError as error:
            if orm.is_unique_violation(error):
                # The address is taken. We could allow the transaction retry
                # machinery to take care of this, but instead we'll ask it to
                # retry with the `address_allocation` lock. We can't take it
                # here because we're already in a transaction; we need to exit
                # the transaction, take the lock, and only then try again.
                orm.request_transaction_retry(locks.address_allocation)
            else:
                raise
        else:
            # We deliberately do *not* save the user until now because it
            # might result in an IntegrityError, and we rely on the latter
            # in the code above to indicate an already allocated IP
            # address and nothing else.
            ipaddress.user = user
            ipaddress.save()
            return ipaddress