mirror of
https://github.com/jech/galene.git
synced 2024-11-10 02:35:58 +01:00
Expire idle groups from memory.
Also get rid of dead groups, they're not useful.
This commit is contained in:
parent
dc3256ca19
commit
0265df6331
2 changed files with 78 additions and 27 deletions
|
@ -97,11 +97,10 @@ type Group struct {
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
description *description
|
description *description
|
||||||
// indicates that the group no longer exists, but it still has clients
|
|
||||||
dead bool
|
|
||||||
locked *string
|
locked *string
|
||||||
clients map[string]Client
|
clients map[string]Client
|
||||||
history []ChatHistoryEntry
|
history []ChatHistoryEntry
|
||||||
|
timestamp time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Group) Name() string {
|
func (g *Group) Name() string {
|
||||||
|
@ -201,6 +200,7 @@ func Add(name string, desc *description) (*Group, error) {
|
||||||
name: name,
|
name: name,
|
||||||
description: desc,
|
description: desc,
|
||||||
clients: make(map[string]Client),
|
clients: make(map[string]Client),
|
||||||
|
timestamp: time.Now(),
|
||||||
}
|
}
|
||||||
groups.groups[name] = g
|
groups.groups[name] = g
|
||||||
return g, nil
|
return g, nil
|
||||||
|
@ -211,11 +211,10 @@ func Add(name string, desc *description) (*Group, error) {
|
||||||
|
|
||||||
if desc != nil {
|
if desc != nil {
|
||||||
g.description = desc
|
g.description = desc
|
||||||
g.dead = false
|
|
||||||
return g, nil
|
return g, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if g.dead || time.Since(g.description.loadTime) > 5*time.Second {
|
if time.Since(g.description.loadTime) > 5*time.Second {
|
||||||
if descriptionChanged(name, g.description) {
|
if descriptionChanged(name, g.description) {
|
||||||
desc, err := GetDescription(name)
|
desc, err := GetDescription(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -223,11 +222,9 @@ func Add(name string, desc *description) (*Group, error) {
|
||||||
log.Printf("Reading group %v: %v",
|
log.Printf("Reading group %v: %v",
|
||||||
name, err)
|
name, err)
|
||||||
}
|
}
|
||||||
g.dead = true
|
deleteUnlocked(g)
|
||||||
delGroupUnlocked(name)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
g.dead = false
|
|
||||||
g.description = desc
|
g.description = desc
|
||||||
} else {
|
} else {
|
||||||
g.description.loadTime = time.Now()
|
g.description.loadTime = time.Now()
|
||||||
|
@ -266,20 +263,57 @@ func Get(name string) *Group {
|
||||||
return groups.groups[name]
|
return groups.groups[name]
|
||||||
}
|
}
|
||||||
|
|
||||||
func delGroupUnlocked(name string) bool {
|
func Delete(name string) bool {
|
||||||
|
groups.mu.Lock()
|
||||||
|
defer groups.mu.Unlock()
|
||||||
g := groups.groups[name]
|
g := groups.groups[name]
|
||||||
if g == nil {
|
if g == nil {
|
||||||
return true
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g.mu.Lock()
|
||||||
|
defer g.mu.Unlock()
|
||||||
|
return deleteUnlocked(g)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called with both groups.mu and g.mu taken.
|
||||||
|
func deleteUnlocked(g *Group) bool {
|
||||||
if len(g.clients) != 0 {
|
if len(g.clients) != 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(groups.groups, name)
|
delete(groups.groups, g.name)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Expire() {
|
||||||
|
names := GetNames()
|
||||||
|
now := time.Now()
|
||||||
|
|
||||||
|
for _, name := range names {
|
||||||
|
g := Get(name)
|
||||||
|
if g == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
old := false
|
||||||
|
|
||||||
|
g.mu.Lock()
|
||||||
|
empty := len(g.clients) == 0
|
||||||
|
if empty && !g.description.Public {
|
||||||
|
age := now.Sub(g.timestamp)
|
||||||
|
old = age > maxHistoryAge(g.description)
|
||||||
|
}
|
||||||
|
// We cannot take groups.mu at this point without a deadlock.
|
||||||
|
g.mu.Unlock()
|
||||||
|
|
||||||
|
if empty && old {
|
||||||
|
// Delete will check if the group is still empty
|
||||||
|
Delete(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func AddClient(group string, c Client) (*Group, error) {
|
func AddClient(group string, c Client) (*Group, error) {
|
||||||
g, err := Add(group, nil)
|
g, err := Add(group, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -317,6 +351,7 @@ func AddClient(group string, c Client) (*Group, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
g.clients[c.Id()] = c
|
g.clients[c.Id()] = c
|
||||||
|
g.timestamp = time.Now()
|
||||||
|
|
||||||
go func(clients []Client) {
|
go func(clients []Client) {
|
||||||
u := c.Username()
|
u := c.Username()
|
||||||
|
@ -344,6 +379,7 @@ func DelClient(c Client) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
delete(g.clients, c.Id())
|
delete(g.clients, c.Id())
|
||||||
|
g.timestamp = time.Now()
|
||||||
|
|
||||||
go func(clients []Client) {
|
go func(clients []Client) {
|
||||||
for _, cc := range clients {
|
for _, cc := range clients {
|
||||||
|
@ -437,16 +473,10 @@ func (g *Group) AddToChatHistory(id, user string, time int64, kind, value string
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func discardObsoleteHistory(h []ChatHistoryEntry, seconds int) []ChatHistoryEntry {
|
func discardObsoleteHistory(h []ChatHistoryEntry, duration time.Duration) []ChatHistoryEntry {
|
||||||
now := time.Now()
|
|
||||||
d := 4 * time.Hour
|
|
||||||
if seconds > 0 {
|
|
||||||
d = time.Duration(seconds) * time.Second
|
|
||||||
}
|
|
||||||
|
|
||||||
i := 0
|
i := 0
|
||||||
for i < len(h) {
|
for i < len(h) {
|
||||||
if now.Sub(FromJSTime(h[i].Time)) <= d {
|
if time.Since(FromJSTime(h[i].Time)) <= duration {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
|
@ -462,7 +492,9 @@ func (g *Group) GetChatHistory() []ChatHistoryEntry {
|
||||||
g.mu.Lock()
|
g.mu.Lock()
|
||||||
defer g.mu.Unlock()
|
defer g.mu.Unlock()
|
||||||
|
|
||||||
g.history = discardObsoleteHistory(g.history, g.description.MaxHistoryAge)
|
g.history = discardObsoleteHistory(
|
||||||
|
g.history, maxHistoryAge(g.description),
|
||||||
|
)
|
||||||
|
|
||||||
h := make([]ChatHistoryEntry, len(g.history))
|
h := make([]ChatHistoryEntry, len(g.history))
|
||||||
copy(h, g.history)
|
copy(h, g.history)
|
||||||
|
@ -504,6 +536,15 @@ type description struct {
|
||||||
Other []ClientCredentials `json:"other,omitempty"`
|
Other []ClientCredentials `json:"other,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DefaultMaxHistoryAge = 4 * time.Hour
|
||||||
|
|
||||||
|
func maxHistoryAge(desc *description) time.Duration {
|
||||||
|
if desc.MaxHistoryAge != 0 {
|
||||||
|
return time.Duration(desc.MaxHistoryAge) * time.Second
|
||||||
|
}
|
||||||
|
return DefaultMaxHistoryAge
|
||||||
|
}
|
||||||
|
|
||||||
func openDescriptionFile(name string) (*os.File, string, bool, error) {
|
func openDescriptionFile(name string) (*os.File, string, bool, error) {
|
||||||
isParent := false
|
isParent := false
|
||||||
for name != "" {
|
for name != "" {
|
||||||
|
|
10
sfu.go
10
sfu.go
|
@ -14,6 +14,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"sfu/diskwriter"
|
"sfu/diskwriter"
|
||||||
"sfu/group"
|
"sfu/group"
|
||||||
|
@ -94,10 +95,19 @@ func main() {
|
||||||
|
|
||||||
terminate := make(chan os.Signal, 1)
|
terminate := make(chan os.Signal, 1)
|
||||||
signal.Notify(terminate, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(terminate, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
||||||
|
ticker := time.NewTicker(15 * time.Minute)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for {
|
||||||
select {
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
go group.Expire()
|
||||||
case <-terminate:
|
case <-terminate:
|
||||||
webserver.Shutdown()
|
webserver.Shutdown()
|
||||||
|
return
|
||||||
case <-serverDone:
|
case <-serverDone:
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue