platform: preserve order of objects during dump

NMPCache can preserve the order of the objects. Until now, the order
was however arbitrary. Soon we will require to preserve the order of
routes.

During a dump, force appending new objects at the end. That ensures,
correct ordering during the dump.

Note that we track objects in several distrinct indexes. Those partition the
set of all objects. Outside a dump when receiving events about new objects (e.g.
RTM_NEWROUTE), it is very unclear at which place the new object should be sorted.
It is especially unclear, as an object might move from one partition (of
an index) to another.
In general, a deterministic order will only be useful in one particular
instance: the NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION index for routes.
In this case, we will ensure a particular order of the routes.
This commit is contained in:
Thomas Haller
2017-08-05 15:14:44 +02:00
parent 9012ae00aa
commit 94c025452b
5 changed files with 69 additions and 25 deletions

View File

@@ -311,6 +311,7 @@ link_add (NMPlatform *platform,
link_add_prepare (platform, device, (NMPObject *) device->obj); link_add_prepare (platform, device, (NMPObject *) device->obj);
cache_op = nmp_cache_update_netlink (nm_platform_get_cache (platform), cache_op = nmp_cache_update_netlink (nm_platform_get_cache (platform),
(NMPObject *) device->obj, (NMPObject *) device->obj,
FALSE,
&obj_old, &obj_new); &obj_old, &obj_new);
g_assert (cache_op == NMP_CACHE_OPS_ADDED); g_assert (cache_op == NMP_CACHE_OPS_ADDED);
nmp_object_unref (device->obj); nmp_object_unref (device->obj);
@@ -319,6 +320,7 @@ link_add (NMPlatform *platform,
link_add_prepare (platform, device_veth, (NMPObject *) device_veth->obj); link_add_prepare (platform, device_veth, (NMPObject *) device_veth->obj);
cache_op_veth = nmp_cache_update_netlink (nm_platform_get_cache (platform), cache_op_veth = nmp_cache_update_netlink (nm_platform_get_cache (platform),
(NMPObject *) device_veth->obj, (NMPObject *) device_veth->obj,
FALSE,
&obj_old_veth, &obj_new_veth); &obj_old_veth, &obj_new_veth);
g_assert (cache_op == NMP_CACHE_OPS_ADDED); g_assert (cache_op == NMP_CACHE_OPS_ADDED);
nmp_object_unref (device->obj); nmp_object_unref (device->obj);
@@ -359,6 +361,7 @@ link_add_one (NMPlatform *platform,
link_add_prepare (platform, device, (NMPObject *) device->obj); link_add_prepare (platform, device, (NMPObject *) device->obj);
cache_op = nmp_cache_update_netlink (nm_platform_get_cache (platform), cache_op = nmp_cache_update_netlink (nm_platform_get_cache (platform),
(NMPObject *) device->obj, (NMPObject *) device->obj,
FALSE,
&obj_old, &obj_new); &obj_old, &obj_new);
g_assert (cache_op == NMP_CACHE_OPS_ADDED); g_assert (cache_op == NMP_CACHE_OPS_ADDED);
nmp_object_unref (device->obj); nmp_object_unref (device->obj);
@@ -431,7 +434,9 @@ link_set_obj (NMPlatform *platform,
link_add_prepare (platform, device, obj_tmp); link_add_prepare (platform, device, obj_tmp);
cache_op = nmp_cache_update_netlink (nm_platform_get_cache (platform), cache_op = nmp_cache_update_netlink (nm_platform_get_cache (platform),
obj_tmp, &obj_old, &obj_new); obj_tmp,
FALSE,
&obj_old, &obj_new);
g_assert (NM_IN_SET (cache_op, NMP_CACHE_OPS_UNCHANGED, g_assert (NM_IN_SET (cache_op, NMP_CACHE_OPS_UNCHANGED,
NMP_CACHE_OPS_UPDATED)); NMP_CACHE_OPS_UPDATED));
g_assert (obj_old == device->obj); g_assert (obj_old == device->obj);
@@ -971,7 +976,7 @@ ipx_address_add (NMPlatform *platform, int addr_family, const NMPlatformObject *
: NMP_OBJECT_TYPE_IP6_ADDRESS, : NMP_OBJECT_TYPE_IP6_ADDRESS,
address); address);
cache_op = nmp_cache_update_netlink (cache, obj, &obj_old, &obj_new); cache_op = nmp_cache_update_netlink (cache, obj, FALSE, &obj_old, &obj_new);
nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new); nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new);
return TRUE; return TRUE;
} }
@@ -1275,7 +1280,7 @@ ip_route_add (NMPlatform *platform,
} }
} }
cache_op = nmp_cache_update_netlink (cache, obj, &obj_old, &obj_new); cache_op = nmp_cache_update_netlink (cache, obj, FALSE, &obj_old, &obj_new);
nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new); nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new);
return TRUE; return TRUE;
} }

View File

@@ -3429,9 +3429,7 @@ cache_on_change (NMPlatform *platform,
NMPCache *cache = nm_platform_get_cache (platform); NMPCache *cache = nm_platform_get_cache (platform);
ASSERT_nmp_cache_ops (cache, cache_op, obj_old, obj_new); ASSERT_nmp_cache_ops (cache, cache_op, obj_old, obj_new);
nm_assert (cache_op != NMP_CACHE_OPS_UNCHANGED);
if (cache_op == NMP_CACHE_OPS_UNCHANGED)
return;
klass = obj_old ? NMP_OBJECT_GET_CLASS (obj_old) : NMP_OBJECT_GET_CLASS (obj_new); klass = obj_old ? NMP_OBJECT_GET_CLASS (obj_old) : NMP_OBJECT_GET_CLASS (obj_new);
@@ -3892,6 +3890,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
char buf_nlmsghdr[400]; char buf_nlmsghdr[400];
gboolean id_only = FALSE; gboolean id_only = FALSE;
NMPCache *cache = nm_platform_get_cache (platform); NMPCache *cache = nm_platform_get_cache (platform);
gboolean is_dump;
msghdr = nlmsg_hdr (msg); msghdr = nlmsg_hdr (msg);
@@ -3914,8 +3913,20 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
return; return;
} }
_LOGT ("event-notification: %s: %s", switch (msghdr->nlmsg_type) {
case RTM_NEWADDR:
case RTM_NEWLINK:
case RTM_NEWROUTE:
is_dump = delayed_action_refresh_all_in_progress (platform,
delayed_action_refresh_from_object_type (NMP_OBJECT_GET_TYPE (obj)));
break;
default:
is_dump = FALSE;
}
_LOGT ("event-notification: %s%s: %s",
_nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr)), _nl_nlmsghdr_to_str (msghdr, buf_nlmsghdr, sizeof (buf_nlmsghdr)),
is_dump ? ", in-dump" : "",
nmp_object_to_string (obj, nmp_object_to_string (obj,
id_only ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC, id_only ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC,
NULL, 0)); NULL, 0));
@@ -3930,7 +3941,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
case RTM_NEWADDR: case RTM_NEWADDR:
case RTM_NEWROUTE: case RTM_NEWROUTE:
case RTM_GETLINK: case RTM_GETLINK:
cache_op = nmp_cache_update_netlink (cache, obj, &obj_old, &obj_new); cache_op = nmp_cache_update_netlink (cache, obj, is_dump, &obj_old, &obj_new);
if (cache_op != NMP_CACHE_OPS_UNCHANGED) { if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
cache_on_change (platform, cache_op, obj_old, obj_new); cache_on_change (platform, cache_op, obj_old, obj_new);
cache_post (platform, msghdr, cache_op, obj, obj_old, obj_new); cache_post (platform, msghdr, cache_op, obj, obj_old, obj_new);

View File

@@ -1792,10 +1792,11 @@ nmp_cache_lookup_link_full (const NMPCache *cache,
/*****************************************************************************/ /*****************************************************************************/
static void static void
_idxcache_update_box_move (NMPCache *cache, _idxcache_update_other_cache_ids (NMPCache *cache,
NMPCacheIdType cache_id_type, NMPCacheIdType cache_id_type,
const NMPObject *obj_old, const NMPObject *obj_old,
const NMPObject *obj_new) const NMPObject *obj_new,
gboolean is_dump)
{ {
const NMDedupMultiEntry *entry_new; const NMDedupMultiEntry *entry_new;
const NMDedupMultiEntry *entry_old; const NMDedupMultiEntry *entry_old;
@@ -1847,8 +1848,12 @@ _idxcache_update_box_move (NMPCache *cache,
nm_dedup_multi_index_add_full (cache->multi_idx, nm_dedup_multi_index_add_full (cache->multi_idx,
idx_type, idx_type,
obj_new, obj_new,
NM_DEDUP_MULTI_IDX_MODE_APPEND, is_dump
entry_order, ? NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE
: NM_DEDUP_MULTI_IDX_MODE_APPEND,
is_dump
? NULL
: entry_order,
entry_new ?: NM_DEDUP_MULTI_ENTRY_MISSING, entry_new ?: NM_DEDUP_MULTI_ENTRY_MISSING,
entry_new ? entry_new->head : (entry_order ? entry_order->head : NULL), entry_new ? entry_new->head : (entry_order ? entry_order->head : NULL),
&entry_new, &entry_new,
@@ -1874,6 +1879,7 @@ static void
_idxcache_update (NMPCache *cache, _idxcache_update (NMPCache *cache,
const NMDedupMultiEntry *entry_old, const NMDedupMultiEntry *entry_old,
NMPObject *obj_new, NMPObject *obj_new,
gboolean is_dump,
const NMDedupMultiEntry **out_entry_new) const NMDedupMultiEntry **out_entry_new)
{ {
const NMPClass *klass; const NMPClass *klass;
@@ -1920,7 +1926,9 @@ _idxcache_update (NMPCache *cache,
nm_dedup_multi_index_add_full (cache->multi_idx, nm_dedup_multi_index_add_full (cache->multi_idx,
idx_type_o, idx_type_o,
obj_new, obj_new,
NM_DEDUP_MULTI_IDX_MODE_APPEND, is_dump
? NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE
: NM_DEDUP_MULTI_IDX_MODE_APPEND,
NULL, NULL,
entry_old ?: NM_DEDUP_MULTI_ENTRY_MISSING, entry_old ?: NM_DEDUP_MULTI_ENTRY_MISSING,
NULL, NULL,
@@ -1940,9 +1948,10 @@ _idxcache_update (NMPCache *cache,
if (id_type == NMP_CACHE_ID_TYPE_OBJECT_TYPE) if (id_type == NMP_CACHE_ID_TYPE_OBJECT_TYPE)
continue; continue;
_idxcache_update_box_move (cache, id_type, _idxcache_update_other_cache_ids (cache, id_type,
obj_old, obj_old,
entry_new ? entry_new->obj : NULL); entry_new ? entry_new->obj : NULL,
is_dump);
} }
NM_SET_OUT (out_entry_new, entry_new); NM_SET_OUT (out_entry_new, entry_new);
@@ -1974,7 +1983,7 @@ nmp_cache_remove (NMPCache *cache,
* @obj_needle. */ * @obj_needle. */
return NMP_CACHE_OPS_UNCHANGED; return NMP_CACHE_OPS_UNCHANGED;
} }
_idxcache_update (cache, entry_old, NULL, NULL); _idxcache_update (cache, entry_old, NULL, FALSE, NULL);
return NMP_CACHE_OPS_REMOVED; return NMP_CACHE_OPS_REMOVED;
} }
@@ -2015,7 +2024,7 @@ nmp_cache_remove_netlink (NMPCache *cache,
if (!obj_old->_link.udev.device) { if (!obj_old->_link.udev.device) {
/* the update would make @obj_old invalid. Remove it. */ /* the update would make @obj_old invalid. Remove it. */
_idxcache_update (cache, entry_old, NULL, NULL); _idxcache_update (cache, entry_old, NULL, FALSE, NULL);
NM_SET_OUT (out_obj_new, NULL); NM_SET_OUT (out_obj_new, NULL);
return NMP_CACHE_OPS_REMOVED; return NMP_CACHE_OPS_REMOVED;
} }
@@ -2029,6 +2038,7 @@ nmp_cache_remove_netlink (NMPCache *cache,
_idxcache_update (cache, _idxcache_update (cache,
entry_old, entry_old,
obj_new, obj_new,
FALSE,
&entry_new); &entry_new);
NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj)); NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj));
return NMP_CACHE_OPS_UPDATED; return NMP_CACHE_OPS_UPDATED;
@@ -2036,7 +2046,7 @@ nmp_cache_remove_netlink (NMPCache *cache,
NM_SET_OUT (out_obj_old, nmp_object_ref (obj_old)); NM_SET_OUT (out_obj_old, nmp_object_ref (obj_old));
NM_SET_OUT (out_obj_new, NULL); NM_SET_OUT (out_obj_new, NULL);
_idxcache_update (cache, entry_old, NULL, NULL); _idxcache_update (cache, entry_old, NULL, FALSE, NULL);
return NMP_CACHE_OPS_REMOVED; return NMP_CACHE_OPS_REMOVED;
} }
@@ -2050,6 +2060,12 @@ nmp_cache_remove_netlink (NMPCache *cache,
* calling nmp_cache_update_netlink() you hand @obj over to the cache. * calling nmp_cache_update_netlink() you hand @obj over to the cache.
* Except, that the cache will increment the ref count as appropriate. You * Except, that the cache will increment the ref count as appropriate. You
* must still unref the obj to release your part of the ownership. * must still unref the obj to release your part of the ownership.
* @is_dump: whether this update comes during a dump of object of the same kind.
* kernel dumps objects in a certain order, which matters especially for routes.
* Before a dump we mark all objects as dirty, and remove all untouched objects
* afterwards. Hence, during a dump, every update should move the object to the
* end of the list, to obtain the correct order. That means, to use NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE,
* instead of NM_DEDUP_MULTI_IDX_MODE_APPEND.
* @out_obj_old: (allow-none): (out): return the object with same ID as @obj_hand_over, * @out_obj_old: (allow-none): (out): return the object with same ID as @obj_hand_over,
* that was in the cache before update. If an object is returned, the caller must * that was in the cache before update. If an object is returned, the caller must
* unref it afterwards. * unref it afterwards.
@@ -2064,6 +2080,7 @@ nmp_cache_remove_netlink (NMPCache *cache,
NMPCacheOpsType NMPCacheOpsType
nmp_cache_update_netlink (NMPCache *cache, nmp_cache_update_netlink (NMPCache *cache,
NMPObject *obj_hand_over, NMPObject *obj_hand_over,
gboolean is_dump,
const NMPObject **out_obj_old, const NMPObject **out_obj_old,
const NMPObject **out_obj_new) const NMPObject **out_obj_new)
{ {
@@ -2102,6 +2119,7 @@ nmp_cache_update_netlink (NMPCache *cache,
_idxcache_update (cache, _idxcache_update (cache,
entry_old, entry_old,
obj_hand_over, obj_hand_over,
is_dump,
&entry_new); &entry_new);
NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj)); NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj));
return NMP_CACHE_OPS_ADDED; return NMP_CACHE_OPS_ADDED;
@@ -2155,7 +2173,7 @@ nmp_cache_update_netlink (NMPCache *cache,
if (!is_alive) { if (!is_alive) {
/* the update would make @obj_old invalid. Remove it. */ /* the update would make @obj_old invalid. Remove it. */
_idxcache_update (cache, entry_old, NULL, NULL); _idxcache_update (cache, entry_old, NULL, FALSE, NULL);
NM_SET_OUT (out_obj_new, NULL); NM_SET_OUT (out_obj_new, NULL);
return NMP_CACHE_OPS_REMOVED; return NMP_CACHE_OPS_REMOVED;
} }
@@ -2169,6 +2187,7 @@ nmp_cache_update_netlink (NMPCache *cache,
_idxcache_update (cache, _idxcache_update (cache,
entry_old, entry_old,
obj_hand_over, obj_hand_over,
is_dump,
&entry_new); &entry_new);
NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj)); NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj));
return NMP_CACHE_OPS_UPDATED; return NMP_CACHE_OPS_UPDATED;
@@ -2204,6 +2223,7 @@ nmp_cache_update_link_udev (NMPCache *cache,
_idxcache_update (cache, _idxcache_update (cache,
NULL, NULL,
obj_new, obj_new,
FALSE,
&entry_new); &entry_new);
NM_SET_OUT (out_obj_old, NULL); NM_SET_OUT (out_obj_old, NULL);
NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj)); NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj));
@@ -2219,7 +2239,7 @@ nmp_cache_update_link_udev (NMPCache *cache,
if (!udevice && !obj_old->_link.netlink.is_in_netlink) { if (!udevice && !obj_old->_link.netlink.is_in_netlink) {
/* the update would make @obj_old invalid. Remove it. */ /* the update would make @obj_old invalid. Remove it. */
_idxcache_update (cache, entry_old, NULL, NULL); _idxcache_update (cache, entry_old, NULL, FALSE, NULL);
NM_SET_OUT (out_obj_new, NULL); NM_SET_OUT (out_obj_new, NULL);
return NMP_CACHE_OPS_REMOVED; return NMP_CACHE_OPS_REMOVED;
} }
@@ -2234,6 +2254,7 @@ nmp_cache_update_link_udev (NMPCache *cache,
_idxcache_update (cache, _idxcache_update (cache,
entry_old, entry_old,
obj_new, obj_new,
FALSE,
&entry_new); &entry_new);
NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj)); NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj));
return NMP_CACHE_OPS_UPDATED; return NMP_CACHE_OPS_UPDATED;
@@ -2274,6 +2295,7 @@ nmp_cache_update_link_master_connected (NMPCache *cache,
_idxcache_update (cache, _idxcache_update (cache,
entry_old, entry_old,
obj_new, obj_new,
FALSE,
&entry_new); &entry_new);
NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj)); NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj));
return NMP_CACHE_OPS_UPDATED; return NMP_CACHE_OPS_UPDATED;

