On 4/24/20 10:23 PM, Han Zhou wrote: > > > On Thu, Apr 23, 2020 at 12:04 PM Ilya Maximets <i.maxim...@ovn.org > <mailto:i.maxim...@ovn.org>> wrote: >> >> On 4/23/20 8:22 PM, Ilya Maximets wrote: >> > On 4/22/20 8:38 PM, Dumitru Ceara wrote: >> >> Assuming an ovsdb client connected to a database using OVSDB_MONITOR_V3 >> >> (i.e., "monitor_cond_since" method) with the initial monitor condition >> >> MC1. >> >> >> >> Assuming the following two transactions are executed on the >> >> ovsdb-server: >> >> TXN1: "insert record R1 in table T1" >> >> TXN2: "insert record R2 in table T2" >> >> >> >> If the client's monitor condition MC1 for table T2 matches R2 then the >> >> client will receive the following update3 message: >> >> method="update3", "insert record R2 in table T2", last-txn-id=TXN2 >> >> >> >> At this point, if the presence of the new record R2 in the IDL triggers >> >> the client to update its monitor condition to MC2 and add a clause for >> >> table T1 which matches R1, a monitor_cond_change message is sent to the >> >> server: >> >> method="monitor_cond_change", "clauses from MC2" >> >> >> >> In normal operation the ovsdb-server will reply with a new update3 >> >> message of the form: >> >> method="update3", "insert record R1 in table T1", last-txn-id=TXN2 >> >> >> >> However, if the connection drops in the meantime, this last update might >> >> get lost. >> >> >> >> It might happen that during the reconnect a new transaction happens >> >> that modifies the original record R1: >> >> TXN3: "modify record R1 in table T1" >> >> >> >> When the client reconnects, it will try to perform a fast resync by >> >> sending: >> >> method="monitor_cond_since", "clauses from MC2", last-txn-id=TXN2 >> >> >> >> Because TXN2 is still in the ovsdb-server transaction history, the >> >> server replies with the changes from the most recent transactions only, >> >> i.e., TXN3: >> >> result="true", last-txbb-id=TXN3, "modify record R1 in table T1" >> >> >> >> This causes the IDL on the client in to end up in an inconsistent >> >> state because it has never seen the update that created R1. >> >> >> >> Such a scenario is described in: >> >> https://bugzilla.redhat.com/show_bug.cgi?id=1808580#c22 >> >> >> >> To avoid hitting this issue, whenever a reconnect happens (either >> >> due to an IDL retry or due to network issues), we clear db->last_id >> >> in ovsdb_idl_restart_fsm() in any of the following cases: >> >> - a monitor condition has been changed locally and the corresponding >> >> request was not sent yet (i.e., idl->data.cond_changed == true). >> >> - a monitor_cond_change request is in flight. >> >> >> >> This ensures that updates of type "insert" that happened before the last >> >> transaction known by the IDL but didn't match old monitor conditions are >> >> sent upon reconnect if the monitor condition has changed to include them >> >> in the meantime. >> >> >> >> CC: Han Zhou <hz...@ovn.org <mailto:hz...@ovn.org>> >> >> Fixes: 403a6a0cb003 ("ovsdb-idl: Fast resync from server when connection >> >> reset.") >> >> Signed-off-by: Dumitru Ceara <dce...@redhat.com >> >> <mailto:dce...@redhat.com>> >> >> --- >> >> lib/ovsdb-idl.c | 19 +++++++++++++++++++ >> >> 1 file changed, 19 insertions(+) >> >> >> >> diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c >> >> index 1535ad7..67c4745 100644 >> >> --- a/lib/ovsdb-idl.c >> >> +++ b/lib/ovsdb-idl.c >> >> @@ -690,6 +690,25 @@ ovsdb_idl_send_request(struct ovsdb_idl *idl, struct >> >> jsonrpc_msg *request) >> >> static void >> >> ovsdb_idl_restart_fsm(struct ovsdb_idl *idl) >> >> { >> >> + /* If there's an outstanding request of type monitor_cond_change and >> >> + * we're in monitor_cond_since mode then we can't trust that all >> >> relevant >> >> + * updates from transaction idl->data.last_id have been received as >> >> we >> >> + * might have relaxed the monitor condition with our last request and >> >> + * might be missing previously not monitored records. >> >> + * >> >> + * Same reasoning applies for the case when a monitor condition has >> >> been >> >> + * changed locally but the monitor_cond_change request was not sent >> >> yet. >> >> + * >> >> + * In both cases, clear last_id to make sure that the next time >> >> + * monitor_cond_since is sent (i.e., after reconnect) we get the >> >> complete >> >> + * view of the database. >> >> + */ >> >> + if (idl->data.cond_changed || >> >> + (idl->request_id && >> >> + idl->data.monitoring == >> >> OVSDB_IDL_MONITORING_COND_SINCE)) { >> >> + uuid_zero(&idl->data.last_id); >> > >> > As Han pointed out during OVN IRC meeting, when there is a change to SB, >> > e.g. >> > creating a new DP, it causes all HVs changing the condition, and at the >> > same time >> > one of the SB servers might be disconnected triggering this bug on a big >> > number >> > of nodes at once. If all of these nodes will request the full database at >> > the >> > same time, this might be an issue. >> > >> > One possibility that came to mind is that we could store 'last_id' for the >> > previous successful cond_change and use it instead of 0 on re-connection >> > if there >> > was in-flight cond_change. This way we could reduce the pressure on SB >> > server. >> >> Thinking more about this, this idea should not work because with new >> conditions we >> might need to receive changes that happened even before the last successful >> cond_change >> because we might relax conditions incrementally. >> >> So, current solution seems the most correct for now. I'd like to hear some >> other >> thoughts about this issue with massive re-connections, though, if any. >> > > Ideally, this can be solved by below mechanism: > 1. If there is an uncompleted cond_change (either not sent, or in-flight) > while server > disconnected, the IDL firsty reconnect with old condition with last_id being > the current > data position, so that server knows the old condition first. > 2. Then it retry the cond_change request with the new condition. Server will > send all > needed updates for the delta between old and new condition.
Yeah, we've been discussing same approach today with Dumitru. > This may need more complex logic in the IDL implementation, if not too > complex. Implementation suggestion might be to store "new_conditions" along with "conditions": - set_conditions() should set "new_conditions" if they are not equal to "conditions" or current "new_conditions". - monitor_cond_since should always use old "conditions". - monitor_cond_change should always send "new_conditions". On reply from the server "conditions" should be freed, "new_conditions" moved to "conditions" and "new_conditions" cleared. In this case, on re-connection, both "conditions" and "new_conditions" will be present and two sequential requests (monitor_cond_since, monitor_cond_change) will be triggered naturally by the existing code. > > Thanks, > Han > >> > >> >> + } >> >> + >> >> ovsdb_idl_send_schema_request(idl, &idl->server); >> >> ovsdb_idl_transition(idl, IDL_S_SERVER_SCHEMA_REQUESTED); >> >> idl->data.monitoring = OVSDB_IDL_NOT_MONITORING; >> >> >> > >> _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev