Add RoomInfo metadata struct (#1367)

* Add RoomInfo struct

* Remove RoomNID and replace with RoomInfo

* Bugfix and remove another needless query

* nil guard
This commit is contained in:
Kegsay 2020-09-01 12:40:49 +01:00 committed by GitHub
parent 0ab5bccd11
commit 6d79f04354
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 106 additions and 85 deletions

View file

@ -293,11 +293,11 @@ func joinEventsFromHistoryVisibility(
return nil, nil
}
// get joined members
roomNID, err := db.RoomNID(ctx, roomID)
info, err := db.RoomInfo(ctx, roomID)
if err != nil {
return nil, err
}
joinEventNIDs, err := db.GetMembershipEventNIDsForRoom(ctx, roomNID, true, false)
joinEventNIDs, err := db.GetMembershipEventNIDsForRoom(ctx, info.RoomNID, true, false)
if err != nil {
return nil, err
}

View file

@ -26,12 +26,17 @@ func (r *RoomserverInternalAPI) PerformInvite(
roomID := event.RoomID()
targetUserID := *event.StateKey()
info, err := r.DB.RoomInfo(ctx, roomID)
if err != nil {
return fmt.Errorf("Failed to load RoomInfo: %w", err)
}
log.WithFields(log.Fields{
"event_id": event.EventID(),
"room_id": roomID,
"room_version": req.RoomVersion,
"target_user_id": targetUserID,
"room_info_exists": info != nil,
}).Info("processing invite event")
_, domain, _ := gomatrixserverlib.SplitID('@', targetUserID)
@ -39,25 +44,25 @@ func (r *RoomserverInternalAPI) PerformInvite(
isOriginLocal := event.Origin() == r.Cfg.Matrix.ServerName
inviteState := req.InviteRoomState
if len(inviteState) == 0 {
if is, err := buildInviteStrippedState(ctx, r.DB, req); err == nil {
if len(inviteState) == 0 && info != nil {
var is []gomatrixserverlib.InviteV2StrippedState
if is, err = buildInviteStrippedState(ctx, r.DB, info, req); err == nil {
inviteState = is
}
}
if len(inviteState) == 0 {
if err := event.SetUnsignedField("invite_room_state", struct{}{}); err != nil {
if err = event.SetUnsignedField("invite_room_state", struct{}{}); err != nil {
return fmt.Errorf("event.SetUnsignedField: %w", err)
}
} else {
if err := event.SetUnsignedField("invite_room_state", inviteState); err != nil {
if err = event.SetUnsignedField("invite_room_state", inviteState); err != nil {
return fmt.Errorf("event.SetUnsignedField: %w", err)
}
}
var isAlreadyJoined bool
roomNID, err := r.DB.RoomNID(ctx, roomID)
if err == nil {
_, isAlreadyJoined, err = r.DB.GetMembership(ctx, roomNID, *event.StateKey())
if info != nil {
_, isAlreadyJoined, err = r.DB.GetMembership(ctx, info.RoomNID, *event.StateKey())
if err != nil {
return fmt.Errorf("r.DB.GetMembership: %w", err)
}
@ -187,12 +192,9 @@ func (r *RoomserverInternalAPI) PerformInvite(
func buildInviteStrippedState(
ctx context.Context,
db storage.Database,
info *types.RoomInfo,
input *api.PerformInviteRequest,
) ([]gomatrixserverlib.InviteV2StrippedState, error) {
roomNID, err := db.RoomNID(ctx, input.Event.RoomID())
if err != nil || roomNID == 0 {
return nil, fmt.Errorf("room %q unknown", input.Event.RoomID())
}
stateWanted := []gomatrixserverlib.StateKeyTuple{}
// "If they are set on the room, at least the state for m.room.avatar, m.room.canonical_alias, m.room.join_rules, and m.room.name SHOULD be included."
// https://matrix.org/docs/spec/client_server/r0.6.0#m-room-member
@ -206,13 +208,9 @@ func buildInviteStrippedState(
StateKey: "",
})
}
_, currentStateSnapshotNID, _, err := db.LatestEventIDs(ctx, roomNID)
if err != nil {
return nil, err
}
roomState := state.NewStateResolution(db)
stateEntries, err := roomState.LoadStateAtSnapshotForStringTuples(
ctx, currentStateSnapshotNID, stateWanted,
ctx, info.StateSnapshotNID, stateWanted,
)
if err != nil {
return nil, err

View file

@ -172,9 +172,12 @@ func (r *RoomserverInternalAPI) isInvitePending(
roomID, userID string,
) (bool, string, string, error) {
// Look up the room NID for the supplied room ID.
roomNID, err := r.DB.RoomNID(ctx, roomID)
info, err := r.DB.RoomInfo(ctx, roomID)
if err != nil {
return false, "", "", fmt.Errorf("r.DB.RoomNID: %w", err)
return false, "", "", fmt.Errorf("r.DB.RoomInfo: %w", err)
}
if info == nil {
return false, "", "", fmt.Errorf("cannot get RoomInfo: unknown room ID %s", roomID)
}
// Look up the state key NID for the supplied user ID.
@ -190,7 +193,7 @@ func (r *RoomserverInternalAPI) isInvitePending(
// Let's see if we have an event active for the user in the room. If
// we do then it will contain a server name that we can direct the
// send_leave to.
senderUserNIDs, eventIDs, err := r.DB.GetInvitesForUser(ctx, roomNID, targetUserNID)
senderUserNIDs, eventIDs, err := r.DB.GetInvitesForUser(ctx, info.RoomNID, targetUserNID)
if err != nil {
return false, "", "", fmt.Errorf("r.DB.GetInvitesForUser: %w", err)
}

View file

@ -46,11 +46,11 @@ func (r *RoomserverInternalAPI) QueryLatestEventsAndState(
roomState := state.NewStateResolution(r.DB)
roomNID, err := r.DB.RoomNIDExcludingStubs(ctx, request.RoomID)
info, err := r.DB.RoomInfo(ctx, request.RoomID)
if err != nil {
return err
}
if roomNID == 0 {
if info.IsStub {
return nil
}
response.RoomExists = true
@ -58,7 +58,7 @@ func (r *RoomserverInternalAPI) QueryLatestEventsAndState(
var currentStateSnapshotNID types.StateSnapshotNID
response.LatestEvents, currentStateSnapshotNID, response.Depth, err =
r.DB.LatestEventIDs(ctx, roomNID)
r.DB.LatestEventIDs(ctx, info.RoomNID)
if err != nil {
return err
}
@ -105,11 +105,11 @@ func (r *RoomserverInternalAPI) QueryStateAfterEvents(
roomState := state.NewStateResolution(r.DB)
roomNID, err := r.DB.RoomNIDExcludingStubs(ctx, request.RoomID)
info, err := r.DB.RoomInfo(ctx, request.RoomID)
if err != nil {
return err
}
if roomNID == 0 {
if info.IsStub {
return nil
}
response.RoomExists = true
@ -128,7 +128,7 @@ func (r *RoomserverInternalAPI) QueryStateAfterEvents(
// Look up the currrent state for the requested tuples.
stateEntries, err := roomState.LoadStateAfterEventsForStringTuples(
ctx, roomNID, prevStates, request.StateToFetch,
ctx, info.RoomNID, prevStates, request.StateToFetch,
)
if err != nil {
return err
@ -210,12 +210,12 @@ func (r *RoomserverInternalAPI) QueryMembershipForUser(
request *api.QueryMembershipForUserRequest,
response *api.QueryMembershipForUserResponse,
) error {
roomNID, err := r.DB.RoomNID(ctx, request.RoomID)
info, err := r.DB.RoomInfo(ctx, request.RoomID)
if err != nil {
return err
}
membershipEventNID, stillInRoom, err := r.DB.GetMembership(ctx, roomNID, request.UserID)
membershipEventNID, stillInRoom, err := r.DB.GetMembership(ctx, info.RoomNID, request.UserID)
if err != nil {
return err
}
@ -247,12 +247,12 @@ func (r *RoomserverInternalAPI) QueryMembershipsForRoom(
request *api.QueryMembershipsForRoomRequest,
response *api.QueryMembershipsForRoomResponse,
) error {
roomNID, err := r.DB.RoomNID(ctx, request.RoomID)
info, err := r.DB.RoomInfo(ctx, request.RoomID)
if err != nil {
return err
}
membershipEventNID, stillInRoom, err := r.DB.GetMembership(ctx, roomNID, request.Sender)
membershipEventNID, stillInRoom, err := r.DB.GetMembership(ctx, info.RoomNID, request.Sender)
if err != nil {
return err
}
@ -270,7 +270,7 @@ func (r *RoomserverInternalAPI) QueryMembershipsForRoom(
var stateEntries []types.StateEntry
if stillInRoom {
var eventNIDs []types.EventNID
eventNIDs, err = r.DB.GetMembershipEventNIDsForRoom(ctx, roomNID, request.JoinedOnly, false)
eventNIDs, err = r.DB.GetMembershipEventNIDsForRoom(ctx, info.RoomNID, request.JoinedOnly, false)
if err != nil {
return err
}
@ -555,12 +555,15 @@ func (r *RoomserverInternalAPI) backfillViaFederation(ctx context.Context, req *
}
func (r *RoomserverInternalAPI) isServerCurrentlyInRoom(ctx context.Context, serverName gomatrixserverlib.ServerName, roomID string) (bool, error) {
roomNID, err := r.DB.RoomNID(ctx, roomID)
info, err := r.DB.RoomInfo(ctx, roomID)
if err != nil {
return false, err
}
if info == nil {
return false, fmt.Errorf("unknown room %s", roomID)
}
eventNIDs, err := r.DB.GetMembershipEventNIDsForRoom(ctx, roomNID, true, false)
eventNIDs, err := r.DB.GetMembershipEventNIDsForRoom(ctx, info.RoomNID, true, false)
if err != nil {
return false, err
}
@ -737,20 +740,15 @@ func (r *RoomserverInternalAPI) QueryStateAndAuthChain(
request *api.QueryStateAndAuthChainRequest,
response *api.QueryStateAndAuthChainResponse,
) error {
roomNID, err := r.DB.RoomNIDExcludingStubs(ctx, request.RoomID)
info, err := r.DB.RoomInfo(ctx, request.RoomID)
if err != nil {
return err
}
if roomNID == 0 {
if info.IsStub {
return nil
}
response.RoomExists = true
roomVersion, err := r.DB.GetRoomVersionForRoom(ctx, request.RoomID)
if err != nil {
return err
}
response.RoomVersion = roomVersion
response.RoomVersion = info.RoomVersion
stateEvents, err := r.loadStateAtEventIDs(ctx, request.PrevEventIDs)
if err != nil {
@ -773,18 +771,18 @@ func (r *RoomserverInternalAPI) QueryStateAndAuthChain(
if request.ResolveState {
if stateEvents, err = state.ResolveConflictsAdhoc(
roomVersion, stateEvents, authEvents,
info.RoomVersion, stateEvents, authEvents,
); err != nil {
return err
}
}
for _, event := range stateEvents {
response.StateEvents = append(response.StateEvents, event.Headered(roomVersion))
response.StateEvents = append(response.StateEvents, event.Headered(info.RoomVersion))
}
for _, event := range authEvents {
response.AuthChainEvents = append(response.AuthChainEvents, event.Headered(roomVersion))
response.AuthChainEvents = append(response.AuthChainEvents, event.Headered(info.RoomVersion))
}
return err

View file

@ -26,6 +26,8 @@ import (
type Database interface {
// Do we support processing input events for more than one room at a time?
SupportsConcurrentRoomInputs() bool
// RoomInfo returns room information for the given room ID, or nil if there is no room.
RoomInfo(ctx context.Context, roomID string) (*types.RoomInfo, error)
// Store the room state at an event in the database
AddState(
ctx context.Context,
@ -94,14 +96,6 @@ type Database interface {
// This is used to determine if the room event is processed/processing already.
// Returns an empty string if no such event exists.
GetTransactionEventID(ctx context.Context, transactionID string, sessionID int64, userID string) (string, error)
// Look up the numeric ID for the room.
// Returns 0 if the room doesn't exists.
// Returns an error if there was a problem talking to the database.
RoomNID(ctx context.Context, roomID string) (types.RoomNID, error)
// RoomNIDExcludingStubs is a special variation of RoomNID that will return 0 as if the room
// does not exist if the room has no latest events. This can happen when we've received an
// invite over federation for a room that we don't know anything else about yet.
RoomNIDExcludingStubs(ctx context.Context, roomID string) (types.RoomNID, error)
// Look up event references for the latest events in the room and the current state snapshot.
// Returns the latest events, the current state and the maximum depth of the latest events plus 1.
// Returns an error if there was a problem talking to the database.

View file

@ -74,6 +74,9 @@ const selectRoomVersionForRoomIDSQL = "" +
const selectRoomVersionForRoomNIDSQL = "" +
"SELECT room_version FROM roomserver_rooms WHERE room_nid = $1"
const selectRoomInfoSQL = "" +
"SELECT room_version, room_nid, state_snapshot_nid, latest_event_nids FROM roomserver_rooms WHERE room_id = $1"
type roomStatements struct {
insertRoomNIDStmt *sql.Stmt
selectRoomNIDStmt *sql.Stmt
@ -82,6 +85,7 @@ type roomStatements struct {
updateLatestEventNIDsStmt *sql.Stmt
selectRoomVersionForRoomIDStmt *sql.Stmt
selectRoomVersionForRoomNIDStmt *sql.Stmt
selectRoomInfoStmt *sql.Stmt
}
func NewPostgresRoomsTable(db *sql.DB) (tables.Rooms, error) {
@ -98,6 +102,7 @@ func NewPostgresRoomsTable(db *sql.DB) (tables.Rooms, error) {
{&s.updateLatestEventNIDsStmt, updateLatestEventNIDsSQL},
{&s.selectRoomVersionForRoomIDStmt, selectRoomVersionForRoomIDSQL},
{&s.selectRoomVersionForRoomNIDStmt, selectRoomVersionForRoomNIDSQL},
{&s.selectRoomInfoStmt, selectRoomInfoSQL},
}.Prepare(db)
}
@ -111,6 +116,19 @@ func (s *roomStatements) InsertRoomNID(
return types.RoomNID(roomNID), err
}
func (s *roomStatements) SelectRoomInfo(ctx context.Context, roomID string) (*types.RoomInfo, error) {
var info types.RoomInfo
var latestNIDs pq.Int64Array
err := s.selectRoomInfoStmt.QueryRowContext(ctx, roomID).Scan(
&info.RoomVersion, &info.RoomNID, &info.StateSnapshotNID, &latestNIDs,
)
if err == sql.ErrNoRows {
return nil, nil
}
info.IsStub = len(latestNIDs) == 0
return &info, err
}
func (s *roomStatements) SelectRoomNID(
ctx context.Context, txn *sql.Tx, roomID string,
) (types.RoomNID, error) {

View file

@ -120,6 +120,10 @@ func (d *Database) StateEntriesForTuples(
)
}
func (d *Database) RoomInfo(ctx context.Context, roomID string) (*types.RoomInfo, error) {
return d.RoomsTable.SelectRoomInfo(ctx, roomID)
}
func (d *Database) AddState(
ctx context.Context,
roomNID types.RoomNID,
@ -194,34 +198,6 @@ func (d *Database) EventsFromIDs(ctx context.Context, eventIDs []string) ([]type
return d.Events(ctx, nids)
}
func (d *Database) RoomNID(ctx context.Context, roomID string) (types.RoomNID, error) {
if nid, ok := d.Cache.GetRoomServerRoomNID(roomID); ok {
return nid, nil
}
roomNID, err := d.RoomsTable.SelectRoomNID(ctx, nil, roomID)
if err == sql.ErrNoRows {
return 0, nil
}
d.Cache.StoreRoomServerRoomNID(roomID, roomNID)
return roomNID, err
}
func (d *Database) RoomNIDExcludingStubs(ctx context.Context, roomID string) (roomNID types.RoomNID, err error) {
roomNID, err = d.RoomNID(ctx, roomID)
if err != nil {
return
}
latestEvents, _, err := d.RoomsTable.SelectLatestEventNIDs(ctx, nil, roomNID)
if err != nil {
return
}
if len(latestEvents) == 0 {
roomNID = 0
return
}
return
}
func (d *Database) LatestEventIDs(
ctx context.Context, roomNID types.RoomNID,
) (references []gomatrixserverlib.EventReference, currentStateSnapshotNID types.StateSnapshotNID, depth int64, err error) {

View file

@ -64,6 +64,9 @@ const selectRoomVersionForRoomIDSQL = "" +
const selectRoomVersionForRoomNIDSQL = "" +
"SELECT room_version FROM roomserver_rooms WHERE room_nid = $1"
const selectRoomInfoSQL = "" +
"SELECT room_version, room_nid, state_snapshot_nid, latest_event_nids FROM roomserver_rooms WHERE room_id = $1"
type roomStatements struct {
db *sql.DB
insertRoomNIDStmt *sql.Stmt
@ -73,6 +76,7 @@ type roomStatements struct {
updateLatestEventNIDsStmt *sql.Stmt
selectRoomVersionForRoomIDStmt *sql.Stmt
selectRoomVersionForRoomNIDStmt *sql.Stmt
selectRoomInfoStmt *sql.Stmt
}
func NewSqliteRoomsTable(db *sql.DB) (tables.Rooms, error) {
@ -91,9 +95,30 @@ func NewSqliteRoomsTable(db *sql.DB) (tables.Rooms, error) {
{&s.updateLatestEventNIDsStmt, updateLatestEventNIDsSQL},
{&s.selectRoomVersionForRoomIDStmt, selectRoomVersionForRoomIDSQL},
{&s.selectRoomVersionForRoomNIDStmt, selectRoomVersionForRoomNIDSQL},
{&s.selectRoomInfoStmt, selectRoomInfoSQL},
}.Prepare(db)
}
func (s *roomStatements) SelectRoomInfo(ctx context.Context, roomID string) (*types.RoomInfo, error) {
var info types.RoomInfo
var latestNIDsJSON string
err := s.selectRoomInfoStmt.QueryRowContext(ctx, roomID).Scan(
&info.RoomVersion, &info.RoomNID, &info.StateSnapshotNID, &latestNIDsJSON,
)
if err != nil {
if err == sql.ErrNoRows {
return nil, nil
}
return nil, err
}
var latestNIDs []int64
if err = json.Unmarshal([]byte(latestNIDsJSON), &latestNIDs); err != nil {
return nil, err
}
info.IsStub = len(latestNIDs) == 0
return &info, err
}
func (s *roomStatements) InsertRoomNID(
ctx context.Context, txn *sql.Tx,
roomID string, roomVersion gomatrixserverlib.RoomVersion,

View file

@ -65,6 +65,7 @@ type Rooms interface {
UpdateLatestEventNIDs(ctx context.Context, txn *sql.Tx, roomNID types.RoomNID, eventNIDs []types.EventNID, lastEventSentNID types.EventNID, stateSnapshotNID types.StateSnapshotNID) error
SelectRoomVersionForRoomID(ctx context.Context, txn *sql.Tx, roomID string) (gomatrixserverlib.RoomVersion, error)
SelectRoomVersionForRoomNID(ctx context.Context, roomNID types.RoomNID) (gomatrixserverlib.RoomVersion, error)
SelectRoomInfo(ctx context.Context, roomID string) (*types.RoomInfo, error)
}
type Transactions interface {

View file

@ -144,3 +144,11 @@ type StateEntryList struct {
type MissingEventError string
func (e MissingEventError) Error() string { return string(e) }
// RoomInfo contains metadata about a room
type RoomInfo struct {
RoomNID RoomNID
RoomVersion gomatrixserverlib.RoomVersion
StateSnapshotNID StateSnapshotNID
IsStub bool
}