Qijing,
As a simple example, let's assume that I use this schema. I realize that
it does not provide the resource provider thing that Jay talked about in
a previous (couple of weeks ago) email, but I believe that it serves to
illustrate how the generations are used.
create table resources (
resource_id varchar(36) primary key,
resource varchar(32),
generation integer
) engine=innodb;
create table allocations (
consumer_id varchar(36),
resource_id varchar(36),
amount integer,
foreign key (resource_id)
references resources(resource_id)
) engine=innodb;
I've also populated it with this sample data.
insert into resources values ('b587d300-1a94-11e6-8478-000c291e9f7b',
'memory', 3);
insert into resources values ('b587ddb1-1a94-11e6-8478-000c291e9f7b',
'cpu', 3);
insert into resources values ('b587de7d-1a94-11e6-8478-000c291e9f7b',
'disk', 3);
insert into allocations values
( '61412e76-1a95-11e6-8478-000c291e9f7b',
'b587d300-1a94-11e6-8478-000c291e9f7b', 1024 ),
( '61412e76-1a95-11e6-8478-000c291e9f7b',
'b587ddb1-1a94-11e6-8478-000c291e9f7b', 6 ),
( '61412e76-1a95-11e6-8478-000c291e9f7b',
'b587de7d-1a94-11e6-8478-000c291e9f7b',10240 ),
( '61412e76-1a95-11e6-8478-000c291e9f7b',
'b587d300-1a94-11e6-8478-000c291e9f7b', 2048 ),
( '61412e76-1a95-11e6-8478-000c291e9f7b',
'b587ddb1-1a94-11e6-8478-000c291e9f7b', 2 ),
( '61412e76-1a95-11e6-8478-000c291e9f7b',
'b587de7d-1a94-11e6-8478-000c291e9f7b', 512 ),
( 'be03c4f7-1a96-11e6-8478-000c291e9f7b',
'b587d300-1a94-11e6-8478-000c291e9f7b', 2048 ),
( 'be03c4f7-1a96-11e6-8478-000c291e9f7b',
'b587ddb1-1a94-11e6-8478-000c291e9f7b', 2 ),
( 'be03c4f7-1a96-11e6-8478-000c291e9f7b',
'b587de7d-1a94-11e6-8478-000c291e9f7b', 512 );
That gives me this as a starting point.
mysql> select distinct resource from resources;
+----------+
| resource |
+----------+
| memory |
| cpu |
| disk |
+----------+
3 rows in set (0.00 sec)
mysql> select distinct consumer_id from allocations;
+--------------------------------------+
| consumer_id |
+--------------------------------------+
| 61412e76-1a95-11e6-8478-000c291e9f7b |
| be03c4f7-1a96-11e6-8478-000c291e9f7b |
+--------------------------------------+
2 rows in set (0.00 sec)
-----
Assume that the consumer (61412e76-1a95-11e6-8478-000c291e9f7b) has a
CPU quota of 12, we can see that the user has not yet hit his quota.
mysql> select sum(amount) from resources, allocations where
resources.resource_id = allocations.resource_id and resources.resource =
'cpu' and consumer_id = '61412e76-1a95-11e6-8478-000c291e9f7b';
+-------------+
| sum(amount) |
+-------------+
| 8 |
+-------------+
1 row in set (0.00 sec)
In this situation, assume that this consumer wishes to consume two
CPU's. Here's what quota library would do.
The caller of quota library would provide something like:
consumer_id: 61412e76-1a95-11e6-8478-000c291e9f7b
resource: cpu
quota: 12
request: 2
Here's what the quota library would do.
mysql> select resources.resource_id, generation, sum(amount) from
resources, allocations where resources.resource_id =
allocations.resource_id and resources.resource = 'cpu' and consumer_id =
'61412e76-1a95-11e6-8478-000c291e9f7b' group by resources.resource_id,
generation\g
+--------------------------------------+------------+-------------+
| resource_id | generation | sum(amount) |
+--------------------------------------+------------+-------------+
| b587ddb1-1a94-11e6-8478-000c291e9f7b | 3 | 8 |
+--------------------------------------+------------+-------------+
1 row in set (0.00 sec)
-- it can now determine that the quota of 12 won't be violated by
allocating two more. So it goes ahead and does this.
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into allocations values
( '61412e76-1a95-11e6-8478-000c291e9f7b',
'b587ddb1-1a94-11e6-8478-000c291e9f7b', 2);
Query OK, 1 row affected (0.00 sec)
And then does this:
mysql> update resources set generation = generation + 1
-> where resource_id = 'b587ddb1-1a94-11e6-8478-000c291e9f7b'
-> and generation = 3;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
It observes that 1 row was matched, so the allocation succeeded and
therefore it does this.
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
-------
Assume now that consumer 'be03c4f7-1a96-11e6-8478-000c291e9f7b' with a
cpu quota of 50 comes along and wants 4 more. The library does this.
mysql> select resources.resource_id, generation, sum(amount) from
resources, allocations where resources.resource_id =
allocations.resource_id and resources.resource = 'cpu' and consumer_id =
'be03c4f7-1a96-11e6-8478-000c291e9f7b' group by resources.resource_id,
generation;
+--------------------------------------+------------+-------------+
| resource_id | generation | sum(amount) |
+--------------------------------------+------------+-------------+
| b587ddb1-1a94-11e6-8478-000c291e9f7b | 4 | 2 |
+--------------------------------------+------------+-------------+
1 row in set (0.00 sec)
Clearly the user has only two cores in use and 4 more will not violate
the quota.
Therefore the quota library does this.
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into allocations values (
-> 'be03c4f7-1a96-11e6-8478-000c291e9f7b',
-> 'b587ddb1-1a94-11e6-8478-000c291e9f7b',
-> 4);
Query OK, 1 row affected (0.00 sec)
mysql> update resources set generation = generation + 1 where
resource_id = 'b587ddb1-1a94-11e6-8478-000c291e9f7b' and generation = 4;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 0 Changed: 0 Warnings: 0
Since, in the period of time between the select of the generations and
the time when the quota library decided to finish this allocation, some
other requester had made an allocation of CPU, the query updated 0 rows.
This is an error and therefore the quota library will rollback and
retry.
mysql> rollback;
Query OK, 0 rows affected (0.01 sec)
mysql> select resources.resource_id, generation, sum(amount) from
resources, allocations where resources.resource_id =
allocations.resource_id and resources.resource = 'cpu' and consumer_id =
'be03c4f7-1a96-11e6-8478-000c291e9f7b' group by resources.resource_id,
generation;
+--------------------------------------+------------+-------------+
| resource_id | generation | sum(amount) |
+--------------------------------------+------------+-------------+
| b587ddb1-1a94-11e6-8478-000c291e9f7b | 5 | 2 |
+--------------------------------------+------------+-------------+
1 row in set (0.00 sec)
-- it sees that the generation is now 5
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into allocations values
( 'be03c4f7-1a96-11e6-8478-000c291e9f7b',
'b587ddb1-1a94-11e6-8478-000c291e9f7b', 4);
Query OK, 1 row affected (0.00 sec)
mysql> update resources set generation = generation + 1 where
resource_id = 'b587ddb1-1a94-11e6-8478-000c291e9f7b' and generation = 5;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
This time it works, 1 row was updated, so we commit.
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
Treat freeing of a resource identically. First delete rows from
allocations and in the same transaction attempt to update resources
again. If you get a row updated, commit and if no row is updated,
rollback and try again.
Hope this helps!
-amrith
On Sun, 2016-05-15 at 01:16 -0700, Qijing Li wrote:
Hi Vilobh,
Here is my thoughts on how Delimiter uses generation-id to guarantee
sequencing. Please correct me if I understand it wrong.
First, the Delimiter need to introduce another model ResourceProvider
who has two attributes:
* resource_id
* generation_id
The followings are the steps of how to consume a quota:
Step 1. Check if there is enough available quota
If yes, then get the $generation_id by querying the model
ResourceProvider with the given resource_id which is the point in time
view of resource usage.
If no, terminate the process of consuming the quota and return the
message of “No enough quotas available."
Step 2. Consume the quota.
2.1 Begin transaction
2.2 Update the QuotaUsage model: QuotaUsage.in_use =
QuotaUsage.in_use + amount of quota requested.
2.3 Get the $generation_id by querying the ResourceProvider by the
given resource_id.
If the $generation_id is larger than the $generation_id in
Step 1, then roll back transaction and GOTO step 1.
this case means there is someone else has changed the
QuotaUsage during this process.
If the $generation_id is the same as the $generation_id in
Step 1, then increase the ResourceProvider.generation_id by one and
Commit the transaction. Done!
Note: no case the $generation_id is less than the
$generation_id in Step 1 because the $generation_id is nondecreasing.
— Qijing
__________________________________________________________________________
OpenStack Development Mailing List (not for usage questions)
Unsubscribe: [email protected]?subject:unsubscribe
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
__________________________________________________________________________
OpenStack Development Mailing List (not for usage questions)
Unsubscribe: [email protected]?subject:unsubscribe
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev