'Insert some number of room events into the necessary database tables.
Rejected events are only inserted into the events table, the events_json table,
and the rejections table. Things reading from those table will need to check
whether the event was rejected.
Args:
txn (twisted.enterprise.adbapi.Connection): db connection
events_and_contexts (list[(EventBase, EventContext)]):
events to persist
backfilled (bool): True if the events were backfilled
delete_existing (bool): True to purge existing table rows for the
events from the database. This is useful when retrying due to
IntegrityError.
current_state_for_room (dict[str, (list[str], list[str])]):
The current-state delta for each room. For each room, a tuple
(to_delete, to_insert), being a list of event ids to be removed
from the current state, and a list of event ids to be added to
the current state.
new_forward_extremeties (dict[str, list[str]]):
The new forward extremities for each room. For each room, a
list of the event ids which are the forward extremities.'

@log_function
def _persist_events_txn(self, txn, events_and_contexts, backfilled, delete_existing=False, current_state_for_room={}, new_forward_extremeties={}):

    max_stream_order = events_and_contexts[(-1)][0].internal_metadata.stream_ordering
    self._update_current_state_txn(txn, current_state_for_room, max_stream_order)
    self._update_forward_extremities_txn(txn, new_forward_extremities=new_forward_extremeties, max_stream_order=max_stream_order)
    events_and_contexts = self._filter_events_and_contexts_for_duplicates(events_and_contexts)
    self._update_room_depths_txn(txn, events_and_contexts=events_and_contexts, backfilled=backfilled)
    events_and_contexts = self._update_outliers_txn(txn, events_and_contexts=events_and_contexts)
    if delete_existing:
        self._delete_existing_rows_txn(txn, events_and_contexts=events_and_contexts)
    self._store_event_txn(txn, events_and_contexts=events_and_contexts)
    self._store_mult_state_groups_txn(txn, events_and_contexts)
    events_and_contexts = self._store_rejected_events_txn(txn, events_and_contexts=events_and_contexts)
    self._update_metadata_tables_txn(txn, events_and_contexts=events_and_contexts, backfilled=backfilled)
