Skip to content

Commit

Permalink
improve snmp: cache request to a buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
mei-rune committed Oct 9, 2013
1 parent 31d2589 commit 9f6ce21
Show file tree
Hide file tree
Showing 7 changed files with 453 additions and 277 deletions.
3 changes: 3 additions & 0 deletions bsnmp/config.h
Expand Up @@ -5,7 +5,10 @@

#ifdef _WIN32

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif

#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
Expand Down
19 changes: 13 additions & 6 deletions pdu.go
Expand Up @@ -320,6 +320,15 @@ func (pdu *V3PDU) String() string {
return buffer.String()
}

var (
context_engine_failed = newError(SNMP_CODE_FAILED, nil, "copy context_engine failed")
context_name_failed = newError(SNMP_CODE_FAILED, nil, "copy context_name failed")
engine_id_failed = newError(SNMP_CODE_FAILED, nil, "copy engine_id failed")
security_model_is_nil = newError(SNMP_CODE_FAILED, nil, "security model is nil")
security_model_failed = newError(SNMP_CODE_FAILED, nil, "fill security model failed")
encode_bindings_failed = newError(SNMP_CODE_FAILED, nil, "fill encode bindings failed")
)

func (pdu *V3PDU) encodePDU(bs []byte, is_dump bool) ([]byte, SnmpError) {
var internal C.snmp_pdu_t
C.snmp_pdu_init(&internal)
Expand Down Expand Up @@ -354,20 +363,20 @@ func (pdu *V3PDU) encodePDU(bs []byte, is_dump bool) ([]byte, SnmpError) {
} else {
err := memcpy(&internal.context_engine[0], SNMP_ENGINE_ID_LEN, pdu.contextEngine)
if nil != err {
return nil, newError(SNMP_CODE_FAILED, err, "copy context_engine failed")
return nil, context_engine_failed //newError(SNMP_CODE_FAILED, err, "copy context_engine failed")
}
internal.context_engine_len = C.uint32_t(len(pdu.contextEngine))
}

err := strcpy(&internal.context_name[0], SNMP_CONTEXT_NAME_LEN, pdu.contextName)
if nil != err {
return nil, newError(SNMP_CODE_FAILED, err, "copy context_name failed")
return nil, context_name_failed //newError(SNMP_CODE_FAILED, err, "copy context_name failed")
}

if nil != pdu.engine {
err = memcpy(&internal.engine.engine_id[0], SNMP_ENGINE_ID_LEN, pdu.engine.engine_id)
if nil != err {
return nil, newError(SNMP_CODE_FAILED, err, "copy engine_id failed")
return nil, engine_id_failed //newError(SNMP_CODE_FAILED, err, "copy engine_id failed")
}
internal.engine.engine_len = C.uint32_t(len(pdu.engine.engine_id))
internal.engine.engine_boots = C.int32_t(pdu.engine.engine_boots)
Expand All @@ -381,16 +390,14 @@ func (pdu *V3PDU) encodePDU(bs []byte, is_dump bool) ([]byte, SnmpError) {

internal.security_model = SNMP_SECMODEL_USM
if nil == pdu.securityModel {
return nil, newError(SNMP_CODE_FAILED, nil, "security model is nil")
return nil, security_model_is_nil //newError(SNMP_CODE_FAILED, nil, "security model is nil")
}
err = pdu.securityModel.Write(&internal.user)

if nil != err {
return nil, newError(SNMP_CODE_FAILED, err, "fill security model failed")
}

err = encodeBindings(&internal, pdu.GetVariableBindings())

if nil != err {
return nil, newError(SNMP_CODE_FAILED, err, "fill encode bindings failed")
}
Expand Down
3 changes: 1 addition & 2 deletions pinger.go
Expand Up @@ -10,7 +10,6 @@ package snmpclient
// #include "bsnmp/gobindings.h"
import "C"
import (
"errors"
"fmt"
"net"
"strings"
Expand All @@ -20,7 +19,7 @@ import (
"unsafe"
)

var TimeoutError = errors.New("time out")
var TimeoutError = newError(SNMP_CODE_TIMEOUT, nil, "time out")

type PingResult struct {
Id int
Expand Down
112 changes: 112 additions & 0 deletions request_buffer.go
@@ -0,0 +1,112 @@
package snmpclient

/* Circular buffer object */
type requestBuffer struct {
start int /* index of oldest element */
count int /* the count of elements */
elements []*clientRequest /* vector of elements */
}

func newRequestBuffer(elements []*clientRequest) *requestBuffer {
return &requestBuffer{elements: elements}
}

func (self *requestBuffer) Init(elements []*clientRequest) {
self.elements = elements
self.start = 0
self.count = 0
}

/* clear all elements.*/
func (self *requestBuffer) Clear() {
self.start = 0
self.count = 0
}

func (self *requestBuffer) IsFull() bool {
return self.count == len(self.elements)
}

/* return true while size is 0, otherwise return false */
func (self *requestBuffer) IsEmpty() bool {
return 0 == self.count
}

/* Write an element, overwriting oldest element if buffer is full. App can
choose to avoid the overwrite by checking isFull(). */
func (self *requestBuffer) Push(elem *clientRequest) {
end := (self.start + self.count) % len(self.elements)
self.elements[end] = elem
if self.count == len(self.elements) {
self.start = (self.start + 1) % len(self.elements) /* full, overwrite */
} else {
self.count++
}
}

func (self *requestBuffer) Get(idx int) *clientRequest {
if self.IsEmpty() {
return nil
}

current := (self.start + idx) % len(self.elements)
return self.elements[current]
}

/* Read oldest element. App must ensure !isEmpty() first. */
func (self *requestBuffer) Pop() *clientRequest {
if self.IsEmpty() {
return nil
}

elem := self.elements[self.start]
self.start = (self.start + 1) % len(self.elements)
self.count--
return elem
}

func (self *requestBuffer) First() *clientRequest {
if self.IsEmpty() {
return nil
}

return self.elements[self.start]
}

func (self *requestBuffer) Last() *clientRequest {
if self.IsEmpty() {
return nil
}

end := (self.start + self.count - 1) % len(self.elements)
return self.elements[end]
}

/* Read all elements.*/
func (self *requestBuffer) Size() int {
return self.count
}

/* Read all elements.*/
func (self *requestBuffer) All() []*clientRequest {
if 0 == self.count {
return nil
}

res := make([]*clientRequest, 0, self.count)
if self.count <= (len(self.elements) - self.start) {
for i := self.start; i < (self.start + self.count); i++ {
res = append(res, self.elements[i])
}
return res
}

for i := self.start; i < len(self.elements); i++ {
res = append(res, self.elements[i])
}
for i := 0; len(res) < self.count; i++ {
res = append(res, self.elements[i])
}

return res
}
86 changes: 86 additions & 0 deletions request_buffer_test.go
@@ -0,0 +1,86 @@
package snmpclient

import (
"testing"
"time"
)

func TestRequestBuffer(t *testing.T) {
cb := newRequestBuffer(make([]*clientRequest, 10))

check := func(cb *requestBuffer, c int) {
if c < 10 {
if cb.Size() != (1 + c) {
t.Error("size is error, excepted is", 1+c, ", actual is", cb.Size())
}

all := cb.All()
if len(all) != (1 + c) {
t.Error("len(all) is error, excepted is 10, actual is", cb.Size())
}

for i := 0; i <= c; i++ {
if all[i].timeout != time.Duration(i) {
t.Error("all[", i, "] is error, excepted is ", all[i].timeout, ", actual is", i)
}
}

for i := 0; i <= c; i++ {
if all[i].timeout != cb.Get(i).timeout {
t.Error("all[", i, "] != cb.Get(", i, "), excepted is ", all[i].timeout, ", actual is", cb.Get(i).timeout)
}
}

if time.Duration(c) != cb.Last().timeout {
t.Error("excepted last is", c, ", actual is", cb.Last().timeout)
}

if all[0].timeout != cb.First().timeout {
t.Error("excepted first is", all[0].timeout, ", actual is", cb.First().timeout)
}

} else {
if cb.Size() != 10 {
t.Error("size is error, excepted is 10, actual is", cb.Size())
}

all := cb.All()
if len(all) != 10 {
t.Error("len(all) is error, excepted is 10, actual is", cb.Size())
}

for i := 0; i < 10; i++ {
if all[i].timeout != time.Duration(c-9+i) {
t.Error("all[", i, "] is error, excepted is", all[i].timeout, ", actual is", c-9+i)
}
}

for i := 0; i < 10; i++ {
if all[i].timeout != cb.Get(i).timeout {
t.Error("all[", i, "] != cb.Get(", i, "), excepted is ", all[i].timeout, ", actual is", cb.Get(i).timeout)
}
}

if time.Duration(c) != cb.Last().timeout {
t.Error("excepted last is", c, ", actual is", cb.Last().timeout)
}

if time.Duration(c-9) != cb.First().timeout {
t.Error("excepted first is", c-9, ", actual is", cb.First().timeout)
}

if all[0].timeout != cb.First().timeout {
t.Error("excepted first is", all[0].timeout, ", actual is", cb.First().timeout)
}

if all[len(all)-1].timeout != cb.Last().timeout {
t.Error("excepted first is", all[len(all)-1].timeout, ", actual is", cb.Last().timeout)
}
}
}

for i := 0; i < 100; i++ {
cb.Push(&clientRequest{timeout: time.Duration(i)})
check(cb, i)
}
}

0 comments on commit 9f6ce21

Please sign in to comment.