Skip to content

Commit 5f4d1ce

Browse files
committed
Merge branch 'crud-optimize' into 'ee-v0.10.0'
added crud block optimisation to share db drivers See merge request spaceuptech/space-cloud-ee!7
2 parents a38753d + 57843c9 commit 5f4d1ce

File tree

6 files changed

+168
-54
lines changed

6 files changed

+168
-54
lines changed

Diff for: modules/crud/crud.go

+31-49
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,30 @@
11
package crud
22

33
import (
4-
"context"
54
"errors"
65
"sync"
76

87
"github.com/spaceuptech/space-cloud/config"
9-
"github.com/spaceuptech/space-cloud/model"
108
"github.com/spaceuptech/space-cloud/utils"
119

12-
"github.com/spaceuptech/space-cloud/modules/crud/mgo"
13-
"github.com/spaceuptech/space-cloud/modules/crud/sql"
10+
"github.com/spaceuptech/space-cloud/modules/crud/driver"
1411
)
1512

1613
// Module is the root block providing convenient wrappers
1714
type Module struct {
1815
sync.RWMutex
19-
blocks map[string]Crud
16+
blocks map[string]*stub
2017
primaryDB string
21-
}
22-
23-
// Crud abstracts the implementation crud operations of databases
24-
type Crud interface {
25-
Create(ctx context.Context, project, col string, req *model.CreateRequest) error
26-
Read(ctx context.Context, project, col string, req *model.ReadRequest) (interface{}, error)
27-
Update(ctx context.Context, project, col string, req *model.UpdateRequest) error
28-
Delete(ctx context.Context, project, col string, req *model.DeleteRequest) error
29-
Aggregate(ctx context.Context, project, col string, req *model.AggregateRequest) (interface{}, error)
30-
Batch(ctx context.Context, project string, req *model.BatchRequest) error
31-
GetDBType() utils.DBType
32-
Close() error
18+
h *driver.Handler
3319
}
3420

