Skip to content

Commit f5814b5

Browse files
committed
renamed budget.New() => budget.Limited()
added `budget.Percent()`
1 parent 1484dbb commit f5814b5

File tree

8 files changed

+62
-17
lines changed

8 files changed

+62
-17
lines changed

internal/config/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"github.com/ydb-platform/ydb-go-sdk/v3/trace"
88
)
99

10-
var defaultRetryBudget = budget.New(-1)
10+
var defaultRetryBudget = budget.Limited(-1)
1111

1212
type Common struct {
1313
operationTimeout time.Duration

retry/budget/budget.go

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,43 @@ package budget
22

33
import (
44
"context"
5+
"fmt"
56
"time"
67

78
"github.com/jonboulle/clockwork"
89

910
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
11+
"github.com/ydb-platform/ydb-go-sdk/v3/internal/xrand"
1012
)
1113

1214
type (
1315
// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
1416
Budget interface {
17+
// Acquire called from retryer on second and subsequence attempts
1518
Acquire(ctx context.Context) error
1619
}
17-
budget struct {
20+
fixedBudget struct {
1821
clock clockwork.Clock
1922
ticker clockwork.Ticker
2023
quota chan struct{}
2124
done chan struct{}
2225
}
23-
option func(q *budget)
26+
fixedBudgetOption func(q *fixedBudget)
27+
percentBudget struct {
28+
percent int
29+
rand xrand.Rand
30+
}
2431
)
2532

26-
func withBudgetClock(clock clockwork.Clock) option {
27-
return func(q *budget) {
33+
func withFixedBudgetClock(clock clockwork.Clock) fixedBudgetOption {
34+
return func(q *fixedBudget) {
2835
q.clock = clock
2936
}
3037
}
3138

3239
// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
33-
func New(attemptsPerSecond int, opts ...option) *budget {
34-
q := &budget{
40+
func Limited(attemptsPerSecond int, opts ...fixedBudgetOption) *fixedBudget {
41+
q := &fixedBudget{
3542
clock: clockwork.NewRealClock(),
3643
done: make(chan struct{}),
3744
}
@@ -68,15 +75,15 @@ func New(attemptsPerSecond int, opts ...option) *budget {
6875
}
6976

7077
// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
71-
func (q *budget) Stop() {
78+
func (q *fixedBudget) Stop() {
7279
if q.ticker != nil {
7380
q.ticker.Stop()
7481
}
7582
close(q.done)
7683
}
7784

7885
// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
79-
func (q *budget) Acquire(ctx context.Context) error {
86+
func (q *fixedBudget) Acquire(ctx context.Context) error {
8087
if err := ctx.Err(); err != nil {
8188
return xerrors.WithStackTrace(err)
8289
}
@@ -89,3 +96,22 @@ func (q *budget) Acquire(ctx context.Context) error {
8996
return xerrors.WithStackTrace(ctx.Err())
9097
}
9198
}
99+
100+
// Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental
101+
func Percent(percent int) *percentBudget {
102+
if percent > 100 || percent < 0 {
103+
panic(fmt.Sprintf("wrong percent value: %d", percent))
104+
}
105+
return &percentBudget{
106+
percent: percent,
107+
rand: xrand.New(xrand.WithLock()),
108+
}
109+
}
110+
111+
func (b *percentBudget) Acquire(ctx context.Context) error {
112+
if b.rand.Int(100) < b.percent {
113+
return nil
114+
}
115+
116+
return ErrNoQuota
117+
}

retry/budget/budget_test.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,18 @@ import (
1515
func TestUnlimitedBudget(t *testing.T) {
1616
xtest.TestManyTimes(t, func(t testing.TB) {
1717
ctx, cancel := xcontext.WithCancel(xtest.Context(t))
18-
q := New(-1)
18+
q := Limited(-1)
1919
require.NoError(t, q.Acquire(ctx))
2020
cancel()
2121
require.ErrorIs(t, q.Acquire(ctx), context.Canceled)
2222
})
2323
}
2424

25-
func TestBudget(t *testing.T) {
25+
func TestLimited(t *testing.T) {
2626
xtest.TestManyTimes(t, func(t testing.TB) {
2727
ctx, cancel := xcontext.WithCancel(xtest.Context(t))
2828
clock := clockwork.NewFakeClock()
29-
q := New(1, withBudgetClock(clock))
29+
q := Limited(1, withFixedBudgetClock(clock))
3030
defer q.Stop()
3131
require.NoError(t, q.Acquire(ctx))
3232
acquireCh := make(chan struct{})
@@ -51,3 +51,22 @@ func TestBudget(t *testing.T) {
5151
require.ErrorIs(t, q.Acquire(ctx), context.Canceled)
5252
})
5353
}
54+
55+
func TestPercent(t *testing.T) {
56+
xtest.TestManyTimes(t, func(t testing.TB) {
57+
var (
58+
total = 1000000
59+
percent = 0.25
60+
ctx = xtest.Context(t)
61+
b = Percent(int(percent * 100))
62+
success int
63+
)
64+
for i := 0; i < total; i++ {
65+
if b.Acquire(ctx) == nil {
66+
success++
67+
}
68+
}
69+
require.GreaterOrEqual(t, success, int(float64(total)*(percent-0.1*percent)))
70+
require.LessOrEqual(t, success, int(float64(total)*(percent+0.1*percent)))
71+
}, xtest.StopAfter(5*time.Second))
72+
}

retry/retry.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ func Retry(ctx context.Context, op retryOperation, opts ...Option) (finalErr err
261261
options := &retryOptions{
262262
call: stack.FunctionID("github.com/ydb-platform/ydb-go-sdk/3/retry.Retry"),
263263
trace: &trace.Retry{},
264-
budget: budget.New(-1),
264+
budget: budget.Limited(-1),
265265
fastBackoff: backoff.Fast,
266266
slowBackoff: backoff.Slow,
267267
}

tests/integration/retry_budget_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func (n noQuota) Acquire(ctx context.Context) error {
3131
func TestRetryBudget(t *testing.T) {
3232
ctx := xtest.Context(t)
3333

34-
defaultLimiter := budget.New(1)
34+
defaultLimiter := budget.Limited(1)
3535
defer defaultLimiter.Stop()
3636

3737
nativeDriver, err := ydb.Open(ctx, os.Getenv("YDB_CONNECTION_STRING"),

tests/slo/database/sql/storage.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ func NewStorage(ctx context.Context, cfg *config.Config, poolSize int) (s *Stora
8686
ctx, cancel := context.WithTimeout(ctx, time.Minute*5) //nolint:gomnd
8787
defer cancel()
8888

89-
retryBudget := budget.New(int(float64(poolSize) * 0.1)) //nolint:gomnd
89+
retryBudget := budget.Limited(int(float64(poolSize) * 0.1)) //nolint:gomnd
9090

9191
s = &Storage{
9292
cfg: cfg,

tests/slo/native/query/storage.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func NewStorage(ctx context.Context, cfg *config.Config, poolSize int) (*Storage
7373
ctx, cancel := context.WithTimeout(ctx, time.Minute*5) //nolint:gomnd
7474
defer cancel()
7575

76-
retryBudget := budget.New(int(float64(poolSize) * 0.1)) //nolint:gomnd
76+
retryBudget := budget.Limited(int(float64(poolSize) * 0.1)) //nolint:gomnd
7777

7878
db, err := ydb.Open(ctx,
7979
cfg.Endpoint+cfg.DB,

tests/slo/native/table/storage.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func NewStorage(ctx context.Context, cfg *config.Config, poolSize int) (*Storage
7474
ctx, cancel := context.WithTimeout(ctx, time.Minute*5) //nolint:gomnd
7575
defer cancel()
7676

77-
retryBudget := budget.New(int(float64(poolSize) * 0.1)) //nolint:gomnd
77+
retryBudget := budget.Limited(int(float64(poolSize) * 0.1)) //nolint:gomnd
7878

7979
db, err := ydb.Open(
8080
ctx,

0 commit comments

Comments
 (0)