Optimize random string generator to avoid multiple locks & use bitmasking

This commit is contained in:
Shyam Jeedigunta 2017-10-12 13:40:00 +02:00
parent 0564d52985
commit c279a53ca0
2 changed files with 41 additions and 16 deletions

View File

@ -73,7 +73,7 @@ func tokenSecretReferences() []v1.ObjectReference {
// addTokenSecretReference adds a reference to the ServiceAccountToken that will be created // addTokenSecretReference adds a reference to the ServiceAccountToken that will be created
func addTokenSecretReference(refs []v1.ObjectReference) []v1.ObjectReference { func addTokenSecretReference(refs []v1.ObjectReference) []v1.ObjectReference {
return addNamedTokenSecretReference(refs, "default-token-stdpg") return addNamedTokenSecretReference(refs, "default-token-xn8fg")
} }
// addNamedTokenSecretReference adds a reference to the named ServiceAccountToken // addNamedTokenSecretReference adds a reference to the named ServiceAccountToken
@ -118,9 +118,9 @@ func opaqueSecret() *v1.Secret {
} }
// createdTokenSecret returns the ServiceAccountToken secret posted when creating a new token secret. // createdTokenSecret returns the ServiceAccountToken secret posted when creating a new token secret.
// Named "default-token-stdpg", since that is the first generated name after rand.Seed(1) // Named "default-token-xn8fg", since that is the first generated name after rand.Seed(1)
func createdTokenSecret(overrideName ...string) *v1.Secret { func createdTokenSecret(overrideName ...string) *v1.Secret {
return namedCreatedTokenSecret("default-token-stdpg") return namedCreatedTokenSecret("default-token-xn8fg")
} }
// namedTokenSecret returns the ServiceAccountToken secret posted when creating a new token secret with the given name. // namedTokenSecret returns the ServiceAccountToken secret posted when creating a new token secret with the given name.
@ -264,12 +264,12 @@ func TestTokenCreation(t *testing.T) {
// Attempt 2 // Attempt 2
core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, metav1.NamespaceDefault, "default"), core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, metav1.NamespaceDefault, "default"),
core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, metav1.NamespaceDefault, namedCreatedTokenSecret("default-token-jk9rt")), core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, metav1.NamespaceDefault, namedCreatedTokenSecret("default-token-txhzt")),
// Attempt 3 // Attempt 3
core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, metav1.NamespaceDefault, "default"), core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, metav1.NamespaceDefault, "default"),
core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, metav1.NamespaceDefault, namedCreatedTokenSecret("default-token-684pg")), core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, metav1.NamespaceDefault, namedCreatedTokenSecret("default-token-vnmz7")),
core.NewUpdateAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, metav1.NamespaceDefault, serviceAccount(addNamedTokenSecretReference(emptySecretReferences(), "default-token-684pg"))), core.NewUpdateAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, metav1.NamespaceDefault, serviceAccount(addNamedTokenSecretReference(emptySecretReferences(), "default-token-vnmz7"))),
}, },
}, },
"new serviceaccount with no secrets encountering unending create error": { "new serviceaccount with no secrets encountering unending create error": {
@ -293,10 +293,10 @@ func TestTokenCreation(t *testing.T) {
core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, metav1.NamespaceDefault, createdTokenSecret()), core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, metav1.NamespaceDefault, createdTokenSecret()),
// Retry 1 // Retry 1
core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, metav1.NamespaceDefault, "default"), core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, metav1.NamespaceDefault, "default"),
core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, metav1.NamespaceDefault, namedCreatedTokenSecret("default-token-jk9rt")), core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, metav1.NamespaceDefault, namedCreatedTokenSecret("default-token-txhzt")),
// Retry 2 // Retry 2
core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, metav1.NamespaceDefault, "default"), core.NewGetAction(schema.GroupVersionResource{Version: "v1", Resource: "serviceaccounts"}, metav1.NamespaceDefault, "default"),
core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, metav1.NamespaceDefault, namedCreatedTokenSecret("default-token-684pg")), core.NewCreateAction(schema.GroupVersionResource{Version: "v1", Resource: "secrets"}, metav1.NamespaceDefault, namedCreatedTokenSecret("default-token-vnmz7")),
}, },
}, },
"new serviceaccount with missing secrets": { "new serviceaccount with missing secrets": {

View File

@ -70,16 +70,41 @@ func Perm(n int) []int {
return rng.rand.Perm(n) return rng.rand.Perm(n)
} }
// We omit vowels from the set of available characters to reduce the chances const (
// of "bad words" being formed. // We omit vowels from the set of available characters to reduce the chances
var alphanums = []rune("bcdfghjklmnpqrstvwxz2456789") // of "bad words" being formed.
alphanums = "bcdfghjklmnpqrstvwxz2456789"
// No. of bits required to index into alphanums string.
alphanumsIdxBits = 5
// Mask used to extract last alphanumsIdxBits of an int.
alphanumsIdxMask = 1<<alphanumsIdxBits - 1
// No. of random letters we can extract from a single int63.
maxAlphanumsPerInt = 63 / alphanumsIdxBits
)
// String generates a random alphanumeric string, without vowels, which is n // String generates a random alphanumeric string, without vowels, which is n
// characters long. This will panic if n is less than zero. // characters long. This will panic if n is less than zero.
func String(length int) string { // How the random string is created:
b := make([]rune, length) // - we generate random int63's
for i := range b { // - from each int63, we are extracting multiple random letters by bit-shifting and masking
b[i] = alphanums[Intn(len(alphanums))] // - if some index is out of range of alphanums we neglect it (unlikely to happen multiple times in a row)
func String(n int) string {
b := make([]byte, n)
rng.Lock()
defer rng.Unlock()
randomInt63 := rng.rand.Int63()
remaining := maxAlphanumsPerInt
for i := 0; i < n; {
if remaining == 0 {
randomInt63, remaining = rng.rand.Int63(), maxAlphanumsPerInt
}
if idx := int(randomInt63 & alphanumsIdxMask); idx < len(alphanums) {
b[i] = alphanums[idx]
i++
}
randomInt63 >>= alphanumsIdxBits
remaining--
} }
return string(b) return string(b)
} }
@ -87,7 +112,7 @@ func String(length int) string {
// SafeEncodeString encodes s using the same characters as rand.String. This reduces the chances of bad words and // SafeEncodeString encodes s using the same characters as rand.String. This reduces the chances of bad words and
// ensures that strings generated from hash functions appear consistent throughout the API. // ensures that strings generated from hash functions appear consistent throughout the API.
func SafeEncodeString(s string) string { func SafeEncodeString(s string) string {
r := make([]rune, len(s)) r := make([]byte, len(s))
for i, b := range []rune(s) { for i, b := range []rune(s) {
r[i] = alphanums[(int(b) % len(alphanums))] r[i] = alphanums[(int(b) % len(alphanums))]
} }