Skip to content

Commit

Permalink
SeqIDMaker
Browse files Browse the repository at this point in the history
an IDMaker that simply generate a sequence, which is useful for local
mode.
  • Loading branch information
mission-liao committed Jan 5, 2016
1 parent 6d5a77e commit 63c77d2
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 35 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ I initiated this project after [machinery](https://github.com/RichardKnop/machin
- Await and receive reports through channels. (_channel_ is a natural way to represent asynchronous results)
- I want to get familiar with those concepts of #golang: **interface**, **routine**, **channel**, and a distributed task framework is a good topic for practice, :)

One important concept I learned from [Celery](http://www.celeryproject.org/) and inherited in _Dingo_ is that __Caller__ and __Worker__ could share the same codebase.
One important concept I learned from [Celery](http://www.celeryproject.org/) and inherited in __Dingo__ is that __Caller__ and __Worker__ could share the same codebase.
> When you send a task message in Celery, that message will not contain any source code, but only the name of the task you want to execute. This works similarly to how host names work on the internet: every worker maintains a mapping of task names to their actual functions, called the task registry.
Below is a quicklink to go through this README:
Expand Down
11 changes: 1 addition & 10 deletions backend_test_suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,15 +228,6 @@ func (ts *BackendTestSuite) TestOrder() {
ts.Tasks = append(ts.Tasks, tasks...)
}

type testSeqID struct {
cur int
}

func (ts *testSeqID) NewID() (string, error) {
ts.cur++
return fmt.Sprintf("%d", ts.cur), nil
}

func (ts *BackendTestSuite) TestSameID() {
// different type of tasks, with the same id,
// backend(s) should not get mass.
Expand All @@ -256,7 +247,7 @@ func (ts *BackendTestSuite) TestSameID() {
// register idMaker, task
for i := 0; i < countOfTypes; i++ {
name := fmt.Sprintf("SameID.%d", i)
err = ts.Trans.AddIDMaker(100+i, &testSeqID{})
err = ts.Trans.AddIDMaker(100+i, &SeqIDMaker{})
if err != nil {
return
}
Expand Down
12 changes: 1 addition & 11 deletions bench_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package dingo_test

import (
"fmt"
"sync/atomic"
"testing"

"github.com/mission-liao/dingo"
Expand All @@ -22,14 +20,6 @@ func BenchmarkRaw(b *testing.B) {
}
}

type testSeqID struct {
i int32
}

func (me *testSeqID) NewID() (string, error) {
return fmt.Sprintf("%d", atomic.AddInt32(&me.i, 1)), nil
}

func BenchmarkLocal(b *testing.B) {
var (
err error
Expand Down Expand Up @@ -74,7 +64,7 @@ func BenchmarkLocal(b *testing.B) {
}

// setup for idmaker
err = app.AddIDMaker(101, &testSeqID{})
err = app.AddIDMaker(101, &dingo.SeqIDMaker{})
if err != nil {
return
}
Expand Down
4 changes: 4 additions & 0 deletions bridge_local.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,10 @@ func (bdg *localBridge) Poll(t *Task) (reports <-chan *Report, err error) {
defer bdg.objLock.Unlock()

if chain, ok := bdg.reporters[t.Name()]; ok {
// a 'localReporterNode' is composed of a reporting channel and task, then sent to
// the linked channel, every reporter routine belongs to that task would check it,
// and once a reporter with the same 'ID' found, the 'localReporterNode' would settle
// down, and its reporting channel would be used to deliver reports.
chain.Send(&localStorePoller{
task: t,
reports: reports2,
Expand Down
2 changes: 1 addition & 1 deletion bridge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ func (ts *bridgeTestSuite) TestDifferentReportsWithSameID() {
// register idMaker, task
for i := 0; i < countOfTypes; i++ {
name := fmt.Sprintf("DifferentReportsWithSameID.%d", i)
err = ts.trans.AddIDMaker(100+i, &testSeqID{})
err = ts.trans.AddIDMaker(100+i, &SeqIDMaker{})
if err != nil {
return
}
Expand Down
2 changes: 1 addition & 1 deletion dingo_multi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ func (ts *DingoMultiAppTestSuite) TestSameID() {
ts.register(name, fn)
ts.allocate(name, 2, 2)

err = v.AddIDMaker(101, &testIDMaker{})
err = v.AddIDMaker(101, &dingo.SeqIDMaker{})
if err != nil {
return
}
Expand Down
12 changes: 1 addition & 11 deletions dingo_single_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package dingo_test
import (
"fmt"
"sync"
"sync/atomic"

"github.com/mission-liao/dingo"
"github.com/stretchr/testify/suite"
Expand Down Expand Up @@ -140,15 +139,6 @@ func (ts *DingoSingleAppTestSuite) TestBasic() {
}
}

type testIDMaker struct {
cur int32
}

func (idm *testIDMaker) NewID() (string, error) {
v := atomic.AddInt32(&idm.cur, 1)
return fmt.Sprintf("%d", v), nil
}

func (ts *DingoSingleAppTestSuite) TestSameID() {
// tasks of different name have the same IDs
var (
Expand All @@ -171,7 +161,7 @@ func (ts *DingoSingleAppTestSuite) TestSameID() {
if err != nil {
return
}
err = ts.app.AddIDMaker(100+i, &testIDMaker{})
err = ts.app.AddIDMaker(100+i, &dingo.SeqIDMaker{})
if err != nil {
return
}
Expand Down
20 changes: 20 additions & 0 deletions id_maker.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package dingo

import (
"errors"
"fmt"
"sync/atomic"

"github.com/satori/go.uuid"
)

Expand All @@ -27,3 +31,19 @@ type uuidMaker struct{}
func (*uuidMaker) NewID() (string, error) {
return uuid.NewV4().String(), nil
}

/*SeqIDMaker is an implementation of IDMaker suited for local mode.
A sequence of number would be generated when called. Usage:
err := app.AddIDMaker(101, &dingo.SeqIDMaker{})
*/
type SeqIDMaker struct {
i uint64
}

func (seq *SeqIDMaker) NewID() (string, error) {
r := atomic.AddUint64(&seq.i, 1)
if r > ^uint64(0)>>1 {
return "", errors.New("sequential id generate failed: overflow")
}
return fmt.Sprintf("%d", r), nil
}
41 changes: 41 additions & 0 deletions id_maker_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package dingo

import (
"strconv"
"testing"

"github.com/stretchr/testify/assert"
)

func TestSeqIDMaker(t *testing.T) {
ass := assert.New(t)

// test overflow
{
m := &SeqIDMaker{i: ^uint64(0)>>1 - 1}
id, err := m.NewID()
ass.Nil(err)
ass.NotEqual("", id)

id, err = m.NewID()
ass.NotNil(err)
ass.Equal("", id)
}

// test normal usaage
{
m := &SeqIDMaker{}
id1, err := m.NewID()
ass.Nil(err)

id2, err := m.NewID()
ass.Nil(err)

num1, err := strconv.Atoi(id1)
ass.Nil(err)
num2, err := strconv.Atoi(id2)
ass.Nil(err)

ass.Equal(1, num2-num1)
}
}

0 comments on commit 63c77d2

Please sign in to comment.