core: remove NMDedupMultiBox object and track NMDedupMultiObj instances directly

Implement the reference counting of NMPObject as part of
NMDedupMultiObj and get rid of NMDedupMultiBox.

With this change, the NMPObject is aware in which NMDedupMultiIndex
instance it is tracked.

- this saves an additional GSlice allocation for the NMDedupMultiBox.

- it is immediately known, whether an NMPObject is tracked by a
  certain NMDedupMultiIndex or not. This saves an additional hash
  lookup.

- previously, when all idx-types cease to reference an NMDedupMultiObj
  instance, it was removed. Now, a tracked objects stays in the
  NMDedupMultiIndex until it's last reference is deleted. This possibly
  extends the lifetime of the object and we may reuse it better.

- it is no longer possible to add one object to more then one
  NMDedupMultiIndex instance. As we anyway want to have only one
  instance to deduplicate the objects, this is fine.

- the ref-counting implementation is now part of NMDedupMultiObj.
  Previously, NMDedupMultiIndex could also track objects that were
  not ref-counted. Hoever, the object anyway *must* implement the
  NMDedupMultiObj API, so this flexibility is unneeded and was not
  used.

- a downside is, that NMPObject grows by one pointer size, even if
  it isn't tracked in the NMDedupMultiIndex. But we really want to
  put all objects into the index for sharing and deduplication. So
  this downside should be acceptable. Still, code like
  nmp_object_stackinit*() needs to handle a larger object.
This commit is contained in:
Thomas Haller 2017-07-02 23:46:06 +02:00
parent 667c50f5d9
commit 28340588d9
8 changed files with 360 additions and 355 deletions

View file

@ -78,7 +78,6 @@ G_STATIC_ASSERT (sizeof (bool) <= sizeof (int));
typedef struct {
NMDedupMultiObj parent;
int ref_count;
guint val;
guint other;
} DedupObj;
@ -93,39 +92,34 @@ _dedup_obj_assert (const NMDedupMultiObj *obj)
g_assert (obj);
o = (DedupObj *) obj;
g_assert (o->parent.klass == &dedup_obj_class);
g_assert (o->ref_count > 0);
g_assert (o->parent._ref_count > 0);
g_assert (o->val > 0);
return o;
}
static NMDedupMultiObj *
_dedup_obj_get_ref (const NMDedupMultiObj *obj)
static const NMDedupMultiObj *
_dedup_obj_clone (const NMDedupMultiObj *obj)
{
DedupObj *o, *o2;
o = _dedup_obj_assert (obj);
if (o->ref_count == NM_OBJ_REF_COUNT_STACKINIT) {
o2 = g_slice_new0 (DedupObj);
o2->parent.klass = &dedup_obj_class;
o2->ref_count = 1;
o2->val = o->val;
o2->other = o->other;
return (NMDedupMultiObj *) o2;
}
o->ref_count++;
return (NMDedupMultiObj *) o;
o2 = g_slice_new0 (DedupObj);
o2->parent.klass = &dedup_obj_class;
o2->parent._ref_count = 1;
o2->val = o->val;
o2->other = o->other;
return (NMDedupMultiObj *) o2;
}
static void
_dedup_obj_put_ref (NMDedupMultiObj *obj)
_dedup_obj_destroy (NMDedupMultiObj *obj)
{
DedupObj *o;
DedupObj *o = (DedupObj *) obj;
nm_assert (o->parent._ref_count == 0);
o->parent._ref_count = 1;
o = _dedup_obj_assert (obj);
g_assert (o->ref_count != NM_OBJ_REF_COUNT_STACKINIT);
if (--o->ref_count == 0)
g_slice_free (DedupObj, o);
g_slice_free (DedupObj, o);
}
static guint
@ -149,8 +143,8 @@ _dedup_obj_full_equal (const NMDedupMultiObj *obj_a,
}
static const NMDedupMultiObjClass dedup_obj_class = {
.obj_get_ref = _dedup_obj_get_ref,
.obj_put_ref = _dedup_obj_put_ref,
.obj_clone = _dedup_obj_clone,
.obj_destroy = _dedup_obj_destroy,
.obj_full_equality_allows_different_class = FALSE,
.obj_full_hash = _dedup_obj_full_hash,
.obj_full_equal = _dedup_obj_full_equal,
@ -160,8 +154,8 @@ static const NMDedupMultiObjClass dedup_obj_class = {
(&((DedupObj) { \
.parent = { \
.klass = &dedup_obj_class, \
._ref_count = NM_OBJ_REF_COUNT_STACKINIT, \
}, \
.ref_count = NM_OBJ_REF_COUNT_STACKINIT, \
.val = (val_val), \
.other = (other_other), \
}))
@ -295,7 +289,7 @@ _dedup_entry_assert (const NMDedupMultiEntry *entry)
g_assert (!entry->is_head);
g_assert (entry->head != (gpointer) entry);
_dedup_head_entry_assert (entry->head);
return _dedup_obj_assert (entry->box->obj);
return _dedup_obj_assert (entry->obj);
}
static const DedupIdxType *
@ -341,8 +335,8 @@ _dedup_entry_assert_all (const NMDedupMultiEntry *entry, gssize expected_idx, co
if (expected_idx == i)
g_assert (entry_current == entry);
g_assert (idx_type->parent.klass->idx_obj_partition_equal (&idx_type->parent,
entry_current->box->obj,
c_list_entry (entry->head->lst_entries_head.next, NMDedupMultiEntry, lst_entries)->box->obj));
entry_current->obj,
c_list_entry (entry->head->lst_entries_head.next, NMDedupMultiEntry, lst_entries)->obj));
i++;
}
}
@ -361,14 +355,14 @@ test_dedup_multi (void)
g_assert (_dedup_idx_add (idx, IDX_20_3_a, DEDUP_OBJ_INIT (1, 1), NM_DEDUP_MULTI_IDX_MODE_APPEND, &entry1));
_dedup_entry_assert_all (entry1, 0, DEDUP_OBJ_INIT (1, 1));
g_assert (nm_dedup_multi_box_find (idx, (NMDedupMultiObj *) DEDUP_OBJ_INIT (1, 1)));
g_assert (!nm_dedup_multi_box_find (idx, (NMDedupMultiObj *) DEDUP_OBJ_INIT (1, 2)));
g_assert (nm_dedup_multi_index_obj_find (idx, (NMDedupMultiObj *) DEDUP_OBJ_INIT (1, 1)));
g_assert (!nm_dedup_multi_index_obj_find (idx, (NMDedupMultiObj *) DEDUP_OBJ_INIT (1, 2)));
g_assert (_dedup_idx_add (idx, IDX_20_3_a, DEDUP_OBJ_INIT (1, 2), NM_DEDUP_MULTI_IDX_MODE_APPEND, &entry1));
_dedup_entry_assert_all (entry1, 0, DEDUP_OBJ_INIT (1, 2));
g_assert (!nm_dedup_multi_box_find (idx, (NMDedupMultiObj *) DEDUP_OBJ_INIT (1, 1)));
g_assert (nm_dedup_multi_box_find (idx, (NMDedupMultiObj *) DEDUP_OBJ_INIT (1, 2)));
g_assert (!nm_dedup_multi_index_obj_find (idx, (NMDedupMultiObj *) DEDUP_OBJ_INIT (1, 1)));
g_assert (nm_dedup_multi_index_obj_find (idx, (NMDedupMultiObj *) DEDUP_OBJ_INIT (1, 2)));
g_assert (_dedup_idx_add (idx, IDX_20_3_a, DEDUP_OBJ_INIT (2, 2), NM_DEDUP_MULTI_IDX_MODE_APPEND, &entry1));
_dedup_entry_assert_all (entry1, 1, DEDUP_OBJ_INIT (1, 2), DEDUP_OBJ_INIT (2, 2));

View file

