-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathydb.go
139 lines (127 loc) · 3.07 KB
/
ydb.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package main
import (
"errors"
"fmt"
"math/rand"
"os"
"path/filepath"
"sync"
"time"
)
var ydb Ydb
// Ydb maintains rooms and connections
type Ydb struct {
roomsMux sync.RWMutex
rooms map[roomname]*room
// TODO: use guid instead of uint64
sessionsMux sync.Mutex
sessions map[uint64]*session
fswriter fswriter
seed *rand.Rand
seedMux sync.Mutex
}
func (ydb *Ydb) genUint32() uint32 {
ydb.seedMux.Lock()
n := ydb.seed.Uint32()
ydb.seedMux.Unlock()
return n
}
func (ydb *Ydb) genUint64() uint64 {
ydb.seedMux.Lock()
n := ydb.seed.Uint64()
ydb.seedMux.Unlock()
return n
}
func initYdb(dir string) {
// remember to update unsafeClearAllYdbContent when updating here
ydb = Ydb{
rooms: make(map[roomname]*room, 1000),
sessions: make(map[uint64]*session),
fswriter: newFSWriter(dir, 1000, 10), // TODO: have command line arguments for this
seed: rand.New(rand.NewSource(time.Now().UnixNano())),
}
}
// getRoom from the global ydb instance. safe for parallel access.
func getRoom(name roomname) *room {
ydb.roomsMux.RLock()
r := ydb.rooms[name]
ydb.roomsMux.RUnlock()
if r == nil {
ydb.roomsMux.Lock()
r = ydb.rooms[name]
if r == nil {
r = newRoom()
ydb.rooms[name] = r
r.mux.Lock()
ydb.roomsMux.Unlock()
// read room offset..
r.offset = ydb.fswriter.readRoomSize(name)
r.mux.Unlock()
} else {
ydb.roomsMux.Unlock()
}
}
return r
}
func (ydb *Ydb) getSession(sessionid uint64) *session {
ydb.sessionsMux.Lock()
defer ydb.sessionsMux.Unlock()
return ydb.sessions[sessionid]
}
func (ydb *Ydb) createSession() (s *session) {
ydb.sessionsMux.Lock()
sessionid := ydb.genUint64()
if _, ok := ydb.sessions[sessionid]; ok {
panic("Generated the same session id twice! (this is a security vulnerability)")
}
s = newSession(sessionid)
ydb.sessions[sessionid] = s
ydb.sessionsMux.Unlock()
return s
}
func (ydb *Ydb) removeSession(sessionid uint64) (err error) {
ydb.sessionsMux.Lock()
session, ok := ydb.sessions[sessionid]
if !ok {
err = fmt.Errorf("tried to close session %d, but session does not exist", sessionid)
} else if len(session.conns) > 0 || session.conn != nil {
err = errors.New("Cannot close this session because conns are still using it")
} else {
delete(ydb.sessions, sessionid)
}
ydb.sessionsMux.Unlock()
return
}
// TODO: refactor/remove..
func removeFSWriteDirContent(dir string) error {
d, err := os.Open(dir)
if err != nil {
return err
}
defer d.Close()
d.Chmod(0777)
names, err := d.Readdirnames(-1)
if err != nil {
return err
}
debug("read dir names")
for _, name := range names {
os.Chmod(filepath.Join(dir, name), 0777)
err = os.Remove(filepath.Join(dir, name))
debug("removed a file")
if err != nil {
return err
}
}
return nil
}
// Clear all content in Ydb (files, sessions, rooms, ..).
// Unsafe for production, only use for testing!
// only works if dir is tmp
func unsafeClearAllYdbContent() {
dir := ydb.fswriter.dir
debug("Clear Ydb content")
ydb.rooms = make(map[roomname]*room, 1000)
ydb.sessions = make(map[uint64]*session)
removeFSWriteDirContent(dir)
}