mirror of
https://github.com/matrix-org/dendrite.git
synced 2025-12-25 15:53:09 -06:00
Edges table instead of relationships
This commit is contained in:
parent
a7bb1119d7
commit
33f03046a4
|
|
@ -176,7 +176,7 @@ func eventRelationshipHandler(db Database, rsAPI roomserver.RoomserverInternalAP
|
||||||
// If include_parent: true and there is a valid m.relationship field in the event,
|
// If include_parent: true and there is a valid m.relationship field in the event,
|
||||||
// retrieve the referenced event. Apply history visibility check to that event and if it passes, add it to the response array.
|
// retrieve the referenced event. Apply history visibility check to that event and if it passes, add it to the response array.
|
||||||
func includeParent(ctx context.Context, rsAPI roomserver.RoomserverInternalAPI, event *gomatrixserverlib.HeaderedEvent, userID string) (parent *gomatrixserverlib.HeaderedEvent) {
|
func includeParent(ctx context.Context, rsAPI roomserver.RoomserverInternalAPI, event *gomatrixserverlib.HeaderedEvent, userID string) (parent *gomatrixserverlib.HeaderedEvent) {
|
||||||
parentID, _ := parentChildEventIDs(event)
|
parentID, _, _ := parentChildEventIDs(event)
|
||||||
if parentID == "" {
|
if parentID == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -187,7 +187,7 @@ func includeParent(ctx context.Context, rsAPI roomserver.RoomserverInternalAPI,
|
||||||
// Apply history visibility checks to all these events and add the ones which pass into the response array,
|
// Apply history visibility checks to all these events and add the ones which pass into the response array,
|
||||||
// honouring the recent_first flag and the limit.
|
// honouring the recent_first flag and the limit.
|
||||||
func includeChildren(ctx context.Context, rsAPI roomserver.RoomserverInternalAPI, db Database, parentID string, limit int, recentFirst bool, userID string) ([]*gomatrixserverlib.HeaderedEvent, *util.JSONResponse) {
|
func includeChildren(ctx context.Context, rsAPI roomserver.RoomserverInternalAPI, db Database, parentID string, limit int, recentFirst bool, userID string) ([]*gomatrixserverlib.HeaderedEvent, *util.JSONResponse) {
|
||||||
children, err := db.ChildrenForParent(ctx, parentID)
|
children, err := db.ChildrenForParent(ctx, parentID, "m.reference")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.GetLogger(ctx).WithError(err).Error("failed to get ChildrenForParent")
|
util.GetLogger(ctx).WithError(err).Error("failed to get ChildrenForParent")
|
||||||
resErr := jsonerror.InternalServerError()
|
resErr := jsonerror.InternalServerError()
|
||||||
|
|
@ -219,6 +219,10 @@ func includeChildren(ctx context.Context, rsAPI roomserver.RoomserverInternalAPI
|
||||||
func walkThread(
|
func walkThread(
|
||||||
ctx context.Context, db Database, rsAPI roomserver.RoomserverInternalAPI, userID string, req *EventRelationshipRequest, included map[string]int, limit int,
|
ctx context.Context, db Database, rsAPI roomserver.RoomserverInternalAPI, userID string, req *EventRelationshipRequest, included map[string]int, limit int,
|
||||||
) ([]*gomatrixserverlib.HeaderedEvent, bool) {
|
) ([]*gomatrixserverlib.HeaderedEvent, bool) {
|
||||||
|
if req.Direction != "down" {
|
||||||
|
util.GetLogger(ctx).Error("not implemented: direction=up")
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
var result []*gomatrixserverlib.HeaderedEvent
|
var result []*gomatrixserverlib.HeaderedEvent
|
||||||
eventsToWalk := newWalker(req)
|
eventsToWalk := newWalker(req)
|
||||||
parent, siblingNum, current := eventsToWalk.Next()
|
parent, siblingNum, current := eventsToWalk.Next()
|
||||||
|
|
@ -295,22 +299,33 @@ func getEventIfVisible(ctx context.Context, rsAPI roomserver.RoomserverInternalA
|
||||||
return &event
|
return &event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// walker walks the thread DAG
|
||||||
type walker interface {
|
type walker interface {
|
||||||
|
// Next returns the next event. `current` is the event ID being walked.
|
||||||
|
// `parent` is the parent of `current`. `siblingNum` is the sibling number of `current`, starting
|
||||||
|
// from one.
|
||||||
Next() (parent string, siblingNum int, current string)
|
Next() (parent string, siblingNum int, current string)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newWalker(req *EventRelationshipRequest) walker {
|
func newWalker(req *EventRelationshipRequest) walker {
|
||||||
if *req.DepthFirst {
|
if *req.DepthFirst {
|
||||||
return &depthWalker{req}
|
return &depthWalker{
|
||||||
|
req: req,
|
||||||
|
current: req.EventID,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return &breadthWalker{req}
|
return &breadthWalker{req}
|
||||||
}
|
}
|
||||||
|
|
||||||
type depthWalker struct {
|
type depthWalker struct {
|
||||||
req *EventRelationshipRequest
|
req *EventRelationshipRequest
|
||||||
|
db Database
|
||||||
|
current string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *depthWalker) Next() (parent string, siblingNum int, current string) {
|
func (w *depthWalker) Next() (parent string, siblingNum int, current string) {
|
||||||
|
//var events []string
|
||||||
|
//children, err := w.db.ChildrenForParent(w.ctx, w.current)
|
||||||
return "", 0, ""
|
return "", 0, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,140 +13,99 @@ import (
|
||||||
type Database interface {
|
type Database interface {
|
||||||
// StoreRelation stores the parent->child and child->parent relationship for later querying.
|
// StoreRelation stores the parent->child and child->parent relationship for later querying.
|
||||||
StoreRelation(ctx context.Context, ev *gomatrixserverlib.HeaderedEvent) error
|
StoreRelation(ctx context.Context, ev *gomatrixserverlib.HeaderedEvent) error
|
||||||
ChildrenForParent(ctx context.Context, eventID string) ([]string, error)
|
ChildrenForParent(ctx context.Context, eventID, relType string) ([]string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Postgres struct {
|
type DB struct {
|
||||||
db *sql.DB
|
db *sql.DB
|
||||||
insertRelationStmt *sql.Stmt
|
|
||||||
selectChildrenForParentStmt *sql.Stmt
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewPostgresDatabase(dbOpts *config.DatabaseOptions) (Database, error) {
|
|
||||||
var p Postgres
|
|
||||||
var err error
|
|
||||||
if p.db, err = sqlutil.Open(dbOpts); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
_, err = p.db.Exec(`
|
|
||||||
CREATE TABLE IF NOT EXISTS msc2836_relationships (
|
|
||||||
parent_event_id TEXT NOT NULL,
|
|
||||||
child_event_id TEXT NOT NULL,
|
|
||||||
parent_room_id TEXT NOT NULL,
|
|
||||||
parent_origin_server_ts BIGINT NOT NULL,
|
|
||||||
CONSTRAINT msc2836_relationships_unique UNIQUE (parent_event_id, child_event_id)
|
|
||||||
);
|
|
||||||
`)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if p.insertRelationStmt, err = p.db.Prepare(`
|
|
||||||
INSERT INTO msc2836_relationships(parent_event_id, child_event_id, parent_room_id, parent_origin_server_ts) VALUES($1, $2, $3, $4) ON CONFLICT DO NOTHING
|
|
||||||
`); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if p.selectChildrenForParentStmt, err = p.db.Prepare(`
|
|
||||||
SELECT child_event_id FROM msc2836_relationships WHERE parent_event_id = $1
|
|
||||||
`); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &p, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Postgres) StoreRelation(ctx context.Context, ev *gomatrixserverlib.HeaderedEvent) error {
|
|
||||||
parent, child := parentChildEventIDs(ev)
|
|
||||||
if parent == "" || child == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
_, err := p.insertRelationStmt.ExecContext(ctx, parent, child, ev.RoomID(), ev.OriginServerTS())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *Postgres) ChildrenForParent(ctx context.Context, eventID string) ([]string, error) {
|
|
||||||
return childrenForParent(ctx, eventID, p.selectChildrenForParentStmt)
|
|
||||||
}
|
|
||||||
|
|
||||||
type SQLite struct {
|
|
||||||
db *sql.DB
|
|
||||||
insertRelationStmt *sql.Stmt
|
|
||||||
selectChildrenForParentStmt *sql.Stmt
|
|
||||||
writer sqlutil.Writer
|
writer sqlutil.Writer
|
||||||
}
|
insertRelationStmt *sql.Stmt
|
||||||
|
selectChildrenForParentStmt *sql.Stmt
|
||||||
func NewSQLiteDatabase(dbOpts *config.DatabaseOptions) (Database, error) {
|
|
||||||
var s SQLite
|
|
||||||
var err error
|
|
||||||
if s.db, err = sqlutil.Open(dbOpts); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
s.writer = sqlutil.NewExclusiveWriter()
|
|
||||||
_, err = s.db.Exec(`
|
|
||||||
CREATE TABLE IF NOT EXISTS msc2836_relationships (
|
|
||||||
parent_event_id TEXT NOT NULL,
|
|
||||||
child_event_id TEXT NOT NULL,
|
|
||||||
parent_room_id TEXT NOT NULL,
|
|
||||||
parent_origin_server_ts BIGINT NOT NULL,
|
|
||||||
UNIQUE (parent_event_id, child_event_id)
|
|
||||||
);
|
|
||||||
`)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if s.insertRelationStmt, err = s.db.Prepare(`
|
|
||||||
INSERT INTO msc2836_relationships(parent_event_id, child_event_id, parent_room_id, parent_origin_server_ts) VALUES($1, $2, $3, $4) ON CONFLICT (parent_event_id, child_event_id) DO NOTHING
|
|
||||||
`); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if s.selectChildrenForParentStmt, err = s.db.Prepare(`
|
|
||||||
SELECT child_event_id FROM msc2836_relationships WHERE parent_event_id = $1
|
|
||||||
`); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SQLite) StoreRelation(ctx context.Context, ev *gomatrixserverlib.HeaderedEvent) error {
|
|
||||||
parent, child := parentChildEventIDs(ev)
|
|
||||||
if parent == "" || child == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
_, err := s.insertRelationStmt.ExecContext(ctx, parent, child, ev.RoomID(), ev.OriginServerTS())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SQLite) ChildrenForParent(ctx context.Context, eventID string) ([]string, error) {
|
|
||||||
return childrenForParent(ctx, eventID, s.selectChildrenForParentStmt)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDatabase loads the database for msc2836
|
// NewDatabase loads the database for msc2836
|
||||||
func NewDatabase(dbOpts *config.DatabaseOptions) (Database, error) {
|
func NewDatabase(dbOpts *config.DatabaseOptions) (Database, error) {
|
||||||
if dbOpts.ConnectionString.IsPostgres() {
|
if dbOpts.ConnectionString.IsPostgres() {
|
||||||
return NewPostgresDatabase(dbOpts)
|
return newPostgresDatabase(dbOpts)
|
||||||
}
|
}
|
||||||
return NewSQLiteDatabase(dbOpts)
|
return newSQLiteDatabase(dbOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parentChildEventIDs(ev *gomatrixserverlib.HeaderedEvent) (parent string, child string) {
|
func newPostgresDatabase(dbOpts *config.DatabaseOptions) (Database, error) {
|
||||||
if ev == nil {
|
d := DB{
|
||||||
return
|
writer: sqlutil.NewDummyWriter(),
|
||||||
}
|
}
|
||||||
body := struct {
|
var err error
|
||||||
Relationship struct {
|
if d.db, err = sqlutil.Open(dbOpts); err != nil {
|
||||||
RelType string `json:"rel_type"`
|
return nil, err
|
||||||
EventID string `json:"event_id"`
|
|
||||||
} `json:"m.relationship"`
|
|
||||||
}{}
|
|
||||||
if err := json.Unmarshal(ev.Content(), &body); err != nil {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if body.Relationship.RelType == "m.reference" && body.Relationship.EventID != "" {
|
_, err = d.db.Exec(`
|
||||||
return body.Relationship.EventID, ev.EventID()
|
CREATE TABLE IF NOT EXISTS msc2836_edges (
|
||||||
|
parent_event_id TEXT NOT NULL,
|
||||||
|
child_event_id TEXT NOT NULL,
|
||||||
|
rel_type TEXT NOT NULL,
|
||||||
|
CONSTRAINT msc2836_edges UNIQUE (parent_event_id, child_event_id, rel_type)
|
||||||
|
);
|
||||||
|
`)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return
|
if d.insertRelationStmt, err = d.db.Prepare(`
|
||||||
|
INSERT INTO msc2836_edges(parent_event_id, child_event_id, rel_type) VALUES($1, $2, $3) ON CONFLICT DO NOTHING
|
||||||
|
`); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if d.selectChildrenForParentStmt, err = d.db.Prepare(`
|
||||||
|
SELECT child_event_id FROM msc2836_edges WHERE parent_event_id = $1 AND rel_type = $2
|
||||||
|
`); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &d, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func childrenForParent(ctx context.Context, eventID string, stmt *sql.Stmt) ([]string, error) {
|
func newSQLiteDatabase(dbOpts *config.DatabaseOptions) (Database, error) {
|
||||||
rows, err := stmt.QueryContext(ctx, eventID)
|
d := DB{
|
||||||
|
writer: sqlutil.NewExclusiveWriter(),
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
if d.db, err = sqlutil.Open(dbOpts); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
_, err = d.db.Exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS msc2836_edges (
|
||||||
|
parent_event_id TEXT NOT NULL,
|
||||||
|
child_event_id TEXT NOT NULL,
|
||||||
|
rel_type TEXT NOT NULL,
|
||||||
|
UNIQUE (parent_event_id, child_event_id, rel_type)
|
||||||
|
);
|
||||||
|
`)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if d.insertRelationStmt, err = d.db.Prepare(`
|
||||||
|
INSERT INTO msc2836_edges(parent_event_id, child_event_id, rel_type) VALUES($1, $2, $3) ON CONFLICT (parent_event_id, child_event_id, rel_type) DO NOTHING
|
||||||
|
`); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if d.selectChildrenForParentStmt, err = d.db.Prepare(`
|
||||||
|
SELECT child_event_id FROM msc2836_edges WHERE parent_event_id = $1 AND rel_type = $2
|
||||||
|
`); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &d, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *DB) StoreRelation(ctx context.Context, ev *gomatrixserverlib.HeaderedEvent) error {
|
||||||
|
parent, child, relType := parentChildEventIDs(ev)
|
||||||
|
if parent == "" || child == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, err := p.insertRelationStmt.ExecContext(ctx, parent, child, relType)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *DB) ChildrenForParent(ctx context.Context, eventID, relType string) ([]string, error) {
|
||||||
|
rows, err := p.selectChildrenForParentStmt.QueryContext(ctx, eventID, relType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -161,3 +120,22 @@ func childrenForParent(ctx context.Context, eventID string, stmt *sql.Stmt) ([]s
|
||||||
}
|
}
|
||||||
return children, nil
|
return children, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parentChildEventIDs(ev *gomatrixserverlib.HeaderedEvent) (parent, child, relType string) {
|
||||||
|
if ev == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
body := struct {
|
||||||
|
Relationship struct {
|
||||||
|
RelType string `json:"rel_type"`
|
||||||
|
EventID string `json:"event_id"`
|
||||||
|
} `json:"m.relationship"`
|
||||||
|
}{}
|
||||||
|
if err := json.Unmarshal(ev.Content(), &body); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if body.Relationship.EventID == "" || body.Relationship.RelType == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return body.Relationship.EventID, ev.EventID(), body.Relationship.RelType
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue