summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--config.go29
-rw-r--r--docs/cca.scfg.example10
-rw-r--r--wsc.go12
3 files changed, 34 insertions, 17 deletions
diff --git a/config.go b/config.go
index 8d22904..1bbba9a 100644
--- a/config.go
+++ b/config.go
@@ -65,11 +65,11 @@ var configWithPointers struct {
Expr *int `scfg:"expr"`
} `scfg:"auth"`
Perf struct {
- MessageArgumentsCap *int `scfg:"msg_args_cap"`
- MessageBytesCap *int `scfg:"msg_bytes_cap"`
- ReadHeaderTimeout *int `scfg:"read_header_timeout"`
- CourseUpdateInterval *int `scfg:"course_update_interval"`
- PropagateImmediate *bool `scfg:"propagate_immediate"`
+ MessageArgumentsCap *int `scfg:"msg_args_cap"`
+ MessageBytesCap *int `scfg:"msg_bytes_cap"`
+ ReadHeaderTimeout *int `scfg:"read_header_timeout"`
+ UsemDelayShiftBits *int `scfg:"usem_delay_shift_bits"`
+ PropagateImmediate *bool `scfg:"propagate_immediate"`
} `scfg:"perf"`
}
@@ -100,11 +100,11 @@ var config struct {
Expr int
}
Perf struct {
- MessageArgumentsCap int
- MessageBytesCap int
- ReadHeaderTimeout int
- CourseUpdateInterval int
- PropagateImmediate bool
+ MessageArgumentsCap int
+ MessageBytesCap int
+ ReadHeaderTimeout int
+ UsemDelayShiftBits int
+ PropagateImmediate bool
} `scfg:"perf"`
}
@@ -287,10 +287,13 @@ func fetchConfig(path string) (retErr error) {
}
config.Perf.ReadHeaderTimeout = *(configWithPointers.Perf.ReadHeaderTimeout)
- if configWithPointers.Perf.CourseUpdateInterval == nil {
- return fmt.Errorf("%w: perf.course_update_interval", errMissingConfigValue)
+ if configWithPointers.Perf.UsemDelayShiftBits == nil {
+ return fmt.Errorf(
+ "%w: perf.usem_delay_shift_bits",
+ errMissingConfigValue,
+ )
}
- config.Perf.CourseUpdateInterval = *(configWithPointers.Perf.CourseUpdateInterval)
+ config.Perf.UsemDelayShiftBits = *(configWithPointers.Perf.UsemDelayShiftBits)
if configWithPointers.Perf.PropagateImmediate == nil {
return fmt.Errorf(
diff --git a/docs/cca.scfg.example b/docs/cca.scfg.example
index 471d6e9..b01fe40 100644
--- a/docs/cca.scfg.example
+++ b/docs/cca.scfg.example
@@ -83,9 +83,13 @@ perf {
# vulnerable to Slow Loris attacks.
read_header_timeout 5
- # How long, in milliseconds, do we wait before propagating course
- # number update events for conjunction between course and user?
- course_update_interval 200
+ # The number propagation interval per course per connection is
+ # ((course count * connection count) >> usem_delay_shift_bits)
+ # milliseconds. You may configure it here. A smaller value (i.e. longer
+ # delay) could cause more latency in how the numbers update, but a
+ # larger value (i.e. shorter delay) could cause too much lock
+ # contention and degrade the system usability overall.
+ usem_delay_shift_bits 4
# Should we send a course's member count to a user as soon as they
# choose the course? Setting this to true may provide a better
diff --git a/wsc.go b/wsc.go
index 193ff4f..d5a27f9 100644
--- a/wsc.go
+++ b/wsc.go
@@ -25,6 +25,7 @@ import (
"errors"
"fmt"
"sync"
+ "sync/atomic"
"time"
"github.com/coder/websocket"
@@ -35,6 +36,8 @@ type errbytesT struct {
bytes *[]byte
}
+var usemCount int64
+
/*
* This is more appropriately typed as uint64, but it needs to be cast to int64
* later anyway due to time.Duration, so let's just use int64.
@@ -83,6 +86,7 @@ func handleConn(
usems := make(map[int]*usemT)
func() {
+ atomic.AddInt64(&usemCount, int64(len(courses)))
coursesLock.RLock()
defer coursesLock.RUnlock()
for courseID, course := range courses {
@@ -106,6 +110,7 @@ func handleConn(
delete(course.Usems, userID)
}()
}
+ atomic.AddInt64(&usemCount, -int64(len(courses)))
}()
usemParent := make(chan int)
@@ -122,7 +127,12 @@ func handleConn(
case usemParent <- courseID:
}
}
- time.Sleep(time.Duration(config.Perf.CourseUpdateInterval) * time.Millisecond)
+ time.Sleep(
+ time.Duration(
+ atomic.LoadInt64(&usemCount)>>
+ config.Perf.UsemDelayShiftBits,
+ ) * time.Millisecond,
+ )
}
}()
}