119 lines
2.8 KiB
Go
119 lines
2.8 KiB
Go
|
// Licensed to Elasticsearch B.V. under one or more contributor
|
||
|
// license agreements. See the NOTICE file distributed with
|
||
|
// this work for additional information regarding copyright
|
||
|
// ownership. Elasticsearch B.V. licenses this file to you 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 harvester
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"sync"
|
||
|
|
||
|
"github.com/gofrs/uuid"
|
||
|
|
||
|
"github.com/elastic/beats/libbeat/logp"
|
||
|
)
|
||
|
|
||
|
// Registry struct manages (start / stop) a list of harvesters
|
||
|
type Registry struct {
|
||
|
sync.RWMutex
|
||
|
harvesters map[uuid.UUID]Harvester
|
||
|
wg sync.WaitGroup
|
||
|
done chan struct{}
|
||
|
}
|
||
|
|
||
|
// NewRegistry creates a new registry object
|
||
|
func NewRegistry() *Registry {
|
||
|
return &Registry{
|
||
|
harvesters: map[uuid.UUID]Harvester{},
|
||
|
done: make(chan struct{}),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (r *Registry) remove(h Harvester) {
|
||
|
r.Lock()
|
||
|
defer r.Unlock()
|
||
|
delete(r.harvesters, h.ID())
|
||
|
}
|
||
|
|
||
|
// Stop stops all harvesters in the registry
|
||
|
func (r *Registry) Stop() {
|
||
|
r.Lock()
|
||
|
defer func() {
|
||
|
r.Unlock()
|
||
|
r.WaitForCompletion()
|
||
|
}()
|
||
|
// Makes sure no new harvesters are added during stopping
|
||
|
close(r.done)
|
||
|
|
||
|
for _, hv := range r.harvesters {
|
||
|
go func(h Harvester) {
|
||
|
h.Stop()
|
||
|
}(hv)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// WaitForCompletion can be used to wait until all harvesters are stopped
|
||
|
func (r *Registry) WaitForCompletion() {
|
||
|
r.wg.Wait()
|
||
|
}
|
||
|
|
||
|
// Start starts the given harvester and add its to the registry
|
||
|
func (r *Registry) Start(h Harvester) error {
|
||
|
// Make sure stop is not called during starting a harvester
|
||
|
r.Lock()
|
||
|
defer r.Unlock()
|
||
|
|
||
|
// Make sure no new harvesters are started after stop was called
|
||
|
if !r.active() {
|
||
|
return errors.New("registry already stopped")
|
||
|
}
|
||
|
|
||
|
r.wg.Add(1)
|
||
|
|
||
|
// Add the harvester to the registry and share the lock with stop making sure Start() and Stop()
|
||
|
// have a consistent view of the harvesters.
|
||
|
r.harvesters[h.ID()] = h
|
||
|
|
||
|
go func() {
|
||
|
defer func() {
|
||
|
r.remove(h)
|
||
|
r.wg.Done()
|
||
|
}()
|
||
|
// Starts harvester and picks the right type. In case type is not set, set it to default (log)
|
||
|
err := h.Run()
|
||
|
if err != nil {
|
||
|
logp.Err("Error running input: %v", err)
|
||
|
}
|
||
|
}()
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Len returns the current number of harvesters in the registry
|
||
|
func (r *Registry) Len() uint64 {
|
||
|
r.RLock()
|
||
|
defer r.RUnlock()
|
||
|
return uint64(len(r.harvesters))
|
||
|
}
|
||
|
|
||
|
func (r *Registry) active() bool {
|
||
|
select {
|
||
|
case <-r.done:
|
||
|
return false
|
||
|
default:
|
||
|
return true
|
||
|
}
|
||
|
}
|