About db.api.project_get_network()

asked 2011-05-27 16:00:24 -0500

raphael-g gravatar image

Hi

I would like to discuss about the following method project_get_network() that I might not understand fully (method provided at the end of the message)

Let assume that boolean associate is set to true.

We look for the network associated to the project identified by project_id and if there is none, we try to associate the first free available network registered in database

I am a bit confused by the way a concurrent access is handled : I am probably missing some important thing.

In case of concurrent access between two processes, one of them is going to meet an IntegrityError. If this is the case, the request made will be exactly the same as the one made at the beginning of the method


except IntegrityError: result = session.query(models.Network).\ filter_by(project_id=project_id).\ filter_by(deleted=False).\ first()

return result


This means that we consider that a network has been associated to the project. But how can we know that this request will return something ? Everything will be fine if the two concurrent accesses were made with the same context (and thus the same project)

But what if projects proj1 and proj2 tried to associate the network simultenaously ? One of these will have no network and the function will return None

Is there something that I don't understand ?

By the way : as described in the following link ( http://stackoverflow.com/questions/1411350/locking-in-sqlalchemy (http://stackoverflow.com/questions/14...) ), could'nt we meet a case of silent failure with the lock_mode("update") instead of catching an Error ? (if we are using mysql with MyISAM tables)

Thanks for explaining me what I am missing.


@require_context def project_get_network(context, project_id, associate=True): session = get_session() result = session.query(models.Network).\ filter_by(project_id=project_id).\ filter_by(deleted=False).\ first() if not result: if not associate: return None try: return network_associate(context, project_id) except IntegrityError: # NOTE(vish): We hit this if there is a race and two # processes are attempting to allocate the # network at the same time result = session.query(models.Network).\ filter_by(project_id=project_id).\ filter_by(deleted=False).\ first() return result

@require_admin_context def network_associate(context, project_id): session = get_session() with session.begin(): network_ref = session.query(models.Network).\ filter_by(deleted=False).\ filter_by(project_id=None).\ with_lockmode('update').\ first() # NOTE(vish): if with_lockmode isn't supported, as in sqlite, # then this has concurrency issues if not network_ref: raise db.NoMoreNetworks() network_ref['project_id'] = project_id session.add(network_ref) return network_ref

edit retag flag offensive close merge delete

3 answers

Sort by ยป oldest newest most voted
0

answered 2011-05-28 12:28:59 -0500

raphael-g gravatar image

Yes it's clear. Indeed, I had not well understood when the IntegrityError was caught. Thank you for your explanation

edit flag offensive delete link more
0

answered 2011-05-28 12:29:07 -0500

raphael-g gravatar image

Thanks Vish Ishaya, that solved my question.

edit flag offensive delete link more
0

answered 2011-05-27 18:07:34 -0500

vishvananda gravatar image

The IntegrityError means that a constraint was violated, in other words that the unique constraint on project_id failed. This means that two different networks were allocated to the same project. If you allocate two networks to different projects, no constraint is validated and you will not get an Integrity Error.

The same network will not be allocated to two different projects because of the with_lockmode statement.

I hope that is clear.

Vish

On May 27, 2011, at 9:21 AM, Raphael.G wrote:

Question #159286 on OpenStack Compute (nova) changed: https://answers.launchpad.net/nova/+q...

Description changed to: Hi

I would like to discuss about the following method project_get_network() that I might not understand fully (method provided at the end of the message)

Let assume that boolean associate is set to true.

We look for the network associated to the project identified by project_id and if there is none, we try to associate the first free available network registered in database

I am a bit confused by the way a concurrent access is handled : I am probably missing some important thing.

In case of concurrent access between two processes, one of them is going to meet an IntegrityError. If this is the case, the request made will be exactly the same as the one made at the beginning of the method


except IntegrityError: result = session.query(models.Network).\ filter_by(project_id=project_id).\ filter_by(deleted=False).\ first()

return result


This means that we consider that a network has been associated to the project. But how can we know that this request will return something ? Everything will be fine if the two concurrent accesses were made with the same context (and thus the same project)

But what if projects proj1 and proj2 tried to associate the network simultenaously ? One of these will have no network and the function will return None

Is there something that I don't understand ?

By the way : as described in the following link ( http://stackoverflow.com/questions/14... ), could'nt we meet a case of silent failure with the lock_mode("update") instead of catching an Error ? (if we are using mysql with MyISAM tables)

Thanks for explaining me what I am missing.


@require_context def project_get_network(context, project_id, associate=True): session = get_session() result = session.query(models.Network).\ filter_by(project_id=project_id).\ filter_by(deleted=False).\ first() if not result: if not associate: return None try: return network_associate(context, project_id) except IntegrityError: # NOTE(vish): We hit this if there is a race and two # processes are attempting to allocate the # network at the same time result = session.query(models.Network).\ filter_by(project_id=project_id).\ filter_by(deleted=False).\ first() return result

@require_admin_context def network_associate(context, project_id): session = get_session() with session.begin(): network_ref = session.query(models.Network).\ filter_by(deleted=False).\ filter_by(project_id=None).\ with_lockmode('update').\ first() # NOTE(vish): if with_lockmode isn't supported, as in sqlite, # then this has concurrency issues if not network_ref: raise db.NoMoreNetworks() network_ref['project_id'] = project_id session.add(network_ref) return network_ref


You received this question notification because you are a ...

(more)
edit flag offensive delete link more

Get to know Ask OpenStack

Resources for moderators

Question Tools

1 follower

Stats

Asked: 2011-05-27 16:00:24 -0500

Seen: 28 times

Last updated: May 28 '11