Browse Source

Merge "Use dynamic lazy mode for fetching security group rules"

Zuul 1 month ago
parent
commit
1ef77b1796

+ 1
- 1
lower-constraints.txt View File

@@ -81,7 +81,7 @@ oslo.serialization==2.18.0
81 81
 oslo.service==1.24.0
82 82
 oslo.upgradecheck==0.1.0
83 83
 oslo.utils==3.33.0
84
-oslo.versionedobjects==1.31.2
84
+oslo.versionedobjects==1.35.1
85 85
 oslosphinx==4.7.0
86 86
 oslotest==3.2.0
87 87
 osprofiler==1.4.0

+ 1
- 1
neutron/db/models/securitygroup.py View File

@@ -93,7 +93,7 @@ class SecurityGroupRule(standard_attr.HasStandardAttributes, model_base.BASEV2,
93 93
     remote_ip_prefix = sa.Column(sa.String(255))
94 94
     security_group = orm.relationship(
95 95
         SecurityGroup, load_on_pending=True,
96
-        backref=orm.backref('rules', cascade='all,delete', lazy='subquery'),
96
+        backref=orm.backref('rules', cascade='all,delete', lazy='dynamic'),
97 97
         primaryjoin="SecurityGroup.id==SecurityGroupRule.security_group_id")
98 98
     source_group = orm.relationship(
99 99
         SecurityGroup,

+ 44
- 0
neutron/objects/base.py View File

@@ -55,6 +55,25 @@ def register_filter_hook_on_model(model, filter_name):
55 55
     obj_class.add_extra_filter_name(filter_name)
56 56
 
57 57
 
58
+class LazyQueryIterator(six.Iterator):
59
+    def __init__(self, obj_class, lazy_query):
60
+        self.obj_class = obj_class
61
+        self.context = None
62
+        self.query = lazy_query
63
+
64
+    def __iter__(self):
65
+        self.results = self.query.all()
66
+        self.i = 0
67
+        return self
68
+
69
+    def __next__(self):
70
+        if self.i >= len(self.results):
71
+            raise StopIteration()
72
+        item = self.obj_class._load_object(self.context, self.results[self.i])
73
+        self.i += 1
74
+        return item
75
+
76
+
58 77
 class Pager(object):
59 78
     '''Pager class
60 79
 
@@ -131,6 +150,11 @@ class NeutronObject(obj_base.VersionedObject,
131 150
     synthetic_fields = []
132 151
     extra_filter_names = set()
133 152
 
153
+    # To use lazy queries for child objects, you must set the ORM
154
+    # relationship in the db model to 'dynamic'. By default, all
155
+    # children are eager loaded.
156
+    lazy_fields = set()
157
+
134 158
     def __init__(self, context=None, **kwargs):
135 159
         super(NeutronObject, self).__init__(context, **kwargs)
136 160
         self._load_synthetic_fields = True
@@ -428,8 +452,15 @@ class NeutronDbObject(NeutronObject):
428 452
         '''Return a database model that persists object data.'''
429 453
         return self._captured_db_model
430 454
 
455
+    def _set_lazy_contexts(self, fields, context):
456
+        for field in self.lazy_fields.intersection(fields):
457
+            if isinstance(fields[field], LazyQueryIterator):
458
+                fields[field].context = context
459
+
431 460
     def from_db_object(self, db_obj):
432 461
         fields = self.modify_fields_from_db(db_obj)
462
+        if self.lazy_fields:
463
+            self._set_lazy_contexts(fields, self.obj_context)
433 464
         for field in self.fields:
434 465
             if field in fields and not self.is_synthetic(field):
435 466
                 setattr(self, field, fields[field])
@@ -459,12 +490,23 @@ class NeutronDbObject(NeutronObject):
459 490
         :param fields: dict of fields from NeutronDbObject
460 491
         :return: modified dict of fields
461 492
         """
493
+        for k, v in fields.items():
494
+            if isinstance(v, LazyQueryIterator):
495
+                fields[k] = list(v)
462 496
         result = copy.deepcopy(dict(fields))
463 497
         for field, field_db in cls.fields_need_translation.items():
464 498
             if field in result:
465 499
                 result[field_db] = result.pop(field)
466 500
         return result
467 501
 
502
+    @classmethod
503
+    def _get_lazy_iterator(cls, field, appender_query):
504
+        if field not in cls.lazy_fields:
505
+            raise KeyError(_('Field %s is not a lazy query field') % field)
506
+        n_obj_classes = NeutronObjectRegistry.obj_classes()
507
+        n_obj = n_obj_classes.get(cls.fields[field].objname)
508
+        return LazyQueryIterator(n_obj[0], appender_query)
509
+
468 510
     @classmethod
469 511
     def modify_fields_from_db(cls, db_obj):
470 512
         """Modify the fields after data were fetched from DB.
@@ -490,6 +532,8 @@ class NeutronDbObject(NeutronObject):
490 532
             # don't allow sqlalchemy lists to propagate outside
491 533
             if isinstance(v, orm.collections.InstrumentedList):
492 534
                 result[k] = list(v)
535
+            if isinstance(v, orm.dynamic.AppenderQuery):
536
+                result[k] = cls._get_lazy_iterator(k, v)
493 537
         return result
494 538
 
495 539
     @classmethod

+ 2
- 0
neutron/objects/securitygroup.py View File

@@ -60,6 +60,8 @@ class SecurityGroup(rbac_db.NeutronRbacObject):
60 60
 
61 61
     extra_filter_names = {'is_default'}
62 62
 
63
+    lazy_fields = set(['rules'])
64
+
63 65
     def create(self):
64 66
         # save is_default before super() resets it to False
65 67
         is_default = self.is_default

+ 6
- 1
neutron/tests/unit/objects/test_base.py View File

@@ -32,6 +32,7 @@ from oslo_utils import uuidutils
32 32
 from oslo_versionedobjects import base as obj_base
33 33
 from oslo_versionedobjects import exception
34 34
 from oslo_versionedobjects import fields as obj_fields
35
+from sqlalchemy import orm
35 36
 import testtools
36 37
 
37 38
 from neutron import objects
@@ -2126,7 +2127,11 @@ class BaseDbObjectTestCase(_BaseObjectTestCase,
2126 2127
             obj.update()
2127 2128
             self.assertIsNotNone(obj.db_obj)
2128 2129
             for k, v in obj.modify_fields_to_db(fields_to_update).items():
2129
-                self.assertEqual(v, obj.db_obj[k], '%s attribute differs' % k)
2130
+                if isinstance(obj.db_obj[k], orm.dynamic.AppenderQuery):
2131
+                    self.assertIsInstance(v, list)
2132
+                else:
2133
+                    self.assertEqual(v, obj.db_obj[k],
2134
+                                     '%s attribute differs' % k)
2130 2135
 
2131 2136
         obj.delete()
2132 2137
         self.assertIsNone(obj.db_obj)

+ 1
- 1
requirements.txt View File

@@ -41,7 +41,7 @@ oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
41 41
 oslo.service!=1.28.1,>=1.24.0 # Apache-2.0
42 42
 oslo.upgradecheck>=0.1.0 # Apache-2.0
43 43
 oslo.utils>=3.33.0 # Apache-2.0
44
-oslo.versionedobjects>=1.31.2 # Apache-2.0
44
+oslo.versionedobjects>=1.35.1 # Apache-2.0
45 45
 osprofiler>=1.4.0 # Apache-2.0
46 46
 os-ken >= 0.3.0 # Apache-2.0
47 47
 ovs>=2.8.0 # Apache-2.0

Loading…
Cancel
Save