Skip to content

Commit 732ab47

Browse files
authored
Add limit for yproxy writer (#156)
1 parent 5f76095 commit 732ab47

3 files changed

Lines changed: 80 additions & 9 deletions

File tree

pkg/proc/yio/limiter/limiter.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import (
44
"context"
55
"fmt"
66
"io"
7+
"sync"
78

9+
"github.com/yezzey-gp/yproxy/config"
810
"github.com/yezzey-gp/yproxy/pkg/ylogger"
911
"golang.org/x/time/rate"
1012
)
@@ -48,3 +50,67 @@ func (r *Reader) Read(buf []byte) (int, error) {
4850
err = r.limiter.WaitN(r.ctx, n)
4951
return n, err
5052
}
53+
54+
type Writer struct {
55+
writer io.WriteCloser
56+
limiter *rate.Limiter
57+
ctx context.Context
58+
}
59+
60+
// Close implements io.ReadCloser.
61+
func (r *Writer) Close() error {
62+
return r.writer.Close()
63+
}
64+
65+
func NewWriter(writer io.WriteCloser, limiter *rate.Limiter) *Writer {
66+
return &Writer{
67+
ctx: context.Background(),
68+
writer: writer,
69+
limiter: limiter,
70+
}
71+
}
72+
73+
func (r *Writer) Write(buf []byte) (int, error) {
74+
if len(buf) == 0 {
75+
return 0, fmt.Errorf("empty buffer passed")
76+
}
77+
78+
end := min(r.limiter.Burst(), len(buf))
79+
n, err := r.writer.Write(buf[:end])
80+
81+
if err != nil {
82+
N := max(n, 0)
83+
limiterErr := r.limiter.WaitN(r.ctx, N)
84+
if limiterErr != nil {
85+
ylogger.Zero.Error().Err(limiterErr).Msg("Error happened while limiting")
86+
}
87+
return n, err
88+
}
89+
90+
err = r.limiter.WaitN(r.ctx, n)
91+
return n, err
92+
}
93+
94+
var (
95+
/* Single limiter for all external storage interaction */
96+
mu sync.Mutex
97+
netLimiter *rate.Limiter = nil
98+
)
99+
100+
func GetLimiter() *rate.Limiter {
101+
mu.Lock()
102+
defer mu.Unlock()
103+
104+
if netLimiter != nil {
105+
ylogger.Zero.Debug().Msg("reuse limiter")
106+
return netLimiter
107+
}
108+
109+
netLimit := config.InstanceConfig().StorageCnf.StorageRateLimit
110+
ylogger.Zero.Debug().Uint64("bytes per sec", netLimit).Msg("allocate limiter")
111+
112+
netLimiter = rate.NewLimiter(rate.Limit(netLimit),
113+
int(netLimit))
114+
115+
return netLimiter
116+
}

pkg/proc/yio/yrreader.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"io"
66
"time"
77

8-
"github.com/yezzey-gp/yproxy/config"
98
"github.com/yezzey-gp/yproxy/pkg/client"
109
"github.com/yezzey-gp/yproxy/pkg/proc/yio/limiter"
1110
"github.com/yezzey-gp/yproxy/pkg/settings"
@@ -21,7 +20,7 @@ type RestartReader interface {
2120

2221
type YRestartReader struct {
2322
underlying io.ReadCloser
24-
limiter *rate.Limiter
23+
lim *rate.Limiter
2524
s storage.StorageInteractor
2625
name string
2726
settings []settings.StorageSettings
@@ -45,16 +44,13 @@ func (y *YRestartReader) Read(p []byte) (n int, err error) {
4544
func NewRestartReader(s storage.StorageInteractor,
4645
name string, setts []settings.StorageSettings) RestartReader {
4746

48-
netLimit := config.InstanceConfig().StorageCnf.StorageRateLimit
49-
50-
l := rate.NewLimiter(rate.Limit(netLimit),
51-
int(netLimit))
47+
l := limiter.GetLimiter()
5248

5349
return &YRestartReader{
5450
s: s,
5551
name: name,
5652
settings: setts,
57-
limiter: l,
53+
lim: l,
5854
}
5955
}
6056

@@ -74,7 +70,7 @@ func (y *YRestartReader) Restart(offsetStart int64) error {
7470

7571
/* with limiter */
7672

77-
y.underlying = limiter.NewReader(r, y.limiter)
73+
y.underlying = limiter.NewReader(r, y.lim)
7874

7975
return nil
8076
}

pkg/proc/yio/ywriter.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@ import (
44
"io"
55

66
"github.com/yezzey-gp/yproxy/pkg/client"
7+
"github.com/yezzey-gp/yproxy/pkg/proc/yio/limiter"
78
"github.com/yezzey-gp/yproxy/pkg/ylogger"
9+
"golang.org/x/time/rate"
810
)
911

1012
/* TBD: support restart */
1113
type YproxyWriter struct {
1214
underlying io.WriteCloser
1315

16+
lim *rate.Limiter
17+
1418
selfCl client.YproxyClient
1519

1620
offsetReached int64
@@ -34,11 +38,16 @@ func (y *YproxyWriter) Write(p []byte) (n int, err error) {
3438
}
3539

3640
func NewYproxyWriter(under io.WriteCloser, selfCl client.YproxyClient) io.WriteCloser {
37-
return &YproxyWriter{
41+
42+
w := &YproxyWriter{
3843
underlying: under,
44+
lim: limiter.GetLimiter(),
3945
selfCl: selfCl,
4046
offsetReached: 0,
4147
}
48+
49+
w.underlying = limiter.NewWriter(under, w.lim)
50+
return w
4251
}
4352

4453
var _ io.WriteCloser = &YproxyWriter{}

0 commit comments

Comments
 (0)