dendrite/internal/cosmosdbutil/writer_exclusive.go
alexfca 5d68daef80
Implement Cosmos DB for the RoomServer Service (#5)
* - Implement Cosmos for the devices_table
- Use the ConnectionString in the YAML to include the Tenant
- Revert all other non implemented tables back to use SQLLite3

* - Change the Config to use "test.criticicalarc.com" Container
- Add generic function GetDocumentOrNil to standardize GetDocument
- Add func to return CrossPartition queries for Aggregates
- Add func GetNextSequence() as generic seq generator for AutoIncrement
- Add cosmosdbutil.ErrNoRows to return (emulate) sql.ErrNoRows
- Add a "fake" ExclusiveWriterFake
- Add standard "getXX", "setXX" and "queryXX" to all TABLE class files
- Add specific Table SEQ for the Events table
- Add specific Table SEQ for the Rooms table
- Add specific Table SEQ for the StateSnapshot table
2021-05-20 14:42:33 +10:00

78 lines
1.8 KiB
Go

package cosmosdbutil
import (
"database/sql"
"errors"
"github.com/matrix-org/dendrite/internal/sqlutil"
"go.uber.org/atomic"
)
// ExclusiveWriter implements sqlutil.Writer.
// Allows non-SQL DBs to still use the same infrastructure
// as Matrix assumes SQL TXN
type ExclusiveWriterFake struct {
running atomic.Bool
todo chan transactionWriterTaskFake
}
func NewExclusiveWriterFake() sqlutil.Writer {
return &ExclusiveWriterFake{
todo: make(chan transactionWriterTaskFake),
}
}
// transactionWriterTask represents a specific task.
type transactionWriterTaskFake struct {
db *sql.DB
txn *sql.Tx
f func(txn *sql.Tx) error
wait chan error
}
func (w *ExclusiveWriterFake) Do(db *sql.DB, txn *sql.Tx, f func(txn *sql.Tx) error) error {
if w.todo == nil {
return errors.New("not initialised")
}
if !w.running.Load() {
go w.run()
}
task := transactionWriterTaskFake{
db: db,
txn: txn,
f: f,
wait: make(chan error, 1),
}
w.todo <- task
return <-task.wait
}
// run processes the tasks for a given transaction writer. Only one
// of these goroutines will run at a time. A transaction will be
// opened using the database object from the task and then this will
// be passed as a parameter to the task function.
func (w *ExclusiveWriterFake) run() {
if !w.running.CAS(false, true) {
return
}
// if tracingEnabled {
// gid := goid()
// goidToWriter.Store(gid, w)
// defer goidToWriter.Delete(gid)
// }
defer w.running.Store(false)
for task := range w.todo {
if task.db != nil && task.txn != nil {
task.wait <- task.f(task.txn)
// } else if task.db != nil && task.txn == nil {
// task.wait <- WithTransaction(task.db, func(txn *sql.Tx) error {
// return task.f(txn)
// })
} else {
task.wait <- task.f(nil)
}
close(task.wait)
}
}