migrating storage adapters to new structure

This commit is contained in:
Radu Ioan Fericean
2012-02-17 16:36:10 +02:00
parent a37ab4853b
commit 450d2e50a3
9 changed files with 206 additions and 139 deletions

View File

@@ -2,9 +2,6 @@ package main
import (
"flag"
"github.com/simonz05/godis"
"github.com/fsouza/gokabinet/kc"
"launchpad.net/mgo"
"github.com/rif/cgrates/timespans"
"log"
"os"
@@ -45,14 +42,13 @@ func main() {
switch *storage {
case "kyoto":
db, _ := kc.Open(*kyotofile, kc.WRITE)
defer db.Close()
storage, _ := timespans.NewKyotoStorage(*kyotofile)
defer storage.Close()
for _, cd := range callDescriptors{
key := cd.GetKey()
db.Set(key, cd.EncodeValues())
log.Printf("Storing %q", key)
storage.SetActivationPeriods(cd.GetKey(), cd.ActivationPeriods)
log.Printf("Storing %q", cd.GetKey())
}
case "mongo":
/*case "mongo":
session, err := mgo.Dial(*mongoserver)
if err != nil {
panic(err)
@@ -63,17 +59,17 @@ func main() {
c := session.DB(*mongodb).C("ap")
for _, cd := range callDescriptors{
key := cd.GetKey()
c.Insert(&timespans.KeyValue{key, cd.EncodeValues()})
c.Insert(&map[string]string{"_id":key, "value":cd.EncodeValues()})
log.Printf("Storing %q", key)
}
}*/
default:
db := godis.New(*redisserver, *redisdb, *redispass)
defer db.Quit()
storage, _ := timespans.NewKyotoStorage(*redisserver, *redisdb)
defer storage.Close()
for _, cd := range callDescriptors{
key := cd.GetKey()
db.Set(key, cd.EncodeValues())
log.Printf("Storing %q", key)
storage.SetActivationPeriods(cd.GetKey(), cd.ActivationPeriods)
log.Printf("Storing %q", cd.GetKey())
}
}
}

View File

@@ -1,8 +1,6 @@
package timespans
import (
"strconv"
"strings"
"time"
//"log"
)
@@ -23,57 +21,3 @@ func (ap *ActivationPeriod) AddInterval(is ...*Interval) {
ap.Intervals = append(ap.Intervals, i)
}
}
/*
Serializes the objects for the storage.
*/
func (ap *ActivationPeriod) store() (result string) {
result += strconv.FormatInt(ap.ActivationTime.UnixNano(), 10) + ";"
var is string
for _, i := range ap.Intervals {
is = strconv.Itoa(int(i.Month)) + "|"
is += strconv.Itoa(i.MonthDay) + "|"
for _, wd := range i.WeekDays {
is += strconv.Itoa(int(wd)) + ","
}
is = strings.TrimRight(is, ",") + "|"
is += i.StartTime + "|"
is += i.EndTime + "|"
is += strconv.FormatFloat(i.Ponder, 'f', -1, 64) + "|"
is += strconv.FormatFloat(i.ConnectFee, 'f', -1, 64) + "|"
is += strconv.FormatFloat(i.Price, 'f', -1, 64) + "|"
is += strconv.FormatFloat(i.BillingUnit, 'f', -1, 64)
result += is + ";"
}
return
}
/*
De-serializes the objects for the storage.
*/
func (ap *ActivationPeriod) restore(input string) {
elements := strings.Split(input, ";")
unixNano, _ := strconv.ParseInt(elements[0], 10, 64)
ap.ActivationTime = time.Unix(0, unixNano).In(time.UTC)
for _, is := range elements[1 : len(elements)-1] {
i := &Interval{}
ise := strings.Split(is, "|")
month, _ := strconv.Atoi(ise[0])
i.Month = time.Month(month)
i.MonthDay, _ = strconv.Atoi(ise[1])
for _, d := range strings.Split(ise[2], ",") {
if d != "" {
wd, _ := strconv.Atoi(d)
i.WeekDays = append(i.WeekDays, time.Weekday(wd))
}
}
i.StartTime = ise[3]
i.EndTime = ise[4]
i.Ponder, _ = strconv.ParseFloat(ise[5], 64)
i.ConnectFee, _ = strconv.ParseFloat(ise[6], 64)
i.Price, _ = strconv.ParseFloat(ise[7], 64)
i.BillingUnit, _ = strconv.ParseFloat(ise[8], 64)
ap.Intervals = append(ap.Intervals, i)
}
}

View File

@@ -4,7 +4,6 @@ import (
"fmt"
"log"
"math"
"strings"
"time"
)
@@ -44,17 +43,6 @@ func (cd *CallDescriptor) AddActivationPeriod(aps ...*ActivationPeriod) {
}
}
/*
Creates a string ready for storage containing the serialization of all
activation periods held in the internal list.
*/
func (cd *CallDescriptor) EncodeValues() (result string) {
for _, ap := range cd.ActivationPeriods {
result += ap.store() + "\n"
}
return
}
/*
Restores the activation periods from storage.
*/
@@ -63,22 +51,16 @@ func (cd *CallDescriptor) RestoreFromStorage(sg StorageGetter) (destPrefix strin
base := fmt.Sprintf("%s:%s:", cd.CstmId, cd.Subject)
destPrefix = cd.DestinationPrefix
key := base + destPrefix
values, err := sg.Get(key)
values, err := sg.GetActivationPeriods(key)
//get for a smaller prefix if the orignal one was not found
for i := len(cd.DestinationPrefix); err != nil && i > 1; values, err = sg.Get(key) {
for i := len(cd.DestinationPrefix); err != nil && i > 1; values, err = sg.GetActivationPeriods(key) {
i--
destPrefix = cd.DestinationPrefix[:i]
key = base + destPrefix
}
//load the activation preriods
if err == nil {
for _, aps := range strings.Split(values, "\n") {
if len(aps) > 0 {
ap := &ActivationPeriod{}
ap.restore(aps)
cd.ActivationPeriods = append(cd.ActivationPeriods, ap)
}
}
cd.ActivationPeriods = values
}
return
}

View File

@@ -162,7 +162,7 @@ func BenchmarkRedisGetting(b *testing.B) {
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2}
b.StartTimer()
for i := 0; i < b.N; i++ {
getter.Get(cd.GetKey())
getter.GetActivationPeriods(cd.GetKey())
}
}
@@ -205,7 +205,7 @@ func BenchmarkKyotoGetting(b *testing.B) {
b.StartTimer()
for i := 0; i < b.N; i++ {
key := cd.GetKey()
getter.Get(key)
getter.GetActivationPeriods(key)
}
}
@@ -254,7 +254,7 @@ func BenchmarkKyotoGetCost(b *testing.B) {
func BenchmarkMongoGetting(b *testing.B) {
b.StopTimer()
getter, _ := NewMongoStorage("127.0.0.1","test")
getter, _ := NewMongoStorage("127.0.0.1", "test")
defer getter.Close()
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
@@ -267,16 +267,16 @@ func BenchmarkMongoGetting(b *testing.B) {
}
}
func BenchmarkMongoGetCost(b *testing.B) {
b.StopTimer()
getter, _ := NewMongoStorage("127.0.0.1","test")
defer getter.Close()
//func BenchmarkMongoGetCost(b *testing.B) {
// b.StopTimer()
// getter, _ := NewMongoStorage("127.0.0.1", "test")
// defer getter.Close()
t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2}
b.StartTimer()
for i := 0; i < b.N; i++ {
cd.GetCost(getter)
}
}
// t1 := time.Date(2012, time.February, 2, 17, 30, 0, 0, time.UTC)
// t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC)
// cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2}
// b.StartTimer()
// for i := 0; i < b.N; i++ {
// cd.GetCost(getter)
// }
//}

View File

@@ -1,8 +1,10 @@
package timespans
import (
//"log"
"github.com/fsouza/gokabinet/kc"
"time"
"strconv"
"strings"
)
type KyotoStorage struct {
@@ -11,15 +13,87 @@ type KyotoStorage struct {
func NewKyotoStorage(filaName string) (*KyotoStorage, error) {
ndb, err := kc.Open(filaName, kc.READ)
//log.Print("Starting kyoto storage")
return &KyotoStorage{db: ndb}, err
}
func (ks *KyotoStorage) Close() {
//log.Print("Closing kyoto storage")
ks.db.Close()
}
func (ks *KyotoStorage) Get(key string) (value string, err error) {
return ks.db.Get(key)
func (ks *KyotoStorage) GetActivationPeriods(key string) (aps []*ActivationPeriod, err error) {
values, err := ks.db.Get(key)
if err == nil {
for _, ap_string := range strings.Split(values, "\n") {
if len(ap_string) > 0 {
ap := ks.restore(ap_string)
aps = append(aps, ap)
}
}
}
return aps, err
}
func (ks *KyotoStorage) SetActivationPeriods(key string, aps []*ActivationPeriod){
result := ""
for _, ap := range aps {
result += ks.store(ap) + "\n"
}
ks.db.Set(key, result)
}
/*
Serializes the activation periods for the storage.
*/
func (ks *KyotoStorage) store(ap *ActivationPeriod) (result string) {
result += strconv.FormatInt(ap.ActivationTime.UnixNano(), 10) + ";"
var is string
for _, i := range ap.Intervals {
is = strconv.Itoa(int(i.Month)) + "|"
is += strconv.Itoa(i.MonthDay) + "|"
for _, wd := range i.WeekDays {
is += strconv.Itoa(int(wd)) + ","
}
is = strings.TrimRight(is, ",") + "|"
is += i.StartTime + "|"
is += i.EndTime + "|"
is += strconv.FormatFloat(i.Ponder, 'f', -1, 64) + "|"
is += strconv.FormatFloat(i.ConnectFee, 'f', -1, 64) + "|"
is += strconv.FormatFloat(i.Price, 'f', -1, 64) + "|"
is += strconv.FormatFloat(i.BillingUnit, 'f', -1, 64)
result += is + ";"
}
return
}
/*
De-serializes the activation periods for the storage.
*/
func (ks *KyotoStorage) restore(input string) (ap *ActivationPeriod) {
elements := strings.Split(input, ";")
unixNano, _ := strconv.ParseInt(elements[0], 10, 64)
ap = &ActivationPeriod{}
ap.ActivationTime = time.Unix(0, unixNano).In(time.UTC)
for _, is := range elements[1 : len(elements)-1] {
i := &Interval{}
ise := strings.Split(is, "|")
month, _ := strconv.Atoi(ise[0])
i.Month = time.Month(month)
i.MonthDay, _ = strconv.Atoi(ise[1])
for _, d := range strings.Split(ise[2], ",") {
if d != "" {
wd, _ := strconv.Atoi(d)
i.WeekDays = append(i.WeekDays, time.Weekday(wd))
}
}
i.StartTime = ise[3]
i.EndTime = ise[4]
i.Ponder, _ = strconv.ParseFloat(ise[5], 64)
i.ConnectFee, _ = strconv.ParseFloat(ise[6], 64)
i.Price, _ = strconv.ParseFloat(ise[7], 64)
i.BillingUnit, _ = strconv.ParseFloat(ise[8], 64)
ap.Intervals = append(ap.Intervals, i)
}
return
}

View File

@@ -13,15 +13,15 @@ func TestApStoreRestore(t *testing.T) {
WeekDays: []time.Weekday{time.Wednesday, time.Thursday},
StartTime: "14:30:00",
EndTime: "15:00:00"}
ap := ActivationPeriod{ActivationTime: d}
ap := &ActivationPeriod{ActivationTime: d}
ap.AddInterval(i)
result := ap.store()
storage, _ := NewKyotoStorage("test.kch")
result := storage.store(ap)
expected := "1328106601000000000;2|1|3,4|14:30:00|15:00:00|0|0|0|0;"
if result != expected {
t.Errorf("Expected %q was %q", expected, result)
}
ap1 := ActivationPeriod{}
ap1.restore(result)
ap1 := storage.restore(result)
if ap1.ActivationTime != ap.ActivationTime {
t.Errorf("Expected %v was %v", ap.ActivationTime, ap1.ActivationTime)
}
@@ -58,8 +58,8 @@ func TestApStoreRestore(t *testing.T) {
}
func BenchmarkActivationPeriodRestore(b *testing.B) {
ap1 := ActivationPeriod{}
storage, _ := NewKyotoStorage("test.kch")
for i := 0; i < b.N; i++ {
ap1.restore("1328106601;2|1|3,4|14:30:00|15:00:00|0|0|0|0;")
storage.restore("1328106601;2|1|3,4|14:30:00|15:00:00|0|0|0|0;")
}
}

View File

@@ -1,40 +1,37 @@
package timespans
import (
"launchpad.net/mgo/bson"
"launchpad.net/mgo"
"launchpad.net/mgo"
"launchpad.net/mgo/bson"
)
type KeyValue struct {
Key string
Value string
_id string
value string
}
type MongoStorage struct {
db *mgo.Collection
db *mgo.Collection
session *mgo.Session
}
func NewMongoStorage(address, db string) (*MongoStorage, error) {
session, err := mgo.Dial(address)
if err != nil {
panic(err)
}
session.SetMode(mgo.Monotonic, true)
if err != nil {
panic(err)
}
session.SetMode(mgo.Monotonic, true)
ndb := session.DB(db).C("ap")
//log.Print("Starting redis storage")
ndb := session.DB(db).C("ap")
return &MongoStorage{db: ndb, session: session}, nil
}
func (ms *MongoStorage) Close() {
//log.Print("Closing redis storage")
ms.session.Close()
}
func (ms *MongoStorage) Get(key string) (string, error) {
result := KeyValue{}
err := ms.db.Find(bson.M{"key": key}).One(&result)
return result.Value, err
err := ms.db.Find(bson.M{"_id": key}).One(&result)
return result.value, err
}

View File

@@ -1,8 +1,10 @@
package timespans
import (
"strings"
"strconv"
"time"
"github.com/simonz05/godis"
//"log"
)
type RedisStorage struct {
@@ -11,16 +13,87 @@ type RedisStorage struct {
func NewRedisStorage(address string, db int) (*RedisStorage, error) {
ndb := godis.New(address, db, "")
//log.Print("Starting redis storage")
return &RedisStorage{db: ndb}, nil
}
func (rs *RedisStorage) Close() {
//log.Print("Closing redis storage")
rs.db.Quit()
}
func (rs *RedisStorage) Get(key string) (string, error) {
func (rs *RedisStorage) GetActivationPeriods(key string) (aps []*ActivationPeriod, err error) {
elem, err := rs.db.Get(key)
return elem.String(), err
values:= elem.String()
if err == nil {
for _, ap_string := range strings.Split(values, "\n") {
if len(ap_string) > 0 {
ap := rs.restore(ap_string)
aps = append(aps, ap)
}
}
}
return aps, err
}
func (rs *RedisStorage) SetActivationPeriods(key string, aps []*ActivationPeriod){
result := ""
for _, ap := range aps {
result += rs.store(ap) + "\n"
}
rs.db.Set(key, result)
}
/*
Serializes the activation periods for the storage.
*/
func (rs *RedisStorage) store(ap *ActivationPeriod) (result string) {
result += strconv.FormatInt(ap.ActivationTime.UnixNano(), 10) + ";"
var is string
for _, i := range ap.Intervals {
is = strconv.Itoa(int(i.Month)) + "|"
is += strconv.Itoa(i.MonthDay) + "|"
for _, wd := range i.WeekDays {
is += strconv.Itoa(int(wd)) + ","
}
is = strings.TrimRight(is, ",") + "|"
is += i.StartTime + "|"
is += i.EndTime + "|"
is += strconv.FormatFloat(i.Ponder, 'f', -1, 64) + "|"
is += strconv.FormatFloat(i.ConnectFee, 'f', -1, 64) + "|"
is += strconv.FormatFloat(i.Price, 'f', -1, 64) + "|"
is += strconv.FormatFloat(i.BillingUnit, 'f', -1, 64)
result += is + ";"
}
return
}
/*
De-serializes the activation periods for the storage.
*/
func (rs *RedisStorage) restore(input string) (ap *ActivationPeriod) {
elements := strings.Split(input, ";")
unixNano, _ := strconv.ParseInt(elements[0], 10, 64)
ap = &ActivationPeriod{}
ap.ActivationTime = time.Unix(0, unixNano).In(time.UTC)
for _, is := range elements[1 : len(elements)-1] {
i := &Interval{}
ise := strings.Split(is, "|")
month, _ := strconv.Atoi(ise[0])
i.Month = time.Month(month)
i.MonthDay, _ = strconv.Atoi(ise[1])
for _, d := range strings.Split(ise[2], ",") {
if d != "" {
wd, _ := strconv.Atoi(d)
i.WeekDays = append(i.WeekDays, time.Weekday(wd))
}
}
i.StartTime = ise[3]
i.EndTime = ise[4]
i.Ponder, _ = strconv.ParseFloat(ise[5], 64)
i.ConnectFee, _ = strconv.ParseFloat(ise[6], 64)
i.Price, _ = strconv.ParseFloat(ise[7], 64)
i.BillingUnit, _ = strconv.ParseFloat(ise[8], 64)
ap.Intervals = append(ap.Intervals, i)
}
return
}

View File

@@ -5,5 +5,6 @@ Interface for storage providers.
*/
type StorageGetter interface {
Close()
Get(key string) (string, error)
GetActivationPeriods(key string) ([]*ActivationPeriod, error)
SetActivationPeriods(key string, aps []*ActivationPeriod)
}