github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/lib/pq/notify.go (about) 1 package pq 2 3 // Package pq is a pure Go Postgres driver for the database/sql package. 4 // This module contains support for Postgres LISTEN/NOTIFY. 5 6 import ( 7 "errors" 8 "fmt" 9 "sync" 10 "sync/atomic" 11 "time" 12 ) 13 14 // Notification represents a single notification from the database. 15 type Notification struct { 16 // Process ID (PID) of the notifying postgres backend. 17 BePid int 18 // Name of the channel the notification was sent on. 19 Channel string 20 // Payload, or the empty string if unspecified. 21 Extra string 22 } 23 24 func recvNotification(r *readBuf) *Notification { 25 bePid := r.int32() 26 channel := r.string() 27 extra := r.string() 28 29 return &Notification{bePid, channel, extra} 30 } 31 32 const ( 33 connStateIdle int32 = iota 34 connStateExpectResponse 35 connStateExpectReadyForQuery 36 ) 37 38 type message struct { 39 typ byte 40 err error 41 } 42 43 var errListenerConnClosed = errors.New("pq: ListenerConn has been closed") 44 45 // ListenerConn is a low-level interface for waiting for notifications. You 46 // should use Listener instead. 47 type ListenerConn struct { 48 // guards cn and err 49 connectionLock sync.Mutex 50 cn *conn 51 err error 52 53 connState int32 54 55 // the sending goroutine will be holding this lock 56 senderLock sync.Mutex 57 58 notificationChan chan<- *Notification 59 60 replyChan chan message 61 } 62 63 // Creates a new ListenerConn. Use NewListener instead. 64 func NewListenerConn(name string, notificationChan chan<- *Notification) (*ListenerConn, error) { 65 cn, err := Open(name) 66 if err != nil { 67 return nil, err 68 } 69 70 l := &ListenerConn{ 71 cn: cn.(*conn), 72 notificationChan: notificationChan, 73 connState: connStateIdle, 74 replyChan: make(chan message, 2), 75 } 76 77 go l.listenerConnMain() 78 79 return l, nil 80 } 81 82 // We can only allow one goroutine at a time to be running a query on the 83 // connection for various reasons, so the goroutine sending on the connection 84 // must be holding senderLock. 85 // 86 // Returns an error if an unrecoverable error has occurred and the ListenerConn 87 // should be abandoned. 88 func (l *ListenerConn) acquireSenderLock() error { 89 // we must acquire senderLock first to avoid deadlocks; see ExecSimpleQuery 90 l.senderLock.Lock() 91 92 l.connectionLock.Lock() 93 err := l.err 94 l.connectionLock.Unlock() 95 if err != nil { 96 l.senderLock.Unlock() 97 return err 98 } 99 return nil 100 } 101 102 func (l *ListenerConn) releaseSenderLock() { 103 l.senderLock.Unlock() 104 } 105 106 // setState advances the protocol state to newState. Returns false if moving 107 // to that state from the current state is not allowed. 108 func (l *ListenerConn) setState(newState int32) bool { 109 var expectedState int32 110 111 switch newState { 112 case connStateIdle: 113 expectedState = connStateExpectReadyForQuery 114 case connStateExpectResponse: 115 expectedState = connStateIdle 116 case connStateExpectReadyForQuery: 117 expectedState = connStateExpectResponse 118 default: 119 panic(fmt.Sprintf("unexpected listenerConnState %d", newState)) 120 } 121 122 return atomic.CompareAndSwapInt32(&l.connState, expectedState, newState) 123 } 124 125 // Main logic is here: receive messages from the postgres backend, forward 126 // notifications and query replies and keep the internal state in sync with the 127 // protocol state. Returns when the connection has been lost, is about to go 128 // away or should be discarded because we couldn't agree on the state with the 129 // server backend. 130 func (l *ListenerConn) listenerConnLoop() (err error) { 131 defer errRecoverNoErrBadConn(&err) 132 133 r := &readBuf{} 134 for { 135 t, err := l.cn.recvMessage(r) 136 if err != nil { 137 return err 138 } 139 140 switch t { 141 case 'A': 142 // recvNotification copies all the data so we don't need to worry 143 // about the scratch buffer being overwritten. 144 l.notificationChan <- recvNotification(r) 145 146 case 'T', 'D': 147 // only used by tests; ignore 148 149 case 'E': 150 // We might receive an ErrorResponse even when not in a query; it 151 // is expected that the server will close the connection after 152 // that, but we should make sure that the error we display is the 153 // one from the stray ErrorResponse, not io.ErrUnexpectedEOF. 154 if !l.setState(connStateExpectReadyForQuery) { 155 return parseError(r) 156 } 157 l.replyChan <- message{t, parseError(r)} 158 159 case 'C', 'I': 160 if !l.setState(connStateExpectReadyForQuery) { 161 // protocol out of sync 162 return fmt.Errorf("unexpected CommandComplete") 163 } 164 // ExecSimpleQuery doesn't need to know about this message 165 166 case 'Z': 167 if !l.setState(connStateIdle) { 168 // protocol out of sync 169 return fmt.Errorf("unexpected ReadyForQuery") 170 } 171 l.replyChan <- message{t, nil} 172 173 case 'N', 'S': 174 // ignore 175 default: 176 return fmt.Errorf("unexpected message %q from server in listenerConnLoop", t) 177 } 178 } 179 } 180 181 // This is the main routine for the goroutine receiving on the database 182 // connection. Most of the main logic is in listenerConnLoop. 183 func (l *ListenerConn) listenerConnMain() { 184 err := l.listenerConnLoop() 185 186 // listenerConnLoop terminated; we're done, but we still have to clean up. 187 // Make sure nobody tries to start any new queries by making sure the err 188 // pointer is set. It is important that we do not overwrite its value; a 189 // connection could be closed by either this goroutine or one sending on 190 // the connection -- whoever closes the connection is assumed to have the 191 // more meaningful error message (as the other one will probably get 192 // net.errClosed), so that goroutine sets the error we expose while the 193 // other error is discarded. If the connection is lost while two 194 // goroutines are operating on the socket, it probably doesn't matter which 195 // error we expose so we don't try to do anything more complex. 196 l.connectionLock.Lock() 197 if l.err == nil { 198 l.err = err 199 } 200 l.cn.Close() 201 l.connectionLock.Unlock() 202 203 // There might be a query in-flight; make sure nobody's waiting for a 204 // response to it, since there's not going to be one. 205 close(l.replyChan) 206 207 // let the listener know we're done 208 close(l.notificationChan) 209 210 // this ListenerConn is done 211 } 212 213 // Send a LISTEN query to the server. See ExecSimpleQuery. 214 func (l *ListenerConn) Listen(channel string) (bool, error) { 215 return l.ExecSimpleQuery("LISTEN " + QuoteIdentifier(channel)) 216 } 217 218 // Send an UNLISTEN query to the server. See ExecSimpleQuery. 219 func (l *ListenerConn) Unlisten(channel string) (bool, error) { 220 return l.ExecSimpleQuery("UNLISTEN " + QuoteIdentifier(channel)) 221 } 222 223 // Send `UNLISTEN *` to the server. See ExecSimpleQuery. 224 func (l *ListenerConn) UnlistenAll() (bool, error) { 225 return l.ExecSimpleQuery("UNLISTEN *") 226 } 227 228 // Ping the remote server to make sure it's alive. Non-nil error means the 229 // connection has failed and should be abandoned. 230 func (l *ListenerConn) Ping() error { 231 sent, err := l.ExecSimpleQuery("") 232 if !sent { 233 return err 234 } 235 if err != nil { 236 // shouldn't happen 237 panic(err) 238 } 239 return nil 240 } 241 242 // Attempt to send a query on the connection. Returns an error if sending the 243 // query failed, and the caller should initiate closure of this connection. 244 // The caller must be holding senderLock (see acquireSenderLock and 245 // releaseSenderLock). 246 func (l *ListenerConn) sendSimpleQuery(q string) (err error) { 247 defer errRecoverNoErrBadConn(&err) 248 249 // must set connection state before sending the query 250 if !l.setState(connStateExpectResponse) { 251 panic("two queries running at the same time") 252 } 253 254 // Can't use l.cn.writeBuf here because it uses the scratch buffer which 255 // might get overwritten by listenerConnLoop. 256 b := &writeBuf{ 257 buf: []byte("Q\x00\x00\x00\x00"), 258 pos: 1, 259 } 260 b.string(q) 261 l.cn.send(b) 262 263 return nil 264 } 265 266 // Execute a "simple query" (i.e. one with no bindable parameters) on the 267 // connection. The possible return values are: 268 // 1) "executed" is true; the query was executed to completion on the 269 // database server. If the query failed, err will be set to the error 270 // returned by the database, otherwise err will be nil. 271 // 2) If "executed" is false, the query could not be executed on the remote 272 // server. err will be non-nil. 273 // 274 // After a call to ExecSimpleQuery has returned an executed=false value, the 275 // connection has either been closed or will be closed shortly thereafter, and 276 // all subsequently executed queries will return an error. 277 func (l *ListenerConn) ExecSimpleQuery(q string) (executed bool, err error) { 278 if err = l.acquireSenderLock(); err != nil { 279 return false, err 280 } 281 defer l.releaseSenderLock() 282 283 err = l.sendSimpleQuery(q) 284 if err != nil { 285 // We can't know what state the protocol is in, so we need to abandon 286 // this connection. 287 l.connectionLock.Lock() 288 // Set the error pointer if it hasn't been set already; see 289 // listenerConnMain. 290 if l.err == nil { 291 l.err = err 292 } 293 l.connectionLock.Unlock() 294 l.cn.c.Close() 295 return false, err 296 } 297 298 // now we just wait for a reply.. 299 for { 300 m, ok := <-l.replyChan 301 if !ok { 302 // We lost the connection to server, don't bother waiting for a 303 // a response. err should have been set already. 304 l.connectionLock.Lock() 305 err := l.err 306 l.connectionLock.Unlock() 307 return false, err 308 } 309 switch m.typ { 310 case 'Z': 311 // sanity check 312 if m.err != nil { 313 panic("m.err != nil") 314 } 315 // done; err might or might not be set 316 return true, err 317 318 case 'E': 319 // sanity check 320 if m.err == nil { 321 panic("m.err == nil") 322 } 323 // server responded with an error; ReadyForQuery to follow 324 err = m.err 325 326 default: 327 return false, fmt.Errorf("unknown response for simple query: %q", m.typ) 328 } 329 } 330 } 331 332 func (l *ListenerConn) Close() error { 333 l.connectionLock.Lock() 334 if l.err != nil { 335 l.connectionLock.Unlock() 336 return errListenerConnClosed 337 } 338 l.err = errListenerConnClosed 339 l.connectionLock.Unlock() 340 // We can't send anything on the connection without holding senderLock. 341 // Simply close the net.Conn to wake up everyone operating on it. 342 return l.cn.c.Close() 343 } 344 345 // Err() returns the reason the connection was closed. It is not safe to call 346 // this function until l.Notify has been closed. 347 func (l *ListenerConn) Err() error { 348 return l.err 349 } 350 351 var errListenerClosed = errors.New("pq: Listener has been closed") 352 353 var ErrChannelAlreadyOpen = errors.New("pq: channel is already open") 354 var ErrChannelNotOpen = errors.New("pq: channel is not open") 355 356 type ListenerEventType int 357 358 const ( 359 // Emitted only when the database connection has been initially 360 // initialized. err will always be nil. 361 ListenerEventConnected ListenerEventType = iota 362 363 // Emitted after a database connection has been lost, either because of an 364 // error or because Close has been called. err will be set to the reason 365 // the database connection was lost. 366 ListenerEventDisconnected 367 368 // Emitted after a database connection has been re-established after 369 // connection loss. err will always be nil. After this event has been 370 // emitted, a nil pq.Notification is sent on the Listener.Notify channel. 371 ListenerEventReconnected 372 373 // Emitted after a connection to the database was attempted, but failed. 374 // err will be set to an error describing why the connection attempt did 375 // not succeed. 376 ListenerEventConnectionAttemptFailed 377 ) 378 379 type EventCallbackType func(event ListenerEventType, err error) 380 381 // Listener provides an interface for listening to notifications from a 382 // PostgreSQL database. For general usage information, see section 383 // "Notifications". 384 // 385 // Listener can safely be used from concurrently running goroutines. 386 type Listener struct { 387 // Channel for receiving notifications from the database. In some cases a 388 // nil value will be sent. See section "Notifications" above. 389 Notify chan *Notification 390 391 name string 392 minReconnectInterval time.Duration 393 maxReconnectInterval time.Duration 394 eventCallback EventCallbackType 395 396 lock sync.Mutex 397 isClosed bool 398 reconnectCond *sync.Cond 399 cn *ListenerConn 400 connNotificationChan <-chan *Notification 401 channels map[string]struct{} 402 } 403 404 // NewListener creates a new database connection dedicated to LISTEN / NOTIFY. 405 // 406 // name should be set to a connection string to be used to establish the 407 // database connection (see section "Connection String Parameters" above). 408 // 409 // minReconnectInterval controls the duration to wait before trying to 410 // re-establish the database connection after connection loss. After each 411 // consecutive failure this interval is doubled, until maxReconnectInterval is 412 // reached. Successfully completing the connection establishment procedure 413 // resets the interval back to minReconnectInterval. 414 // 415 // The last parameter eventCallback can be set to a function which will be 416 // called by the Listener when the state of the underlying database connection 417 // changes. This callback will be called by the goroutine which dispatches the 418 // notifications over the Notify channel, so you should try to avoid doing 419 // potentially time-consuming operations from the callback. 420 func NewListener(name string, 421 minReconnectInterval time.Duration, 422 maxReconnectInterval time.Duration, 423 eventCallback EventCallbackType) *Listener { 424 l := &Listener{ 425 name: name, 426 minReconnectInterval: minReconnectInterval, 427 maxReconnectInterval: maxReconnectInterval, 428 eventCallback: eventCallback, 429 430 channels: make(map[string]struct{}), 431 432 Notify: make(chan *Notification, 32), 433 } 434 l.reconnectCond = sync.NewCond(&l.lock) 435 436 go l.listenerMain() 437 438 return l 439 } 440 441 // Returns the notification channel for this listener. This is the same 442 // channel as Notify, and will not be recreated during the life time of the 443 // Listener. 444 func (l *Listener) NotificationChannel() <-chan *Notification { 445 return l.Notify 446 } 447 448 // Listen starts listening for notifications on a channel. Calls to this 449 // function will block until an acknowledgement has been received from the 450 // server. Note that Listener automatically re-establishes the connection 451 // after connection loss, so this function may block indefinitely if the 452 // connection can not be re-established. 453 // 454 // Listen will only fail in three conditions: 455 // 1) The channel is already open. The returned error will be 456 // ErrChannelAlreadyOpen. 457 // 2) The query was executed on the remote server, but PostgreSQL returned an 458 // error message in response to the query. The returned error will be a 459 // pq.Error containing the information the server supplied. 460 // 3) Close is called on the Listener before the request could be completed. 461 // 462 // The channel name is case-sensitive. 463 func (l *Listener) Listen(channel string) error { 464 l.lock.Lock() 465 defer l.lock.Unlock() 466 467 if l.isClosed { 468 return errListenerClosed 469 } 470 471 // The server allows you to issue a LISTEN on a channel which is already 472 // open, but it seems useful to be able to detect this case to spot for 473 // mistakes in application logic. If the application genuinely does't 474 // care, it can check the exported error and ignore it. 475 _, exists := l.channels[channel] 476 if exists { 477 return ErrChannelAlreadyOpen 478 } 479 480 if l.cn != nil { 481 // If gotResponse is true but error is set, the query was executed on 482 // the remote server, but resulted in an error. This should be 483 // relatively rare, so it's fine if we just pass the error to our 484 // caller. However, if gotResponse is false, we could not complete the 485 // query on the remote server and our underlying connection is about 486 // to go away, so we only add relname to l.channels, and wait for 487 // resync() to take care of the rest. 488 gotResponse, err := l.cn.Listen(channel) 489 if gotResponse && err != nil { 490 return err 491 } 492 } 493 494 l.channels[channel] = struct{}{} 495 for l.cn == nil { 496 l.reconnectCond.Wait() 497 // we let go of the mutex for a while 498 if l.isClosed { 499 return errListenerClosed 500 } 501 } 502 503 return nil 504 } 505 506 // Unlisten removes a channel from the Listener's channel list. Returns 507 // ErrChannelNotOpen if the Listener is not listening on the specified channel. 508 // Returns immediately with no error if there is no connection. Note that you 509 // might still get notifications for this channel even after Unlisten has 510 // returned. 511 // 512 // The channel name is case-sensitive. 513 func (l *Listener) Unlisten(channel string) error { 514 l.lock.Lock() 515 defer l.lock.Unlock() 516 517 if l.isClosed { 518 return errListenerClosed 519 } 520 521 // Similarly to LISTEN, this is not an error in Postgres, but it seems 522 // useful to distinguish from the normal conditions. 523 _, exists := l.channels[channel] 524 if !exists { 525 return ErrChannelNotOpen 526 } 527 528 if l.cn != nil { 529 // Similarly to Listen (see comment in that function), the caller 530 // should only be bothered with an error if it came from the backend as 531 // a response to our query. 532 gotResponse, err := l.cn.Unlisten(channel) 533 if gotResponse && err != nil { 534 return err 535 } 536 } 537 538 // Don't bother waiting for resync if there's no connection. 539 delete(l.channels, channel) 540 return nil 541 } 542 543 // UnlistenAll removes all channels from the Listener's channel list. Returns 544 // immediately with no error if there is no connection. Note that you might 545 // still get notifications for any of the deleted channels even after 546 // UnlistenAll has returned. 547 func (l *Listener) UnlistenAll() error { 548 l.lock.Lock() 549 defer l.lock.Unlock() 550 551 if l.isClosed { 552 return errListenerClosed 553 } 554 555 if l.cn != nil { 556 // Similarly to Listen (see comment in that function), the caller 557 // should only be bothered with an error if it came from the backend as 558 // a response to our query. 559 gotResponse, err := l.cn.UnlistenAll() 560 if gotResponse && err != nil { 561 return err 562 } 563 } 564 565 // Don't bother waiting for resync if there's no connection. 566 l.channels = make(map[string]struct{}) 567 return nil 568 } 569 570 // Ping the remote server to make sure it's alive. Non-nil return value means 571 // that there is no active connection. 572 func (l *Listener) Ping() error { 573 l.lock.Lock() 574 defer l.lock.Unlock() 575 576 if l.isClosed { 577 return errListenerClosed 578 } 579 if l.cn == nil { 580 return errors.New("no connection") 581 } 582 583 return l.cn.Ping() 584 } 585 586 // Clean up after losing the server connection. Returns l.cn.Err(), which 587 // should have the reason the connection was lost. 588 func (l *Listener) disconnectCleanup() error { 589 l.lock.Lock() 590 defer l.lock.Unlock() 591 592 // sanity check; can't look at Err() until the channel has been closed 593 select { 594 case _, ok := <-l.connNotificationChan: 595 if ok { 596 panic("connNotificationChan not closed") 597 } 598 default: 599 panic("connNotificationChan not closed") 600 } 601 602 err := l.cn.Err() 603 l.cn.Close() 604 l.cn = nil 605 return err 606 } 607 608 // Synchronize the list of channels we want to be listening on with the server 609 // after the connection has been established. 610 func (l *Listener) resync(cn *ListenerConn, notificationChan <-chan *Notification) error { 611 doneChan := make(chan error) 612 go func() { 613 for channel := range l.channels { 614 // If we got a response, return that error to our caller as it's 615 // going to be more descriptive than cn.Err(). 616 gotResponse, err := cn.Listen(channel) 617 if gotResponse && err != nil { 618 doneChan <- err 619 return 620 } 621 622 // If we couldn't reach the server, wait for notificationChan to 623 // close and then return the error message from the connection, as 624 // per ListenerConn's interface. 625 if err != nil { 626 for _ = range notificationChan { 627 } 628 doneChan <- cn.Err() 629 return 630 } 631 } 632 doneChan <- nil 633 }() 634 635 // Ignore notifications while synchronization is going on to avoid 636 // deadlocks. We have to send a nil notification over Notify anyway as 637 // we can't possibly know which notifications (if any) were lost while 638 // the connection was down, so there's no reason to try and process 639 // these messages at all. 640 for { 641 select { 642 case _, ok := <-notificationChan: 643 if !ok { 644 notificationChan = nil 645 } 646 647 case err := <-doneChan: 648 return err 649 } 650 } 651 } 652 653 // caller should NOT be holding l.lock 654 func (l *Listener) closed() bool { 655 l.lock.Lock() 656 defer l.lock.Unlock() 657 658 return l.isClosed 659 } 660 661 func (l *Listener) connect() error { 662 notificationChan := make(chan *Notification, 32) 663 cn, err := NewListenerConn(l.name, notificationChan) 664 if err != nil { 665 return err 666 } 667 668 l.lock.Lock() 669 defer l.lock.Unlock() 670 671 err = l.resync(cn, notificationChan) 672 if err != nil { 673 cn.Close() 674 return err 675 } 676 677 l.cn = cn 678 l.connNotificationChan = notificationChan 679 l.reconnectCond.Broadcast() 680 681 return nil 682 } 683 684 // Close disconnects the Listener from the database and shuts it down. 685 // Subsequent calls to its methods will return an error. Close returns an 686 // error if the connection has already been closed. 687 func (l *Listener) Close() error { 688 l.lock.Lock() 689 defer l.lock.Unlock() 690 691 if l.isClosed { 692 return errListenerClosed 693 } 694 695 if l.cn != nil { 696 l.cn.Close() 697 } 698 l.isClosed = true 699 700 return nil 701 } 702 703 func (l *Listener) emitEvent(event ListenerEventType, err error) { 704 if l.eventCallback != nil { 705 l.eventCallback(event, err) 706 } 707 } 708 709 // Main logic here: maintain a connection to the server when possible, wait 710 // for notifications and emit events. 711 func (l *Listener) listenerConnLoop() { 712 var nextReconnect time.Time 713 714 reconnectInterval := l.minReconnectInterval 715 for { 716 for { 717 err := l.connect() 718 if err == nil { 719 break 720 } 721 722 if l.closed() { 723 return 724 } 725 l.emitEvent(ListenerEventConnectionAttemptFailed, err) 726 727 time.Sleep(reconnectInterval) 728 reconnectInterval *= 2 729 if reconnectInterval > l.maxReconnectInterval { 730 reconnectInterval = l.maxReconnectInterval 731 } 732 } 733 734 if nextReconnect.IsZero() { 735 l.emitEvent(ListenerEventConnected, nil) 736 } else { 737 l.emitEvent(ListenerEventReconnected, nil) 738 l.Notify <- nil 739 } 740 741 reconnectInterval = l.minReconnectInterval 742 nextReconnect = time.Now().Add(reconnectInterval) 743 744 for { 745 notification, ok := <-l.connNotificationChan 746 if !ok { 747 // lost connection, loop again 748 break 749 } 750 l.Notify <- notification 751 } 752 753 err := l.disconnectCleanup() 754 if l.closed() { 755 return 756 } 757 l.emitEvent(ListenerEventDisconnected, err) 758 759 time.Sleep(nextReconnect.Sub(time.Now())) 760 } 761 } 762 763 func (l *Listener) listenerMain() { 764 l.listenerConnLoop() 765 close(l.Notify) 766 }