|
32 | 32 | import synapse.metrics
|
33 | 33 | from synapse.api.constants import EventContentFields, EventTypes
|
34 | 34 | from synapse.api.errors import SynapseError
|
| 35 | +from synapse.api.room_versions import RoomVersions |
35 | 36 | from synapse.events import EventBase # noqa: F401
|
36 | 37 | from synapse.events.snapshot import EventContext # noqa: F401
|
37 | 38 | from synapse.events.utils import prune_event_dict
|
@@ -468,84 +469,93 @@ def _update_current_state_txn(
|
468 | 469 | to_delete = delta_state.to_delete
|
469 | 470 | to_insert = delta_state.to_insert
|
470 | 471 |
|
471 |
| - # First we add entries to the current_state_delta_stream. We |
472 |
| - # do this before updating the current_state_events table so |
473 |
| - # that we can use it to calculate the `prev_event_id`. (This |
474 |
| - # allows us to not have to pull out the existing state |
475 |
| - # unnecessarily). |
476 |
| - # |
477 |
| - # The stream_id for the update is chosen to be the minimum of the stream_ids |
478 |
| - # for the batch of the events that we are persisting; that means we do not |
479 |
| - # end up in a situation where workers see events before the |
480 |
| - # current_state_delta updates. |
481 |
| - # |
482 |
| - sql = """ |
483 |
| - INSERT INTO current_state_delta_stream |
484 |
| - (stream_id, room_id, type, state_key, event_id, prev_event_id) |
485 |
| - SELECT ?, ?, ?, ?, ?, ( |
486 |
| - SELECT event_id FROM current_state_events |
487 |
| - WHERE room_id = ? AND type = ? AND state_key = ? |
| 472 | + if delta_state.no_longer_in_room: |
| 473 | + # Server is no longer in the room so we delete the room from |
| 474 | + # current_state_events, being careful we've already updated the |
| 475 | + # rooms.room_version column (which gets populated in a |
| 476 | + # background task). |
| 477 | + self._upsert_room_version_txn(txn, room_id) |
| 478 | + |
| 479 | + # Before deleting we populate the current_state_delta_stream |
| 480 | + # so that async background tasks get told what happened. |
| 481 | + sql = """ |
| 482 | + INSERT INTO current_state_delta_stream |
| 483 | + (stream_id, room_id, type, state_key, event_id, prev_event_id) |
| 484 | + SELECT ?, room_id, type, state_key, null, event_id |
| 485 | + FROM current_state_events |
| 486 | + WHERE room_id = ? |
| 487 | + """ |
| 488 | + txn.execute(sql, (stream_id, room_id)) |
| 489 | + |
| 490 | + self.db.simple_delete_txn( |
| 491 | + txn, table="current_state_events", keyvalues={"room_id": room_id}, |
488 | 492 | )
|
489 |
| - """ |
490 |
| - txn.executemany( |
491 |
| - sql, |
492 |
| - ( |
493 |
| - ( |
494 |
| - stream_id, |
495 |
| - room_id, |
496 |
| - etype, |
497 |
| - state_key, |
498 |
| - None, |
499 |
| - room_id, |
500 |
| - etype, |
501 |
| - state_key, |
| 493 | + else: |
| 494 | + # We're still in the room, so we update the current state as normal. |
| 495 | + |
| 496 | + # First we add entries to the current_state_delta_stream. We |
| 497 | + # do this before updating the current_state_events table so |
| 498 | + # that we can use it to calculate the `prev_event_id`. (This |
| 499 | + # allows us to not have to pull out the existing state |
| 500 | + # unnecessarily). |
| 501 | + # |
| 502 | + # The stream_id for the update is chosen to be the minimum of the stream_ids |
| 503 | + # for the batch of the events that we are persisting; that means we do not |
| 504 | + # end up in a situation where workers see events before the |
| 505 | + # current_state_delta updates. |
| 506 | + # |
| 507 | + sql = """ |
| 508 | + INSERT INTO current_state_delta_stream |
| 509 | + (stream_id, room_id, type, state_key, event_id, prev_event_id) |
| 510 | + SELECT ?, ?, ?, ?, ?, ( |
| 511 | + SELECT event_id FROM current_state_events |
| 512 | + WHERE room_id = ? AND type = ? AND state_key = ? |
502 | 513 | )
|
503 |
| - for etype, state_key in to_delete |
504 |
| - # We sanity check that we're deleting rather than updating |
505 |
| - if (etype, state_key) not in to_insert |
506 |
| - ), |
507 |
| - ) |
508 |
| - txn.executemany( |
509 |
| - sql, |
510 |
| - ( |
| 514 | + """ |
| 515 | + txn.executemany( |
| 516 | + sql, |
511 | 517 | (
|
512 |
| - stream_id, |
513 |
| - room_id, |
514 |
| - etype, |
515 |
| - state_key, |
516 |
| - ev_id, |
517 |
| - room_id, |
518 |
| - etype, |
519 |
| - state_key, |
520 |
| - ) |
521 |
| - for (etype, state_key), ev_id in iteritems(to_insert) |
522 |
| - ), |
523 |
| - ) |
| 518 | + ( |
| 519 | + stream_id, |
| 520 | + room_id, |
| 521 | + etype, |
| 522 | + state_key, |
| 523 | + to_insert.get((etype, state_key)), |
| 524 | + room_id, |
| 525 | + etype, |
| 526 | + state_key, |
| 527 | + ) |
| 528 | + for etype, state_key in itertools.chain(to_delete, to_insert) |
| 529 | + ), |
| 530 | + ) |
| 531 | + # Now we actually update the current_state_events table |
524 | 532 |
|
525 |
| - # Now we actually update the current_state_events table |
| 533 | + txn.executemany( |
| 534 | + "DELETE FROM current_state_events" |
| 535 | + " WHERE room_id = ? AND type = ? AND state_key = ?", |
| 536 | + ( |
| 537 | + (room_id, etype, state_key) |
| 538 | + for etype, state_key in itertools.chain(to_delete, to_insert) |
| 539 | + ), |
| 540 | + ) |
526 | 541 |
|
527 |
| - txn.executemany( |
528 |
| - "DELETE FROM current_state_events" |
529 |
| - " WHERE room_id = ? AND type = ? AND state_key = ?", |
530 |
| - ( |
531 |
| - (room_id, etype, state_key) |
532 |
| - for etype, state_key in itertools.chain(to_delete, to_insert) |
533 |
| - ), |
534 |
| - ) |
| 542 | + # We include the membership in the current state table, hence we do |
| 543 | + # a lookup when we insert. This assumes that all events have already |
| 544 | + # been inserted into room_memberships. |
| 545 | + txn.executemany( |
| 546 | + """INSERT INTO current_state_events |
| 547 | + (room_id, type, state_key, event_id, membership) |
| 548 | + VALUES (?, ?, ?, ?, (SELECT membership FROM room_memberships WHERE event_id = ?)) |
| 549 | + """, |
| 550 | + [ |
| 551 | + (room_id, key[0], key[1], ev_id, ev_id) |
| 552 | + for key, ev_id in iteritems(to_insert) |
| 553 | + ], |
| 554 | + ) |
535 | 555 |
|
536 |
| - # We include the membership in the current state table, hence we do |
537 |
| - # a lookup when we insert. This assumes that all events have already |
538 |
| - # been inserted into room_memberships. |
539 |
| - txn.executemany( |
540 |
| - """INSERT INTO current_state_events |
541 |
| - (room_id, type, state_key, event_id, membership) |
542 |
| - VALUES (?, ?, ?, ?, (SELECT membership FROM room_memberships WHERE event_id = ?)) |
543 |
| - """, |
544 |
| - [ |
545 |
| - (room_id, key[0], key[1], ev_id, ev_id) |
546 |
| - for key, ev_id in iteritems(to_insert) |
547 |
| - ], |
548 |
| - ) |
| 556 | + # We now update `local_current_membership`. We do this regardless |
| 557 | + # of whether we're still in the room or not to handle the case where |
| 558 | + # e.g. we just got banned (where we need to record that fact here). |
549 | 559 |
|
550 | 560 | # Note: Do we really want to delete rows here (that we do not
|
551 | 561 | # subsequently reinsert below)? While technically correct it means
|
@@ -601,6 +611,35 @@ def _update_current_state_txn(
|
601 | 611 |
|
602 | 612 | self._invalidate_state_caches_and_stream(txn, room_id, members_changed)
|
603 | 613 |
|
| 614 | + def _upsert_room_version_txn(self, txn: LoggingTransaction, room_id: str): |
| 615 | + """Update the room version in the database based off current state |
| 616 | + events. |
| 617 | +
|
| 618 | + This is used when we're about to delete current state and we want to |
| 619 | + ensure that the `rooms.room_version` column is up to date. |
| 620 | + """ |
| 621 | + |
| 622 | + sql = """ |
| 623 | + SELECT json FROM event_json |
| 624 | + INNER JOIN current_state_events USING (room_id, event_id) |
| 625 | + WHERE room_id = ? AND type = ? AND state_key = ? |
| 626 | + """ |
| 627 | + txn.execute(sql, (room_id, EventTypes.Create, "")) |
| 628 | + row = txn.fetchone() |
| 629 | + if row: |
| 630 | + event_json = json.loads(row[0]) |
| 631 | + content = event_json.get("content", {}) |
| 632 | + creator = content.get("creator") |
| 633 | + room_version_id = content.get("room_version", RoomVersions.V1.identifier) |
| 634 | + |
| 635 | + self.db.simple_upsert_txn( |
| 636 | + txn, |
| 637 | + table="rooms", |
| 638 | + keyvalues={"room_id": room_id}, |
| 639 | + values={"room_version": room_version_id}, |
| 640 | + insertion_values={"is_public": False, "creator": creator}, |
| 641 | + ) |
| 642 | + |
604 | 643 | def _update_forward_extremities_txn(
|
605 | 644 | self, txn, new_forward_extremities, max_stream_order
|
606 | 645 | ):
|
|
0 commit comments