View File

@@ -413,6 +413,11 @@ const NMPClass *nmp_class_from_type (NMPObjectType obj_type);
static inline const NMPObject * static inline const NMPObject *
nmp_object_ref (const NMPObject *obj) nmp_object_ref (const NMPObject *obj)
{ {
if (!obj) {
/* for convenience, allow NULL. */
return NULL;
}
/* ref and unref accept const pointers. NMPObject is supposed to be shared /* ref and unref accept const pointers. NMPObject is supposed to be shared
* and kept immutable. Disallowing to take/retrun a reference to a const * and kept immutable. Disallowing to take/retrun a reference to a const
* NMPObject is cumbersome, because callers are precisely expected to * NMPObject is cumbersome, because callers are precisely expected to
@@ -599,7 +604,8 @@ NMPCacheOpsType nmp_cache_remove_netlink (NMPCache *cache,
const NMPObject **out_obj_old, const NMPObject **out_obj_old,
const NMPObject **out_obj_new); const NMPObject **out_obj_new);
NMPCacheOpsType nmp_cache_update_netlink (NMPCache *cache, NMPCacheOpsType nmp_cache_update_netlink (NMPCache *cache,
NMPObject *obj, NMPObject *obj_hand_over,
gboolean is_dump,
const NMPObject **out_obj_old, const NMPObject **out_obj_old,
const NMPObject **out_obj_new); const NMPObject **out_obj_new);
NMPCacheOpsType nmp_cache_update_link_udev (NMPCache *cache, NMPCacheOpsType nmp_cache_update_link_udev (NMPCache *cache,

View File

@@ -235,7 +235,7 @@ _nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, const NMPObject **ou
obj_new_expected->_link.udev.device = udev_device_ref (obj_prev->_link.udev.device); obj_new_expected->_link.udev.device = udev_device_ref (obj_prev->_link.udev.device);
_nmp_object_fixup_link_udev_fields (&obj_new_expected, NULL, nmp_cache_use_udev_get (cache)); _nmp_object_fixup_link_udev_fields (&obj_new_expected, NULL, nmp_cache_use_udev_get (cache));
ops_type = nmp_cache_update_netlink (cache, obj, &obj_old, &obj_new); ops_type = nmp_cache_update_netlink (cache, obj, FALSE, &obj_old, &obj_new);
ops_post_check (cache, ops_type, obj_old, obj_new, ops_post_check (cache, ops_type, obj_old, obj_new,
nmp_object_is_alive (obj_new_expected) ? obj_new_expected : NULL, nmp_object_is_alive (obj_new_expected) ? obj_new_expected : NULL,
expected_ops_type); expected_ops_type);