From a16a75d8e8f6b316de152fa34d9af55d6b43480a Mon Sep 17 00:00:00 2001 From: Radu Ioan Fericean Date: Wed, 29 Feb 2012 14:07:03 +0200 Subject: [PATCH] gob switch tests --- cmd/loader/loader.go | 25 ++++++++++++- timespans/activationperiod.go | 56 ----------------------------- timespans/activationperiod_test.go | 55 ---------------------------- timespans/calldesc.go | 12 +++---- timespans/calldesc_test.go | 16 ++++----- timespans/kyoto_storage.go | 51 ++++++++++++++------------ timespans/redis_storage.go | 56 +++++++++++++++++------------ timespans/test.kch | Bin 6298936 -> 6300264 bytes 8 files changed, 100 insertions(+), 171 deletions(-) diff --git a/cmd/loader/loader.go b/cmd/loader/loader.go index cca8528f4..1a2dd75f1 100644 --- a/cmd/loader/loader.go +++ b/cmd/loader/loader.go @@ -18,6 +18,8 @@ along with this program. If not, see package main import ( + "bytes" + //"encoding/gob" "encoding/json" "flag" "github.com/rif/cgrates/timespans" @@ -39,6 +41,27 @@ var ( ubfile = flag.String("ubfile", "ub.json", "User budgets file") ) +func testGob(key string, aps []*timespans.ActivationPeriod) { + var buf bytes.Buffer + enc := json.NewEncoder(&buf) + dec := json.NewDecoder(&buf) + + enc.Encode(aps) + result := buf.String() + + aps1 := make([]*timespans.ActivationPeriod, 0) + buf.Reset() + buf.WriteString(result) + err := dec.Decode(&aps1) + log.Print("Err: ", err) + + buf.Reset() + enc.Encode(aps1) + result1 := buf.String() + + log.Print("Equal? ", result == result1, len(result), len(result1)) +} + func writeToStorage(storage timespans.StorageGetter, callDescriptors []*timespans.CallDescriptor, destinations []*timespans.Destination, @@ -47,6 +70,7 @@ func writeToStorage(storage timespans.StorageGetter, for _, cd := range callDescriptors { storage.SetActivationPeriods(cd.GetKey(), cd.ActivationPeriods) log.Printf("Storing activation periods for %q", cd.GetKey()) + testGob(cd.GetKey(), cd.ActivationPeriods) } for _, d := range destinations { storage.SetDestination(d) @@ -64,7 +88,6 @@ func writeToStorage(storage timespans.StorageGetter, func main() { flag.Parse() - log.Printf("Reading from %s, %s, %s", *apfile, *destfile, *tpfile) // reading activation periods diff --git a/timespans/activationperiod.go b/timespans/activationperiod.go index 613e69e2d..9f8b4b0dd 100644 --- a/timespans/activationperiod.go +++ b/timespans/activationperiod.go @@ -18,8 +18,6 @@ along with this program. If not, see package timespans import ( - "strconv" - "strings" "time" //"log" ) @@ -40,57 +38,3 @@ func (ap *ActivationPeriod) AddInterval(is ...*Interval) { ap.Intervals = append(ap.Intervals, i) } } - -/* -Serializes the activation periods for the storage. Used for key-value storages. -*/ -func (ap *ActivationPeriod) store() (result string) { - result += strconv.FormatInt(ap.ActivationTime.UnixNano(), 10) + ";" - for _, i := range ap.Intervals { - var is string - 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. Used for key-value storages. -*/ -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) - } -} diff --git a/timespans/activationperiod_test.go b/timespans/activationperiod_test.go index e30fef9a2..04a0b80e9 100644 --- a/timespans/activationperiod_test.go +++ b/timespans/activationperiod_test.go @@ -19,64 +19,9 @@ package timespans import ( "testing" - "time" //"log" ) func TestApStoreRestore(t *testing.T) { - d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) - i := &Interval{Month: time.February, - MonthDay: 1, - WeekDays: []time.Weekday{time.Wednesday, time.Thursday}, - StartTime: "14:30:00", - EndTime: "15:00:00"} - ap := &ActivationPeriod{ActivationTime: d} - ap.AddInterval(i) - result := ap.store() - 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) - if ap1.ActivationTime != ap.ActivationTime { - t.Errorf("Expected %v was %v", ap.ActivationTime, ap1.ActivationTime) - } - i1 := ap1.Intervals[0] - if i1.Month != i.Month { - t.Errorf("Expected %q was %q", i.Month, i1.Month) - } - if i1.MonthDay != i.MonthDay { - t.Errorf("Expected %q was %q", i.MonthDay, i1.MonthDay) - } - for j, wd := range i1.WeekDays { - if wd != i1.WeekDays[j] { - t.Errorf("Expected %q was %q", i.StartTime, i1.StartTime) - } - } - if i1.StartTime != i.StartTime { - t.Errorf("Expected %q was %q", i.StartTime, i1.StartTime) - } - if i1.EndTime != i.EndTime { - t.Errorf("Expected %q was %q", i.EndTime, i1.EndTime) - } - if i1.Ponder != i.Ponder { - t.Errorf("Expected %q was %q", i.Ponder, i1.Ponder) - } - if i1.ConnectFee != i.ConnectFee { - t.Errorf("Expected %q was %q", i.ConnectFee, i1.ConnectFee) - } - if i1.Price != i.Price { - t.Errorf("Expected %q was %q", i.Price, i1.Price) - } - if i1.BillingUnit != i.BillingUnit { - t.Errorf("Expected %q was %q", i.BillingUnit, i1.BillingUnit) - } -} -func BenchmarkActivationPeriodRestore(b *testing.B) { - ap := ActivationPeriod{} - for i := 0; i < b.N; i++ { - ap.restore("1328106601;2|1|3,4|14:30:00|15:00:00|0|0|0|0;") - } } diff --git a/timespans/calldesc.go b/timespans/calldesc.go index 01ef57f15..888081061 100644 --- a/timespans/calldesc.go +++ b/timespans/calldesc.go @@ -86,9 +86,9 @@ func (cd *CallDescriptor) SetStorageGetter(sg StorageGetter) { } /* -Restores the activation periods from storage. +Restores the activation periods for the specified prefix from storage. */ -func (cd *CallDescriptor) RestoreFromStorage() (destPrefix string, err error) { +func (cd *CallDescriptor) SearchStorageForPrefix() (destPrefix string, err error) { cd.ActivationPeriods = make([]*ActivationPeriod, 0) base := fmt.Sprintf("%s:%s:", cd.CstmId, cd.Subject) destPrefix = cd.DestinationPrefix @@ -200,14 +200,14 @@ func (cd *CallDescriptor) splitTimeSpan(firstSpan *TimeSpan) (timespans []*TimeS Creates a CallCost structure with the cost nformation calculated for the received CallDescriptor. */ func (cd *CallDescriptor) GetCost() (*CallCost, error) { - destPrefix, err := cd.RestoreFromStorage() + destPrefix, err := cd.SearchStorageForPrefix() timespans := cd.splitInTimeSpans() cost := 0.0 connectionFee := 0.0 for i, ts := range timespans { - if ts.MinuteInfo == nil && i == 0 { + if i == 0 && ts.MinuteInfo == nil && ts.Interval != nil { connectionFee = ts.Interval.ConnectFee } cost += ts.GetCost(cd) @@ -227,7 +227,7 @@ func (cd *CallDescriptor) GetCost() (*CallCost, error) { Returns the cost of a second in the present time conditions. */ func (cd *CallDescriptor) getPresentSecondCost() (cost float64, err error) { - _, err = cd.RestoreFromStorage() + _, err = cd.SearchStorageForPrefix() now := time.Now() oneSecond, _ := time.ParseDuration("1s") ts := &TimeSpan{TimeStart: now, TimeEnd: now.Add(oneSecond)} @@ -245,7 +245,7 @@ and will decrease it by 10% for nine times. So if the user has little credit it If the user has no credit then it will return 0. */ func (cd *CallDescriptor) GetMaxSessionTime() (seconds float64, err error) { - _, err = cd.RestoreFromStorage() + _, err = cd.SearchStorageForPrefix() now := time.Now() availableCredit, availableSeconds := 0.0, 0.0 if userBudget, err := cd.getUserBudget(); err == nil && userBudget != nil { diff --git a/timespans/calldesc_test.go b/timespans/calldesc_test.go index 04f5f6ddf..6ec227f8a 100644 --- a/timespans/calldesc_test.go +++ b/timespans/calldesc_test.go @@ -24,7 +24,7 @@ import ( ) func TestKyotoStoreRestore(t *testing.T) { - getter, _ := NewKyotoStorage("test.kch") + getter, _ := NewRedisStorage("tcp:127.0.0.1:6379", 10) defer getter.Close() d := time.Date(2012, time.February, 1, 14, 30, 1, 0, time.UTC) i := &Interval{Month: time.February, @@ -54,7 +54,7 @@ func TestKyotoSplitSpans(t *testing.T) { 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, storageGetter: getter} - cd.RestoreFromStorage() + cd.SearchStorageForPrefix() timespans := cd.splitInTimeSpans() if len(timespans) != 2 { t.Log(cd.ActivationPeriods) @@ -70,7 +70,7 @@ func TestRedisSplitSpans(t *testing.T) { t2 := time.Date(2012, time.February, 2, 18, 30, 0, 0, time.UTC) cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", TimeStart: t1, TimeEnd: t2, storageGetter: getter} - cd.RestoreFromStorage() + cd.SearchStorageForPrefix() timespans := cd.splitInTimeSpans() if len(timespans) != 2 { t.Log(cd.ActivationPeriods) @@ -136,6 +136,7 @@ func TestFullDestNotFound(t *testing.T) { result, _ := cd.GetCost() expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", Cost: 540, ConnectFee: 0} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { + t.Log(cd.ActivationPeriods) t.Errorf("Expected %v was %v", expected, result) } } @@ -150,8 +151,7 @@ func TestMultipleActivationPeriods(t *testing.T) { result, _ := cd.GetCost() expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", Cost: 330, ConnectFee: 0} if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee { - t.Log(result.Timespans[0].ActivationPeriod) - t.Log(result.Timespans[1].ActivationPeriod) + t.Log(result.Timespans) t.Errorf("Expected %v was %v", expected, result) } } @@ -298,7 +298,7 @@ func BenchmarkRedisRestoring(b *testing.B) { cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter} b.StartTimer() for i := 0; i < b.N; i++ { - cd.RestoreFromStorage() + cd.SearchStorageForPrefix() } } @@ -341,7 +341,7 @@ func BenchmarkKyotoRestoring(b *testing.B) { cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter} b.StartTimer() for i := 0; i < b.N; i++ { - cd.RestoreFromStorage() + cd.SearchStorageForPrefix() } } @@ -353,7 +353,7 @@ func BenchmarkSplitting(b *testing.B) { 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, storageGetter: getter} - cd.RestoreFromStorage() + cd.SearchStorageForPrefix() b.StartTimer() for i := 0; i < b.N; i++ { cd.splitInTimeSpans() diff --git a/timespans/kyoto_storage.go b/timespans/kyoto_storage.go index eef3eb6c5..6a9d299ca 100644 --- a/timespans/kyoto_storage.go +++ b/timespans/kyoto_storage.go @@ -18,45 +18,52 @@ along with this program. If not, see package timespans import ( + "bytes" + "encoding/gob" "github.com/fsouza/gokabinet/kc" - //"log" - "strings" + // "log" + "sync" ) type KyotoStorage struct { - db *kc.DB + db *kc.DB + buf bytes.Buffer + enc *gob.Encoder + dec *gob.Decoder + mux sync.Mutex // we need norma lock because we reset the buf variable } func NewKyotoStorage(filaName string) (*KyotoStorage, error) { ndb, err := kc.Open(filaName, kc.WRITE) - return &KyotoStorage{db: ndb}, err + ks := &KyotoStorage{db: ndb} + ks.enc = gob.NewEncoder(&ks.buf) + ks.dec = gob.NewDecoder(&ks.buf) + return ks, err } func (ks *KyotoStorage) Close() { ks.db.Close() } -func (ks *KyotoStorage) GetActivationPeriods(key string) (aps []*ActivationPeriod, err error) { - values, err := ks.db.Get(key) +func (ks *KyotoStorage) SetActivationPeriods(key string, aps []*ActivationPeriod) error { + ks.mux.Lock() + defer ks.mux.Unlock() - if err == nil { - for _, ap_string := range strings.Split(values, "\n") { - if len(ap_string) > 0 { - ap := &ActivationPeriod{} - ap.restore(ap_string) - aps = append(aps, ap) - } - } - } - return aps, err + ks.buf.Reset() + ks.enc.Encode(aps) + return ks.db.Set(key, ks.buf.String()) } -func (ks *KyotoStorage) SetActivationPeriods(key string, aps []*ActivationPeriod) error { - result := "" - for _, ap := range aps { - result += ap.store() + "\n" - } - return ks.db.Set(key, result) +func (ks *KyotoStorage) GetActivationPeriods(key string) (aps []*ActivationPeriod, err error) { + ks.mux.Lock() + defer ks.mux.Unlock() + + values, err := ks.db.Get(key) + + ks.buf.Reset() + ks.buf.WriteString(values) + ks.dec.Decode(&aps) + return } func (ks *KyotoStorage) GetDestination(key string) (dest *Destination, err error) { diff --git a/timespans/redis_storage.go b/timespans/redis_storage.go index c70d5e0d1..8987d9865 100644 --- a/timespans/redis_storage.go +++ b/timespans/redis_storage.go @@ -18,47 +18,57 @@ along with this program. If not, see package timespans import ( + "bytes" + "encoding/gob" "github.com/simonz05/godis" - "strings" + "log" + "sync" ) type RedisStorage struct { dbNb int db *godis.Client + buf bytes.Buffer + enc *gob.Encoder + dec *gob.Decoder + mux sync.Mutex } func NewRedisStorage(address string, db int) (*RedisStorage, error) { ndb := godis.New(address, db, "") - return &RedisStorage{db: ndb, dbNb: db}, nil + rs := &RedisStorage{db: ndb, dbNb: db} + + rs.enc = gob.NewEncoder(&rs.buf) + rs.dec = gob.NewDecoder(&rs.buf) + return rs, nil } func (rs *RedisStorage) Close() { rs.db.Quit() } -func (rs *RedisStorage) GetActivationPeriods(key string) (aps []*ActivationPeriod, err error) { - //rs.db.Select(rs.dbNb) - elem, err := rs.db.Get(key) - values := elem.String() - if err == nil { - for _, ap_string := range strings.Split(values, "\n") { - if len(ap_string) > 0 { - ap := &ActivationPeriod{} - ap.restore(ap_string) - aps = append(aps, ap) - } - } - } - return aps, err -} - func (rs *RedisStorage) SetActivationPeriods(key string, aps []*ActivationPeriod) error { //.db.Select(rs.dbNb) - result := "" - for _, ap := range aps { - result += ap.store() + "\n" - } - return rs.db.Set(key, result) + rs.mux.Lock() + defer rs.mux.Unlock() + + rs.buf.Reset() + rs.enc.Encode(aps) + return rs.db.Set(key, rs.buf.Bytes()) +} + +func (rs *RedisStorage) GetActivationPeriods(key string) (aps []*ActivationPeriod, err error) { + //rs.db.Select(rs.dbNb) + rs.mux.Lock() + defer rs.mux.Unlock() + + elem, err := rs.db.Get(key) + rs.buf.Reset() + rs.buf.Write(elem.Bytes()) + + e := rs.dec.Decode(&aps) + log.Print(e) + return } func (rs *RedisStorage) GetDestination(key string) (dest *Destination, err error) { diff --git a/timespans/test.kch b/timespans/test.kch index 99f1e2ebf2990f1e480089ba23b5fdff6dfcc905..4c956cefe1ac22db6bafd814151f081339ae56f8 100644 GIT binary patch delta 2485 zcmb_d-A@x)6u)<-#mZJxkSJ0%al$^hjyO}dfJ0)34?kD|Nz`ltY0^RmnNX*j=|D7w z3}qKwbu&C!&%@VR*CRBy=UhB^CXm4*=hKi$Q7R-Z?!ACWCc@^?>z)^?_Xg zy9jm(>@rwC*w(^pK9fjgu>AnC9dLN_Q(5aE3nw4^((8BS|SMaKbz zYkSk0ri>dG6@|F|VO<@Ek%{nUJ!&eYYBz6assSN{LiRnNSvMLZEZYcF5?~3E51}bi z4SW#8yte3(DWf5k^)JXh>CCvhClIqe3= ztvr0(>^n{4^_{x3?=Wf$^IS>eIZ2%5?{bs?omZq{mT)0d+Ie9&64il=+rVQ4zWh*u zq_7~G;nM=Vo!9BEf{ir-5bmKNgetP$Li!`>XI3tt2puY`U%RkF0js1^(mk)GAl2Nn zms^WjEtBdxX)5|I`=|nTY&KSFAyiuZzC>`qI~2${6%D3kIk#$c zz1F5vsa+09HT$znlxc7hRMb&LG!^`%$_`Uyw^VJ~NN1)cp-Op>!ckanS>!)sCv`W= z_s^%6S5%jKbUgm#U|G}r-8rE-F67pl<4qjg{ob>`H>rYTC1E5)LFghsQOFI4;zx78 zHpg3Aph#u6cAP+08Boe#w$#|mW$Yud;3^pv6tG}@WF9g5%K%2N2lX=75+Vf`i^ LLF~%mQ2dMcX{XI$ delta 1189 zcmaEHq=9+It_J1_dQ7qwje)I!j9UYloF-08P-Ny|PJju_><03tz<5p*8xyuBFxJio z3OY0fZVhC--V0<_Bjh(Gtlt0>i2zH!vFsZCqPyC_*G%k3HEfVD^PO~LNm~(rtOwR_CV|a#EwAh z1jNoj>;lBDK;uHUK!k(a-=G2G$_b&|rF=LW218M+yll zQmFCDVG47Rk>T`0#RN04Gi=CKv6&