coredns plugin -- Final fix for deadlock during coredns reload
This commit is contained in:
parent
3109529dbb
commit
763dcc46e9
|
@ -25,7 +25,8 @@ type hourTop struct {
|
||||||
domains gcache.Cache
|
domains gcache.Cache
|
||||||
blocked gcache.Cache
|
blocked gcache.Cache
|
||||||
clients gcache.Cache
|
clients gcache.Cache
|
||||||
sync.RWMutex
|
|
||||||
|
mutex sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (top *hourTop) init() {
|
func (top *hourTop) init() {
|
||||||
|
@ -36,30 +37,32 @@ func (top *hourTop) init() {
|
||||||
|
|
||||||
type dayTop struct {
|
type dayTop struct {
|
||||||
hours []*hourTop
|
hours []*hourTop
|
||||||
|
hoursLock sync.RWMutex // writelock this lock ONLY WHEN rotating or intializing hours!
|
||||||
|
|
||||||
loaded bool
|
loaded bool
|
||||||
sync.RWMutex // write -- rotating hourTop, read -- anything else
|
loadedLock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
var runningTop dayTop
|
var runningTop dayTop
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
runningTop.Lock()
|
runningTop.hoursWriteLock()
|
||||||
for i := 0; i < 24; i++ {
|
for i := 0; i < 24; i++ {
|
||||||
hour := hourTop{}
|
hour := hourTop{}
|
||||||
hour.init()
|
hour.init()
|
||||||
runningTop.hours = append(runningTop.hours, &hour)
|
runningTop.hours = append(runningTop.hours, &hour)
|
||||||
}
|
}
|
||||||
runningTop.Unlock()
|
runningTop.hoursWriteUnlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func rotateHourlyTop() {
|
func rotateHourlyTop() {
|
||||||
log.Printf("Rotating hourly top")
|
log.Printf("Rotating hourly top")
|
||||||
hour := &hourTop{}
|
hour := &hourTop{}
|
||||||
hour.init()
|
hour.init()
|
||||||
runningTop.Lock()
|
runningTop.hoursWriteLock()
|
||||||
runningTop.hours = append([]*hourTop{hour}, runningTop.hours...)
|
runningTop.hours = append([]*hourTop{hour}, runningTop.hours...)
|
||||||
runningTop.hours = runningTop.hours[:24]
|
runningTop.hours = runningTop.hours[:24]
|
||||||
runningTop.Unlock()
|
runningTop.hoursWriteUnlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func periodicHourlyTopRotate() {
|
func periodicHourlyTopRotate() {
|
||||||
|
@ -180,8 +183,8 @@ func (r *dayTop) addEntry(entry *logEntry, now time.Time) error {
|
||||||
hostname := strings.ToLower(strings.TrimSuffix(q.Question[0].Name, "."))
|
hostname := strings.ToLower(strings.TrimSuffix(q.Question[0].Name, "."))
|
||||||
|
|
||||||
// get value, if not set, crate one
|
// get value, if not set, crate one
|
||||||
runningTop.RLock()
|
runningTop.hoursReadLock()
|
||||||
defer runningTop.RUnlock()
|
defer runningTop.hoursReadUnlock()
|
||||||
err := runningTop.hours[hour].incrementDomains(hostname)
|
err := runningTop.hours[hour].incrementDomains(hostname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to increment value: %s", err)
|
log.Printf("Failed to increment value: %s", err)
|
||||||
|
@ -209,8 +212,8 @@ func (r *dayTop) addEntry(entry *logEntry, now time.Time) error {
|
||||||
|
|
||||||
func loadTopFromFiles() error {
|
func loadTopFromFiles() error {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
runningTop.Lock() // not rlock because we set it at the end of the function
|
runningTop.loadedWriteLock()
|
||||||
defer runningTop.Unlock()
|
defer runningTop.loadedWriteUnlock()
|
||||||
if runningTop.loaded {
|
if runningTop.loaded {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -255,7 +258,7 @@ func handleStatsTop(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
runningTop.RLock()
|
runningTop.hoursReadLock()
|
||||||
for hour := 0; hour < 24; hour++ {
|
for hour := 0; hour < 24; hour++ {
|
||||||
runningTop.hours[hour].RLock()
|
runningTop.hours[hour].RLock()
|
||||||
do(runningTop.hours[hour].domains.Keys(), runningTop.hours[hour].lockedGetDomains, domains)
|
do(runningTop.hours[hour].domains.Keys(), runningTop.hours[hour].lockedGetDomains, domains)
|
||||||
|
@ -263,7 +266,7 @@ func handleStatsTop(w http.ResponseWriter, r *http.Request) {
|
||||||
do(runningTop.hours[hour].clients.Keys(), runningTop.hours[hour].lockedGetClients, clients)
|
do(runningTop.hours[hour].clients.Keys(), runningTop.hours[hour].lockedGetClients, clients)
|
||||||
runningTop.hours[hour].RUnlock()
|
runningTop.hours[hour].RUnlock()
|
||||||
}
|
}
|
||||||
runningTop.RUnlock()
|
runningTop.hoursReadUnlock()
|
||||||
|
|
||||||
// use manual json marshalling because we want maps to be sorted by value
|
// use manual json marshalling because we want maps to be sorted by value
|
||||||
json := bytes.Buffer{}
|
json := bytes.Buffer{}
|
||||||
|
@ -329,3 +332,28 @@ func sortByValue(m map[string]int) []string {
|
||||||
}
|
}
|
||||||
return sorted
|
return sorted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *dayTop) hoursWriteLock() { tracelock(); d.hoursLock.Lock() }
|
||||||
|
func (d *dayTop) hoursWriteUnlock() { tracelock(); d.hoursLock.Unlock() }
|
||||||
|
func (d *dayTop) hoursReadLock() { tracelock(); d.hoursLock.RLock() }
|
||||||
|
func (d *dayTop) hoursReadUnlock() { tracelock(); d.hoursLock.RUnlock() }
|
||||||
|
func (d *dayTop) loadedWriteLock() { tracelock(); d.loadedLock.Lock() }
|
||||||
|
func (d *dayTop) loadedWriteUnlock() { tracelock(); d.loadedLock.Unlock() }
|
||||||
|
|
||||||
|
// func (d *dayTop) loadedReadLock() { tracelock(); d.loadedLock.RLock() }
|
||||||
|
// func (d *dayTop) loadedReadUnlock() { tracelock(); d.loadedLock.RUnlock() }
|
||||||
|
|
||||||
|
func (h *hourTop) Lock() { tracelock(); h.mutex.Lock() }
|
||||||
|
func (h *hourTop) RLock() { tracelock(); h.mutex.RLock() }
|
||||||
|
func (h *hourTop) RUnlock() { tracelock(); h.mutex.RUnlock() }
|
||||||
|
func (h *hourTop) Unlock() { tracelock(); h.mutex.Unlock() }
|
||||||
|
|
||||||
|
func tracelock() {
|
||||||
|
/*
|
||||||
|
pc := make([]uintptr, 10) // at least 1 entry needed
|
||||||
|
runtime.Callers(2, pc)
|
||||||
|
f := path.Base(runtime.FuncForPC(pc[1]).Name())
|
||||||
|
lockf := path.Base(runtime.FuncForPC(pc[0]).Name())
|
||||||
|
fmt.Fprintf(os.Stderr, "%s(): %s\n", f, lockf)
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue