-
Notifications
You must be signed in to change notification settings - Fork 10
feat(client): add sender pool #47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
4bcc562
initial feature commit
sklarsa 1afb3f5
adds a test
sklarsa fc9b6f8
chore(ci): fix haproxy configuration for archlinux (#46)
sklarsa 55d78d9
address some pr comments around lifecycle
sklarsa 03b3329
chore(test): move test utils into an internal package
sklarsa 1b7eff2
add license to new files
sklarsa 14dda3f
fix error wrapping
sklarsa 0486e47
Merge branch 'steve/move-test-clients' into steve/pooled-senders
sklarsa da7e244
godocs
sklarsa 2e10c4c
adds sender tests
sklarsa 14c94a6
fix assertions
sklarsa f80d111
another try
sklarsa 2421757
Revert "chore(test): move test utils into an internal package"
sklarsa 660f91e
move everything into 1 package
sklarsa e956e1a
exit test reader goroutines
sklarsa f7bd180
Apply suggestions from code review
sklarsa b28d3d4
a few more suggestions
sklarsa ebe9478
Merge branch 'main' into steve/pooled-senders
sklarsa d3a4164
Remove extra new lines
puzpuzpuz 8f70e34
return error with tcp connection
sklarsa 283fbe2
Minor tweaks
puzpuzpuz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,179 @@ | ||
| /******************************************************************************* | ||
| * ___ _ ____ ____ | ||
| * / _ \ _ _ ___ ___| |_| _ \| __ ) | ||
| * | | | | | | |/ _ \/ __| __| | | | _ \ | ||
| * | |_| | |_| | __/\__ \ |_| |_| | |_) | | ||
| * \__\_\\__,_|\___||___/\__|____/|____/ | ||
| * | ||
| * Copyright (c) 2014-2019 Appsicle | ||
| * Copyright (c) 2019-2022 QuestDB | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| * | ||
| ******************************************************************************/ | ||
|
|
||
| package questdb | ||
|
|
||
| import ( | ||
| "context" | ||
| "errors" | ||
| "fmt" | ||
| "strings" | ||
| "sync" | ||
| ) | ||
|
|
||
| // LineSenderPool wraps a mutex-protected slice of [LineSender]. It allows a goroutine to | ||
sklarsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // Acquire a sender from the pool and Release it back to the pool when it's done being used. | ||
| // | ||
| // WARNING: This is an experimental API that is designed to work with HTTP senders ONLY. | ||
| type LineSenderPool struct { | ||
| maxSenders int | ||
| conf string | ||
|
|
||
| closed bool | ||
|
|
||
| senders []LineSender | ||
| mu *sync.Mutex | ||
| } | ||
|
|
||
| // LineSenderPoolOption defines line sender pool config option. | ||
| type LineSenderPoolOption func(*LineSenderPool) | ||
|
|
||
| // PoolFromConf instantiates a new LineSenderPool with a QuestDB configuration string. | ||
| // Any sender acquired from this pool will be initialized with the same configuration | ||
| // string that was passed into the conf argument. | ||
| // | ||
| // The default maximum number of senders is 64, but can be customized by using the | ||
| // [WithMaxSenders] option. | ||
| func PoolFromConf(conf string, opts ...LineSenderPoolOption) (*LineSenderPool, error) { | ||
| if strings.HasPrefix(conf, "tcp") { | ||
| return nil, errors.New("tcp/s not supported for pooled senders, use http/s only") | ||
| } | ||
|
|
||
| pool := &LineSenderPool{ | ||
| maxSenders: 64, | ||
| conf: conf, | ||
| senders: []LineSender{}, | ||
| mu: &sync.Mutex{}, | ||
| } | ||
|
|
||
| for _, opt := range opts { | ||
| opt(pool) | ||
| } | ||
|
|
||
| return pool, nil | ||
| } | ||
|
|
||
| // WithMaxSenders sets the maximum number of senders in the pool. | ||
| // The default maximum number of senders is 64. | ||
| func WithMaxSenders(count int) LineSenderPoolOption { | ||
| return func(lsp *LineSenderPool) { | ||
| lsp.maxSenders = count | ||
| } | ||
| } | ||
|
|
||
| // Acquire obtains a LineSender from the pool. If the pool is empty, a new | ||
| // LineSender will be instantiated using the pool's config string. | ||
| func (p *LineSenderPool) Acquire(ctx context.Context) (LineSender, error) { | ||
| p.mu.Lock() | ||
| defer p.mu.Unlock() | ||
|
|
||
| if p.closed { | ||
| return nil, fmt.Errorf("cannot Acquire a LineSender from a closed LineSenderPool") | ||
| } | ||
|
|
||
| if len(p.senders) > 0 { | ||
| // Pop sender off the slice and return it | ||
| s := p.senders[len(p.senders)-1] | ||
| p.senders = p.senders[0 : len(p.senders)-1] | ||
| return s, nil | ||
| } | ||
|
|
||
| return LineSenderFromConf(ctx, p.conf) | ||
| } | ||
|
|
||
| // Release flushes the LineSender and returns it back to the pool. If the pool | ||
| // is full, the sender is closed and discarded. In cases where the sender's | ||
| // flush fails, it is not added back to the pool. | ||
| func (p *LineSenderPool) Release(ctx context.Context, s LineSender) error { | ||
| // If there is an error on flush, do not add the sender back to the pool | ||
| if err := s.Flush(ctx); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| p.mu.Lock() | ||
| defer p.mu.Unlock() | ||
|
|
||
| for i := range p.senders { | ||
| if p.senders[i] == s { | ||
| return fmt.Errorf("LineSender %p has already been released back to the pool", s) | ||
| } | ||
| } | ||
|
|
||
| if p.closed || len(p.senders) >= p.maxSenders { | ||
| return s.Close(ctx) | ||
| } | ||
|
|
||
| p.senders = append(p.senders, s) | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // Close sets the pool's status to "closed" and closes all cached LineSenders. | ||
sklarsa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // When LineSenders are released back into a closed pool, they will be closed and discarded. | ||
| func (p *LineSenderPool) Close(ctx context.Context) error { | ||
| p.mu.Lock() | ||
| defer p.mu.Unlock() | ||
|
|
||
| p.closed = true | ||
|
|
||
| var senderErrors []error | ||
|
|
||
| for _, s := range p.senders { | ||
| senderErr := s.Close(ctx) | ||
| if senderErr != nil { | ||
| senderErrors = append(senderErrors, senderErr) | ||
|
|
||
| } | ||
| } | ||
|
|
||
| if len(senderErrors) == 0 { | ||
| return nil | ||
| } | ||
|
|
||
| err := fmt.Errorf("error closing one or more LineSenders in the pool") | ||
| for _, senderErr := range senderErrors { | ||
| err = fmt.Errorf("%s %w", err, senderErr) | ||
| } | ||
|
|
||
| return err | ||
| } | ||
|
|
||
| // IsClosed will return true if the pool is closed. Once a pool is closed, | ||
| // you will not be able to Acquire any new LineSenders from it. When | ||
| // LineSenders are released back into a closed pool, they will be closed and | ||
| // discarded. | ||
| func (p *LineSenderPool) IsClosed() bool { | ||
| p.mu.Lock() | ||
| defer p.mu.Unlock() | ||
|
|
||
| return p.closed | ||
| } | ||
|
|
||
| // Len returns the numbers of cached LineSenders in the pool. | ||
| func (p *LineSenderPool) Len() int { | ||
| p.mu.Lock() | ||
| defer p.mu.Unlock() | ||
|
|
||
| return len(p.senders) | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.