mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
started created timespans for minute buckets
This commit is contained in:
@@ -28,7 +28,8 @@ RPC method providing the rating information from the storage.
|
||||
*/
|
||||
func (s *Storage) GetCost(cd timespans.CallDescriptor, reply *timespans.CallCost) (err error) {
|
||||
descriptor := &cd
|
||||
r, e := descriptor.GetCost(s.sg)
|
||||
descriptor.storageGetter = s.sg
|
||||
r, e := descriptor.GetCost()
|
||||
*reply, err = *r, e
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ type CallDescriptor struct {
|
||||
CstmId, Subject, DestinationPrefix string
|
||||
TimeStart, TimeEnd time.Time
|
||||
ActivationPeriods []*ActivationPeriod
|
||||
storageGetter StorageGetter
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -51,15 +52,15 @@ func (cd *CallDescriptor) AddActivationPeriod(aps ...*ActivationPeriod) {
|
||||
/*
|
||||
Restores the activation periods from storage.
|
||||
*/
|
||||
func (cd *CallDescriptor) RestoreFromStorage(sg StorageGetter) (destPrefix string, err error) {
|
||||
func (cd *CallDescriptor) RestoreFromStorage() (destPrefix string, err error) {
|
||||
cd.ActivationPeriods = make([]*ActivationPeriod, 0)
|
||||
base := fmt.Sprintf("%s:%s:", cd.CstmId, cd.Subject)
|
||||
destPrefix = cd.DestinationPrefix
|
||||
key := base + destPrefix
|
||||
values, err := sg.GetActivationPeriods(key)
|
||||
values, err := cd.storageGetter.GetActivationPeriods(key)
|
||||
//get for a smaller prefix if the orignal one was not found
|
||||
|
||||
for i := len(cd.DestinationPrefix); err != nil && i >= MinPrefixLength; values, err = sg.GetActivationPeriods(key) {
|
||||
for i := len(cd.DestinationPrefix); err != nil && i >= MinPrefixLength; values, err = cd.storageGetter.GetActivationPeriods(key) {
|
||||
i--
|
||||
destPrefix = cd.DestinationPrefix[:i]
|
||||
key = base + destPrefix
|
||||
@@ -90,6 +91,24 @@ func (cd *CallDescriptor) splitInTimeSpans() (timespans []*TimeSpan) {
|
||||
Splits the received timespan into sub time spans according to the activation periods intervals.
|
||||
*/
|
||||
func (cd *CallDescriptor) splitTimeSpan(firstSpan *TimeSpan) (timespans []*TimeSpan) {
|
||||
timespans = append(timespans, firstSpan)
|
||||
// split on (free) minute buckets
|
||||
if userBudget, err := cd.storageGetter.GetUserBudget(cd.Subject); err == nil {
|
||||
_, bucketList := userBudget.getSecondsForPrefix(cd.storageGetter, cd.DestinationPrefix)
|
||||
for _, mb := range bucketList {
|
||||
for i := 0; i < len(timespans); i++ {
|
||||
newTs := timespans[i].SplitByMinuteBucket(mb)
|
||||
if newTs != nil {
|
||||
timespans = append(timespans, newTs)
|
||||
firstSpan = newTs // we move the firstspan to the newly created one for further spliting
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if firstSpan.MinuteBucket != nil {
|
||||
return // all the timespans are on minutes
|
||||
}
|
||||
if len(cd.ActivationPeriods) == 0 {
|
||||
log.Print("Nothing to split, move along... ", cd)
|
||||
return
|
||||
@@ -97,7 +116,6 @@ func (cd *CallDescriptor) splitTimeSpan(firstSpan *TimeSpan) (timespans []*TimeS
|
||||
firstSpan.ActivationPeriod = cd.ActivationPeriods[0]
|
||||
|
||||
// split on activation periods
|
||||
timespans = append(timespans, firstSpan)
|
||||
afterStart, afterEnd := false, false //optimization for multiple activation periods
|
||||
for _, ap := range cd.ActivationPeriods {
|
||||
if !afterStart && !afterEnd && ap.ActivationTime.Before(cd.TimeStart) {
|
||||
@@ -105,6 +123,9 @@ func (cd *CallDescriptor) splitTimeSpan(firstSpan *TimeSpan) (timespans []*TimeS
|
||||
} else {
|
||||
afterStart = true
|
||||
for i := 0; i < len(timespans); i++ {
|
||||
if timespans[i].MinuteBucket != nil {
|
||||
continue
|
||||
}
|
||||
newTs := timespans[i].SplitByActivationPeriod(ap)
|
||||
if newTs != nil {
|
||||
timespans = append(timespans, newTs)
|
||||
@@ -118,6 +139,9 @@ func (cd *CallDescriptor) splitTimeSpan(firstSpan *TimeSpan) (timespans []*TimeS
|
||||
// split on price intervals
|
||||
for i := 0; i < len(timespans); i++ {
|
||||
ap := timespans[i].ActivationPeriod
|
||||
if timespans[i].MinuteBucket != nil {
|
||||
continue
|
||||
}
|
||||
//timespans[i].ActivationPeriod = nil
|
||||
for _, interval := range ap.Intervals {
|
||||
newTs := timespans[i].SplitByInterval(interval)
|
||||
@@ -133,33 +157,26 @@ 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(sg StorageGetter) (*CallCost, error) {
|
||||
destPrefix, err := cd.RestoreFromStorage(sg)
|
||||
cc := &CallCost{TOR: cd.TOR, CstmId: cd.CstmId, Subject: cd.Subject, DestinationPrefix: destPrefix}
|
||||
|
||||
if userBudget, err := sg.GetUserBudget(cd.Subject); err == nil {
|
||||
nbSeconds := cd.TimeEnd.Sub(cd.TimeStart).Seconds()
|
||||
log.Print("seconds: ", nbSeconds)
|
||||
avaliableNbSeconds := userBudget.getSecondsForPrefix(sg, cd.DestinationPrefix)
|
||||
log.Print("available: ", avaliableNbSeconds)
|
||||
if nbSeconds < avaliableNbSeconds {
|
||||
cc.Cost, cc.ConnectFee = 0, 0
|
||||
return cc, nil
|
||||
}
|
||||
}
|
||||
func (cd *CallDescriptor) GetCost() (*CallCost, error) {
|
||||
destPrefix, err := cd.RestoreFromStorage()
|
||||
|
||||
timespans := cd.splitInTimeSpans()
|
||||
|
||||
cost := 0.0
|
||||
connectionFee := 0.0
|
||||
for i, ts := range timespans {
|
||||
if i == 0 {
|
||||
if ts.MinuteBucket == nil && i == 0 {
|
||||
connectionFee = ts.Interval.ConnectFee
|
||||
}
|
||||
cost += ts.GetCost()
|
||||
}
|
||||
|
||||
cc.Cost, cc.ConnectFee, cc.Timespans = cost, connectionFee, timespans
|
||||
cc := &CallCost{TOR: cd.TOR,
|
||||
CstmId: cd.CstmId,
|
||||
Subject: cd.Subject,
|
||||
DestinationPrefix: destPrefix,
|
||||
Cost: cost,
|
||||
ConnectFee: connectionFee,
|
||||
Timespans: timespans}
|
||||
|
||||
return cc, err
|
||||
}
|
||||
@@ -167,8 +184,8 @@ func (cd *CallDescriptor) GetCost(sg StorageGetter) (*CallCost, error) {
|
||||
/*
|
||||
Returns the cost of a second in the present time conditions.
|
||||
*/
|
||||
func (cd *CallDescriptor) getPresentSecondCost(sg StorageGetter) (cost float64, err error) {
|
||||
_, err = cd.RestoreFromStorage(sg)
|
||||
func (cd *CallDescriptor) getPresentSecondCost() (cost float64, err error) {
|
||||
_, err = cd.RestoreFromStorage()
|
||||
now := time.Now()
|
||||
oneSecond, _ := time.ParseDuration("1s")
|
||||
ts := &TimeSpan{TimeStart: now, TimeEnd: now.Add(oneSecond)}
|
||||
@@ -183,8 +200,8 @@ func (cd *CallDescriptor) getPresentSecondCost(sg StorageGetter) (cost float64,
|
||||
/*
|
||||
Returns the cost of a second in the present time conditions.
|
||||
*/
|
||||
func (cd *CallDescriptor) GetMaxSessionTime(sg StorageGetter, maxSessionSeconds int) (seconds int, err error) {
|
||||
_, err = cd.RestoreFromStorage(sg)
|
||||
func (cd *CallDescriptor) GetMaxSessionTime(maxSessionSeconds int) (seconds int, err error) {
|
||||
_, err = cd.RestoreFromStorage()
|
||||
now := time.Now()
|
||||
maxDuration, _ := time.ParseDuration(fmt.Sprintf("%ds", maxSessionSeconds))
|
||||
ts := &TimeSpan{TimeStart: now, TimeEnd: now.Add(maxDuration)}
|
||||
|
||||
@@ -12,9 +12,9 @@ func TestKyotoSplitSpans(t *testing.T) {
|
||||
|
||||
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}
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
|
||||
|
||||
cd.RestoreFromStorage(getter)
|
||||
cd.RestoreFromStorage()
|
||||
timespans := cd.splitInTimeSpans()
|
||||
if len(timespans) != 2 {
|
||||
t.Error("Wrong number of timespans: ", len(timespans))
|
||||
@@ -27,8 +27,8 @@ func TestRedisSplitSpans(t *testing.T) {
|
||||
|
||||
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: "0257", TimeStart: t1, TimeEnd: t2}
|
||||
cd.RestoreFromStorage(getter)
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
|
||||
cd.RestoreFromStorage()
|
||||
|
||||
timespans := cd.splitInTimeSpans()
|
||||
if len(timespans) != 2 {
|
||||
@@ -42,14 +42,14 @@ func TestKyotoGetCost(t *testing.T) {
|
||||
|
||||
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}
|
||||
result, _ := cd.GetCost(getter)
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
|
||||
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.Errorf("Expected %v was %v", expected, result)
|
||||
}
|
||||
cd = &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", TimeStart: t1, TimeEnd: t2}
|
||||
result, _ = cd.GetCost(getter)
|
||||
cd = &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
|
||||
result, _ = cd.GetCost()
|
||||
expected = &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", Cost: 540, ConnectFee: 0}
|
||||
}
|
||||
|
||||
@@ -59,8 +59,8 @@ func TestRedisGetCost(t *testing.T) {
|
||||
|
||||
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}
|
||||
result, _ := cd.GetCost(getter)
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
|
||||
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.Errorf("Expected %v was %v", expected, result)
|
||||
@@ -73,8 +73,8 @@ func TestMongoGetCost(t *testing.T) {
|
||||
|
||||
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}
|
||||
result, _ := cd.GetCost(getter)
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
|
||||
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.Errorf("Expected %v was %v", expected, result)
|
||||
@@ -87,8 +87,8 @@ func TestFullDestNotFound(t *testing.T) {
|
||||
|
||||
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: "0256308200", TimeStart: t1, TimeEnd: t2}
|
||||
result, _ := cd.GetCost(getter)
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256308200", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
|
||||
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.Errorf("Expected %v was %v", expected, result)
|
||||
@@ -101,8 +101,8 @@ func TestMultipleActivationPeriods(t *testing.T) {
|
||||
|
||||
t1 := time.Date(2012, time.February, 8, 17, 30, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 8, 18, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257308200", TimeStart: t1, TimeEnd: t2}
|
||||
result, _ := cd.GetCost(getter)
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257308200", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
|
||||
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)
|
||||
@@ -117,8 +117,8 @@ func TestSpansMultipleActivationPeriods(t *testing.T) {
|
||||
|
||||
t1 := time.Date(2012, time.February, 7, 23, 50, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 8, 0, 30, 0, 0, time.UTC)
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257308200", TimeStart: t1, TimeEnd: t2}
|
||||
result, _ := cd.GetCost(getter)
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257308200", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
|
||||
result, _ := cd.GetCost()
|
||||
expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", Cost: 360, ConnectFee: 0}
|
||||
if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee {
|
||||
t.Errorf("Expected %v was %v", expected, result)
|
||||
@@ -131,8 +131,8 @@ func TestLessThanAMinute(t *testing.T) {
|
||||
|
||||
t1 := time.Date(2012, time.February, 8, 23, 50, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 8, 23, 50, 30, 0, time.UTC)
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257308200", TimeStart: t1, TimeEnd: t2}
|
||||
result, _ := cd.GetCost(getter)
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257308200", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
|
||||
result, _ := cd.GetCost()
|
||||
expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0257", Cost: 0.5, ConnectFee: 0}
|
||||
if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee {
|
||||
t.Errorf("Expected %v was %v", expected, result)
|
||||
@@ -145,8 +145,8 @@ func TestUniquePrice(t *testing.T) {
|
||||
|
||||
t1 := time.Date(2012, time.February, 8, 22, 50, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 8, 23, 50, 21, 0, time.UTC)
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723045326", TimeStart: t1, TimeEnd: t2}
|
||||
result, _ := cd.GetCost(getter)
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723045326", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
|
||||
result, _ := cd.GetCost()
|
||||
expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723", Cost: 60.35, ConnectFee: 0}
|
||||
if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee {
|
||||
t.Errorf("Expected %v was %v", expected, result)
|
||||
@@ -159,8 +159,8 @@ func TestPresentSecodCost(t *testing.T) {
|
||||
|
||||
t1 := time.Date(2012, time.February, 8, 22, 50, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 8, 23, 50, 21, 0, time.UTC)
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723", TimeStart: t1, TimeEnd: t2}
|
||||
result, _ := cd.getPresentSecondCost(getter)
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
|
||||
result, _ := cd.getPresentSecondCost()
|
||||
expected := 0.016
|
||||
if result != expected {
|
||||
t.Errorf("Expected %v was %v", expected, result)
|
||||
@@ -173,8 +173,8 @@ func TestMinutesCost(t *testing.T) {
|
||||
|
||||
t1 := time.Date(2012, time.February, 8, 22, 50, 0, 0, time.UTC)
|
||||
t2 := time.Date(2012, time.February, 8, 23, 50, 21, 0, time.UTC)
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723", TimeStart: t1, TimeEnd: t2}
|
||||
result, _ := cd.GetCost(getter)
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
|
||||
result, _ := cd.GetCost()
|
||||
expected := &CallCost{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0723", Cost: 0, ConnectFee: 0}
|
||||
if result.Cost != expected.Cost || result.ConnectFee != expected.ConnectFee {
|
||||
t.Errorf("Expected %v was %v", expected, result)
|
||||
@@ -203,10 +203,10 @@ func BenchmarkRedisRestoring(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}
|
||||
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(getter)
|
||||
cd.RestoreFromStorage()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,10 +217,10 @@ func BenchmarkRedisGetCost(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}
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
cd.GetCost(getter)
|
||||
cd.GetCost()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,7 +231,7 @@ func BenchmarkKyotoGetting(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}
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
key := cd.GetKey()
|
||||
@@ -246,10 +246,10 @@ func BenchmarkKyotoRestoring(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}
|
||||
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(getter)
|
||||
cd.RestoreFromStorage()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,8 +260,8 @@ 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}
|
||||
cd.RestoreFromStorage(getter)
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
|
||||
cd.RestoreFromStorage()
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
cd.splitInTimeSpans()
|
||||
@@ -275,10 +275,10 @@ func BenchmarkKyotoGetCost(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}
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
cd.GetCost(getter)
|
||||
cd.GetCost()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,9 +303,9 @@ func BenchmarkMongoGetCost(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}
|
||||
cd := &CallDescriptor{CstmId: "vdf", Subject: "rif", DestinationPrefix: "0256", TimeStart: t1, TimeEnd: t2, storageGetter: getter}
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
cd.GetCost(getter)
|
||||
cd.GetCost()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package timespans
|
||||
|
||||
import "math"
|
||||
|
||||
type MinuteBucket struct {
|
||||
Seconds int
|
||||
Seconds float64
|
||||
Priority int
|
||||
Price float64
|
||||
DestinationId string
|
||||
@@ -18,3 +20,11 @@ func (mb *MinuteBucket) getDestination(storage StorageGetter) (dest *Destination
|
||||
}
|
||||
return mb.destination
|
||||
}
|
||||
|
||||
func (mb *MinuteBucket) GetSecondsForCredit(credit float64) (seconds float64) {
|
||||
seconds = mb.Seconds
|
||||
if mb.Price > 0 {
|
||||
seconds = math.Min(credit/mb.Price, mb.Seconds)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ func (tp *TariffPlan) restore(input string) {
|
||||
for _, mbs := range elements[1 : len(elements)-1] {
|
||||
mb := &MinuteBucket{}
|
||||
mbse := strings.Split(mbs, "|")
|
||||
mb.Seconds, _ = strconv.Atoi(mbse[0])
|
||||
mb.Seconds, _ = strconv.ParseFloat(mbse[0], 64)
|
||||
mb.Priority, _ = strconv.Atoi(mbse[1])
|
||||
mb.Price, _ = strconv.ParseFloat(mbse[2], 64)
|
||||
mb.DestinationId = mbse[3]
|
||||
|
||||
@@ -2,6 +2,7 @@ package timespans
|
||||
|
||||
import (
|
||||
"time"
|
||||
"fmt"
|
||||
//"log"
|
||||
)
|
||||
|
||||
@@ -12,6 +13,7 @@ type TimeSpan struct {
|
||||
TimeStart, TimeEnd time.Time
|
||||
ActivationPeriod *ActivationPeriod
|
||||
Interval *Interval
|
||||
MinuteBucket *MinuteBucket
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -110,3 +112,21 @@ func (ts *TimeSpan) SplitByActivationPeriod(ap *ActivationPeriod) (newTs *TimeSp
|
||||
ts.TimeEnd = ap.ActivationTime
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Splits the given timespan on activation period's activation time.
|
||||
*/
|
||||
func (ts *TimeSpan) SplitByMinuteBucket(mb *MinuteBucket) (newTs *TimeSpan) {
|
||||
ts.MinuteBucket = mb
|
||||
s := ts.GetDuration().Seconds()
|
||||
if s <= mb.Seconds {
|
||||
mb.Seconds -= s
|
||||
return nil
|
||||
}
|
||||
secDuration,_ := time.ParseDuration(fmt.Sprintf("%ds", mb.Seconds))
|
||||
newTimeEnd := ts.TimeStart.Add(secDuration)
|
||||
newTs = &TimeSpan{TimeStart: newTimeEnd, TimeEnd: ts.TimeEnd}
|
||||
ts.TimeEnd = newTimeEnd
|
||||
mb.Seconds = 0
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@ package timespans
|
||||
|
||||
import (
|
||||
"log"
|
||||
"math"
|
||||
"strconv"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -37,7 +36,7 @@ func (bs BucketSorter) Swap(i, j int) {
|
||||
func (bs BucketSorter) Less(j, i int) bool {
|
||||
return bs[i].Priority < bs[j].Priority ||
|
||||
bs[i].precision < bs[j].precision ||
|
||||
bs[i].Price < bs[j].Price
|
||||
bs[i].Price > bs[j].Price
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -71,7 +70,7 @@ func (ub *UserBudget) restore(input string) {
|
||||
for _, mbs := range elements[4 : len(elements)-1] {
|
||||
mb := &MinuteBucket{}
|
||||
mbse := strings.Split(mbs, "|")
|
||||
mb.Seconds, _ = strconv.Atoi(mbse[0])
|
||||
mb.Seconds, _ = strconv.ParseFloat(mbse[0], 64)
|
||||
mb.Priority, _ = strconv.Atoi(mbse[1])
|
||||
mb.Price, _ = strconv.ParseFloat(mbse[2], 64)
|
||||
mb.DestinationId = mbse[3]
|
||||
@@ -93,12 +92,12 @@ func (ub *UserBudget) getTariffPlan(storage StorageGetter) (tp *TariffPlan) {
|
||||
/*
|
||||
Returns user's avaliable minutes for the specified destination
|
||||
*/
|
||||
func (ub *UserBudget) getSecondsForPrefix(storage StorageGetter, prefix string) (seconds float64) {
|
||||
func (ub *UserBudget) getSecondsForPrefix(storage StorageGetter, prefix string) (seconds float64, bucketList BucketSorter) {
|
||||
if len(ub.MinuteBuckets) == 0 {
|
||||
log.Print("There are no minute buckets to check for user", ub.Id)
|
||||
return
|
||||
}
|
||||
var bucketList BucketSorter
|
||||
|
||||
for _, mb := range ub.MinuteBuckets {
|
||||
d := mb.getDestination(storage)
|
||||
if d == nil {
|
||||
@@ -107,17 +106,16 @@ func (ub *UserBudget) getSecondsForPrefix(storage StorageGetter, prefix string)
|
||||
contains, precision := d.containsPrefix(prefix)
|
||||
if contains {
|
||||
mb.precision = precision
|
||||
bucketList = append(bucketList, mb)
|
||||
if mb.Seconds > 0 {
|
||||
bucketList = append(bucketList, mb)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Sort(bucketList)
|
||||
sort.Sort(bucketList) // sorts the buckets according to priority, precision or price
|
||||
credit := ub.Credit
|
||||
for _, mb := range bucketList {
|
||||
s := float64(mb.Seconds)
|
||||
if mb.Price > 0 {
|
||||
s = math.Min(credit/mb.Price, s)
|
||||
credit -= s
|
||||
}
|
||||
s := mb.GetSecondsForCredit(credit)
|
||||
credit -= s
|
||||
seconds += s
|
||||
}
|
||||
return
|
||||
|
||||
@@ -16,9 +16,9 @@ func TestGetSeconds(t *testing.T) {
|
||||
tf1 := &TariffPlan{MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
|
||||
ub1 := &UserBudget{Id: "rif", MinuteBuckets: []*MinuteBucket{b1, b2}, Credit: 200, tariffPlan: tf1, ResetDayOfTheMonth: 10}
|
||||
seconds := ub1.getSecondsForPrefix(nil, "0723")
|
||||
seconds, bucketList := ub1.getSecondsForPrefix(nil, "0723")
|
||||
expected := 110.0
|
||||
if seconds != expected {
|
||||
if seconds != expected || bucketList[0].Priority < bucketList[1].Priority {
|
||||
t.Errorf("Expected %v was %v", expected, seconds)
|
||||
}
|
||||
}
|
||||
@@ -29,9 +29,9 @@ func TestGetPricedSeconds(t *testing.T) {
|
||||
tf1 := &TariffPlan{MinuteBuckets: []*MinuteBucket{b1, b2}}
|
||||
|
||||
ub1 := &UserBudget{Id: "rif", MinuteBuckets: []*MinuteBucket{b1, b2}, Credit: 21, tariffPlan: tf1, ResetDayOfTheMonth: 10}
|
||||
seconds := ub1.getSecondsForPrefix(nil, "0723")
|
||||
seconds, bucketList := ub1.getSecondsForPrefix(nil, "0723")
|
||||
expected := 21.0
|
||||
if seconds != expected {
|
||||
if seconds != expected || bucketList[0].Priority < bucketList[1].Priority {
|
||||
t.Errorf("Expected %v was %v", expected, seconds)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user