On 12.03.2026 15:30, Ilya Maximets wrote:
> On 2/18/26 7:34 PM, Alexandra Rukomoinikova wrote:
>> Currently, when row is inserted, we don't reparse its backrefs at once.
>> Instead, we add it to the 'rows_to_reparse' list - these backreference
>> links will be processed only after all updates are complete in current IDL 
>> run.
>>
>> Therefore, deleting records at the same run they were inserted may cause 
>> problems,
> Hi, Alexandra.  Thanks for working on this and sorry for delay.
>
>> there are 3 options for significant cases
>> 1. update1:
>>        table A - insert
>>        table B refA- insert
> nit:  There are tabs and spaces mixed here.  Should just use spaces.
> Also, it's better to limit the line lenght in commit messages to 72,
> so it fits into 80 when displayed with 'git log'.
>
>>     update2:
>>        table A - delete
>>        table B - delete
>>
>> Table B would have been deleted without errors, since A already existed in 
>> memory
> nit: *Row in the table B
> Same for the other text in the commit message.
>
>> at the time of B's row creation and parsing.
>>
>> 2. update1:
>>        table B refA- insert
>>        table A - insert
>>     update2:
>>        table B - delete
>>        table A - delete
>>
>> In this case B would have been deleted without any problems because B was 
>> added
>> to rows_to_reparse and was reparsed before deletion, thanks to commit [0]
>>
>> There was an overlooked scenario where the table processing order could shift
>> during updates, for example:
>> update1:
>>               table B refA- insert
>>               table A - insert
>> update2:
>>               table A - delete
>>               table B - delete
>> In this case deleting B would trigger B.ref_a=[]
>>
>> IDL process tables in the order they appear in the JSON object, i.e., in the 
>> order
>> they appear in the hash table. This means that different table processing 
>> orders can
>> occur in updates when resizing the table's hash. Currently, this corresponds 
>> to
>> inserting 4 → 8 → 16 elements.
>>
>> In [1], a solution was proposed to not perform all deletions at once,
>> but to submit them for further processing after all inserts backers reparsed,
>> and then perform the deletions (without changing the logic of untracked 
>> deletions).
>>
>> To reproduce this situation, test was added that inserts more than 8 tables
>> in the first update, and deletes only necessary rows in the second update.
> May be good to mention that the test depends on the hashing order, i.e.
> the hashing function, so it may not fail depending on the compiler flags
> or CPU architecture.  It fails for me only if I build with -msse4.2.
>
>> [0] 
>> https://github.com/openvswitch/ovs/commit/02f31a1262fccab21d6ef2726a8ac877a07a7e06
> nit: Use the same format as for the Fixes tag instead of a link.
>
>> [1] https://mail.openvswitch.org/pipermail/ovs-dev/2023-July/406152.html
>>
>> Fixes: 02f31a1262fc ("ovsdb-idl: Preserve references for rows deleted in 
>> same IDL run as their insertion.")
> Shouldn't this be the previous commit instead:
>    7b8aeadd60c8 ("ovsdb-idl: Re-parse backrefs of inserted rows only once.")
> ?
>
>> Signed-off-by: Alexandra Rukomoinikova <[email protected]>
>> ---
>>   lib/ovsdb-idl-provider.h |   1 +
>>   lib/ovsdb-idl.c          |  60 ++++++++++----
>>   tests/idltest.ovsschema  |  26 +++++++
>>   tests/ovsdb-idl.at       | 164 ++++++++++++++++++++++++++++-----------
>>   tests/test-ovsdb.c       |  51 ++++++++++++
>>   tests/test-ovsdb.py      |   2 +
>>   6 files changed, 246 insertions(+), 58 deletions(-)
>>
>> diff --git a/lib/ovsdb-idl-provider.h b/lib/ovsdb-idl-provider.h
>> index 6cf32fb50..fcb8725ae 100644
>> --- a/lib/ovsdb-idl-provider.h
>> +++ b/lib/ovsdb-idl-provider.h
>> @@ -76,6 +76,7 @@ struct ovsdb_idl_row {
>>       struct ovsdb_datum *old_datum; /* Committed data (null if orphaned). */
>>       bool persist_uuid;          /* Persist 'uuid' during insert txn if 
>> set. */
>>       bool parsed; /* Whether the row is parsed. */
>> +    struct ovs_list pending_deletion_node;
> Need a comment for this one explaining what this node is for.
> But also, can we use the track_node for this?  These rows must
> not be tracked until the deletion and they also must not be
> queued for re-parsing via 'deleted_untracked_rows' either until
> the deletion is processed.
>
> The comment for track_node is generic enough to fit the delayed
> deletion use case.
>
>>       struct ovs_list reparse_node; /* Rows that needs to be re-parsed due to
>>                                      * insertion of a referenced row. */
>>   
>> diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
>> index d8094458d..c00245f92 100644
>> --- a/lib/ovsdb-idl.c
>> +++ b/lib/ovsdb-idl.c
>> @@ -93,6 +93,9 @@ struct ovsdb_idl {
>>       struct ovsdb_idl_txn *txn;
>>       struct hmap outstanding_txns;
>>       bool verify_write_only;
>> +    struct ovs_list pending_deletions_rows; /* Stores rows deleted in the
> s/pending_deletions_rows/pending_deletion_rows/
>
>> +                                             * current run until all inserts
>> +                                             * and updates will be parsed. 
>> */
> What happens if the row is deleted and then re-inserted within the same run?
>
> This might be the concern I was referring to here:
>    https://mail.openvswitch.org/pipermail/ovs-dev/2024-January/410541.html
> Though I don't remember, it's been a hot minute.  Might be good to have a
> test case for that.
>
> Note: alternative solution to re-processign things as soon as a different
> type of update is received is maybe to add a new CS event that signifies
> a border between two separate updates and do re-processing on these events.
> Not sure.  Some performance testing would be needed.
>
Hi! Thanks a lot for the review and sorry for the long answer! Yes, I'll 
take this situation into account in the tests. I'll try to cover all 
possible options.

>>       struct ovs_list deleted_untracked_rows; /* Stores rows deleted in the
>>                                                * current run, that are not 
>> yet
>>                                                * added to the track_list. */
>> @@ -152,7 +155,8 @@ static bool ovsdb_idl_modify_row(struct ovsdb_idl_row *,
>>                                    const struct shash *values, bool xor);
>>   static void ovsdb_idl_parse_update(struct ovsdb_idl *,
>>                                      const struct ovsdb_cs_update_event *);
>> -static void ovsdb_idl_reparse_deleted(struct ovsdb_idl *);
>> +static void ovsdb_idl_process_pending_deletions(struct ovsdb_idl *db);
>> +static void ovsdb_idl_reparse_untracked_deletions(struct ovsdb_idl *);
> These two functions are always called together, AFAICT.  It may be better
> to morge the second one into the first.  The "process_pending_deletions"
> name fits both operations.
>
>>   static void ovsdb_idl_reparse_refs_to_inserted(struct ovsdb_idl *);
>>   
>>   static void ovsdb_idl_txn_process_reply(struct ovsdb_idl *,
>> @@ -266,6 +270,8 @@ ovsdb_idl_create_unconnected(const struct 
>> ovsdb_idl_class *class,
>>           .txn = NULL,
>>           .outstanding_txns = HMAP_INITIALIZER(&idl->outstanding_txns),
>>           .verify_write_only = false,
>> +        .pending_deletions_rows
>> +            = OVS_LIST_INITIALIZER(&idl->pending_deletions_rows),
>>           .deleted_untracked_rows
>>               = OVS_LIST_INITIALIZER(&idl->deleted_untracked_rows),
>>           .rows_to_reparse
>> @@ -399,10 +405,14 @@ ovsdb_idl_set_leader_only(struct ovsdb_idl *idl, bool 
>> leader_only)
>>   static void
>>   ovsdb_idl_clear(struct ovsdb_idl *db)
>>   {
>> -    /* Process deleted rows, removing them from the 'deleted_untracked_rows'
>> -     * list and reparsing their backrefs.
>> +    /* Process rows that have been marked for deletion. */
>> +    ovsdb_idl_process_pending_deletions(db);
>> +
>> +    /* Process deleted rows that are not yet added to the track_list,
>> +     * removing them from the 'deleted_untracked_rows' list and reparsing
>> +     * their backrefs.
>>        */
>> -    ovsdb_idl_reparse_deleted(db);
>> +    ovsdb_idl_reparse_untracked_deletions(db);
>>   
>>       /* Process backrefs of inserted rows, removing them from the
>>        * 'rows_to_reparse' list.
>> @@ -447,6 +457,7 @@ ovsdb_idl_clear(struct ovsdb_idl *db)
>>   
>>       /* Free rows deleted from tables with change tracking enabled. */
>>       ovsdb_idl_track_clear__(db, true);
>> +    ovs_assert(ovs_list_is_empty(&db->pending_deletions_rows));
>>       ovs_assert(ovs_list_is_empty(&db->deleted_untracked_rows));
>>       ovs_assert(ovs_list_is_empty(&db->rows_to_reparse));
>>       db->change_seqno++;
>> @@ -493,7 +504,8 @@ ovsdb_idl_run(struct ovsdb_idl *idl)
>>           ovsdb_cs_event_destroy(event);
>>       }
>>       ovsdb_idl_reparse_refs_to_inserted(idl);
>> -    ovsdb_idl_reparse_deleted(idl);
>> +    ovsdb_idl_process_pending_deletions(idl);
>> +    ovsdb_idl_reparse_untracked_deletions(idl);
>>       ovsdb_idl_row_destroy_postprocess(idl);
>>   }
>>   
>> @@ -1588,14 +1600,33 @@ ovsdb_idl_parse_update(struct ovsdb_idl *idl,
>>       }
>>   }
>>   
>> -/* Reparses references to rows that have been deleted in the current IDL 
>> run.
>> +/* Processes all rows that have been deleted in the current IDL run.
>> + *
>> + * This function must be called after all iserts and updates from the 
>> current
> * inserts
> But also, it's better to use the full word 'insertions'.  Here and in other 
> places
> in the patch.
>
>> + * IDL run have been parsed i.e., after all calls to 
>> ovsdb_idl_parse_update().
>> + */
>> +static void
>> +ovsdb_idl_process_pending_deletions(struct ovsdb_idl *db)
>> +{
>> +    struct ovsdb_idl_row *row;
>> +
>> +    LIST_FOR_EACH_POP (row, pending_deletion_node,
>> +                       &db->pending_deletions_rows) {
>> +        ovs_list_init(&row->pending_deletion_node);
>> +
>> +        ovsdb_idl_delete_row(row);
>> +    }
>> +}
>> +
>> +/* Reparses references to rows that have been deleted in the current IDL run
>> + * and that are not yet added to the track_list.
>>    *
>>    * To ensure that reference sources that are deleted are not reparsed,
>> - * this function must be called after all updates have been processed in
>> - * the current IDL run, i.e., after all calls to ovsdb_idl_parse_update().
>> + * this function must be called after all deletions have been processed
>> + * i.e., after all calls to ovsdb_idl_process_pending_deletions().
>>    */
>>   static void
>> -ovsdb_idl_reparse_deleted(struct ovsdb_idl *db)
>> +ovsdb_idl_reparse_untracked_deletions(struct ovsdb_idl *db)
>>   {
>>       struct ovsdb_idl_row *row;
>>   
>> @@ -1674,7 +1705,11 @@ ovsdb_idl_process_update(struct ovsdb_idl_table 
>> *table,
>>       case OVSDB_CS_ROW_DELETE:
>>           if (row && !ovsdb_idl_row_is_orphan(row)) {
>>               /* XXX perhaps we should check the 'old' values? */
>> -            ovsdb_idl_delete_row(row);
>> +            /* Defer deletion processing until all updates of the
>> +             * current IDL run.
>> +             */
> I'd combine the comment blocks and move the XXX one after the new one, with
> a single empty line between them.
>
>> +            ovs_list_push_back(&row->table->idl->pending_deletions_rows,
>> +                               &row->pending_deletion_node);
>>           } else {
>>               VLOG_ERR_RL(&semantic_rl, "cannot delete missing row 
>> "UUID_FMT" "
>>                           "from table %s",
>> @@ -2359,6 +2394,7 @@ ovsdb_idl_row_create__(const struct 
>> ovsdb_idl_table_class *class)
>>       class->row_init(row);
>>       ovs_list_init(&row->src_arcs);
>>       ovs_list_init(&row->dst_arcs);
>> +    ovs_list_init(&row->pending_deletion_node);
>>       ovs_list_init(&row->reparse_node);
>>       hmap_node_nullify(&row->txn_node);
>>       ovs_list_init(&row->track_node);
>> @@ -2489,10 +2525,6 @@ ovsdb_idl_insert_row(struct ovsdb_idl_row *row, const 
>> struct shash *data)
>>   static void
>>   ovsdb_idl_delete_row(struct ovsdb_idl_row *row)
>>   {
>> -    /* If row has to be reparsed, reparse it before it's deleted. */
>> -    if (!ovs_list_is_empty(&row->reparse_node)) {
>> -        ovsdb_idl_row_parse(row);
>> -    }
>>       ovsdb_idl_remove_from_indexes(row);
>>       ovsdb_idl_row_clear_arcs(row, true);
>>       ovsdb_idl_row_destroy(row);
>> diff --git a/tests/idltest.ovsschema b/tests/idltest.ovsschema
>> index 65eadb961..4263076a1 100644
>> --- a/tests/idltest.ovsschema
>> +++ b/tests/idltest.ovsschema
>> @@ -33,6 +33,15 @@
>>               },
>>               "min": 0
>>             }
>> +        },
>> +        "l3": {
>> +          "type": {
>> +            "key": {
>> +              "type": "uuid",
>> +              "refTable": "link3"
>> +            },
>> +            "min": 0
>> +          }
>>           }
>>         },
>>         "isRoot" : true
>> @@ -54,6 +63,23 @@
>>         },
>>         "isRoot" : true
>>       },
>> +    "link3": {
>> +      "columns": {
>> +        "i": {
>> +          "type": "integer"
>> +        },
>> +        "l1": {
>> +          "type": {
>> +            "key": {
>> +              "type": "uuid",
>> +              "refTable": "link1"
>> +            },
>> +            "min": 0
>> +          }
>> +        }
>> +      },
>> +      "isRoot" : true
>> +    },
>>       "indexed": {
>>         "columns": {
>>           "i": {
>> diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at
>> index 728d761d4..1a9075f17 100644
>> --- a/tests/ovsdb-idl.at
>> +++ b/tests/ovsdb-idl.at
>> @@ -172,7 +172,7 @@ m4_define([OVSDB_CHECK_IDL_REGISTER_COLUMNS_PY],
>>        [simple3:name,uset,uref],
>>        [simple4:name],
>>        [simple6:name,weak_ref],
>> -     [link1:i,k,ka,l2],
>> +     [link1:i,k,ka,l2,l3],
>>        [link2:i,l1],
>>        [indexed:i],
>>        [singleton:name]))
>> @@ -755,11 +755,11 @@ OVSDB_CHECK_IDL([simple idl, conditional, multiple 
>> tables],
>>   002: simple: change conditions
>>   003: table simple: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] 
>> uuid=<1>
>>   004: link1: change conditions
>> -005: table link1: i=0 k=0 ka=[] l2= uuid=<2>
>> +005: table link1: i=0 k=0 ka=[] l2= l3= uuid=<2>
>>   005: table simple: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] 
>> uuid=<1>
>>   006: link2: change conditions
>>   007: {"error":null,"result":[{"uuid":["uuid","<3>"]}]}
>> -008: table link1: i=0 k=0 ka=[] l2= uuid=<2>
>> +008: table link1: i=0 k=0 ka=[] l2= l3= uuid=<2>
>>   008: table link2: i=3 l1= uuid=<3>
>>   008: table simple: i=1 r=2 b=true s= u=<0> ia=[] ra=[] ba=[] sa=[] ua=[] 
>> uuid=<1>
>>   009: done
>> @@ -818,19 +818,19 @@ OVSDB_CHECK_IDL([self-linking idl, consistent ops],
>>          "row": {"k": ["uuid", "#0#"]}}]']],
>>     [[000: empty
>>   001: {"error":null,"result":[{"uuid":["uuid","<0>"]}]}
>> -002: table link1: i=0 k=0 ka=[] l2= uuid=<0>
>> +002: table link1: i=0 k=0 ka=[] l2= l3= uuid=<0>
>>   003: 
>> {"error":null,"result":[{"uuid":["uuid","<1>"]},{"uuid":["uuid","<2>"]}]}
>> -004: table link1: i=0 k=0 ka=[] l2= uuid=<0>
>> -004: table link1: i=1 k=2 ka=[] l2= uuid=<1>
>> -004: table link1: i=2 k=1 ka=[] l2= uuid=<2>
>> +004: table link1: i=0 k=0 ka=[] l2= l3= uuid=<0>
>> +004: table link1: i=1 k=2 ka=[] l2= l3= uuid=<1>
>> +004: table link1: i=2 k=1 ka=[] l2= l3= uuid=<2>
>>   005: {"error":null,"result":[{"count":1}]}
>> -006: table link1: i=0 k=0 ka=[] l2= uuid=<0>
>> -006: table link1: i=1 k=1 ka=[] l2= uuid=<1>
>> -006: table link1: i=2 k=1 ka=[] l2= uuid=<2>
>> +006: table link1: i=0 k=0 ka=[] l2= l3= uuid=<0>
>> +006: table link1: i=1 k=1 ka=[] l2= l3= uuid=<1>
>> +006: table link1: i=2 k=1 ka=[] l2= l3= uuid=<2>
>>   007: {"error":null,"result":[{"count":3}]}
>> -008: table link1: i=0 k=0 ka=[] l2= uuid=<0>
>> -008: table link1: i=1 k=0 ka=[] l2= uuid=<1>
>> -008: table link1: i=2 k=0 ka=[] l2= uuid=<2>
>> +008: table link1: i=0 k=0 ka=[] l2= l3= uuid=<0>
>> +008: table link1: i=1 k=0 ka=[] l2= l3= uuid=<1>
>> +008: table link1: i=2 k=0 ka=[] l2= l3= uuid=<2>
>>   009: done
>>   ]])
>>   
>> @@ -869,12 +869,12 @@ OVSDB_CHECK_IDL([self-linking idl, inconsistent ops],
>>     [[000: empty
>>   001: {"error":null,"result":[{"uuid":["uuid","<0>"]},{"details":"Table 
>> link1 column k row <0> references nonexistent row <1> in table 
>> link1.","error":"referential integrity violation"}]}
>>   002: 
>> {"error":null,"result":[{"uuid":["uuid","<2>"]},{"uuid":["uuid","<3>"]}]}
>> -003: table link1: i=1 k=1 ka=[] l2= uuid=<2>
>> -003: table link1: i=2 k=1 ka=[] l2= uuid=<3>
>> +003: table link1: i=1 k=1 ka=[] l2= l3= uuid=<2>
>> +003: table link1: i=2 k=1 ka=[] l2= l3= uuid=<3>
>>   004: {"error":null,"result":[{"count":2},{"details":"Table link1 column k 
>> row <x> references nonexistent row <4> in table link1.","error":"referential 
>> integrity violation"}]}
>>   005: {"error":null,"result":[{"count":1},{"details":"cannot delete link1 
>> row <2> because of 1 remaining reference(s)","error":"referential integrity 
>> violation"}]}
>>   006: {"error":null,"result":[{"count":1}]}
>> -007: table link1: i=1 k=1 ka=[] l2= uuid=<2>
>> +007: table link1: i=1 k=1 ka=[] l2= l3= uuid=<2>
>>   008: {"error":null,"result":[{"count":1}]}
>>   009: empty
>>   010: done
>> @@ -917,15 +917,15 @@ OVSDB_CHECK_IDL([self-linking idl, sets],
>>          "where": []}]']],
>>     [[000: empty
>>   001: 
>> {"error":null,"result":[{"uuid":["uuid","<0>"]},{"uuid":["uuid","<1>"]},{"uuid":["uuid","<2>"]},{"uuid":["uuid","<3>"]}]}
>> -002: table link1: i=0 k=0 ka=[0] l2= uuid=<0>
>> -002: table link1: i=1 k=0 ka=[1] l2= uuid=<1>
>> -002: table link1: i=2 k=0 ka=[2] l2= uuid=<2>
>> -002: table link1: i=3 k=0 ka=[3] l2= uuid=<3>
>> +002: table link1: i=0 k=0 ka=[0] l2= l3= uuid=<0>
>> +002: table link1: i=1 k=0 ka=[1] l2= l3= uuid=<1>
>> +002: table link1: i=2 k=0 ka=[2] l2= l3= uuid=<2>
>> +002: table link1: i=3 k=0 ka=[3] l2= l3= uuid=<3>
>>   003: {"error":null,"result":[{"count":4}]}
>> -004: table link1: i=0 k=0 ka=[0 1 2 3] l2= uuid=<0>
>> -004: table link1: i=1 k=0 ka=[0 1 2 3] l2= uuid=<1>
>> -004: table link1: i=2 k=0 ka=[0 1 2 3] l2= uuid=<2>
>> -004: table link1: i=3 k=0 ka=[0 1 2 3] l2= uuid=<3>
>> +004: table link1: i=0 k=0 ka=[0 1 2 3] l2= l3= uuid=<0>
>> +004: table link1: i=1 k=0 ka=[0 1 2 3] l2= l3= uuid=<1>
>> +004: table link1: i=2 k=0 ka=[0 1 2 3] l2= l3= uuid=<2>
>> +004: table link1: i=3 k=0 ka=[0 1 2 3] l2= l3= uuid=<3>
>>   005: {"error":null,"result":[{"count":1},{"details":"Table link1 column ka 
>> row <2> references nonexistent row <4> in table link1.","error":"referential 
>> integrity violation"}]}
>>   006: {"error":null,"result":[{"count":4}]}
>>   007: empty
>> @@ -945,7 +945,7 @@ OVSDB_CHECK_IDL([external-linking idl, consistent ops],
>>          "uuid-name": "row1"}]']],
>>     [[000: empty
>>   001: 
>> {"error":null,"result":[{"uuid":["uuid","<0>"]},{"uuid":["uuid","<1>"]}]}
>> -002: table link1: i=1 k=1 ka=[] l2=0 uuid=<1>
>> +002: table link1: i=1 k=1 ka=[] l2=0 l3= uuid=<1>
>>   002: table link2: i=0 l1= uuid=<0>
>>   003: done
>>   ]])
>> @@ -1010,8 +1010,8 @@ OVSDB_CHECK_IDL_PY([external-linking idl, insert ops],
>>     [['linktest']],
>>     [[000: empty
>>   001: commit, status=success
>> -002: table link1: i=1 k=1 ka=[1] l2= uuid=<0>
>> -002: table link1: i=2 k=1 ka=[1 2] l2= uuid=<1>
>> +002: table link1: i=1 k=1 ka=[1] l2= l3= uuid=<0>
>> +002: table link1: i=2 k=1 ka=[1 2] l2= l3= uuid=<1>
>>   003: done
>>   ]])
>>   
>> @@ -1020,7 +1020,7 @@ OVSDB_CHECK_IDL_PY([getattr idl, insert ops],
>>     [['getattrtest']],
>>     [[000: empty
>>   001: commit, status=success
>> -002: table link1: i=2 k=2 ka=[] l2= uuid=<0>
>> +002: table link1: i=2 k=2 ka=[] l2= l3= uuid=<0>
>>   003: done
>>   ]])
>>   
>> @@ -1077,19 +1077,19 @@ AT_CHECK([test-ovsdb 
>> '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 idl uni
>>   AT_CHECK([sort stdout | uuidfilt], [0],
>>       [[000: empty
>>   001: {"error":null,"result":[{"uuid":["uuid","<0>"]}]}
>> -002: table link1: i=0 k=0 ka=[] l2= uuid=<0>
>> +002: table link1: i=0 k=0 ka=[] l2= l3= uuid=<0>
>>   003: 
>> {"error":null,"result":[{"uuid":["uuid","<1>"]},{"uuid":["uuid","<2>"]}]}
>> -004: table link1: i=0 k=0 ka=[] l2= uuid=<0>
>> -004: table link1: i=1 k=2 ka=[] l2= uuid=<1>
>> -004: table link1: i=2 k=1 ka=[] l2= uuid=<2>
>> +004: table link1: i=0 k=0 ka=[] l2= l3= uuid=<0>
>> +004: table link1: i=1 k=2 ka=[] l2= l3= uuid=<1>
>> +004: table link1: i=2 k=1 ka=[] l2= l3= uuid=<2>
>>   005: {"error":null,"result":[{"count":1}]}
>> -006: table link1: i=0 k=0 ka=[] l2= uuid=<0>
>> -006: table link1: i=1 k=1 ka=[] l2= uuid=<1>
>> -006: table link1: i=2 k=1 ka=[] l2= uuid=<2>
>> +006: table link1: i=0 k=0 ka=[] l2= l3= uuid=<0>
>> +006: table link1: i=1 k=1 ka=[] l2= l3= uuid=<1>
>> +006: table link1: i=2 k=1 ka=[] l2= l3= uuid=<2>
>>   007: {"error":null,"result":[{"count":3}]}
>> -008: table link1: i=0 k=0 ka=[] l2= uuid=<0>
>> -008: table link1: i=1 k=0 ka=[] l2= uuid=<1>
>> -008: table link1: i=2 k=0 ka=[] l2= uuid=<2>
>> +008: table link1: i=0 k=0 ka=[] l2= l3= uuid=<0>
>> +008: table link1: i=1 k=0 ka=[] l2= l3= uuid=<1>
>> +008: table link1: i=2 k=0 ka=[] l2= l3= uuid=<2>
>>   009: done
>>   ]])
>>   
>> @@ -1097,10 +1097,12 @@ AT_CHECK([sort stdout | uuidfilt], [0],
>>   AT_CHECK([grep ovsdb_idl stderr | sort], [0], [dnl
>>   test-ovsdb|ovsdb_idl|idltest database lacks indexed table (database needs 
>> upgrade?)
>>   test-ovsdb|ovsdb_idl|idltest database lacks link2 table (database needs 
>> upgrade?)
>> +test-ovsdb|ovsdb_idl|idltest database lacks link3 table (database needs 
>> upgrade?)
>>   test-ovsdb|ovsdb_idl|idltest database lacks simple5 table (database needs 
>> upgrade?)
>>   test-ovsdb|ovsdb_idl|idltest database lacks simple6 table (database needs 
>> upgrade?)
>>   test-ovsdb|ovsdb_idl|idltest database lacks singleton table (database 
>> needs upgrade?)
>>   test-ovsdb|ovsdb_idl|link1 table in idltest database lacks l2 column 
>> (database needs upgrade?)
>> +test-ovsdb|ovsdb_idl|link1 table in idltest database lacks l3 column 
>> (database needs upgrade?)
>>   test-ovsdb|ovsdb_idl|simple7 table in idltest database lacks id column 
>> (database needs upgrade?)
>>   ])
>>   
>> @@ -1780,7 +1782,7 @@ OVSDB_CHECK_IDL_TRACK([track, simple idl, initially 
>> empty, strong references, in
>>   001: 
>> {"error":null,"result":[{"uuid":["uuid","<0>"]},{"uuid":["uuid","<1>"]}]}
>>   002: {"error":null,"result":[{"count":1}]}
>>   003: sleep
>> -004: table link1: inserted row: i=1 k=1 ka=[] l2= uuid=<0>
>> +004: table link1: inserted row: i=1 k=1 ka=[] l2= l3= uuid=<0>
>>   004: table link1: updated columns: i k
>>   005: done
>>   ]])
>> @@ -2015,7 +2017,7 @@ OVSDB_CHECK_IDL_NOTIFY([simple link idl verify notify],
>>   001: 
>> {"error":null,"result":[{"uuid":["uuid","<0>"]},{"uuid":["uuid","<1>"]}]}
>>   002: event:create, row={i=1 l2=[<1>]}, uuid=<0>, updates=None
>>   002: event:create, row={i=2 l1=[<0>]}, uuid=<1>, updates=None
>> -002: table link1: i=1 k=1 ka=[] l2=2 uuid=<0>
>> +002: table link1: i=1 k=1 ka=[] l2=2 l3= uuid=<0>
>>   002: table link2: i=2 l1=1 uuid=<1>
>>   003: done
>>   ]])
>> @@ -2762,14 +2764,14 @@ OVSDB_CHECK_IDL_TRACK([track, insert and delete, 
>> refs to link1],
>>   001: 
>> {"error":null,"result":[{"uuid":["uuid","<0>"]},{"uuid":["uuid","<1>"]},{"uuid":["uuid","<2>"]}]}
>>   002: {"error":null,"result":[{"count":1}]}
>>   003: sleep
>> -004: table link1: inserted row: i=1 k=1 ka=[] l2= uuid=<1>
>> +004: table link1: inserted row: i=1 k=1 ka=[] l2= l3= uuid=<1>
>>   004: table link1: updated columns: i k
>>   004: table link2: inserted row: i=1 l1=1 uuid=<0>
>>   004: table link2: inserted/deleted row: i=2 l1=1 uuid=<2>
>>   004: table link2: updated columns: i l1
>>   004: table link2: updated columns: i l1
>>   005: {"error":null,"result":[{"count":1}]}
>> -006: table link1: i=1 k=1 ka=[] l2= uuid=<1>
>> +006: table link1: i=1 k=1 ka=[] l2= l3= uuid=<1>
>>   007: done
>>   ]])
>>   OVSDB_CHECK_IDL_TRACK([track, insert and delete, refs to link2],
>> @@ -2807,8 +2809,8 @@ OVSDB_CHECK_IDL_TRACK([track, insert and delete, refs 
>> to link2],
>>   001: 
>> {"error":null,"result":[{"uuid":["uuid","<0>"]},{"uuid":["uuid","<1>"]},{"uuid":["uuid","<2>"]}]}
>>   002: {"error":null,"result":[{"count":1}]}
>>   003: sleep
>> -004: table link1: inserted row: i=1 k=1 ka=[] l2=1 uuid=<0>
>> -004: table link1: inserted/deleted row: i=2 k=1 ka=[] l2=1 uuid=<2>
>> +004: table link1: inserted row: i=1 k=1 ka=[] l2=1 l3= uuid=<0>
>> +004: table link1: inserted/deleted row: i=2 k=1 ka=[] l2=1 l3= uuid=<2>
>>   004: table link1: updated columns: i k l2
>>   004: table link1: updated columns: i k l2
>>   004: table link2: inserted row: i=1 l1= uuid=<1>
>> @@ -3057,3 +3059,77 @@ AT_CHECK([grep -qE "assertion 
>> !.*txn->assert_read_only failed" stderr])
>>   
>>   OVSDB_SERVER_SHUTDOWN
>>   AT_CLEANUP
>> +
>> +dnl This test checks the order of insert and delete operations, ensuring 
>> that
>> +dnl dependent rows (e.g., `link3` before `link1`) are processed correctly.
>> +dnl It's assumed that in the first update, link1 is processed before link3,
>> +dnl and in the second update, link3 is deleted before link1. We expect to 
>> see
>> +dnl a valid link to link3 after link1 is deleted.
> May need to add a note that this depends on the order of hashes and so on the
> compiler flags and the CPU architecture.
>
> Best regards, Ilya Maximets.


_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to