mirror of https://github.com/prometheus/prometheus
Julien Pivotto
4 years ago
committed by
GitHub
8 changed files with 141 additions and 15 deletions
@ -0,0 +1,91 @@
|
||||
// Copyright 2021 The Prometheus Authors
|
||||
// This code is partly borrowed from Caddy:
|
||||
// Copyright 2015 Matthew Holt and The Caddy 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 web |
||||
|
||||
import ( |
||||
weakrand "math/rand" |
||||
"sync" |
||||
"time" |
||||
) |
||||
|
||||
var cacheSize = 100 |
||||
|
||||
func init() { |
||||
weakrand.Seed(time.Now().UnixNano()) |
||||
} |
||||
|
||||
type cache struct { |
||||
cache map[string]bool |
||||
mtx sync.Mutex |
||||
} |
||||
|
||||
// newCache returns a cache that contains a mapping of plaintext passwords
|
||||
// to their hashes (with random eviction). This can greatly improve the
|
||||
// performance of traffic-heavy servers that use secure password hashing
|
||||
// algorithms, with the downside that plaintext passwords will be stored in
|
||||
// memory for a longer time (this should not be a problem as long as your
|
||||
// machine is not compromised, at which point all bets are off, since basicauth
|
||||
// necessitates plaintext passwords being received over the wire anyway).
|
||||
func newCache() *cache { |
||||
return &cache{ |
||||
cache: make(map[string]bool), |
||||
} |
||||
} |
||||
|
||||
func (c *cache) get(key string) (bool, bool) { |
||||
c.mtx.Lock() |
||||
defer c.mtx.Unlock() |
||||
v, ok := c.cache[key] |
||||
return v, ok |
||||
} |
||||
|
||||
func (c *cache) set(key string, value bool) { |
||||
c.mtx.Lock() |
||||
defer c.mtx.Unlock() |
||||
c.makeRoom() |
||||
c.cache[key] = value |
||||
} |
||||
|
||||
func (c *cache) makeRoom() { |
||||
if len(c.cache) < cacheSize { |
||||
return |
||||
} |
||||
// We delete more than just 1 entry so that we don't have
|
||||
// to do this on every request; assuming the capacity of
|
||||
// the cache is on a long tail, we can save a lot of CPU
|
||||
// time by doing a whole bunch of deletions now and then
|
||||
// we won't have to do them again for a while.
|
||||
numToDelete := len(c.cache) / 10 |
||||
if numToDelete < 1 { |
||||
numToDelete = 1 |
||||
} |
||||
for deleted := 0; deleted <= numToDelete; deleted++ { |
||||
// Go maps are "nondeterministic" not actually random,
|
||||
// so although we could just chop off the "front" of the
|
||||
// map with less code, this is a heavily skewed eviction
|
||||
// strategy; generating random numbers is cheap and
|
||||
// ensures a much better distribution.
|
||||
rnd := weakrand.Intn(len(c.cache)) |
||||
i := 0 |
||||
for key := range c.cache { |
||||
if i == rnd { |
||||
delete(c.cache, key) |
||||
break |
||||
} |
||||
i++ |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue