On 1/11/24 16:02, Dumitru Ceara wrote:
> On 1/11/24 15:44, Ilya Maximets wrote:
>> On 1/10/24 14:12, Dumitru Ceara wrote:
>>> On 1/9/24 20:54, Ilya Maximets wrote:
>>>> Database file contains the column diff, but it is discarded once
>>>> the 'new' state of a row is constructed.  Keep it in the transaction
>>>> row, as it can be used later by other parts of the code.
>>>>
>>>> Diffs do not live long, we keep them around only while transaction
>>>> is alive, so should not affect memory consumption.
>>>>
>>>> Users for this data will be added in later commits.
>>>>
>>>> Acked-by: Mike Pattrick <m...@redhat.com>
>>>> Signed-off-by: Ilya Maximets <i.maxim...@ovn.org>
>>>> ---
>>>>  ovsdb/execution.c    | 14 ++++++++---
>>>>  ovsdb/file.c         | 22 +++++++++++-----
>>>>  ovsdb/ovsdb-server.c |  7 ++++--
>>>>  ovsdb/table.c        |  6 +++--
>>>>  ovsdb/transaction.c  | 60 +++++++++++++++++++++++++++++++++-----------
>>>>  ovsdb/transaction.h  |  6 +++--
>>>>  tests/test-ovsdb.c   |  2 +-
>>>>  7 files changed, 86 insertions(+), 31 deletions(-)
>>>>
>>>> diff --git a/ovsdb/execution.c b/ovsdb/execution.c
>>>> index 5587ef96f..8c20c3b54 100644
>>>> --- a/ovsdb/execution.c
>>>> +++ b/ovsdb/execution.c
>>>> @@ -490,9 +490,11 @@ update_row_cb(const struct ovsdb_row *row, void *ur_)
>>>>  
>>>>      ur->n_matches++;
>>>>      if (!ovsdb_row_equal_columns(row, ur->row, ur->columns)) {
>>>> +        struct ovsdb_row *rw_row;
>>>> +
>>>> +        ovsdb_txn_row_modify(ur->txn, row, &rw_row, NULL);
>>>>          ovsdb_error_assert(ovsdb_row_update_columns(
>>>> -                               ovsdb_txn_row_modify(ur->txn, row),
>>>> -                               ur->row, ur->columns, false));
>>>> +                               rw_row, ur->row, ur->columns, false));
>>>>      }
>>>>  
>>>>      return true;
>>>> @@ -572,10 +574,14 @@ static bool
>>>>  mutate_row_cb(const struct ovsdb_row *row, void *mr_)
>>>>  {
>>>>      struct mutate_row_cbdata *mr = mr_;
>>>> +    struct ovsdb_row *rw_row;
>>>> +
>>>> +    /* Not trying to track the row diff here, because user transactions
>>>> +     * may attempt to add duplicates or remove elements that do not 
>>>> exist. */
>>>> +    ovsdb_txn_row_modify(mr->txn, row, &rw_row, NULL);
>>>>  
>>>>      mr->n_matches++;
>>>> -    *mr->error = ovsdb_mutation_set_execute(ovsdb_txn_row_modify(mr->txn, 
>>>> row),
>>>> -                                            mr->mutations);
>>>> +    *mr->error = ovsdb_mutation_set_execute(rw_row, mr->mutations);
>>>>      return *mr->error == NULL;
>>>>  }
>>>>  
>>>> diff --git a/ovsdb/file.c b/ovsdb/file.c
>>>> index 8bd1d4af3..77a89fd1a 100644
>>>> --- a/ovsdb/file.c
>>>> +++ b/ovsdb/file.c
>>>> @@ -80,8 +80,8 @@ ovsdb_file_column_diff_disable(void)
>>>>  }
>>>>  
>>>>  static struct ovsdb_error *
>>>> -ovsdb_file_update_row_from_json(struct ovsdb_row *row, bool converting,
>>>> -                                bool row_contains_diff,
>>>> +ovsdb_file_update_row_from_json(struct ovsdb_row *row, struct ovsdb_row 
>>>> *diff,
>>>> +                                bool converting, bool row_contains_diff,
>>>>                                  const struct json *json)
>>>>  {
>>>>      struct ovsdb_table_schema *schema = row->table->schema;
>>>> @@ -122,6 +122,12 @@ ovsdb_file_update_row_from_json(struct ovsdb_row 
>>>> *row, bool converting,
>>>>              error = ovsdb_datum_apply_diff_in_place(
>>>>                                             &row->fields[column->index],
>>>>                                             &datum, &column->type);
>>>> +            if (!error && diff) {
>>>> +                
>>>> ovs_assert(ovsdb_datum_is_default(&diff->fields[column->index],
>>>> +                                                  &column->type));
>>>> +                ovsdb_datum_swap(&diff->fields[column->index], &datum);
>>>> +            }
>>>> +
>>>>              ovsdb_datum_destroy(&datum, &column->type);
>>>>              if (error) {
>>>>                  return error;
>>>> @@ -150,16 +156,20 @@ ovsdb_file_txn_row_from_json(struct ovsdb_txn *txn, 
>>>> struct ovsdb_table *table,
>>>>          ovsdb_txn_row_delete(txn, row);
>>>>          return NULL;
>>>>      } else if (row) {
>>>> -        return ovsdb_file_update_row_from_json(ovsdb_txn_row_modify(txn, 
>>>> row),
>>>> -                                               converting, 
>>>> row_contains_diff,
>>>> -                                               json);
>>>> +        struct ovsdb_row *new, *diff = NULL;
>>>> +
>>>> +        ovsdb_txn_row_modify(txn, row, &new,
>>>> +                             row_contains_diff ? &diff : NULL);
>>>> +        return ovsdb_file_update_row_from_json(new, diff, converting,
>>>> +                                               row_contains_diff, json);
>>>>      } else {
>>>>          struct ovsdb_error *error;
>>>>          struct ovsdb_row *new;
>>>>  
>>>>          new = ovsdb_row_create(table);
>>>>          *ovsdb_row_get_uuid_rw(new) = *row_uuid;
>>>> -        error = ovsdb_file_update_row_from_json(new, converting, false, 
>>>> json);
>>>> +        error = ovsdb_file_update_row_from_json(new, NULL, converting,
>>>> +                                                false, json);
>>>>          if (error) {
>>>>              ovsdb_row_destroy(new);
>>>>          } else {
>>>> diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c
>>>> index 4d29043f4..dbf85fe3b 100644
>>>> --- a/ovsdb/ovsdb-server.c
>>>> +++ b/ovsdb/ovsdb-server.c
>>>> @@ -1111,7 +1111,7 @@ update_remote_row(const struct ovsdb_row *row, 
>>>> struct ovsdb_txn *txn,
>>>>          /* Bad remote spec or incorrect schema. */
>>>>          return;
>>>>      }
>>>> -    rw_row = ovsdb_txn_row_modify(txn, row);
>>>> +    ovsdb_txn_row_modify(txn, row, &rw_row, NULL);
>>>>      ovsdb_jsonrpc_server_get_remote_status(jsonrpc, target, &status);
>>>>  
>>>>      /* Update status information columns. */
>>>> @@ -1301,7 +1301,10 @@ update_server_status(struct shash *all_dbs)
>>>>          if (!db || !db->db) {
>>>>              ovsdb_txn_row_delete(txn, row);
>>>>          } else {
>>>> -            update_database_status(ovsdb_txn_row_modify(txn, row), db);
>>>> +            struct ovsdb_row *rw_row;
>>>> +
>>>> +            ovsdb_txn_row_modify(txn, row, &rw_row, NULL);
>>>> +            update_database_status(rw_row, db);
>>>>          }
>>>>      }
>>>>  
>>>> diff --git a/ovsdb/table.c b/ovsdb/table.c
>>>> index 0792e1580..3e89ddd44 100644
>>>> --- a/ovsdb/table.c
>>>> +++ b/ovsdb/table.c
>>>> @@ -415,8 +415,10 @@ ovsdb_table_execute_update(struct ovsdb_txn *txn, 
>>>> const struct uuid *row_uuid,
>>>>                                                      NULL, &columns, xor);
>>>>  
>>>>      if (!error && (xor || !ovsdb_row_equal_columns(row, update, 
>>>> &columns))) {
>>>> -        error = ovsdb_row_update_columns(ovsdb_txn_row_modify(txn, row),
>>>> -                                         update, &columns, xor);
>>>> +        struct ovsdb_row *rw_row;
>>>> +
>>>> +        ovsdb_txn_row_modify(txn, row, &rw_row, NULL);
>>>> +        error = ovsdb_row_update_columns(rw_row, update, &columns, xor);
>>>>      }
>>>>  
>>>>      ovsdb_column_set_destroy(&columns);
>>>> diff --git a/ovsdb/transaction.c b/ovsdb/transaction.c
>>>> index a482588a0..b69d03b5a 100644
>>>> --- a/ovsdb/transaction.c
>>>> +++ b/ovsdb/transaction.c
>>>> @@ -72,6 +72,8 @@ struct ovsdb_txn_table {
>>>>   *        'new'.
>>>>   *
>>>>   *      - A row modified by a transaction will have non-null 'old' and 
>>>> 'new'.
>>>> + *        It may have non-null 'diff' as well in this case, but it is not
>>>> + *        necessary.
>>>>   *
>>>>   *      - 'old' and 'new' both null indicates that a row was added then 
>>>> deleted
>>>>   *        within a single transaction.  Most of the time we instead 
>>>> delete the
>>>> @@ -83,6 +85,7 @@ struct ovsdb_txn_row {
>>>>      struct hmap_node hmap_node; /* In ovsdb_txn_table's txn_rows hmap. */
>>>>      struct ovsdb_row *old;      /* The old row. */
>>>>      struct ovsdb_row *new;      /* The new row. */
>>>> +    struct ovsdb_row *diff;     /* The difference between old and new. */
>>>>      size_t n_refs;              /* Number of remaining references. */
>>>>  
>>>>      /* These members are the same as the corresponding members of 'old' or
>>>> @@ -155,6 +158,7 @@ ovsdb_txn_row_abort(struct ovsdb_txn *txn OVS_UNUSED,
>>>>  {
>>>>      struct ovsdb_row *old = txn_row->old;
>>>>      struct ovsdb_row *new = txn_row->new;
>>>> +    struct ovsdb_row *diff = txn_row->diff;
>>>>  
>>>>      ovsdb_txn_row_prefree(txn_row);
>>>>      if (!old) {
>>>> @@ -184,6 +188,7 @@ ovsdb_txn_row_abort(struct ovsdb_txn *txn OVS_UNUSED,
>>>>      }
>>>>  
>>>>      ovsdb_row_destroy(new);
>>>> +    ovsdb_row_destroy(diff);
>>>>      free(txn_row);
>>>>  
>>>>      return NULL;
>>>> @@ -250,7 +255,10 @@ find_or_make_txn_row(struct ovsdb_txn *txn, const 
>>>> struct ovsdb_table *table,
>>>>      if (!txn_row) {
>>>>          const struct ovsdb_row *row = ovsdb_table_get_row(table, uuid);
>>>>          if (row) {
>>>> -            txn_row = ovsdb_txn_row_modify(txn, row)->txn_row;
>>>> +            struct ovsdb_row *rw_row;
>>>> +
>>>> +            ovsdb_txn_row_modify(txn, row, &rw_row, NULL);
>>>> +            txn_row = rw_row->txn_row;
>>>>          }
>>>>      }
>>>>      return txn_row;
>>>> @@ -433,6 +441,7 @@ delete_garbage_row(struct ovsdb_txn *txn, struct 
>>>> ovsdb_txn_row *txn_row)
>>>>          return NULL;
>>>>      }
>>>>  
>>>> +    ovsdb_row_destroy(txn_row->diff);
>>>
>>> I think in practice 'txn_row' will always be destroyed by the time we
>>> exit the delete_garbage_row() function.  But given that we do have some
>>> theoretical error cases (when delete_row_refs() returns error) in which
>>> we don't destroy 'row' should we set txn_row->diff to NULL here?
>>
>> delete_row_refs() can't actually fail, because we just checked the
>> referential integrity of strong references before colliecting
>> garbage rows.  And you may see that garbage collection failure is
>> wrapped in OVSDB_WRAP_BUG("can't happen", error).  And it actually
>> can't happen, otherwise we have a serious referential integrity
>> bug in ovsdb-server.
>>
> 
> Right, I saw that, that's why in practice this will probably never happen.
> 
>> But I can add txn_row->diff = NULL, just to not crash somewhere
>> later because of this, even if we could crash due to referential
>> integrity issues.
>>
>> What do you think?
>>
> 
> Sounds good.
> 
> With that:
> 
> Acked-by: Dumitru Ceara <dce...@redhat.com>

Thanks, Mike and Dumitru!  I added this, addessed nits from the patch
#2 and applied the set.

Best regards, Ilya Maximets.
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to