github.com/hdt3213/godis@v1.2.9/redis/connection/conn.go (about) 1 package connection 2 3 import ( 4 "github.com/hdt3213/godis/lib/logger" 5 "github.com/hdt3213/godis/lib/sync/wait" 6 "net" 7 "sync" 8 "time" 9 ) 10 11 const ( 12 // flagSlave means this a connection with slave 13 flagSlave = uint64(1 << iota) 14 // flagSlave means this a connection with master 15 flagMaster 16 // flagMulti means this connection is within a transaction 17 flagMulti 18 ) 19 20 // Connection represents a connection with a redis-cli 21 type Connection struct { 22 conn net.Conn 23 24 // wait until finish sending data, used for graceful shutdown 25 sendingData wait.Wait 26 27 // lock while server sending response 28 mu sync.Mutex 29 flags uint64 30 31 // subscribing channels 32 subs map[string]bool 33 34 // password may be changed by CONFIG command during runtime, so store the password 35 password string 36 37 // queued commands for `multi` 38 queue [][][]byte 39 watching map[string]uint32 40 txErrors []error 41 42 // selected db 43 selectedDB int 44 } 45 46 var connPool = sync.Pool{ 47 New: func() interface{} { 48 return &Connection{} 49 }, 50 } 51 52 // RemoteAddr returns the remote network address 53 func (c *Connection) RemoteAddr() net.Addr { 54 return c.conn.RemoteAddr() 55 } 56 57 // Close disconnect with the client 58 func (c *Connection) Close() error { 59 c.sendingData.WaitWithTimeout(10 * time.Second) 60 _ = c.conn.Close() 61 c.subs = nil 62 c.password = "" 63 c.queue = nil 64 c.watching = nil 65 c.txErrors = nil 66 c.selectedDB = 0 67 connPool.Put(c) 68 return nil 69 } 70 71 // NewConn creates Connection instance 72 func NewConn(conn net.Conn) *Connection { 73 c, ok := connPool.Get().(*Connection) 74 if !ok { 75 logger.Error("connection pool make wrong type") 76 return &Connection{ 77 conn: conn, 78 } 79 } 80 c.conn = conn 81 return c 82 } 83 84 // Write sends response to client over tcp connection 85 func (c *Connection) Write(b []byte) (int, error) { 86 if len(b) == 0 { 87 return 0, nil 88 } 89 c.sendingData.Add(1) 90 defer func() { 91 c.sendingData.Done() 92 }() 93 94 return c.conn.Write(b) 95 } 96 97 func (c *Connection) Name() string { 98 if c.conn != nil { 99 return c.conn.RemoteAddr().String() 100 } 101 return "" 102 } 103 104 // Subscribe add current connection into subscribers of the given channel 105 func (c *Connection) Subscribe(channel string) { 106 c.mu.Lock() 107 defer c.mu.Unlock() 108 109 if c.subs == nil { 110 c.subs = make(map[string]bool) 111 } 112 c.subs[channel] = true 113 } 114 115 // UnSubscribe removes current connection into subscribers of the given channel 116 func (c *Connection) UnSubscribe(channel string) { 117 c.mu.Lock() 118 defer c.mu.Unlock() 119 120 if len(c.subs) == 0 { 121 return 122 } 123 delete(c.subs, channel) 124 } 125 126 // SubsCount returns the number of subscribing channels 127 func (c *Connection) SubsCount() int { 128 return len(c.subs) 129 } 130 131 // GetChannels returns all subscribing channels 132 func (c *Connection) GetChannels() []string { 133 if c.subs == nil { 134 return make([]string, 0) 135 } 136 channels := make([]string, len(c.subs)) 137 i := 0 138 for channel := range c.subs { 139 channels[i] = channel 140 i++ 141 } 142 return channels 143 } 144 145 // SetPassword stores password for authentication 146 func (c *Connection) SetPassword(password string) { 147 c.password = password 148 } 149 150 // GetPassword get password for authentication 151 func (c *Connection) GetPassword() string { 152 return c.password 153 } 154 155 // InMultiState tells is connection in an uncommitted transaction 156 func (c *Connection) InMultiState() bool { 157 return c.flags&flagMulti > 0 158 } 159 160 // SetMultiState sets transaction flag 161 func (c *Connection) SetMultiState(state bool) { 162 if !state { // reset data when cancel multi 163 c.watching = nil 164 c.queue = nil 165 c.flags &= ^flagMulti // clean multi flag 166 return 167 } 168 c.flags |= flagMulti 169 } 170 171 // GetQueuedCmdLine returns queued commands of current transaction 172 func (c *Connection) GetQueuedCmdLine() [][][]byte { 173 return c.queue 174 } 175 176 // EnqueueCmd enqueues command of current transaction 177 func (c *Connection) EnqueueCmd(cmdLine [][]byte) { 178 c.queue = append(c.queue, cmdLine) 179 } 180 181 // AddTxError stores syntax error within transaction 182 func (c *Connection) AddTxError(err error) { 183 c.txErrors = append(c.txErrors, err) 184 } 185 186 // GetTxErrors returns syntax error within transaction 187 func (c *Connection) GetTxErrors() []error { 188 return c.txErrors 189 } 190 191 // ClearQueuedCmds clears queued commands of current transaction 192 func (c *Connection) ClearQueuedCmds() { 193 c.queue = nil 194 } 195 196 // GetWatching returns watching keys and their version code when started watching 197 func (c *Connection) GetWatching() map[string]uint32 { 198 if c.watching == nil { 199 c.watching = make(map[string]uint32) 200 } 201 return c.watching 202 } 203 204 // GetDBIndex returns selected db 205 func (c *Connection) GetDBIndex() int { 206 return c.selectedDB 207 } 208 209 // SelectDB selects a database 210 func (c *Connection) SelectDB(dbNum int) { 211 c.selectedDB = dbNum 212 } 213 214 func (c *Connection) SetSlave() { 215 c.flags |= flagSlave 216 } 217 218 func (c *Connection) IsSlave() bool { 219 return c.flags&flagSlave > 0 220 } 221 222 func (c *Connection) SetMaster() { 223 c.flags |= flagMaster 224 } 225 226 func (c *Connection) IsMaster() bool { 227 return c.flags&flagMaster > 0 228 }