~emersion/soju

4dae0da59f5f28a3a72ebc2db8f5f4887666a5fa — Simon Ser 3 months ago 81c7e80
Replace networkHistory.offlineClients with clients

Keep the ring buffer alive even if all clients are connected. Keep the
ID of the latest delivered message even for online clients.

As-is, this is a net downgrade: memory usage increases because ring
buffers aren't free'd anymore. However upcoming commits will replace the
ring buffer with log files. This change makes reading from log files
easier.
3 files changed, 14 insertions(+), 28 deletions(-)

M downstream.go
M upstream.go
M user.go
M downstream.go => downstream.go +2 -8
@@ 864,17 864,11 @@ func (dc *downstreamConn) sendNetworkHistory(net *network) {
			continue
		}

		seq, ok := history.offlineClients[dc.clientName]
		seq, ok := history.clients[dc.clientName]
		if !ok {
			continue
		}
		delete(history.offlineClients, dc.clientName)

		// If all clients have received history, no need to keep the
		// ring buffer around
		if len(history.offlineClients) == 0 {
			delete(net.history, target)
		}
		history.clients[dc.clientName] = history.ring.Cur()

		consumer := history.ring.NewConsumer(seq)


M upstream.go => upstream.go +10 -9
@@ 1635,33 1635,34 @@ func (uc *upstreamConn) appendHistory(entity string, msg *irc.Message) {
		detached = ch.Detached
	}

	// If no client is offline, no need to append the message to the buffer
	if len(uc.network.offlineClients) == 0 && !detached {
		return
	}

	history, ok := uc.network.history[entity]
	if !ok {
		history = &networkHistory{
			offlineClients: make(map[string]uint64),
			ring:           NewRing(uc.srv.RingCap),
			clients: make(map[string]uint64),
			ring:    NewRing(uc.srv.RingCap),
		}
		uc.network.history[entity] = history

		for clientName, _ := range uc.network.offlineClients {
			history.offlineClients[clientName] = 0
			history.clients[clientName] = 0
		}

		if detached {
			// If the channel is detached, online clients act as offline
			// clients too
			uc.forEachDownstream(func(dc *downstreamConn) {
				history.offlineClients[dc.clientName] = 0
				history.clients[dc.clientName] = 0
			})
		}
	}

	history.ring.Produce(msg)

	if !detached {
		uc.forEachDownstream(func(dc *downstreamConn) {
			history.clients[dc.clientName] = history.ring.Cur()
		})
	}
}

// produce appends a message to the logs, adds it to the history and forwards

M user.go => user.go +2 -11
@@ 51,8 51,8 @@ type eventDownstreamDisconnected struct {
type eventStop struct{}

type networkHistory struct {
	offlineClients map[string]uint64 // indexed by client name
	ring           *Ring             // can be nil if there are no offline clients
	clients map[string]uint64 // indexed by client name
	ring    *Ring             // can be nil if there are no offline clients
}

type network struct {


@@ 193,9 193,6 @@ func (net *network) createUpdateChannel(ch *Channel) error {
			net.user.srv.Logger.Printf("network %q: detaching channel %q", net.GetName(), ch.Name)
			net.forEachDownstream(func(dc *downstreamConn) {
				net.offlineClients[dc.clientName] = struct{}{}
				if history != nil {
					history.offlineClients[dc.clientName] = history.ring.Cur()
				}

				dc.SendMessage(&irc.Message{
					Prefix:  dc.prefix(),


@@ 423,12 420,6 @@ func (u *user) run() {
				}

				net.offlineClients[dc.clientName] = struct{}{}
				for target, history := range net.history {
					if ch, ok := net.channels[target]; ok && ch.Detached {
						continue
					}
					history.offlineClients[dc.clientName] = history.ring.Cur()
				}
			})

			u.forEachUpstream(func(uc *upstreamConn) {