github.com/orofarne/hammy@v0.0.0-20130409105742-374fadfd6ecb/src/hammy/send_buffer.go (about)

     1  package hammy
     2  
     3  import (
     4  	"log"
     5  	"time"
     6  	"container/list"
     7  	"encoding/json"
     8  )
     9  
    10  // Buffer for reprocessed data
    11  type SendBufferImpl struct {
    12  	dataChan chan *IncomingData
    13  	data *list.List
    14  	// Timeout between sends
    15  	sleepTime time.Duration
    16  	rHandler RequestHandler
    17  
    18  	//Metics
    19  	ms *MetricSet
    20  	mPushes *CounterMetric
    21  	mSendedValues *CounterMetric
    22  	mSend *TimerMetric
    23  	mErrors *CounterMetric
    24  }
    25  
    26  // Creates and initialize new SendBuffer
    27  func NewSendBufferImpl(rh RequestHandler, cfg Config, metricsNamespace string) (sb *SendBufferImpl) {
    28  	sb = new(SendBufferImpl)
    29  	sb.dataChan = make(chan *IncomingData)
    30  	sb.data = list.New()
    31  	sb.sleepTime = time.Duration(1000 * cfg.SendBuffer.SleepTime) * time.Millisecond
    32  	sb.rHandler = rh
    33  
    34  	sb.ms = NewMetricSet(metricsNamespace, 30*time.Second)
    35  	sb.mPushes = sb.ms.NewCounter("pushes")
    36  	sb.mSendedValues = sb.ms.NewCounter("sended_values")
    37  	sb.mSend = sb.ms.NewTimer("send")
    38  	sb.mErrors = sb.ms.NewCounter("errors")
    39  
    40  	return
    41  }
    42  
    43  // Locks and begins data processing
    44  func (sb *SendBufferImpl) Listen() {
    45  	timer := time.Tick(sb.sleepTime)
    46  
    47  	for {
    48  		select {
    49  			case newData := <- sb.dataChan:
    50  				sb.data.PushBack(newData)
    51  			case <- timer:
    52  				go sb.send(sb.data)
    53  				sb.data = list.New()
    54  		}
    55  	}
    56  }
    57  
    58  // Enqueue data for reprocessing
    59  func (sb *SendBufferImpl) Push(data *IncomingData) {
    60  	sb.dataChan <- data
    61  	sb.mPushes.Add(1)
    62  }
    63  
    64  // Process detached data buffer
    65  func (sb *SendBufferImpl) send(data *list.List) {
    66  	if data.Len() == 0 {
    67  		return
    68  	}
    69  
    70  	// Statistics
    71  	τ := sb.mSend.NewObservation()
    72  	defer func() { τ.End() } ()
    73  	var sended_values uint64
    74  
    75  	// 1) Merge list
    76  	mData := make(IncomingData)
    77  	// iterates over data list
    78  	for e := data.Front(); e != nil; e = e.Next() {
    79  		// e.Value is *IncomingData (panic otherwise)
    80  		eData := e.Value.(*IncomingData)
    81  		for hostK, hostV := range *eData {
    82  			mV, hostFound := mData[hostK]
    83  			if hostFound {
    84  				for k, v := range hostV {
    85  					iArr, kFound := mV[k]
    86  					if kFound {
    87  						newIArr := make([]IncomingValueData, len(v) + len(iArr))
    88  						for i, vE := range iArr {
    89  							newIArr[i] = vE
    90  							sended_values++ // Statistics
    91  						}
    92  						for j, vE := range v {
    93  							newIArr[len(iArr) + j] = vE
    94  							sended_values++ // Statistics
    95  						}
    96  						mV[k] = newIArr
    97  					} else {
    98  						mV[k] = v
    99  					}
   100  				}
   101  			} else {
   102  				mData[hostK] = hostV
   103  			}
   104  		}
   105  	}
   106  
   107  	sb.mSendedValues.Add(sended_values) // Statistics
   108  
   109  	// 2) Process merged data
   110  	errs := sb.rHandler.Handle(mData)
   111  
   112  	if len(errs) > 0 {
   113  		sb.mErrors.Add(uint64(len(errs))) // Statistics
   114  
   115  		// FIXME
   116  		errs_str := make(map[string]string)
   117  		for k, v := range errs {
   118  			errs_str[k] = v.Error()
   119  		}
   120  		b, err := json.Marshal(errs_str)
   121  		if err == nil {
   122  			log.Printf("!! Error in SendBuffer: %s", b)
   123  		} else {
   124  			log.Printf("!! Error in SendBuffer: <unable to dump errs: %#v>", err)
   125  		}
   126  	}
   127  }