github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/network/simulation/simulation.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:43</date>
    10  //</624450114806616064>
    11  
    12  
    13  package simulation
    14  
    15  import (
    16  	"context"
    17  	"errors"
    18  	"net/http"
    19  	"sync"
    20  	"time"
    21  
    22  	"github.com/ethereum/go-ethereum/log"
    23  	"github.com/ethereum/go-ethereum/node"
    24  	"github.com/ethereum/go-ethereum/p2p/enode"
    25  	"github.com/ethereum/go-ethereum/p2p/simulations"
    26  	"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
    27  	"github.com/ethereum/go-ethereum/swarm/network"
    28  )
    29  
    30  //此包中的函数返回的常见错误。
    31  var (
    32  	ErrNodeNotFound = errors.New("node not found")
    33  )
    34  
    35  //仿真提供了网络、节点和服务的方法
    36  //管理它们。
    37  type Simulation struct {
    38  //NET作为一种访问低级功能的方式被公开
    39  //P2P/Simulations.Network的。
    40  	Net *simulations.Network
    41  
    42  	serviceNames      []string
    43  	cleanupFuncs      []func()
    44  	buckets           map[enode.ID]*sync.Map
    45  	shutdownWG        sync.WaitGroup
    46  	done              chan struct{}
    47  	mu                sync.RWMutex
    48  	neighbourhoodSize int
    49  
    50  httpSrv *http.Server        //通过模拟选项附加HTTP服务器
    51  handler *simulations.Server //服务器的HTTP处理程序
    52  runC    chan struct{}       //前端信号准备就绪的通道
    53  }
    54  
    55  //servicefunc在new中用于声明新的服务构造函数。
    56  //第一个参数提供来自适配器包的ServiceContext
    57  //例如对nodeid的访问。第二个参数是sync.map
    58  //所有与服务相关的“全局”状态都应该保存在哪里。
    59  //施工服务和任何其他施工所需的所有清理
    60  //对象应该在单个返回的清理函数中提供。
    61  //close函数将调用返回的cleanup函数
    62  //网络关闭后。
    63  type ServiceFunc func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error)
    64  
    65  //新建创建新的模拟实例
    66  //服务映射必须具有唯一的键作为服务名和
    67  //每个servicefunc都必须返回一个唯一类型的node.service。
    68  //node.node.start()函数需要此限制
    69  //用于启动node.servicefunc返回的服务。
    70  func New(services map[string]ServiceFunc) (s *Simulation) {
    71  	s = &Simulation{
    72  		buckets:           make(map[enode.ID]*sync.Map),
    73  		done:              make(chan struct{}),
    74  		neighbourhoodSize: network.NewKadParams().NeighbourhoodSize,
    75  	}
    76  
    77  	adapterServices := make(map[string]adapters.ServiceFunc, len(services))
    78  	for name, serviceFunc := range services {
    79  //正确地确定这个变量的范围
    80  //因为它们将出现在稍后访问的adapterservices[name]函数中。
    81  		name, serviceFunc := name, serviceFunc
    82  		s.serviceNames = append(s.serviceNames, name)
    83  		adapterServices[name] = func(ctx *adapters.ServiceContext) (node.Service, error) {
    84  			b := new(sync.Map)
    85  			service, cleanup, err := serviceFunc(ctx, b)
    86  			if err != nil {
    87  				return nil, err
    88  			}
    89  			s.mu.Lock()
    90  			defer s.mu.Unlock()
    91  			if cleanup != nil {
    92  				s.cleanupFuncs = append(s.cleanupFuncs, cleanup)
    93  			}
    94  			s.buckets[ctx.Config.ID] = b
    95  			return service, nil
    96  		}
    97  	}
    98  
    99  	s.Net = simulations.NewNetwork(
   100  		adapters.NewTCPAdapter(adapterServices),
   101  		&simulations.NetworkConfig{ID: "0"},
   102  	)
   103  
   104  	return s
   105  }
   106  
   107  //runfunc是将调用的函数
   108  //在Simulation.Run方法调用中。
   109  type RunFunc func(context.Context, *Simulation) error
   110  
   111  //结果是Simulation.Run方法的返回值。
   112  type Result struct {
   113  	Duration time.Duration
   114  	Error    error
   115  }
   116  
   117  //run在处理时调用runfunc函数
   118  //通过上下文提供的取消。
   119  func (s *Simulation) Run(ctx context.Context, f RunFunc) (r Result) {
   120  //如果该选项设置为使用模拟运行HTTP服务器,
   121  //初始化服务器并启动它
   122  	start := time.Now()
   123  	if s.httpSrv != nil {
   124  		log.Info("Waiting for frontend to be ready...(send POST /runsim to HTTP server)")
   125  //等待前端连接
   126  		select {
   127  		case <-s.runC:
   128  		case <-ctx.Done():
   129  			return Result{
   130  				Duration: time.Since(start),
   131  				Error:    ctx.Err(),
   132  			}
   133  		}
   134  		log.Info("Received signal from frontend - starting simulation run.")
   135  	}
   136  	errc := make(chan error)
   137  	quit := make(chan struct{})
   138  	defer close(quit)
   139  	go func() {
   140  		select {
   141  		case errc <- f(ctx, s):
   142  		case <-quit:
   143  		}
   144  	}()
   145  	var err error
   146  	select {
   147  	case <-ctx.Done():
   148  		err = ctx.Err()
   149  	case err = <-errc:
   150  	}
   151  	return Result{
   152  		Duration: time.Since(start),
   153  		Error:    err,
   154  	}
   155  }
   156  
   157  //对上清理函数的最大并行调用数
   158  //模拟关闭。
   159  var maxParallelCleanups = 10
   160  
   161  //close调用由返回的所有清理函数
   162  //servicefunc,等待它们全部完成
   163  //显式阻止shutdownwg的函数
   164  //(如Simulation.PeerEvents)并关闭网络
   165  //最后。它用于清除
   166  //模拟。
   167  func (s *Simulation) Close() {
   168  	close(s.done)
   169  
   170  	sem := make(chan struct{}, maxParallelCleanups)
   171  	s.mu.RLock()
   172  	cleanupFuncs := make([]func(), len(s.cleanupFuncs))
   173  	for i, f := range s.cleanupFuncs {
   174  		if f != nil {
   175  			cleanupFuncs[i] = f
   176  		}
   177  	}
   178  	s.mu.RUnlock()
   179  	var cleanupWG sync.WaitGroup
   180  	for _, cleanup := range cleanupFuncs {
   181  		cleanupWG.Add(1)
   182  		sem <- struct{}{}
   183  		go func(cleanup func()) {
   184  			defer cleanupWG.Done()
   185  			defer func() { <-sem }()
   186  
   187  			cleanup()
   188  		}(cleanup)
   189  	}
   190  	cleanupWG.Wait()
   191  
   192  	if s.httpSrv != nil {
   193  		ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
   194  		defer cancel()
   195  		err := s.httpSrv.Shutdown(ctx)
   196  		if err != nil {
   197  			log.Error("Error shutting down HTTP server!", "err", err)
   198  		}
   199  		close(s.runC)
   200  	}
   201  
   202  	s.shutdownWG.Wait()
   203  	s.Net.Shutdown()
   204  }
   205  
   206  //完成返回模拟时关闭的通道
   207  //用Close方法关闭。它对信号终端很有用
   208  //在测试中创建的所有可能的goroutine中。
   209  func (s *Simulation) Done() <-chan struct{} {
   210  	return s.done
   211  }
   212