started created timespans for minute buckets

This commit is contained in:
Radu Ioan Fericean
2012-02-22 19:33:36 +02:00
parent 1f9fd63026
commit dcea9a3a8f
8 changed files with 130 additions and 84 deletions

View File

@@ -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
}

View File

@@ -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)}

View File

@@ -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()
}
}

View File

@@ -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
}

View File

@@ -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]

View File

@@ -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
}

View File

@@ -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

View File

@@ -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)
}
}