diff --git a/internal/caching/cache_roomservernids.go b/internal/caching/cache_roomservernids.go new file mode 100644 index 000000000..fdd7fadcc --- /dev/null +++ b/internal/caching/cache_roomservernids.go @@ -0,0 +1,79 @@ +package caching + +import ( + "github.com/matrix-org/dendrite/roomserver/types" +) + +const ( + RoomServerStateKeyNIDsCacheName = "roomserver_statekey_nids" + RoomServerStateKeyNIDsCacheMaxEntries = 1024 + RoomServerStateKeyNIDsCacheMutable = false + + RoomServerEventTypeNIDsCacheName = "roomserver_eventtype_nids" + RoomServerEventTypeNIDsCacheMaxEntries = 64 + RoomServerEventTypeNIDsCacheMutable = false + + RoomServerRoomNIDsCacheName = "roomserver_room_nids" + RoomServerRoomNIDsCacheMaxEntries = 1024 + RoomServerRoomNIDsCacheMutable = false +) + +type RoomServerCaches interface { + RoomServerNIDsCache + RoomVersionCache +} + +// RoomServerNIDsCache contains the subset of functions needed for +// a roomserver NID cache. +type RoomServerNIDsCache interface { + GetRoomServerStateKeyNID(stateKey string) (types.EventStateKeyNID, bool) + StoreRoomServerStateKeyNID(stateKey string, nid types.EventStateKeyNID) + + GetRoomServerEventTypeNID(eventType string) (types.EventTypeNID, bool) + StoreRoomServerEventTypeNID(eventType string, nid types.EventTypeNID) + + GetRoomServerRoomNID(roomID string) (types.RoomNID, bool) + StoreRoomServerRoomNID(roomID string, nid types.RoomNID) +} + +func (c Caches) GetRoomServerStateKeyNID(stateKey string) (types.EventStateKeyNID, bool) { + val, found := c.RoomServerStateKeyNIDs.Get(stateKey) + if found && val != nil { + if stateKeyNID, ok := val.(types.EventStateKeyNID); ok { + return stateKeyNID, true + } + } + return 0, false +} + +func (c Caches) StoreRoomServerStateKeyNID(stateKey string, nid types.EventStateKeyNID) { + c.RoomVersions.Set(stateKey, nid) +} + +func (c Caches) GetRoomServerEventTypeNID(eventType string) (types.EventTypeNID, bool) { + val, found := c.RoomServerEventTypeNIDs.Get(eventType) + if found && val != nil { + if eventTypeNID, ok := val.(types.EventTypeNID); ok { + return eventTypeNID, true + } + } + return 0, false +} + +func (c Caches) StoreRoomServerEventTypeNID(eventType string, nid types.EventTypeNID) { + c.RoomVersions.Set(eventType, nid) +} + +func (c Caches) GetRoomServerRoomNID(roomID string) (types.RoomNID, bool) { + val, found := c.RoomServerRoomNIDs.Get(roomID) + if found && val != nil { + if roomNID, ok := val.(types.RoomNID); ok { + return roomNID, true + } + } + return 0, false +} + +func (c Caches) StoreRoomServerRoomNID(roomID string, nid types.RoomNID) { + c.RoomVersions.Set(roomID, nid) +} diff --git a/internal/caching/caches.go b/internal/caching/caches.go index 419623e27..79512d153 100644 --- a/internal/caching/caches.go +++ b/internal/caching/caches.go @@ -4,8 +4,11 @@ package caching // different implementations as long as they satisfy the Cache // interface. type Caches struct { - RoomVersions Cache // implements RoomVersionCache - ServerKeys Cache // implements ServerKeyCache + RoomVersions Cache // RoomVersionCache + ServerKeys Cache // ServerKeyCache + RoomServerStateKeyNIDs Cache // RoomServerNIDsCache + RoomServerEventTypeNIDs Cache // RoomServerNIDsCache + RoomServerRoomNIDs Cache // RoomServerNIDsCache } // Cache is the interface that an implementation must satisfy. diff --git a/internal/caching/impl_inmemorylru.go b/internal/caching/impl_inmemorylru.go index 7bb791dd8..9187b792a 100644 --- a/internal/caching/impl_inmemorylru.go +++ b/internal/caching/impl_inmemorylru.go @@ -27,9 +27,39 @@ func NewInMemoryLRUCache(enablePrometheus bool) (*Caches, error) { if err != nil { return nil, err } + roomServerStateKeyNIDs, err := NewInMemoryLRUCachePartition( + RoomServerStateKeyNIDsCacheName, + RoomServerStateKeyNIDsCacheMutable, + RoomServerStateKeyNIDsCacheMaxEntries, + enablePrometheus, + ) + if err != nil { + return nil, err + } + roomServerEventTypeNIDs, err := NewInMemoryLRUCachePartition( + RoomServerEventTypeNIDsCacheName, + RoomServerEventTypeNIDsCacheMutable, + RoomServerEventTypeNIDsCacheMaxEntries, + enablePrometheus, + ) + if err != nil { + return nil, err + } + roomServerRoomNIDs, err := NewInMemoryLRUCachePartition( + RoomServerRoomNIDsCacheName, + RoomServerRoomNIDsCacheMutable, + RoomServerRoomNIDsCacheMaxEntries, + enablePrometheus, + ) + if err != nil { + return nil, err + } return &Caches{ - RoomVersions: roomVersions, - ServerKeys: serverKeys, + RoomVersions: roomVersions, + ServerKeys: serverKeys, + RoomServerStateKeyNIDs: roomServerStateKeyNIDs, + RoomServerEventTypeNIDs: roomServerEventTypeNIDs, + RoomServerRoomNIDs: roomServerRoomNIDs, }, nil } diff --git a/roomserver/internal/api.go b/roomserver/internal/api.go index efe9bdcdc..f94c72f05 100644 --- a/roomserver/internal/api.go +++ b/roomserver/internal/api.go @@ -16,7 +16,7 @@ type RoomserverInternalAPI struct { DB storage.Database Cfg *config.RoomServer Producer sarama.SyncProducer - Cache caching.RoomVersionCache + Cache caching.RoomServerCaches ServerName gomatrixserverlib.ServerName KeyRing gomatrixserverlib.JSONVerifier FedClient *gomatrixserverlib.FederationClient diff --git a/roomserver/storage/postgres/storage.go b/roomserver/storage/postgres/storage.go index d217b5d24..02ff072d7 100644 --- a/roomserver/storage/postgres/storage.go +++ b/roomserver/storage/postgres/storage.go @@ -18,6 +18,7 @@ package postgres import ( "database/sql" + "github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/config" "github.com/matrix-org/dendrite/internal/sqlutil" @@ -33,7 +34,7 @@ type Database struct { // Open a postgres database. // nolint: gocyclo -func Open(dbProperties *config.DatabaseOptions) (*Database, error) { +func Open(dbProperties *config.DatabaseOptions, cache caching.RoomServerCaches) (*Database, error) { var d Database var db *sql.DB var err error @@ -98,6 +99,7 @@ func Open(dbProperties *config.DatabaseOptions) (*Database, error) { } d.Database = shared.Database{ DB: db, + Cache: cache, Writer: sqlutil.NewDummyWriter(), EventTypesTable: eventTypes, EventStateKeysTable: eventStateKeys, diff --git a/roomserver/storage/shared/storage.go b/roomserver/storage/shared/storage.go index 7101376a7..81f90b50d 100644 --- a/roomserver/storage/shared/storage.go +++ b/roomserver/storage/shared/storage.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" + "github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/storage/tables" @@ -27,6 +28,7 @@ const redactionsArePermanent = false type Database struct { DB *sql.DB + Cache caching.RoomServerCaches Writer sqlutil.Writer EventsTable tables.Events EventJSONTable tables.EventJSON @@ -51,7 +53,25 @@ func (d *Database) SupportsConcurrentRoomInputs() bool { func (d *Database) EventTypeNIDs( ctx context.Context, eventTypes []string, ) (map[string]types.EventTypeNID, error) { - return d.EventTypesTable.BulkSelectEventTypeNID(ctx, eventTypes) + result := make(map[string]types.EventTypeNID) + remaining := []string{} + for _, eventType := range eventTypes { + if nid, ok := d.Cache.GetRoomServerEventTypeNID(eventType); ok { + result[eventType] = nid + } else { + remaining = append(remaining, eventType) + } + } + if len(remaining) > 0 { + nids, err := d.EventTypesTable.BulkSelectEventTypeNID(ctx, remaining) + if err != nil { + return nil, err + } + for eventType, nid := range nids { + result[eventType] = nid + } + } + return result, nil } func (d *Database) EventStateKeys( @@ -63,7 +83,25 @@ func (d *Database) EventStateKeys( func (d *Database) EventStateKeyNIDs( ctx context.Context, eventStateKeys []string, ) (map[string]types.EventStateKeyNID, error) { - return d.EventStateKeysTable.BulkSelectEventStateKeyNID(ctx, eventStateKeys) + result := make(map[string]types.EventStateKeyNID) + remaining := []string{} + for _, eventStateKey := range eventStateKeys { + if nid, ok := d.Cache.GetRoomServerStateKeyNID(eventStateKey); ok { + result[eventStateKey] = nid + } else { + remaining = append(remaining, eventStateKey) + } + } + if len(remaining) > 0 { + nids, err := d.EventStateKeysTable.BulkSelectEventStateKeyNID(ctx, remaining) + if err != nil { + return nil, err + } + for eventStateKey, nid := range nids { + result[eventStateKey] = nid + } + } + return result, nil } func (d *Database) StateEntriesForEventIDs( @@ -157,6 +195,9 @@ func (d *Database) EventsFromIDs(ctx context.Context, eventIDs []string) ([]type } 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 @@ -165,9 +206,13 @@ func (d *Database) RoomNID(ctx context.Context, roomID string) (types.RoomNID, e } func (d *Database) RoomNIDExcludingStubs(ctx context.Context, roomID string) (roomNID types.RoomNID, err error) { - roomNID, err = d.RoomNID(ctx, roomID) - if err != nil { - return + if nid, ok := d.Cache.GetRoomServerRoomNID(roomID); ok { + roomNID = nid + } else { + roomNID, err = d.RoomNID(ctx, roomID) + if err != nil { + return + } } latestEvents, _, err := d.RoomsTable.SelectLatestEventNIDs(ctx, nil, roomNID) if err != nil { diff --git a/roomserver/storage/sqlite3/storage.go b/roomserver/storage/sqlite3/storage.go index d17389663..87dce6ad1 100644 --- a/roomserver/storage/sqlite3/storage.go +++ b/roomserver/storage/sqlite3/storage.go @@ -19,6 +19,7 @@ import ( "context" "database/sql" + "github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/config" "github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/roomserver/storage/shared" @@ -46,7 +47,7 @@ type Database struct { // Open a sqlite database. // nolint: gocyclo -func Open(dbProperties *config.DatabaseOptions) (*Database, error) { +func Open(dbProperties *config.DatabaseOptions, cache caching.RoomServerCaches) (*Database, error) { var d Database var err error if d.db, err = sqlutil.Open(dbProperties); err != nil { @@ -120,6 +121,7 @@ func Open(dbProperties *config.DatabaseOptions) (*Database, error) { } d.Database = shared.Database{ DB: d.db, + Cache: cache, Writer: sqlutil.NewExclusiveWriter(), EventsTable: d.events, EventTypesTable: d.eventTypes, diff --git a/roomserver/storage/storage.go b/roomserver/storage/storage.go index c6561fdc5..cfbb7b554 100644 --- a/roomserver/storage/storage.go +++ b/roomserver/storage/storage.go @@ -19,18 +19,19 @@ package storage import ( "fmt" + "github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/config" "github.com/matrix-org/dendrite/roomserver/storage/postgres" "github.com/matrix-org/dendrite/roomserver/storage/sqlite3" ) // Open opens a database connection. -func Open(dbProperties *config.DatabaseOptions) (Database, error) { +func Open(dbProperties *config.DatabaseOptions, cache caching.RoomServerCaches) (Database, error) { switch { case dbProperties.ConnectionString.IsSQLite(): - return sqlite3.Open(dbProperties) + return sqlite3.Open(dbProperties, cache) case dbProperties.ConnectionString.IsPostgres(): - return postgres.Open(dbProperties) + return postgres.Open(dbProperties, cache) default: return nil, fmt.Errorf("unexpected database type") }