3521
// Init create a new instance of the Module object
36-
func Init() *Module {
37-
return &Module{blocks: make(map[string]Crud)}
38-
}
39-
40-
func initBlock(dbType utils.DBType, connection string) (Crud, error) {
41-
switch dbType {
42-
case utils.Mongo:
43-
return mgo.Init(connection)
44-
45-
case utils.MySQL, utils.Postgres:
46-
return sql.Init(dbType, connection)
47-
48-
default:
49-
return nil, utils.ErrInvalidParams
50-
}
22+
func Init(h *driver.Handler) *Module {
23+
return &Module{blocks: make(map[string]*stub), h: h}
5124
}
5225

5326
// GetPrimaryDB get the database configured as primary
54-
func (m *Module) GetPrimaryDB() (Crud, error) {
27+
func (m *Module) GetPrimaryDB() (driver.Crud, error) {
5528
m.RLock()
5629
defer m.RUnlock()
5730

@@ -60,15 +33,7 @@ func (m *Module) GetPrimaryDB() (Crud, error) {
6033
return nil, errors.New("CRUD: Primary DB not configured")
6134
}
6235

63-
return c, nil
64-
}
65-
66-
func (m *Module) getCrudBlock(dbType string) (Crud, error) {
67-
if crud, p := m.blocks[dbType]; p {
68-
return crud, nil
69-
}
70-
71-
return nil, errors.New("CRUD: No crud block present for db")
36+
return c.c, nil
7237
}
7338

7439
// SetConfig set the rules adn secret key required by the crud block
@@ -78,26 +43,43 @@ func (m *Module) SetConfig(crud config.Crud) error {
7843

7944
// Close the previous database connections
8045
for _, v := range m.blocks {
81-
v.Close()
46+
m.h.RemoveBlock(v.dbType, v.conn)
8247
}
83-
m.blocks = make(map[string]Crud, len(crud))
48+
49+
m.blocks = make(map[string]*stub, len(crud))
8450

8551
// Create a new crud blocks
86-
for k, v := range crud {
52+
for dbType, v := range crud {
8753
// Skip this block if it is not enabled
8854
if !v.Enabled {
8955
continue
9056
}
9157

92-
c, err := initBlock(utils.DBType(k), v.Conn)
58+
// Initialise a new block
59+
c, err := m.h.InitBlock(utils.DBType(dbType), v.Conn)
9360
if err != nil {
94-
return errors.New("CURD: Error - " + k + " could not be initialised")
61+
return errors.New("CURD: Error - " + dbType + " could not be initialised")
9562
}
63+
9664
if v.IsPrimary {
97-
m.primaryDB = k
65+
m.primaryDB = dbType
9866
}
99-
m.blocks[k] = c
67+
m.blocks[dbType] = &stub{c: c, conn: v.Conn, dbType: utils.DBType(dbType)}
10068
}
10169

10270
return nil
10371
}
72+
73+
type stub struct {
74+
conn string
75+
c driver.Crud
76+
dbType utils.DBType
77+
}
78+
79+
func (m *Module) getCrudBlock(dbType string) (driver.Crud, error) {
80+
if crud, p := m.blocks[dbType]; p {
81+
return crud.c, nil
82+
}
83+
84+
return nil, errors.New("CRUD: No crud block present for db")
85+
}

Diff for: modules/crud/driver/driver.go

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package driver
2+
3+
import (
4+
"context"
5+
"sync"
6+
7+
"github.com/spaceuptech/space-cloud/model"
8+
"github.com/spaceuptech/space-cloud/modules/crud/mgo"
9+
"github.com/spaceuptech/space-cloud/modules/crud/sql"
10+
"github.com/spaceuptech/space-cloud/utils"
11+
)
12+
13+
// Crud abstracts the implementation crud operations of databases
14+
type Crud interface {
15+
Create(ctx context.Context, project, col string, req *model.CreateRequest) error
16+
Read(ctx context.Context, project, col string, req *model.ReadRequest) (interface{}, error)
17+
Update(ctx context.Context, project, col string, req *model.UpdateRequest) error
18+
Delete(ctx context.Context, project, col string, req *model.DeleteRequest) error
19+
Aggregate(ctx context.Context, project, col string, req *model.AggregateRequest) (interface{}, error)
20+
Batch(ctx context.Context, project string, req *model.BatchRequest) error
21+
GetDBType() utils.DBType
22+
Close() error
23+
}
24+
25+
// Handler is the object managing the database connections
26+
type Handler struct {
27+
lock sync.Mutex
28+
drivers map[string]*stub
29+
}
30+
31+
// New creates a new driver handler
32+
func New() *Handler {
33+
return &Handler{drivers: map[string]*stub{}}
34+
}
35+
36+
// InitBlock creates and returns a new crud object. If the driver already exists, it returns that instead
37+
func (h *Handler) InitBlock(dbType utils.DBType, connection string) (Crud, error) {
38+
h.lock.Lock()
39+
defer h.lock.Unlock()
40+
41+
// See if driver is present in cache
42+
s, p := h.getBlock(dbType, connection)
43+
if p {
44+
s.addCount()
45+
return s.getCrud(), nil
46+
}
47+
48+
return h.addBlock(dbType, connection)
49+
}
50+
51+
// RemoveBlock removes a crud object if other module is referencing it
52+
func (h *Handler) RemoveBlock(dbType utils.DBType, connection string) {
53+
h.lock.Lock()
54+
defer h.lock.Unlock()
55+
56+
// See if driver is present in cache
57+
s, p := h.getBlock(dbType, connection)
58+
if !p {
59+
return
60+
}
61+
62+
// Subtract the count of references
63+
s.subtractCount()
64+
65+
// Close then delete the driver if there are no references
66+
if s.getCount() == 0 {
67+
s.getCrud().Close()
68+
delete(h.drivers, generateKey(dbType, connection))
69+
}
70+
}
71+
72+
func (h *Handler) getBlock(dbType utils.DBType, connection string) (s *stub, p bool) {
73+
s, p = h.drivers[generateKey(dbType, connection)]
74+
return
75+
}
76+
77+
func (h *Handler) addBlock(dbType utils.DBType, connection string) (Crud, error) {
78+
var c Crud
79+
var err error
80+
81+
switch dbType {
82+
case utils.Mongo:
83+
c, err = mgo.Init(connection)
84+
85+
case utils.MySQL, utils.Postgres:
86+
c, err = sql.Init(dbType, connection)
87+
88+
default:
89+
c, err = nil, utils.ErrInvalidParams
90+
}
91+
92+
// Return the error of exists
93+
if err != nil {
94+
return nil, err
95+
}
96+
97+
h.drivers[generateKey(dbType, connection)] = newStub(c)
98+
return c, nil
99+
}
100+
101+
func generateKey(dbType utils.DBType, connection string) string {
102+
return string(dbType) + ":" + connection
103+
}

Diff for: modules/crud/driver/stub.go

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package driver
2+
3+
type stub struct {
4+
c Crud
5+
count int
6+
}
7+
8+
func newStub(c Crud) *stub {
9+
return &stub{c: c, count: 1}
10+
}
11+
12+
func (s *stub) addCount() {
13+
s.count++
14+
}
15+
16+
func (s *stub) subtractCount() {
17+
s.count--
18+
}
19+
20+
func (s *stub) getCount() int {
21+
return s.count
22+
}
23+
24+
func (s *stub) getCrud() Crud {
25+
return s.c
26+
}

Diff for: modules/crud/operations.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func (m *Module) Aggregate(ctx context.Context, dbType, project, col string, req
7171
return crud.Aggregate(ctx, project, col, req)
7272
}
7373

74-
// Create inserts a document (or multiple when op is "all") into the database based on dbType
74+
// Batch performs an transactional batch
7575
func (m *Module) Batch(ctx context.Context, dbType, project string, req *model.BatchRequest) error {
7676
m.RLock()
7777
defer m.RUnlock()

Diff for: utils/projects/projects.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66

77
"github.com/spaceuptech/space-cloud/modules/auth"
88
"github.com/spaceuptech/space-cloud/modules/crud"
9+
"github.com/spaceuptech/space-cloud/modules/crud/driver"
910
"github.com/spaceuptech/space-cloud/modules/filestore"
1011
"github.com/spaceuptech/space-cloud/modules/functions"
1112
"github.com/spaceuptech/space-cloud/modules/realtime"
@@ -29,11 +30,12 @@ type ProjectState struct {
2930
type Projects struct {
3031
lock sync.RWMutex
3132
projects map[string]*ProjectState
33+
h *driver.Handler
3234
}
3335

3436
// New creates a new Projects instance
35-
func New() *Projects {
36-
return &Projects{projects: map[string]*ProjectState{}}
37+
func New(h *driver.Handler) *Projects {
38+
return &Projects{projects: map[string]*ProjectState{}, h: h}
3739
}
3840

3941
// LoadProject returns the state of the project specified
@@ -77,7 +79,7 @@ func (p *Projects) NewProject(project string) *ProjectState {
7779
p.lock.Lock()
7880
defer p.lock.Unlock()
7981

80-
c := crud.Init()
82+
c := crud.Init(p.h)
8183
f := functions.Init()
8284
a := auth.Init(c, nil)
8385
u := userman.Init(c, a)

Diff for: utils/server/server.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"google.golang.org/grpc/credentials"
1616

1717
"github.com/spaceuptech/space-cloud/config"
18+
"github.com/spaceuptech/space-cloud/modules/crud/driver"
1819
"github.com/spaceuptech/space-cloud/proto"
1920
"github.com/spaceuptech/space-cloud/utils/projects"
2021
)
@@ -33,7 +34,7 @@ type Server struct {
3334
// New creates a new server instance
3435
func New(isProd bool) *Server {
3536
r := mux.NewRouter()
36-
projects := projects.New()
37+
projects := projects.New(driver.New())
3738
id := uuid.NewV1().String()
3839
return &Server{id: id, router: r, projects: projects, isProd: isProd}
3940
}

0 commit comments

Comments
 (0)