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

     1  package hammy
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"bytes"
     7  	"github.com/couchbaselabs/go-couchbase"
     8  	"github.com/ugorji/go-msgpack"
     9  	"github.com/dustin/gomemcached"
    10  )
    11  
    12  // Reads data from write cache (couchbase-based)
    13  type CouchbaseDataReader struct {
    14  	client *couchbase.Client
    15  	pool *couchbase.Pool
    16  	bucket *couchbase.Bucket
    17  }
    18  
    19  // Create new saver
    20  func NewCouchbaseDataReader(cfg Config) (*CouchbaseDataReader, error) {
    21  	s := new(CouchbaseDataReader)
    22  
    23  	c, err := couchbase.Connect(cfg.CouchbaseDataReader.ConnectTo)
    24  	if err != nil {
    25  		return nil, err
    26  	}
    27  	s.client = &c
    28  
    29  	p, err := s.client.GetPool(cfg.CouchbaseDataReader.Pool)
    30  	if err != nil {
    31  		return nil, err
    32  	}
    33  	s.pool = &p
    34  
    35  	b, err := s.pool.GetBucket(cfg.CouchbaseDataReader.Bucket)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  	s.bucket = b
    40  
    41  	return s, nil
    42  }
    43  
    44  func (cr *CouchbaseDataReader) Read(hostKey string, itemKey string, from uint64, to uint64) (data []IncomingValueData, err error) {
    45  	// Construct keys slice
    46  	bucketFrom, bucketTo := (from / CouchbaseDataBucketQuantum), (to / CouchbaseDataBucketQuantum)
    47  	keys := make([]string, (bucketTo - bucketFrom + 1))
    48  	for i, k := 0, bucketFrom; k <= bucketTo; k++ {
    49  		keys[i] = fmt.Sprintf("%s$%s$%d", hostKey, itemKey, k)
    50  		i++
    51  	}
    52  
    53  	// Retrive data
    54  	ans := cr.bucket.GetBulk(keys)
    55  	dataLen := 0
    56  
    57  	for _, r := range ans {
    58  		switch r.Status {
    59  			case gomemcached.SUCCESS:
    60  				dataLen += len(r.Body)
    61  			case gomemcached.KEY_ENOENT:
    62  				// nil
    63  			default:
    64  				err = fmt.Errorf("GetBult error: %s", r.Error())
    65  				return
    66  		}
    67  	}
    68  
    69  	if dataLen == 0 {
    70  		data = make([]IncomingValueData, 0)
    71  		return
    72  	}
    73  
    74  	dataRaw := make([]byte, dataLen)
    75  	j := 0
    76  	for _, r := range ans {
    77  		if r.Status == gomemcached.SUCCESS {
    78  			for i := 0; i < len(r.Body); i++ {
    79  				dataRaw[j] = r.Body[i]
    80  				j++
    81  				if j > dataLen {
    82  					panic("Invalid j")
    83  				}
    84  			}
    85  		}
    86  	}
    87  
    88  	data = make([]IncomingValueData, 0)
    89  	dataRawBuffer := bytes.NewBuffer(dataRaw)
    90  	dec := msgpack.NewDecoder(dataRawBuffer, nil)
    91  	for {
    92  		var val IncomingValueData
    93  		err = dec.Decode(&val)
    94  		if err != nil {
    95  			if err.Error() == "EOF" {
    96  				err = nil
    97  				break
    98  			} else {
    99  				//err = fmt.Errorf("Unmarshal error: %#v (data: %#v)", err, dataRaw)
   100  				err = fmt.Errorf("Unmarshal error: %v", err)
   101  				return
   102  			}
   103  		}
   104  
   105  		data = append(data, val)
   106  	}
   107  
   108  	ds := DataTimeSorter{
   109  		Data: &data,
   110  	}
   111  	sort.Sort(&ds)
   112  
   113  	// TODO: remove "bad" values
   114  
   115  	return
   116  }