3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-11-21 19:39:43 +01:00

Merge pull request #1949 from slingamn/generic_config.2

genericize atomic config changes
This commit is contained in:
Shivaram Lingamneni 2022-05-04 01:30:52 -04:00 committed by GitHub
commit d5814c10ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 36 additions and 9 deletions

View File

@ -7,7 +7,6 @@ import (
"net"
"sync/atomic"
"time"
"unsafe"
"github.com/ergochat/ergo/irc/caps"
"github.com/ergochat/ergo/irc/languages"
@ -16,11 +15,7 @@ import (
)
func (server *Server) Config() (config *Config) {
return (*Config)(atomic.LoadPointer(&server.config))
}
func (server *Server) SetConfig(config *Config) {
atomic.StorePointer(&server.config, unsafe.Pointer(config))
return server.config.Get()
}
func (server *Server) ChannelRegistrationEnabled() bool {

View File

@ -17,7 +17,6 @@ import (
"sync"
"syscall"
"time"
"unsafe"
"github.com/ergochat/irc-go/ircfmt"
"github.com/okzk/sdnotify"
@ -66,7 +65,7 @@ type Server struct {
channels ChannelManager
channelRegistry ChannelRegistry
clients ClientManager
config unsafe.Pointer
config utils.ConfigStore[Config]
configFilename string
connectionLimiter connection_limits.Limiter
ctime time.Time
@ -706,7 +705,7 @@ func (server *Server) applyConfig(config *Config) (err error) {
config.Server.Cloaks.SetSecret(LoadCloakSecret(server.store))
// activate the new config
server.SetConfig(config)
server.config.Set(config)
// load [dk]-lines, registered users and channels, etc.
if initial {

33
irc/utils/config.go Normal file
View File

@ -0,0 +1,33 @@
// Copyright (c) 2022 Shivaram Lingamneni
// released under the MIT license
package utils
import (
"sync/atomic"
"unsafe"
)
/*
This can be used to implement the following pattern:
1. Prepare a config object (this can be arbitrarily expensive)
2. Take a pointer to the config object and use Set() to install it
3. Use Get() to access the config from any goroutine
4. To update the config, call Set() again with a new prepared config object
5. As long as any individual config object is not modified (by any goroutine)
after it is installed with Set(), this is free of data races, and Get()
is extremely cheap (on amd64 it compiles down to plain MOV instructions).
*/
type ConfigStore[Config any] struct {
ptr unsafe.Pointer
}
func (c *ConfigStore[Config]) Get() *Config {
return (*Config)(atomic.LoadPointer(&c.ptr))
}
func (c *ConfigStore[Config]) Set(ptr *Config) {
atomic.StorePointer(&c.ptr, unsafe.Pointer(ptr))
}