@ -25,11 +25,6 @@
/*****************************************************************************/
typedef struct {
NMDedupMultiBox parent;
int ref_count;
} Box;
typedef struct {
/* the stack-allocated lookup entry. It has a compatible
* memory layout with NMDedupMultiEntry and NMDedupMultiHeadEntry.
@ -47,16 +42,11 @@ typedef struct {
struct _NMDedupMultiIndex {
int ref_count;
GHashTable *idx_entries;
GHashTable *idx_box;
GHashTable *idx_objs;
};
/*****************************************************************************/
static void _box_unref (NMDedupMultiIndex *self,
Box *box);
/*****************************************************************************/
static void
ASSERT_idx_type (const NMDedupMultiIdxType *idx_type)
{
@ -142,7 +132,7 @@ _entry_unpack (const NMDedupMultiEntry *entry,
G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (LookupEntry, lst_entries_sentinel) == G_STRUCT_OFFSET (NMDedupMultiEntry, lst_entries));
G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMDedupMultiEntry, lst_entries) == G_STRUCT_OFFSET (NMDedupMultiHeadEntry, lst_entries_head));
G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMDedupMultiEntry, box) == G_STRUCT_OFFSET (NMDedupMultiHeadEntry, idx_type));
G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMDedupMultiEntry, obj) == G_STRUCT_OFFSET (NMDedupMultiHeadEntry, idx_type));
G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMDedupMultiEntry, is_head) == G_STRUCT_OFFSET (NMDedupMultiHeadEntry, is_head));
if (!entry->lst_entries.next) {
@ -154,11 +144,11 @@ _entry_unpack (const NMDedupMultiEntry *entry,
} else if (entry->is_head) {
head_entry = (NMDedupMultiHeadEntry *) entry;
nm_assert (!c_list_is_empty (&head_entry->lst_entries_head));
*out_obj = c_list_entry (head_entry->lst_entries_head.next, NMDedupMultiEntry, lst_entries)->box->obj;
*out_obj = c_list_entry (head_entry->lst_entries_head.next, NMDedupMultiEntry, lst_entries)->obj;
*out_idx_type = head_entry->idx_type;
*out_lookup_head = TRUE;
} else {
*out_obj = entry->box->obj;
*out_obj = entry->obj;
*out_idx_type = entry->head->idx_type;
*out_lookup_head = FALSE;
}
@ -223,12 +213,11 @@ _add (NMDedupMultiIndex *self,
NMDedupMultiIdxMode mode,
const NMDedupMultiEntry *entry_order,
NMDedupMultiHeadEntry *head_existing,
const NMDedupMultiBox *box_existing,
const NMDedupMultiEntry **out_entry,
const NMDedupMultiBox **out_old_box)
const NMDedupMultiObj **out_obj_old)
{
NMDedupMultiHeadEntry *head_entry;
const NMDedupMultiBox *box, *box_new;
const NMDedupMultiObj *obj_new, *obj_old;
gboolean add_head_entry = FALSE;
nm_assert (self);
@ -239,7 +228,6 @@ _add (NMDedupMultiIndex *self,
NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE,
NM_DEDUP_MULTI_IDX_MODE_APPEND,
NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE));
nm_assert (!box_existing || box_existing == nm_dedup_multi_box_find (self, obj));
nm_assert (!head_existing || head_existing->idx_type == idx_type);
nm_assert (({
const NMDedupMultiHeadEntry *_h;
@ -299,27 +287,24 @@ _add (NMDedupMultiIndex *self,
break;
};
if ( obj == entry->box->obj
if ( obj == entry->obj
|| obj->klass->obj_full_equal (obj,
entry->box->obj)) {
entry->obj)) {
NM_SET_OUT (out_entry, entry);
NM_SET_OUT (out_old_box, nm_dedup_multi_box_ref (entry->box));
NM_SET_OUT (out_obj_old, nm_dedup_multi_obj_ref (entry->obj));
return FALSE;
}
if (box_existing)
box_new = nm_dedup_multi_box_ref (box_existing);
else
box_new = nm_dedup_multi_box_new (self, obj);
obj_new = nm_dedup_multi_index_obj_intern (self, obj);
box = entry->box;
entry->box = box_new;
obj_old = entry->obj;
entry->obj = obj_new;
NM_SET_OUT (out_entry, entry);
if (out_old_box)
*out_old_box = box;
if (out_obj_old)
*out_obj_old = obj_old;
else
_box_unref (self, (Box *) box);
nm_dedup_multi_obj_unref (obj_old);
return TRUE;
}
@ -328,18 +313,14 @@ _add (NMDedupMultiIndex *self,
/* this object cannot be partitioned by this idx_type. */
nm_assert (!head_existing || head_existing == NM_DEDUP_MULTI_HEAD_ENTRY_MISSING);
NM_SET_OUT (out_entry, NULL);
NM_SET_OUT (out_old_box, NULL);
NM_SET_OUT (out_obj_old, NULL);
return FALSE;
}
if (box_existing)
box_new = nm_dedup_multi_box_ref (box_existing);
else
box_new = nm_dedup_multi_box_new (self, obj);
obj = box_new->obj;
obj_new = nm_dedup_multi_index_obj_intern (self, obj);
if (!head_existing)
head_entry = _entry_lookup_head (self, idx_type, obj);
head_entry = _entry_lookup_head (self, idx_type, obj_new);
else if (head_existing == NM_DEDUP_MULTI_HEAD_ENTRY_MISSING)
head_entry = NULL;
else
@ -363,7 +344,7 @@ _add (NMDedupMultiIndex *self,
}
entry = g_slice_new0 (NMDedupMultiEntry);
entry->box = box_new;
entry->obj = obj_new;
entry->head = head_entry;
switch (mode) {
@ -393,7 +374,7 @@ _add (NMDedupMultiIndex *self,
nm_assert_not_reached ();
NM_SET_OUT (out_entry, entry);
NM_SET_OUT (out_old_box, NULL);
NM_SET_OUT (out_obj_old, NULL);
return TRUE;
}
@ -403,7 +384,7 @@ nm_dedup_multi_index_add (NMDedupMultiIndex *self,
/*const NMDedupMultiObj * */ gconstpointer obj,
NMDedupMultiIdxMode mode,
const NMDedupMultiEntry **out_entry,
const NMDedupMultiBox **out_old_box)
/* const NMDedupMultiObj ** */ gpointer out_obj_old)
{
NMDedupMultiEntry *entry;
@ -419,9 +400,9 @@ nm_dedup_multi_index_add (NMDedupMultiIndex *self,
entry = _entry_lookup_obj (self, idx_type, obj);
return _add (self, idx_type, obj,
entry, mode, NULL,
entry, mode,
NULL, NULL,
out_entry, out_old_box);
out_entry, out_obj_old);
}
/* nm_dedup_multi_index_add_full:
@ -446,16 +427,13 @@ nm_dedup_multi_index_add (NMDedupMultiIndex *self,
* @head_existing: an optional argument to safe a lookup for the head. If specified,
* it must be identical to nm_dedup_multi_index_lookup_head(), with the pecularity
* that if the head is not yet tracked, you may specify %NM_DEDUP_MULTI_HEAD_ENTRY_MISSING
* @box_existing: optional argument to safe the box lookup. If given, @obj and the boxed
* object must be identical, and @box_existing must be tracked by @self. This is to safe
* the additional lookup.
* @out_entry: if give, return the added entry. This entry may have already exists (update)
* or be newly created. If @obj is not partitionable according to @idx_type, @obj
* is not to be added and it returns %NULL.
* @out_old_box: if given, return the previously contained boxed object. It only
* returns a boxed object, if a matching entry was tracked previously, not if a
* new entry was created. Note that when passing @out_old_box you obtain a reference
* to the boxed object and MUST return it with nm_dedup_multi_box_unref().
* @out_obj_old: if given, return the previously contained object. It only
* returns a object, if a matching entry was tracked previously, not if a
* new entry was created. Note that when passing @out_obj_old you obtain a reference
* to the boxed object and MUST return it with nm_dedup_multi_obj_unref().
*
* Adds and object to the index.
*
@ -469,9 +447,8 @@ nm_dedup_multi_index_add_full (NMDedupMultiIndex *self,
const NMDedupMultiEntry *entry_order,
const NMDedupMultiEntry *entry_existing,
const NMDedupMultiHeadEntry *head_existing,
const NMDedupMultiBox *box_existing,
const NMDedupMultiEntry **out_entry,
const NMDedupMultiBox **out_old_box)
/* const NMDedupMultiObj ** */ gpointer out_obj_old)
{
NMDedupMultiEntry *entry;
@ -498,8 +475,7 @@ nm_dedup_multi_index_add_full (NMDedupMultiIndex *self,
entry,
mode, entry_order,
(NMDedupMultiHeadEntry *) head_existing,
box_existing,
out_entry, out_old_box);
out_entry, out_obj_old);
}
/*****************************************************************************/
@ -509,19 +485,19 @@ _remove_entry (NMDedupMultiIndex *self,
NMDedupMultiEntry *entry,
gboolean *out_head_entry_removed)
{
Box *box;
const NMDedupMultiObj *obj;
NMDedupMultiHeadEntry *head_entry;
NMDedupMultiIdxType *idx_type;
nm_assert (self);
nm_assert (entry);
nm_assert (entry->box);
nm_assert (entry->obj);
nm_assert (entry->head);
nm_assert (!c_list_is_empty (&entry->lst_entries));
nm_assert (g_hash_table_lookup (self->idx_entries, entry) == entry);
head_entry = (NMDedupMultiHeadEntry *) entry->head;
box = (Box *) entry->box;
obj = entry->obj;
nm_assert (head_entry);
nm_assert (head_entry->len > 0);
@ -555,7 +531,7 @@ _remove_entry (NMDedupMultiIndex *self,
g_slice_free (NMDedupMultiHeadEntry, head_entry);
}
_box_unref (self, box);
nm_dedup_multi_obj_unref (obj);
}
static guint
@ -791,20 +767,16 @@ nm_dedup_multi_index_dirty_remove_idx (NMDedupMultiIndex *self,
/*****************************************************************************/
static guint
_dict_idx_box_hash (const Box *box)
_dict_idx_objs_hash (const NMDedupMultiObj *obj)
{
const NMDedupMultiObj *obj = box->parent.obj;
return obj->klass->obj_full_hash (obj);
}
static gboolean
_dict_idx_box_equal (const Box *box_a,
const Box *box_b)
_dict_idx_objs_equal (const NMDedupMultiObj *obj_a,
const NMDedupMultiObj *obj_b)
{
const NMDedupMultiObjClass *klass;
const NMDedupMultiObj *obj_a = box_a->parent.obj;
const NMDedupMultiObj *obj_b = box_b->parent.obj;
klass = obj_a->klass;
@ -824,107 +796,141 @@ _dict_idx_box_equal (const Box *box_a,
return klass->obj_full_equal (obj_a, obj_b);
}
static void
_box_unref (NMDedupMultiIndex *self,
Box *box)
void
nm_dedup_multi_index_obj_release (NMDedupMultiIndex *self,
/* const NMDedupMultiObj * */ gconstpointer obj)
{
nm_assert (box);
nm_assert (box->ref_count > 0);
nm_assert (g_hash_table_lookup (self->idx_box, box) == box);
if (--box->ref_count > 0)
return;
if (!g_hash_table_remove (self->idx_box, box))
nm_assert_not_reached ();
((NMDedupMultiObj *) box->parent.obj)->klass->obj_put_ref ((NMDedupMultiObj *) box->parent.obj);
g_slice_free (Box, box);
}
#define BOX_INIT(obj) \
(&((const Box) { .parent = { .obj = obj, }, }))
static Box *
_box_find (NMDedupMultiIndex *index,
/* const NMDedupMultiObj * */ gconstpointer obj)
{
nm_assert (index);
nm_assert (self);
nm_assert (obj);
nm_assert (g_hash_table_lookup (self->idx_objs, obj) == obj);
nm_assert (((const NMDedupMultiObj *) obj)->_multi_idx == self);
return g_hash_table_lookup (index->idx_box, BOX_INIT (obj));
}
const NMDedupMultiBox *
nm_dedup_multi_box_find (NMDedupMultiIndex *index,
/* const NMDedupMultiObj * */ gconstpointer obj)
{
g_return_val_if_fail (index, NULL);
g_return_val_if_fail (obj, NULL);
return (NMDedupMultiBox *) _box_find (index, obj);
}
const NMDedupMultiBox *
nm_dedup_multi_box_new (NMDedupMultiIndex *index,
/* const NMDedupMultiObj * */ gconstpointer obj)
{
Box *box;
const NMDedupMultiObj *o;
g_return_val_if_fail (index, NULL);
g_return_val_if_fail (obj, NULL);
box = _box_find (index, obj);
if (box) {
box->ref_count++;
return (NMDedupMultiBox *) box;
}
o = ((const NMDedupMultiObj *) obj)->klass->obj_get_ref (obj);
if (!o)
g_return_val_if_reached (NULL);
box = g_slice_new (Box);
box->parent.obj = o;
box->ref_count = 1;
nm_assert (_dict_idx_box_equal (box, BOX_INIT (obj)));
nm_assert (_dict_idx_box_equal (BOX_INIT (obj), box));
nm_assert (_dict_idx_box_hash (BOX_INIT (obj)) == _dict_idx_box_hash (box));
if (!nm_g_hash_table_add (index->idx_box, box))
((NMDedupMultiObj *) obj)->_multi_idx = NULL;
if (!g_hash_table_remove (self->idx_objs, obj))
nm_assert_not_reached ();
return &box->parent;
}
const NMDedupMultiBox *
nm_dedup_multi_box_ref (const NMDedupMultiBox *box)
{
Box *b;
b = (Box *) box;
g_return_val_if_fail (b, NULL);
g_return_val_if_fail (b->ref_count > 0, NULL);
b->ref_count++;
return box;
}
const NMDedupMultiBox *
nm_dedup_multi_box_unref (NMDedupMultiIndex *self,
const NMDedupMultiBox *box)
gconstpointer
nm_dedup_multi_index_obj_find (NMDedupMultiIndex *self,
/* const NMDedupMultiObj * */ gconstpointer obj)
{
g_return_val_if_fail (self, NULL);
g_return_val_if_fail (box, NULL);
g_return_val_if_fail (((Box *) box)->ref_count > 0, NULL);
g_return_val_if_fail (obj, NULL);
return g_hash_table_lookup (self->idx_objs, obj);
}
gconstpointer
nm_dedup_multi_index_obj_intern (NMDedupMultiIndex *self,
/* const NMDedupMultiObj * */ gconstpointer obj)
{
const NMDedupMultiObj *obj_new = obj;
const NMDedupMultiObj *obj_old;
nm_assert (self);
nm_assert (obj_new);
if (obj_new->_multi_idx == self) {
nm_assert (g_hash_table_lookup (self->idx_objs, obj_new) == obj_new);
nm_dedup_multi_obj_ref (obj_new);
return obj_new;
}
obj_old = g_hash_table_lookup (self->idx_objs, obj_new);
nm_assert (obj_old != obj_new);
if (obj_old) {
nm_assert (obj_old->_multi_idx == self);
nm_dedup_multi_obj_ref (obj_old);
return obj_old;
}
if (nm_dedup_multi_obj_needs_clone (obj_new))
obj_new = nm_dedup_multi_obj_clone (obj_new);
else
obj_new = nm_dedup_multi_obj_ref (obj_new);
nm_assert (obj_new);
nm_assert (!obj_new->_multi_idx);
if (!nm_g_hash_table_add (self->idx_objs, (gpointer) obj_new))
nm_assert_not_reached ();
((NMDedupMultiObj *) obj_new)->_multi_idx = self;
return obj_new;
}
const NMDedupMultiObj *
nm_dedup_multi_obj_ref (const NMDedupMultiObj *obj)
{
/* ref and unref accept const pointers. Objects is supposed to be shared
* and kept immutable. Disallowing to take/retrun a reference to a const
* NMPObject is cumbersome, because callers are precisely expected to
* keep a ref on the otherwise immutable object. */
nm_assert (obj);
nm_assert (obj->_ref_count != NM_OBJ_REF_COUNT_STACKINIT);
nm_assert (obj->_ref_count > 0);
((NMDedupMultiObj *) obj)->_ref_count++;
return obj;
}
const NMDedupMultiObj *
nm_dedup_multi_obj_unref (const NMDedupMultiObj *obj)
{
if (obj) {
nm_assert (obj->_ref_count > 0);
nm_assert (obj->_ref_count != NM_OBJ_REF_COUNT_STACKINIT);
again:
if (--(((NMDedupMultiObj *) obj)->_ref_count) <= 0) {
if (obj->_multi_idx) {
/* restore the ref-count to 1 and release the object first
* from the index. Then, retry again to unref. */
((NMDedupMultiObj *) obj)->_ref_count++;
nm_dedup_multi_index_obj_release (obj->_multi_idx, obj);
nm_assert (obj->_ref_count == 1);
nm_assert (!obj->_multi_idx);
goto again;
}
obj->klass->obj_destroy ((NMDedupMultiObj *) obj);
}
}
_box_unref (self, (Box *) box);
return NULL;
}
gboolean
nm_dedup_multi_obj_needs_clone (const NMDedupMultiObj *obj)
{
nm_assert (obj);
if ( obj->_multi_idx
|| obj->_ref_count == NM_OBJ_REF_COUNT_STACKINIT)
return TRUE;
if ( obj->klass->obj_needs_clone
&& obj->klass->obj_needs_clone (obj))
return TRUE;
return FALSE;
}
const NMDedupMultiObj *
nm_dedup_multi_obj_clone (const NMDedupMultiObj *obj)
{
const NMDedupMultiObj *o;
nm_assert (obj);
o = obj->klass->obj_clone (obj);
nm_assert (o);
nm_assert (o->_ref_count == 1);
return o;
}
/*****************************************************************************/
NMDedupMultiIndex *
@ -935,7 +941,7 @@ nm_dedup_multi_index_new (void)
self = g_slice_new0 (NMDedupMultiIndex);
self->ref_count = 1;
self->idx_entries = g_hash_table_new ((GHashFunc) _dict_idx_entries_hash, (GEqualFunc) _dict_idx_entries_equal);
self->idx_box = g_hash_table_new ((GHashFunc) _dict_idx_box_hash, (GEqualFunc) _dict_idx_box_equal);
self->idx_objs = g_hash_table_new ((GHashFunc) _dict_idx_objs_hash, (GEqualFunc) _dict_idx_objs_equal);
return self;
}
@ -955,6 +961,7 @@ nm_dedup_multi_index_unref (NMDedupMultiIndex *self)
GHashTableIter iter;
const NMDedupMultiIdxType *idx_type;
NMDedupMultiEntry *entry;
const NMDedupMultiObj *obj;
g_return_val_if_fail (self, NULL);
g_return_val_if_fail (self->ref_count > 0, NULL);
@ -975,13 +982,15 @@ more:
nm_assert (g_hash_table_size (self->idx_entries) == 0);
/* If callers took references to NMDedupMultiBox instances, they
* must keep NMDedupMultiIndex alive for as long as they keep
* the boxed reference. */
nm_assert (g_hash_table_size (self->idx_box) == 0);
g_hash_table_iter_init (&iter, self->idx_objs);
while (g_hash_table_iter_next (&iter, (gpointer *) &obj, NULL)) {
nm_assert (obj->_multi_idx == self);
((NMDedupMultiObj * )obj)->_multi_idx = NULL;
}
g_hash_table_remove_all (self->idx_objs);
g_hash_table_unref (self->idx_entries);
g_hash_table_unref (self->idx_box);
g_hash_table_unref (self->idx_objs);
g_slice_free (NMDedupMultiIndex, self);
return NULL;

View file

@ -29,7 +29,6 @@
typedef struct _NMDedupMultiObj NMDedupMultiObj;
typedef struct _NMDedupMultiObjClass NMDedupMultiObjClass;
typedef struct _NMDedupMultiBox NMDedupMultiBox;
typedef struct _NMDedupMultiIdxType NMDedupMultiIdxType;
typedef struct _NMDedupMultiIdxTypeClass NMDedupMultiIdxTypeClass;
typedef struct _NMDedupMultiEntry NMDedupMultiEntry;
@ -57,16 +56,18 @@ struct _NMDedupMultiObj {
NMObjBaseInst parent;
const NMDedupMultiObjClass *klass;
};
NMDedupMultiIndex *_multi_idx;
guint _ref_count;
};
struct _NMDedupMultiObjClass {
NMObjBaseClass parent;
/* obj_get_ref() may just increase the ref-count, or it may allocate a new object.
* In any case, it returns ownership of an equal object to @obj. */
NMDedupMultiObj *(*obj_get_ref) (const NMDedupMultiObj *obj);
const NMDedupMultiObj *(*obj_clone) (const NMDedupMultiObj *obj);
void (*obj_put_ref) (NMDedupMultiObj *obj);
gboolean (*obj_needs_clone) (const NMDedupMultiObj *obj);
void (*obj_destroy) (NMDedupMultiObj *obj);
gboolean obj_full_equality_allows_different_class;
@ -79,14 +80,19 @@ struct _NMDedupMultiObjClass {
/*****************************************************************************/
struct _NMDedupMultiBox {
gconstpointer obj;
};
const NMDedupMultiObj *nm_dedup_multi_obj_ref (const NMDedupMultiObj *obj);
const NMDedupMultiObj *nm_dedup_multi_obj_unref (const NMDedupMultiObj *obj);
const NMDedupMultiObj *nm_dedup_multi_obj_clone (const NMDedupMultiObj *obj);
gboolean nm_dedup_multi_obj_needs_clone (const NMDedupMultiObj *obj);
const NMDedupMultiBox *nm_dedup_multi_box_new (NMDedupMultiIndex *index, /* const NMDedupMultiObj * */ gconstpointer obj);
const NMDedupMultiBox *nm_dedup_multi_box_find (NMDedupMultiIndex *index, /* const NMDedupMultiObj * */ gconstpointer obj);
const NMDedupMultiBox *nm_dedup_multi_box_ref (const NMDedupMultiBox *box);
const NMDedupMultiBox *nm_dedup_multi_box_unref (NMDedupMultiIndex *index, const NMDedupMultiBox *box);
gconstpointer nm_dedup_multi_index_obj_intern (NMDedupMultiIndex *self,
/* const NMDedupMultiObj * */ gconstpointer obj);
void nm_dedup_multi_index_obj_release (NMDedupMultiIndex *self,
/* const NMDedupMultiObj * */ gconstpointer obj);
/* const NMDedupMultiObj * */ gconstpointer nm_dedup_multi_index_obj_find (NMDedupMultiIndex *self,
/* const NMDedupMultiObj * */ gconstpointer obj);
/*****************************************************************************/
@ -190,12 +196,7 @@ struct _NMDedupMultiEntry {
* All entries compare equal according to idx_obj_partition_equal(). */
CList lst_entries;
/* the object instance. It is ref-counted and shared.
* Note that this instance must be immutable once it
* is added to the list.
*
* For head entries, @box is NULL and @head points to itself. */
const NMDedupMultiBox *box;
/* const NMDedupMultiObj * */ gconstpointer obj;
bool is_head;
bool dirty;
@ -255,16 +256,15 @@ gboolean nm_dedup_multi_index_add_full (NMDedupMultiIndex *self,
const NMDedupMultiEntry *entry_order,
const NMDedupMultiEntry *entry_existing,
const NMDedupMultiHeadEntry *head_existing,
const NMDedupMultiBox *box_existing,
const NMDedupMultiEntry **out_entry,
const NMDedupMultiBox **out_old_box);
/* const NMDedupMultiObj ** */ gpointer out_obj_old);
gboolean nm_dedup_multi_index_add (NMDedupMultiIndex *self,
NMDedupMultiIdxType *idx_type,
/*const NMDedupMultiObj * */ gconstpointer obj,
NMDedupMultiIdxMode mode,
const NMDedupMultiEntry **out_entry,
const NMDedupMultiBox **out_old_box);
/* const NMDedupMultiObj ** */ gpointer out_obj_old);
const NMDedupMultiEntry *nm_dedup_multi_index_lookup_obj (NMDedupMultiIndex *self,
const NMDedupMultiIdxType *idx_type,

View file

@ -215,7 +215,7 @@ static const NMPlatformIP4Route *
_entry_iter_get_ip4_route (const CList *iter)
{
const NMDedupMultiEntry *e = c_list_entry (iter, NMDedupMultiEntry, lst_entries);
const NMPObject *o = (NMPObject *) e->box->obj;
const NMPObject *o = e->obj;
nm_assert (o);
nm_assert (NMP_OBJECT_GET_TYPE (o) == NMP_OBJECT_TYPE_IP4_ROUTE);
@ -236,8 +236,8 @@ nm_ip4_config_iter_ip4_route_next (NMDedupMultiIter *ipconf_iter, const NMPlatfo
has_next = nm_dedup_multi_iter_next (ipconf_iter);
if (has_next) {
nm_assert (NMP_OBJECT_GET_TYPE (ipconf_iter->current->box->obj) == NMP_OBJECT_TYPE_IP4_ROUTE);
NM_SET_OUT (out_route, &(((const NMPObject *) ipconf_iter->current->box->obj)->ip4_route));
nm_assert (NMP_OBJECT_GET_TYPE (ipconf_iter->current->obj) == NMP_OBJECT_TYPE_IP4_ROUTE);
NM_SET_OUT (out_route, &(((const NMPObject *) ipconf_iter->current->obj)->ip4_route));
}
return has_next;
}
@ -1779,7 +1779,7 @@ _add_route (NMIP4Config *config, const NMPObject *o_new, const NMPlatformIP4Rout
{
NMIP4ConfigPrivate *priv;
NMPObject o_new_storage;
const NMDedupMultiBox *box_old;
nm_auto_nmpobj const NMPObject *obj_old = NULL;
nm_assert (NM_IS_IP4_CONFIG (config));
@ -1812,16 +1812,13 @@ _add_route (NMIP4Config *config, const NMPObject *o_new, const NMPlatformIP4Rout
o_new,
NM_DEDUP_MULTI_IDX_MODE_APPEND,
NULL,
&box_old)) {
if (box_old)
nm_dedup_multi_box_unref (priv->multi_idx, box_old);
&obj_old))
return;
}
if (box_old) {
if (obj_old) {
NMIPConfigSource old_source;
old_source = ((const NMPObject *) box_old->obj)->ip_route.rt_source;
old_source = obj_old->ip_route.rt_source;
/* we want to keep the maximum rt_source. But since we expect
* that usually we already add the maxiumum right away, we first try to
* add the new route (replacing the old one). Only if we later
@ -1842,7 +1839,6 @@ _add_route (NMIP4Config *config, const NMPObject *o_new, const NMPlatformIP4Rout
NULL))
nm_assert_not_reached ();
}
nm_dedup_multi_box_unref (priv->multi_idx, box_old);
}
_notify (config, PROP_ROUTE_DATA);

View file

@ -3295,7 +3295,7 @@ cache_prune_one_type (NMPlatform *platform, NMPObjectType obj_type)
if (iter.current->dirty) {
nm_auto_nmpobj const NMPObject *obj_old = NULL;
obj = iter.current->box->obj;
obj = iter.current->obj;
_LOGt ("cache-prune: prune %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0));
cache_op = nmp_cache_remove (cache, obj, TRUE, &obj_old);
nm_assert (cache_op == NMP_CACHE_OPS_REMOVED);

View file

@ -491,38 +491,6 @@ nmp_class_from_type (NMPObjectType obj_type)
/*****************************************************************************/
const NMPObject *
nmp_object_ref (const NMPObject *obj)
{
/* ref and unref accept const pointers. NMPObject is supposed to be shared
* and kept immutable. Disallowing to take/retrun a reference to a const
* NMPObject is cumbersome, because callers are precisely expected to
* keep a ref on the otherwise immutable object. */
g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj), NULL);
g_return_val_if_fail (obj->_ref_count != NM_OBJ_REF_COUNT_STACKINIT, NULL);
((NMPObject *) obj)->_ref_count++;
return obj;
}
void
nmp_object_unref (const NMPObject *obj)
{
if (obj) {
NMPObject *o = (NMPObject *) obj;
g_return_if_fail (o->_ref_count > 0);
g_return_if_fail (o->_ref_count != NM_OBJ_REF_COUNT_STACKINIT);
if (--o->_ref_count <= 0) {
const NMPClass *klass = o->_class;
if (klass->cmd_obj_dispose)
klass->cmd_obj_dispose (o);
g_slice_free1 (klass->sizeof_data + G_STRUCT_OFFSET (NMPObject, object), o);
}
}
}
static void
_vt_cmd_obj_dispose_link (NMPObject *obj)
{
@ -551,7 +519,7 @@ _nmp_object_new_from_class (const NMPClass *klass)
obj = g_slice_alloc0 (klass->sizeof_data + G_STRUCT_OFFSET (NMPObject, object));
obj->_class = klass;
obj->_ref_count = 1;
obj->parent._ref_count = 1;
return obj;
}
@ -587,7 +555,7 @@ _nmp_object_stackinit_from_class (NMPObject *obj, const NMPClass *klass)
memset (obj, 0, sizeof (NMPObject));
obj->_class = klass;
obj->_ref_count = NM_OBJ_REF_COUNT_STACKINIT;
obj->parent._ref_count = NM_OBJ_REF_COUNT_STACKINIT;
}
static NMPObject *
@ -601,7 +569,7 @@ _nmp_object_stackinit_from_type (NMPObject *obj, NMPObjectType obj_type)
memset (obj, 0, sizeof (NMPObject));
obj->_class = klass;
obj->_ref_count = NM_OBJ_REF_COUNT_STACKINIT;
obj->parent._ref_count = NM_OBJ_REF_COUNT_STACKINIT;
return obj;
}
@ -742,7 +710,7 @@ nmp_object_to_string (const NMPObject *obj, NMPObjectToStringMode to_string_mode
case NMP_OBJECT_TO_STRING_ALL:
g_snprintf (buf, buf_size,
"[%s,%p,%u,%calive,%cvisible; %s]",
klass->obj_type_name, obj, obj->_ref_count,
klass->obj_type_name, obj, obj->parent._ref_count,
nmp_object_is_alive (obj) ? '+' : '-',
nmp_object_is_visible (obj) ? '+' : '-',
NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf2, sizeof (buf2)));
@ -768,7 +736,7 @@ _vt_cmd_obj_to_string_link (const NMPObject *obj, NMPObjectToStringMode to_strin
case NMP_OBJECT_TO_STRING_ALL:
g_snprintf (buf, buf_size,
"[%s,%p,%u,%calive,%cvisible,%cin-nl,%p; %s]",
klass->obj_type_name, obj, obj->_ref_count,
klass->obj_type_name, obj, obj->parent._ref_count,
nmp_object_is_alive (obj) ? '+' : '-',
nmp_object_is_visible (obj) ? '+' : '-',
obj->_link.netlink.is_in_netlink ? '+' : '-',
@ -808,7 +776,7 @@ _vt_cmd_obj_to_string_lnk_vlan (const NMPObject *obj, NMPObjectToStringMode to_s
g_snprintf (buf, buf_size,
"[%s,%p,%u,%calive,%cvisible; %s]",
klass->obj_type_name, obj, obj->_ref_count,
klass->obj_type_name, obj, obj->parent._ref_count,
nmp_object_is_alive (obj) ? '+' : '-',
nmp_object_is_visible (obj) ? '+' : '-',
nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof (buf2)));
@ -1339,22 +1307,25 @@ static const guint8 _supported_cache_ids_ipx_route[] = {
/*****************************************************************************/
static NMDedupMultiObj *
_vt_dedup_obj_get_ref (const NMDedupMultiObj *obj)
static void
_vt_dedup_obj_destroy (NMDedupMultiObj *obj)
{
NMPObject *o = (NMPObject *) obj;
const NMPClass *klass;
if (NMP_OBJECT_IS_STACKINIT (o)) {
return (NMDedupMultiObj *) nmp_object_new (NMP_OBJECT_GET_TYPE (o),
&o->object);
}
return (NMDedupMultiObj *) nmp_object_ref (o);
nm_assert (o->parent._ref_count == 0);
nm_assert (!o->parent._multi_idx);
klass = o->_class;
if (klass->cmd_obj_dispose)
klass->cmd_obj_dispose (o);
g_slice_free1 (klass->sizeof_data + G_STRUCT_OFFSET (NMPObject, object), o);
}
static void
_vt_dedup_obj_put_ref (NMDedupMultiObj *obj)
static const NMDedupMultiObj *
_vt_dedup_obj_clone (const NMDedupMultiObj *obj)
{
nmp_object_unref ((NMPObject *) obj);
return (const NMDedupMultiObj *) nmp_object_clone ((const NMPObject *) obj, FALSE);
}
static guint
@ -1373,8 +1344,8 @@ _vt_dedup_obj_full_equal (const NMDedupMultiObj *obj_a,
#define DEDUP_MULTI_OBJ_CLASS_INIT() \
{ \
.obj_get_ref = _vt_dedup_obj_get_ref, \
.obj_put_ref = _vt_dedup_obj_put_ref, \
.obj_clone = _vt_dedup_obj_clone, \
.obj_destroy = _vt_dedup_obj_destroy, \
.obj_full_hash = _vt_dedup_obj_full_hash, \
.obj_full_equal = _vt_dedup_obj_full_equal, \
}
@ -1512,12 +1483,18 @@ nmp_cache_link_connected_needs_toggle_by_ifindex (const NMPCache *cache, int mas
static const NMDedupMultiEntry *
_lookup_obj (const NMPCache *cache, const NMPObject *obj)
{
const NMDedupMultiEntry *entry;
nm_assert (cache);
nm_assert (NMP_OBJECT_IS_VALID (obj));
return nm_dedup_multi_index_lookup_obj (cache->multi_idx,
_idx_type_get (cache, NMP_CACHE_ID_TYPE_OBJECT_TYPE),
obj);
entry = nm_dedup_multi_index_lookup_obj (cache->multi_idx,
_idx_type_get (cache, NMP_CACHE_ID_TYPE_OBJECT_TYPE),
obj);
nm_assert (!entry
|| ( NMP_OBJECT_IS_VALID (entry->obj)
&& NMP_OBJECT_GET_CLASS (entry->obj) == NMP_OBJECT_GET_CLASS (obj)));
return entry;
}
const NMPObject *
@ -1529,7 +1506,7 @@ nmp_cache_lookup_obj (const NMPCache *cache, const NMPObject *obj)
g_return_val_if_fail (obj, NULL);
entry = _lookup_obj (cache, obj);
return entry ? entry->box->obj : NULL;
return entry ? entry->obj : NULL;
}
const NMDedupMultiEntry *
@ -1883,33 +1860,29 @@ nmp_cache_lookup_link_full (const NMPCache *cache,
static void
_idxcache_update_box_move (NMPCache *cache,
NMPCacheIdType cache_id_type,
const NMDedupMultiBox *box_old,
const NMDedupMultiBox *box_new)
const NMPObject *obj_old,
const NMPObject *obj_new)
{
const NMDedupMultiEntry *entry_new;
const NMDedupMultiEntry *entry_old;
const NMDedupMultiEntry *entry_order;
NMDedupMultiIdxType *idx_type;
const NMPObject *new, *old;
new = box_new ? box_new->obj : NULL;
old = box_old ? box_old->obj : NULL;
nm_assert (new || old);
nm_assert (!new || NMP_OBJECT_GET_TYPE (new) != NMP_OBJECT_TYPE_UNKNOWN);
nm_assert (!old || NMP_OBJECT_GET_TYPE (old) != NMP_OBJECT_TYPE_UNKNOWN);
nm_assert (!old || !new || NMP_OBJECT_GET_CLASS (new) == NMP_OBJECT_GET_CLASS (old));
nm_assert (!old || !new || !nmp_object_equal (new, old));
nm_assert (!box_new || box_new == nm_dedup_multi_box_find (cache->multi_idx, new));
nm_assert (!box_old || box_old == nm_dedup_multi_box_find (cache->multi_idx, old));
nm_assert (obj_new || obj_old);
nm_assert (!obj_new || NMP_OBJECT_GET_TYPE (obj_new) != NMP_OBJECT_TYPE_UNKNOWN);
nm_assert (!obj_old || NMP_OBJECT_GET_TYPE (obj_old) != NMP_OBJECT_TYPE_UNKNOWN);
nm_assert (!obj_old || !obj_new || NMP_OBJECT_GET_CLASS (obj_new) == NMP_OBJECT_GET_CLASS (obj_old));
nm_assert (!obj_old || !obj_new || !nmp_object_equal (obj_new, obj_old));
nm_assert (!obj_new || obj_new == nm_dedup_multi_index_obj_find (cache->multi_idx, obj_new));
nm_assert (!obj_old || obj_old == nm_dedup_multi_index_obj_find (cache->multi_idx, obj_old));
idx_type = _idx_type_get (cache, cache_id_type);
if (old) {
if (obj_old) {
entry_old = nm_dedup_multi_index_lookup_obj (cache->multi_idx,
idx_type,
old);
if (!new) {
obj_old);
if (!obj_new) {
if (entry_old)
nm_dedup_multi_index_remove_entry (cache->multi_idx, entry_old);
return;
@ -1917,34 +1890,33 @@ _idxcache_update_box_move (NMPCache *cache,
} else
entry_old = NULL;
if (new) {
if ( old
&& nm_dedup_multi_idx_type_id_equal (idx_type, old, new)
&& nm_dedup_multi_idx_type_partition_equal (idx_type, old, new)) {
/* optimize. We just looked up the @old entry and @new compares equal
if (obj_new) {
if ( obj_old
&& nm_dedup_multi_idx_type_id_equal (idx_type, obj_old, obj_new)
&& nm_dedup_multi_idx_type_partition_equal (idx_type, obj_old, obj_new)) {
/* optimize. We just looked up the @obj_old entry and @obj_new compares equal
* according to idx_obj_id_equal(). entry_new is the same as entry_old. */
entry_new = entry_old;
} else {
entry_new = nm_dedup_multi_index_lookup_obj (cache->multi_idx,
idx_type,
new);
obj_new);
}
if (entry_new)
entry_order = entry_new;
else if ( entry_old
&& nm_dedup_multi_idx_type_partition_equal (idx_type, entry_old->box->obj, new))
&& nm_dedup_multi_idx_type_partition_equal (idx_type, entry_old->obj, obj_new))
entry_order = entry_old;
else
entry_order = NULL;
nm_dedup_multi_index_add_full (cache->multi_idx,
idx_type,
new,
obj_new,
NM_DEDUP_MULTI_IDX_MODE_APPEND,
entry_order,
entry_new ?: NM_DEDUP_MULTI_ENTRY_MISSING,
entry_new ? entry_new->head : (entry_order ? entry_order->head : NULL),
box_new,
&entry_new,
NULL);
@ -1952,8 +1924,8 @@ _idxcache_update_box_move (NMPCache *cache,
if (entry_new) {
nm_assert (idx_type->klass->idx_obj_partitionable);
nm_assert (idx_type->klass->idx_obj_partition_equal);
nm_assert (idx_type->klass->idx_obj_partitionable (idx_type, entry_new->box->obj));
nm_assert (idx_type->klass->idx_obj_partition_equal (idx_type, (gpointer) new, entry_new->box->obj));
nm_assert (idx_type->klass->idx_obj_partitionable (idx_type, entry_new->obj));
nm_assert (idx_type->klass->idx_obj_partition_equal (idx_type, (gpointer) obj_new, entry_new->obj));
}
#endif
} else
@ -1974,8 +1946,7 @@ _idxcache_update (NMPCache *cache,
const guint8 *i_idx_type;
NMDedupMultiIdxType *idx_type_o = _idx_type_get (cache, NMP_CACHE_ID_TYPE_OBJECT_TYPE);
const NMDedupMultiEntry *entry_new = NULL;
const NMDedupMultiBox *box_old;
const NMDedupMultiBox *box_old2 = NULL;
nm_auto_nmpobj const NMPObject *obj_old = NULL;
/* we update an object in the cache.
*
@ -1985,22 +1956,23 @@ _idxcache_update (NMPCache *cache,
nm_assert (cache);
nm_assert (entry_old || obj_new);
nm_assert (!obj_new || nmp_object_is_alive (obj_new));
nm_assert (!entry_old || entry_old == nm_dedup_multi_index_lookup_obj (cache->multi_idx, idx_type_o, entry_old->box->obj));
nm_assert (!entry_old || entry_old == nm_dedup_multi_index_lookup_obj (cache->multi_idx, idx_type_o, entry_old->obj));
nm_assert (!obj_new || entry_old == nm_dedup_multi_index_lookup_obj (cache->multi_idx, idx_type_o, obj_new));
nm_assert (!entry_old || entry_old->head->idx_type == idx_type_o);
nm_assert ( !entry_old
|| !obj_new
|| nm_dedup_multi_idx_type_partition_equal (idx_type_o, entry_old->box->obj, obj_new));
|| nm_dedup_multi_idx_type_partition_equal (idx_type_o, entry_old->obj, obj_new));
nm_assert ( !entry_old
|| !obj_new
|| nm_dedup_multi_idx_type_id_equal (idx_type_o, entry_old->box->obj, obj_new));
|| nm_dedup_multi_idx_type_id_equal (idx_type_o, entry_old->obj, obj_new));
nm_assert ( !entry_old
|| !obj_new
|| ( obj_new->parent.klass == ((const NMPObject *) entry_old->box->obj)->parent.klass
&& !obj_new->parent.klass->obj_full_equal ((NMDedupMultiObj *) obj_new, entry_old->box->obj)));
|| ( obj_new->parent.klass == ((const NMPObject *) entry_old->obj)->parent.klass
&& !obj_new->parent.klass->obj_full_equal ((NMDedupMultiObj *) obj_new, entry_old->obj)));
/* keep a boxed reference to the pre-existing entry */
box_old = entry_old ? nm_dedup_multi_box_ref (entry_old->box) : NULL;
/* keep a reference to the pre-existing entry */
if (entry_old)
obj_old = nmp_object_ref (entry_old->obj);
/* first update the main index NMP_CACHE_ID_TYPE_OBJECT_TYPE.
* We already know the pre-existing @entry old, so all that
@ -2009,6 +1981,8 @@ _idxcache_update (NMPCache *cache,
*
* We also get the new boxed object, which we need below. */
if (obj_new) {
nm_auto_nmpobj NMPObject *obj_old2 = NULL;
nm_dedup_multi_index_add_full (cache->multi_idx,
idx_type_o,
obj_new,
@ -2016,34 +1990,28 @@ _idxcache_update (NMPCache *cache,
NULL,
entry_old ?: NM_DEDUP_MULTI_ENTRY_MISSING,
NULL,
NULL,
&entry_new,
&box_old2);
(const NMDedupMultiObj **) &obj_old2);
nm_assert (entry_new);
nm_assert (box_old == box_old2);
nm_assert (obj_old == obj_old2);
nm_assert (!entry_old || entry_old == entry_new);
if (box_old2)
nm_dedup_multi_box_unref (cache->multi_idx, box_old2);
} else
nm_dedup_multi_index_remove_entry (cache->multi_idx, entry_old);
/* now update all other indexes. We know the previously boxed entry, and the
* newly boxed one. */
klass = NMP_OBJECT_GET_CLASS (entry_new ? entry_new->box->obj : box_old->obj);
klass = NMP_OBJECT_GET_CLASS (entry_new ? entry_new->obj : obj_old);
for (i_idx_type = klass->supported_cache_ids; *i_idx_type; i_idx_type++) {
NMPCacheIdType id_type = *i_idx_type;
if (id_type == NMP_CACHE_ID_TYPE_OBJECT_TYPE)
continue;
_idxcache_update_box_move (cache, id_type,
box_old,
entry_new ? entry_new->box : NULL);
obj_old,
entry_new ? entry_new->obj : NULL);
}
NM_SET_OUT (out_entry_new, entry_new);
if (box_old)
nm_dedup_multi_box_unref (cache->multi_idx, box_old);
}
NMPCacheOpsType
@ -2062,7 +2030,7 @@ nmp_cache_remove (NMPCache *cache,
return NMP_CACHE_OPS_UNCHANGED;
}
obj_old = entry_old->box->obj;
obj_old = entry_old->obj;
NM_SET_OUT (out_obj_old, nmp_object_ref (obj_old));
@ -2095,7 +2063,7 @@ nmp_cache_remove_netlink (NMPCache *cache,
return NMP_CACHE_OPS_UNCHANGED;
}
obj_old = entry_old->box->obj;
obj_old = entry_old->obj;
if (NMP_OBJECT_GET_TYPE (obj_needle) == NMP_OBJECT_TYPE_LINK) {
/* For nmp_cache_remove_netlink() we have an incomplete @obj_needle instance to be
@ -2128,7 +2096,7 @@ nmp_cache_remove_netlink (NMPCache *cache,
entry_old,
obj_new,
&entry_new);
NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->box->obj));
NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj));
return NMP_CACHE_OPS_UPDATED;
}
@ -2182,10 +2150,7 @@ nmp_cache_update_netlink (NMPCache *cache,
nm_assert (NMP_OBJECT_GET_TYPE (obj_hand_over) != NMP_OBJECT_TYPE_LINK ||
( !obj_hand_over->_link.udev.device
&& !obj_hand_over->link.driver));
nm_assert (({
const NMDedupMultiBox *_b = nm_dedup_multi_box_find (cache->multi_idx, obj_hand_over);
!_b || obj_hand_over != _b->obj;
}));
nm_assert (nm_dedup_multi_index_obj_find (cache->multi_idx, obj_hand_over) != obj_hand_over);
entry_old = _lookup_obj (cache, obj_hand_over);
@ -2207,11 +2172,11 @@ nmp_cache_update_netlink (NMPCache *cache,
entry_old,
obj_hand_over,
&entry_new);
NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->box->obj));
NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj));
return NMP_CACHE_OPS_ADDED;
}
obj_old = entry_old->box->obj;
obj_old = entry_old->obj;
if (NMP_OBJECT_GET_TYPE (obj_hand_over) == NMP_OBJECT_TYPE_LINK) {
if (!obj_hand_over->_link.netlink.is_in_netlink) {
@ -2244,6 +2209,13 @@ nmp_cache_update_netlink (NMPCache *cache,
udev_device_unref (obj_hand_over->_link.udev.device);
obj_hand_over->_link.udev.device = obj_old->_link.udev.device ? udev_device_ref (obj_old->_link.udev.device) : NULL;
_nmp_object_fixup_link_udev_fields (&obj_hand_over, NULL, cache->use_udev);
if (obj_hand_over->_link.netlink.lnk) {
nm_auto_nmpobj const NMPObject *lnk_old = obj_hand_over->_link.netlink.lnk;
/* let's dedup/intern the lnk object. */
obj_hand_over->_link.netlink.lnk = nm_dedup_multi_index_obj_intern (cache->multi_idx, lnk_old);
}
}
} else
is_alive = nmp_object_is_alive (obj_hand_over);
@ -2267,7 +2239,7 @@ nmp_cache_update_netlink (NMPCache *cache,
entry_old,
obj_hand_over,
&entry_new);
NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->box->obj));
NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj));
return NMP_CACHE_OPS_UPDATED;
}
@ -2303,10 +2275,10 @@ nmp_cache_update_link_udev (NMPCache *cache,
obj_new,
&entry_new);
NM_SET_OUT (out_obj_old, NULL);
NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->box->obj));
NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj));
return NMP_CACHE_OPS_ADDED;
} else {
obj_old = entry_old->box->obj;
obj_old = entry_old->obj;
NM_SET_OUT (out_obj_old, nmp_object_ref (obj_old));
if (obj_old->_link.udev.device == udevice) {
@ -2332,7 +2304,7 @@ nmp_cache_update_link_udev (NMPCache *cache,
entry_old,
obj_new,
&entry_new);
NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->box->obj));
NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj));
return NMP_CACHE_OPS_UPDATED;
}
}
@ -2356,7 +2328,7 @@ nmp_cache_update_link_master_connected (NMPCache *cache,
return NMP_CACHE_OPS_UNCHANGED;
}
obj_old = entry_old->box->obj;
obj_old = entry_old->obj;
if (!nmp_cache_link_connected_needs_toggle (cache, obj_old, NULL, NULL)) {
NM_SET_OUT (out_obj_old, nmp_object_ref (obj_old));
@ -2372,7 +2344,7 @@ nmp_cache_update_link_master_connected (NMPCache *cache,
entry_old,
obj_new,
&entry_new);
NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->box->obj));
NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj));
return NMP_CACHE_OPS_UPDATED;
}
@ -2542,6 +2514,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip6_route_cmp,
},
[NMP_OBJECT_TYPE_LNK_GRE - 1] = {
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_GRE,
.sizeof_data = sizeof (NMPObjectLnkGre),
.sizeof_public = sizeof (NMPlatformLnkGre),
@ -2552,6 +2525,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_gre_cmp,
},
[NMP_OBJECT_TYPE_LNK_INFINIBAND - 1] = {
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_INFINIBAND,
.sizeof_data = sizeof (NMPObjectLnkInfiniband),
.sizeof_public = sizeof (NMPlatformLnkInfiniband),
@ -2562,6 +2536,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_infiniband_cmp,
},
[NMP_OBJECT_TYPE_LNK_IP6TNL - 1] = {
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_IP6TNL,
.sizeof_data = sizeof (NMPObjectLnkIp6Tnl),
.sizeof_public = sizeof (NMPlatformLnkIp6Tnl),
@ -2572,6 +2547,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ip6tnl_cmp,
},
[NMP_OBJECT_TYPE_LNK_IPIP - 1] = {
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_IPIP,
.sizeof_data = sizeof (NMPObjectLnkIpIp),
.sizeof_public = sizeof (NMPlatformLnkIpIp),
@ -2582,6 +2558,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ipip_cmp,
},
[NMP_OBJECT_TYPE_LNK_MACSEC - 1] = {
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_MACSEC,
.sizeof_data = sizeof (NMPObjectLnkMacsec),
.sizeof_public = sizeof (NMPlatformLnkMacsec),
@ -2592,6 +2569,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_macsec_cmp,
},
[NMP_OBJECT_TYPE_LNK_MACVLAN - 1] = {
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_MACVLAN,
.sizeof_data = sizeof (NMPObjectLnkMacvlan),
.sizeof_public = sizeof (NMPlatformLnkMacvlan),
@ -2602,6 +2580,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_macvlan_cmp,
},
[NMP_OBJECT_TYPE_LNK_MACVTAP - 1] = {
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_MACVTAP,
.sizeof_data = sizeof (NMPObjectLnkMacvtap),
.sizeof_public = sizeof (NMPlatformLnkMacvtap),
@ -2612,6 +2591,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_macvlan_cmp,
},
[NMP_OBJECT_TYPE_LNK_SIT - 1] = {
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_SIT,
.sizeof_data = sizeof (NMPObjectLnkSit),
.sizeof_public = sizeof (NMPlatformLnkSit),
@ -2622,6 +2602,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_sit_cmp,
},
[NMP_OBJECT_TYPE_LNK_VLAN - 1] = {
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_VLAN,
.sizeof_data = sizeof (NMPObjectLnkVlan),
.sizeof_public = sizeof (NMPlatformLnkVlan),
@ -2637,6 +2618,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vlan_cmp,
},
[NMP_OBJECT_TYPE_LNK_VXLAN - 1] = {
.parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_VXLAN,
.sizeof_data = sizeof (NMPObjectLnkVxlan),
.sizeof_public = sizeof (NMPlatformLnkVxlan),

View file

@ -144,7 +144,7 @@ typedef struct {
bool is_in_netlink;
/* Additional data that depends on the link-type (IFLA_INFO_DATA) */
NMPObject *lnk;
const NMPObject *lnk;
} netlink;
struct {
@ -232,7 +232,6 @@ struct _NMPObject {
NMDedupMultiObj parent;
const NMPClass *_class;
};
guint _ref_count;
union {
NMPlatformObject object;
@ -298,7 +297,7 @@ NMP_OBJECT_UP_CAST(const NMPlatformObject *plobj)
obj = plobj
? (NMPObject *) ( &(((char *) plobj)[-((int) G_STRUCT_OFFSET (NMPObject, object))]) )
: NULL;
nm_assert (!obj || (obj->_ref_count > 0 && NMP_CLASS_IS_VALID (obj->_class)));
nm_assert (!obj || (obj->parent._ref_count > 0 && NMP_CLASS_IS_VALID (obj->_class)));
return obj;
}
#define NMP_OBJECT_UP_CAST(plobj) (NMP_OBJECT_UP_CAST ((const NMPlatformObject *) (plobj)))
@ -307,7 +306,7 @@ static inline gboolean
NMP_OBJECT_IS_VALID (const NMPObject *obj)
{
nm_assert (!obj || ( obj
&& obj->_ref_count > 0
&& obj->parent._ref_count > 0
&& NMP_CLASS_IS_VALID (obj->_class)));
/* There isn't really much to check. Either @obj is NULL, or we must
@ -320,7 +319,7 @@ NMP_OBJECT_IS_STACKINIT (const NMPObject *obj)
{
nm_assert (!obj || NMP_OBJECT_IS_VALID (obj));
return obj && obj->_ref_count == NM_OBJ_REF_COUNT_STACKINIT;
return obj && obj->parent._ref_count == NM_OBJ_REF_COUNT_STACKINIT;
}
static inline const NMPClass *
@ -377,8 +376,26 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj)
const NMPClass *nmp_class_from_type (NMPObjectType obj_type);
const NMPObject *nmp_object_ref (const NMPObject *object);
void nmp_object_unref (const NMPObject *object);
static inline const NMPObject *
nmp_object_ref (const NMPObject *obj)
{
/* ref and unref accept const pointers. NMPObject is supposed to be shared
* and kept immutable. Disallowing to take/retrun a reference to a const
* NMPObject is cumbersome, because callers are precisely expected to
* keep a ref on the otherwise immutable object. */
g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj), NULL);
g_return_val_if_fail (obj->parent._ref_count != NM_OBJ_REF_COUNT_STACKINIT, NULL);
return (const NMPObject *) nm_dedup_multi_obj_ref ((const NMDedupMultiObj *) obj);
}
static inline const NMPObject *
nmp_object_unref (const NMPObject *obj)
{
nm_dedup_multi_obj_unref ((const NMDedupMultiObj *) obj);
return NULL;
}
NMPObject *nmp_object_new (NMPObjectType obj_type, const NMPlatformObject *plob);
NMPObject *nmp_object_new_link (int ifindex);
@ -470,8 +487,8 @@ nmp_cache_iter_next (NMDedupMultiIter *iter, const NMPObject **out_obj)
has_next = nm_dedup_multi_iter_next (iter);
if (has_next) {
nm_assert (NMP_OBJECT_IS_VALID (iter->current->box->obj));
NM_SET_OUT (out_obj, iter->current->box->obj);
nm_assert (NMP_OBJECT_IS_VALID (iter->current->obj));
NM_SET_OUT (out_obj, iter->current->obj);
}
return has_next;
}
@ -483,8 +500,8 @@ nmp_cache_iter_next_link (NMDedupMultiIter *iter, const NMPlatformLink **out_obj
has_next = nm_dedup_multi_iter_next (iter);
if (has_next) {
nm_assert (NMP_OBJECT_GET_TYPE (iter->current->box->obj) == NMP_OBJECT_TYPE_LINK);
NM_SET_OUT (out_obj, &(((const NMPObject *) iter->current->box->obj)->link));
nm_assert (NMP_OBJECT_GET_TYPE (iter->current->obj) == NMP_OBJECT_TYPE_LINK);
NM_SET_OUT (out_obj, &(((const NMPObject *) iter->current->obj)->link));
}
return has_next;
}

View file

@ -36,10 +36,18 @@ struct {
static void
test_obj_base (void)
{
static const GObject *g = NULL;
static const GTypeClass *k = NULL;
static const NMPObject *o = NULL;
static const NMPClass *c = NULL;
static const union {
GObject g;
NMPObject k;
} x = { };
static const union {
GTypeClass k;
NMPClass c;
} l = { };
static const GObject *g = &x.g;
static const GTypeClass *k = &l.k;
static const NMPObject *o = &x.k;
static const NMPClass *c = &l.c;
NMObjBaseInst *obj;
gs_unref_object GCancellable *obj_cancellable = g_cancellable_new ();
@ -54,9 +62,8 @@ test_obj_base (void)
STATIC_ASSERT (&g->g_type_instance == (void *) &o->_class);
STATIC_ASSERT (&g->g_type_instance.g_class == (void *) &o->_class);
STATIC_ASSERT (&g->ref_count == (void *) &o->_ref_count);
STATIC_ASSERT (sizeof (o->parent) == sizeof (GTypeInstance));
STATIC_ASSERT (sizeof (o->parent.parent) == sizeof (GTypeInstance));
STATIC_ASSERT (&c->parent == (void *) c);
STATIC_ASSERT (&c->parent.parent.g_type_class == (void *) c);