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  }