Skip to content

Commit

Permalink
Merge branch 'master' of github.com:hyperledger/fabric into Add_role_…
Browse files Browse the repository at this point in the history
…type
  • Loading branch information
GrapeBaBa committed May 12, 2016
2 parents cc5068a + e108db6 commit 8fd6b00
Show file tree
Hide file tree
Showing 506 changed files with 1,561 additions and 266 deletions.
Empty file modified .travis.yml
100755 → 100644
Empty file.
40 changes: 40 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,46 @@ To work on something, whether a new feature or a bugfix:

After your pull request has been reviewed and signed off, a maintainer will merge it into the master branch.

## Coding guidelines

### Coding Golang <a name="coding-go"></a>
- We require a file [header](headers.txt) in all source code files. Simply copy and paste the header when you create a new file.
- We code in Go&trade; and strictly follow the [best practices](http://golang.org/doc/effective_go.html)
and will not accept any deviations. You must run the following tools against your Go code and fix all errors and warnings:
- [golint](https://github.com/golang/lint)
- [go vet](https://golang.org/cmd/vet/)
- [goimports](https://godoc.org/golang.org/x/tools/cmd/goimports)

## Generating gRPC code <a name="gRPC"></a>

If you modify any `.proto` files, run the following command to generate/update the respective `.pb.go` files.

```
cd $GOPATH/src/github.com/hyperledger/fabric
make protos
```

## Adding or updating Go packages <a name="vendoring"></a>

The Hyperledger Fabric Project uses Go 1.6 vendoring for package management. This means that all required packages reside in the `vendor` folder within the fabric project. Go will use packages in this folder instead of the GOPATH when the `go install` or `go build` commands are executed. To manage the packages in the `vendor` folder, we use [Govendor](https://github.com/kardianos/govendor), which is installed in the Vagrant environment. The following commands can be used for package management:

```
# Add external packages.
govendor add +external
# Add a specific package.
govendor add github.com/kardianos/osext
# Update vendor packages.
govendor update +vendor
# Revert back to normal GOPATH packages.
govendor remove +vendor
# List package.
govendor list
```

### Becoming a maintainer
This project is managed under open governance model as described in our [charter](https://www.hyperledger.org/about/charter). Projects or sub-projects will be lead by a set of maintainers. New projects can designate an initial set of maintainers that will be approved by the Technical Steering Committee when the project is first approved. The project's maintainers will, from time-to-time, consider adding a new maintainer. An existing maintainer will post a pull request to the [MAINTAINERS.txt](MAINTAINERS.txt) file. If a majority of the maintainers concur in the comments, the pull request is then merged and the individual becomes a maintainer.

Expand Down
Empty file modified LICENSE
100755 → 100644
Empty file.
Empty file modified README.md
100755 → 100644
Empty file.
Empty file modified bddtests/environment.py
100755 → 100644
Empty file.
Empty file modified consensus/docker-compose-files/Dockerfile
100755 → 100644
Empty file.
Empty file modified consensus/docker-compose-files/compose-consensus-4.yml
100755 → 100644
Empty file.
132 changes: 132 additions & 0 deletions consensus/obcpbft/complainer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/

package obcpbft

import (
"time"

"github.com/hyperledger/fabric/consensus/obcpbft/custodian"
)

// complaintHandler represents a receiver of complaints
type complaintHandler interface {
// Complain is called by the complainer to signal that custody
// or complaint timeout was reached. The second argument
// specifies whether the timeout was a Custody timeout (false)
// or Complaint timeout (true).
Complain(string, *Request, bool)
}

// complainer provideds lifecycle management to ensure that Requests
// are not censored by a primary. Initially Requests are put into the
// custody of the complainer using Custody(). When the Request has
// been processed successfully by the network, Success() signals to
// the complainer to drop custody of the Request. If no success is
// signaled before the custody timeout expires, the complainer will
// signal this fact to the registered handler. Likewise, Complaint()
// will register a Request for complaining. Requests stay
// indefinitely in Custody and will repeatedly signal timeouts until
// they are removed using Success(); Requests registered via
// Complaint() only signal a timeout once.
type complainer struct {
custody *custodian.Custodian
complaints *custodian.Custodian

h complaintHandler
}

// newComplainer creates a new complainer.
func newComplainer(h complaintHandler, custodyTimeout time.Duration, complaintTimeout time.Duration) *complainer {
c := &complainer{}
c.custody = custodian.New(custodyTimeout, c.custodyTimeout)
c.complaints = custodian.New(complaintTimeout, c.complaintTimeout)
c.h = h
return c
}

// Stop cleans up all outstanding goroutines of the complainer.
// Typically only used in tests.
func (c *complainer) Stop() {
c.custody.Stop()
c.complaints.Stop()
}

// Custody adds a Request into custody of the complainer. When the
// custody timeout expires, the complaintHandler will be invoked with
// the bool argument set to false. The Request stays in custody until
// Success() is called.
func (c *complainer) Custody(req *Request) string {
hash := hashReq(req)
c.custody.Register(hash, req)
return hash
}

// custodyTimeout is the callback from the Custodian for requests that
// are in custody.
func (c *complainer) custodyTimeout(hash string, req_ interface{}) {
req := req_.(*Request)
c.custody.Register(hash, req)
c.h.Complain(hash, req, false)
}

// Complaint adds a Request to the complaint queue of the complainer.
// When the complaint timeout expires, the complaintHandler will be
// invoked with the bool argument set to true. The Request is removed
// from the complaint queue once the timeout expires.
func (c *complainer) Complaint(req *Request) string {
hash := hashReq(req)
c.complaints.Register(hash, req)
return hash
}

// complaintTimeout is the callback from the Custodian for requests
// that are in the complaint queue.
func (c *complainer) complaintTimeout(hash string, req_ interface{}) {
req := req_.(*Request)
c.h.Complain(hash, req, true)
}

// Success removes a Request from both custody and complaint queues.
func (c *complainer) Success(req *Request) {
hash := hashReq(req)
c.SuccessHash(hash)
}

// SuccessHash is like Success, but takes directly the hash of the
// Request, as returned by hashReq.
func (c *complainer) SuccessHash(hash string) {
c.custody.Remove(hash)
c.complaints.Remove(hash)
}

// Restart resets custody and complaint queues without calling into
// the complaintHandler. The complaint queue is drained completely.
// The custody queue timeouts are reset. Restart returns all requests
// that are maintained in custody.
func (c *complainer) Restart() map[string]*Request {
c.complaints.RemoveAll()
custody := c.custody.RemoveAll()
reqs := make(map[string]*Request)
for _, pair := range custody {
c.custody.Register(pair.ID, pair.Data)
reqs[pair.ID] = pair.Data.(*Request)
}
return reqs
}
Empty file modified consensus/obcpbft/config.yaml
100755 → 100644
Empty file.
181 changes: 181 additions & 0 deletions consensus/obcpbft/custodian/custodian.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/

package custodian

import (
"sync"
"time"
)

type custody struct {
id string
data interface{}
deadline time.Time
canceled bool
}

// Custodian provides a timeout service for objects. The timeout is
// the same for all enqueued objects. Order is retained.
type Custodian struct {
lock sync.Mutex
timeout time.Duration
timer *time.Timer
notifyCb CustodyNotify
stopCh chan struct{}
requests map[string]*custody
seq []*custody
}

// CustodyPair is a tuple of enqueued id and data object
type CustodyPair struct {
ID string
Data interface{}
}

// CustodyNotify is the callback function type as called by the
// Custodian when the timeout expires
type CustodyNotify func(id string, data interface{})

// New creates a new Custodian. Timeout specifies the timeout of the
// Custodian, notifyCb specifies the callback function that is called
// by the Custodian when a timeout expires.
func New(timeout time.Duration, notifyCb CustodyNotify) *Custodian {
c := &Custodian{
timeout: timeout,
notifyCb: notifyCb,
requests: make(map[string]*custody),
}
c.timer = time.NewTimer(time.Hour)
c.timer.Stop()
c.stopCh = make(chan struct{})
go c.notifyRoutine()
return c
}

// Stop closes down all Custodian activity. Only used for tests.
func (c *Custodian) Stop() {
close(c.stopCh)
}

// Register enqueues a new object to the custodian. The data object
// is referred to by id.
func (c *Custodian) Register(id string, data interface{}) {
obj := &custody{
id: id,
data: data,
deadline: time.Now().Add(c.timeout),
}
c.lock.Lock()
defer c.lock.Unlock()
c.requests[obj.id] = obj
c.seq = append(c.seq, obj)
if len(c.seq) == 1 {
c.resetTimer()
}
}

// Remove removes an object from custody. No callback will be invoked
// on this object anymore.
func (c *Custodian) Remove(id string) bool {
c.lock.Lock()
defer c.lock.Unlock()
obj, ok := c.requests[id]
if ok {
delete(c.requests, id)
obj.canceled = true
obj.data = nil
}
return ok
}

// Elements returns all objects that are currently under custody.
func (c *Custodian) Elements() []CustodyPair {
c.lock.Lock()
defer c.lock.Unlock()
return c.syncElements()
}

func (c *Custodian) syncElements() []CustodyPair {
var m []CustodyPair
for _, obj := range c.seq {
if obj.canceled {
continue
}
m = append(m, CustodyPair{obj.id, obj.data})
}
return m
}

// RemoveAll deletes all objects from custody. No callbacks will be
// invoked. RemoveAll returns all objects that have been under
// custody.
func (c *Custodian) RemoveAll() []CustodyPair {
c.lock.Lock()
defer c.lock.Unlock()
c.timer.Stop()
m := c.syncElements()
c.requests = make(map[string]*custody)
c.seq = nil
return m
}

// resetTimer must be called with lock held
func (c *Custodian) resetTimer() {
if len(c.seq) == 0 {
c.timer.Stop()
return
}
next := c.seq[0]
diff := next.deadline.Sub(time.Now())
if diff < 0 {
diff = 0
}
c.timer.Reset(diff)
}

func (c *Custodian) notifyRoutine() {
for {
select {
case <-c.timer.C:
break
case <-c.stopCh:
c.stopCh = nil
return
}
c.lock.Lock()
var expired []CustodyPair
for _, obj := range c.seq {
if obj.deadline.After(time.Now()) {
break
}
if !obj.canceled {
expired = append(expired, CustodyPair{obj.id, obj.data})
}
delete(c.requests, obj.id)
c.seq = c.seq[1:]
}
c.resetTimer()
c.lock.Unlock()

for _, data := range expired {
c.notifyCb(data.ID, data.Data)
}
}
}
Loading

0 comments on commit 8fd6b00

Please sign in to comment.