-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
xds: add ConfigSelector to support RouteAction timeouts (#3991)
- Loading branch information
Showing
11 changed files
with
774 additions
and
96 deletions.
There are no files selected for viewing
This file contains 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 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,114 @@ | ||
/* | ||
* | ||
* Copyright 2017 gRPC authors. | ||
* | ||
* 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. | ||
* | ||
*/ | ||
|
||
// Benchmark options for safe config selector type. | ||
|
||
package primitives_test | ||
|
||
import ( | ||
"sync" | ||
"sync/atomic" | ||
"testing" | ||
"time" | ||
"unsafe" | ||
) | ||
|
||
type safeUpdaterAtomicAndCounter struct { | ||
ptr unsafe.Pointer // *countingFunc | ||
} | ||
|
||
type countingFunc struct { | ||
mu sync.RWMutex | ||
f func() | ||
} | ||
|
||
func (s *safeUpdaterAtomicAndCounter) call() { | ||
cfPtr := atomic.LoadPointer(&s.ptr) | ||
var cf *countingFunc | ||
for { | ||
cf = (*countingFunc)(cfPtr) | ||
cf.mu.RLock() | ||
cfPtr2 := atomic.LoadPointer(&s.ptr) | ||
if cfPtr == cfPtr2 { | ||
// Use cf with confidence! | ||
break | ||
} | ||
// cf changed; try to use the new one instead, because the old one is | ||
// no longer valid to use. | ||
cf.mu.RUnlock() | ||
cfPtr = cfPtr2 | ||
} | ||
defer cf.mu.RUnlock() | ||
cf.f() | ||
} | ||
|
||
func (s *safeUpdaterAtomicAndCounter) update(f func()) { | ||
newCF := &countingFunc{f: f} | ||
oldCFPtr := atomic.SwapPointer(&s.ptr, unsafe.Pointer(newCF)) | ||
if oldCFPtr == nil { | ||
return | ||
} | ||
(*countingFunc)(oldCFPtr).mu.Lock() | ||
(*countingFunc)(oldCFPtr).mu.Unlock() //lint:ignore SA2001 necessary to unlock after locking to unblock any RLocks | ||
} | ||
|
||
type safeUpdaterRWMutex struct { | ||
mu sync.RWMutex | ||
f func() | ||
} | ||
|
||
func (s *safeUpdaterRWMutex) call() { | ||
s.mu.RLock() | ||
defer s.mu.RUnlock() | ||
s.f() | ||
} | ||
|
||
func (s *safeUpdaterRWMutex) update(f func()) { | ||
s.mu.Lock() | ||
defer s.mu.Unlock() | ||
s.f = f | ||
} | ||
|
||
type updater interface { | ||
call() | ||
update(f func()) | ||
} | ||
|
||
func benchmarkSafeUpdater(b *testing.B, u updater) { | ||
t := time.NewTicker(time.Second) | ||
go func() { | ||
for range t.C { | ||
u.update(func() {}) | ||
} | ||
}() | ||
b.RunParallel(func(pb *testing.PB) { | ||
u.update(func() {}) | ||
for pb.Next() { | ||
u.call() | ||
} | ||
}) | ||
t.Stop() | ||
} | ||
|
||
func BenchmarkSafeUpdaterAtomicAndCounter(b *testing.B) { | ||
benchmarkSafeUpdater(b, &safeUpdaterAtomicAndCounter{}) | ||
} | ||
|
||
func BenchmarkSafeUpdaterRWMutex(b *testing.B) { | ||
benchmarkSafeUpdater(b, &safeUpdaterRWMutex{}) | ||
} |
This file contains 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 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,93 @@ | ||
/* | ||
* | ||
* Copyright 2020 gRPC authors. | ||
* | ||
* 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 resolver provides internal resolver-related functionality. | ||
package resolver | ||
|
||
import ( | ||
"context" | ||
"sync" | ||
|
||
"google.golang.org/grpc/internal/serviceconfig" | ||
"google.golang.org/grpc/resolver" | ||
) | ||
|
||
// ConfigSelector controls what configuration to use for every RPC. | ||
type ConfigSelector interface { | ||
// Selects the configuration for the RPC. | ||
SelectConfig(RPCInfo) *RPCConfig | ||
} | ||
|
||
// RPCInfo contains RPC information needed by a ConfigSelector. | ||
type RPCInfo struct { | ||
// Context is the user's context for the RPC and contains headers and | ||
// application timeout. It is passed for interception purposes and for | ||
// efficiency reasons. SelectConfig should not be blocking. | ||
Context context.Context | ||
Method string // i.e. "/Service/Method" | ||
} | ||
|
||
// RPCConfig describes the configuration to use for each RPC. | ||
type RPCConfig struct { | ||
// The context to use for the remainder of the RPC; can pass info to LB | ||
// policy or affect timeout or metadata. | ||
Context context.Context | ||
MethodConfig serviceconfig.MethodConfig // configuration to use for this RPC | ||
OnCommitted func() // Called when the RPC has been committed (retries no longer possible) | ||
} | ||
|
||
type csKeyType string | ||
|
||
const csKey = csKeyType("grpc.internal.resolver.configSelector") | ||
|
||
// SetConfigSelector sets the config selector in state and returns the new | ||
// state. | ||
func SetConfigSelector(state resolver.State, cs ConfigSelector) resolver.State { | ||
state.Attributes = state.Attributes.WithValues(csKey, cs) | ||
return state | ||
} | ||
|
||
// GetConfigSelector retrieves the config selector from state, if present, and | ||
// returns it or nil if absent. | ||
func GetConfigSelector(state resolver.State) ConfigSelector { | ||
cs, _ := state.Attributes.Value(csKey).(ConfigSelector) | ||
return cs | ||
} | ||
|
||
// SafeConfigSelector allows for safe switching of ConfigSelector | ||
// implementations such that previous values are guaranteed to not be in use | ||
// when UpdateConfigSelector returns. | ||
type SafeConfigSelector struct { | ||
mu sync.RWMutex | ||
cs ConfigSelector | ||
} | ||
|
||
// UpdateConfigSelector swaps to the provided ConfigSelector and blocks until | ||
// all uses of the previous ConfigSelector have completed. | ||
func (scs *SafeConfigSelector) UpdateConfigSelector(cs ConfigSelector) { | ||
scs.mu.Lock() | ||
defer scs.mu.Unlock() | ||
scs.cs = cs | ||
} | ||
|
||
// SelectConfig defers to the current ConfigSelector in scs. | ||
func (scs *SafeConfigSelector) SelectConfig(r RPCInfo) *RPCConfig { | ||
scs.mu.RLock() | ||
defer scs.mu.RUnlock() | ||
return scs.cs.SelectConfig(r) | ||
} |
Oops, something went wrong.