func (s *EtcdServer) processInternalRaftRequest(ctx context.Context, r pb.InternalRaftRequest) (*applyResult, error) { r.ID = s.reqIDGen.Next() data, err := r.Marshal() if err != nil { return nil, err } if len(data) > maxRequestBytes { return nil, ErrRequestTooLarge } ch := s.w.Register(r.ID) s.r.Propose(ctx, data) select { case x := <-ch: return x.(*applyResult), nil case <-ctx.Done(): s.w.Trigger(r.ID, nil) // GC wait return nil, ctx.Err() case <-s.done: return nil, ErrStopped } }
// Do interprets r and performs an operation on s.store according to r.Method // and other fields. If r.Method is "POST", "PUT", "DELETE", or a "GET" with // Quorum == true, r will be sent through consensus before performing its // respective operation. Do will block until an action is performed or there is // an error. func (s *EtcdServer) Do(ctx context.Context, r pb.Request) (Response, error) { r.ID = s.reqIDGen.Next() if r.Method == "GET" && r.Quorum { r.Method = "QGET" } switch r.Method { case "POST", "PUT", "DELETE", "QGET": var raftReq pb.InternalRaftRequest raftReq.V2 = &r data, err := raftReq.Marshal() if err != nil { return Response{}, err } ch := s.w.Register(r.ID) // TODO: benchmark the cost of time.Now() // might be sampling? start := time.Now() s.r.Propose(ctx, data) proposePending.Inc() defer proposePending.Dec() select { case x := <-ch: proposeDurations.Observe(float64(time.Since(start).Nanoseconds() / int64(time.Millisecond))) resp := x.(Response) return resp, resp.err case <-ctx.Done(): proposeFailed.Inc() s.w.Trigger(r.ID, nil) // GC wait return Response{}, parseCtxErr(ctx.Err()) case <-s.done: return Response{}, ErrStopped } case "GET": switch { case r.Wait: wc, err := s.store.Watch(r.Path, r.Recursive, r.Stream, r.Since) if err != nil { return Response{}, err } return Response{Watcher: wc}, nil default: ev, err := s.store.Get(r.Path, r.Recursive, r.Sorted) if err != nil { return Response{}, err } return Response{Event: ev}, nil } case "HEAD": ev, err := s.store.Get(r.Path, r.Recursive, r.Sorted) if err != nil { return Response{}, err } return Response{Event: ev}, nil default: return Response{}, ErrUnknownMethod } }
func (s *EtcdServer) processInternalRaftRequestOnce(ctx context.Context, r pb.InternalRaftRequest) (*applyResult, error) { ai := s.getAppliedIndex() ci := s.getCommittedIndex() if ci > ai+maxGapBetweenApplyAndCommitIndex { return nil, ErrTooManyRequests } r.Header = &pb.RequestHeader{ ID: s.reqIDGen.Next(), } authInfo, err := s.authInfoFromCtx(ctx) if err != nil { return nil, err } if authInfo != nil { r.Header.Username = authInfo.Username r.Header.AuthRevision = authInfo.Revision } data, err := r.Marshal() if err != nil { return nil, err } if len(data) > maxRequestBytes { return nil, ErrRequestTooLarge } id := r.ID if id == 0 { id = r.Header.ID } ch := s.w.Register(id) cctx, cancel := context.WithTimeout(ctx, s.Cfg.ReqTimeout()) defer cancel() start := time.Now() s.r.Propose(cctx, data) proposalsPending.Inc() defer proposalsPending.Dec() select { case x := <-ch: return x.(*applyResult), nil case <-cctx.Done(): proposalsFailed.Inc() s.w.Trigger(id, nil) // GC wait return nil, s.parseProposeCtxErr(cctx.Err(), start) case <-s.done: return nil, ErrStopped } }
// From public API method to proposalc. func (s *etcdStore) proposeInternalRaftRequest(req etcdserverpb.InternalRaftRequest) (<-chan proto.Message, <-chan error, error) { data, err := req.Marshal() if err != nil { return nil, nil, err } if len(data) > maxRequestBytes { return nil, nil, errTooBig } msgc, errc, err := s.registerPending(req.ID) if err != nil { return nil, nil, err } s.proposalc <- data return msgc, errc, nil }
func (s *etcdStore) applyCommittedEntry(entry raftpb.Entry) error { // Set the consistent index regardless of the outcome. Because we need to do // this for all committed entries, we need to receive all committed entries, // and must therefore take responsibility to demux the conf changes to the // configurator via confentryc. // // This requirement is unique to the etcd store. But for symmetry, we assign // the same responsibility to the simple store. s.index.set(entry.Index) switch entry.Type { case raftpb.EntryNormal: break case raftpb.EntryConfChange: s.logger.Printf("etcd store: forwarding ConfChange entry") s.confentryc <- entry return nil default: s.logger.Printf("etcd store: got unknown entry type %s", entry.Type) return fmt.Errorf("unknown entry type %d", entry.Type) } // entry.Size can be nonzero when len(entry.Data) == 0 if len(entry.Data) <= 0 { s.logger.Printf("etcd store: got empty committed entry (term %d, index %d, type %s); skipping", entry.Term, entry.Index, entry.Type) return nil } var req etcdserverpb.InternalRaftRequest if err := req.Unmarshal(entry.Data); err != nil { s.logger.Printf("etcd store: unmarshaling entry data: %v", err) return err } msg, err := s.applyInternalRaftRequest(req) if err != nil { s.logger.Printf("etcd store: applying internal Raft request %d: %v", req.ID, err) s.cancelPending(req.ID, err) return err } s.signalPending(req.ID, msg) return nil }
func (s *EtcdServer) processInternalRaftRequest(ctx context.Context, r pb.InternalRaftRequest) (*applyResult, error) { r.Header = &pb.RequestHeader{ ID: s.reqIDGen.Next(), } username, err := s.usernameFromCtx(ctx) if err != nil { return nil, err } r.Header.Username = username data, err := r.Marshal() if err != nil { return nil, err } if len(data) > maxRequestBytes { return nil, ErrRequestTooLarge } id := r.ID if id == 0 { id = r.Header.ID } ch := s.w.Register(id) cctx, cancel := context.WithTimeout(ctx, maxV3RequestTimeout) defer cancel() start := time.Now() s.r.Propose(cctx, data) proposalsPending.Inc() defer proposalsPending.Dec() select { case x := <-ch: return x.(*applyResult), nil case <-cctx.Done(): proposalsFailed.Inc() s.w.Trigger(id, nil) // GC wait return nil, s.parseProposeCtxErr(cctx.Err(), start) case <-s.done: return nil, ErrStopped } }
func (s *EtcdServer) V3DemoDo(ctx context.Context, r pb.InternalRaftRequest) (proto.Message, error) { r.ID = s.reqIDGen.Next() data, err := r.Marshal() if err != nil { return &pb.EmptyResponse{}, err } ch := s.w.Register(r.ID) s.r.Propose(ctx, data) select { case x := <-ch: resp := x.(proto.Message) return resp, nil case <-ctx.Done(): s.w.Trigger(r.ID, nil) // GC wait return &pb.EmptyResponse{}, ctx.Err() case <-s.done: return &pb.EmptyResponse{}, ErrStopped } }
func main() { from := flag.String("data-dir", "", "") snapfile := flag.String("start-snap", "", "The base name of snapshot file to start dumping") index := flag.Uint64("start-index", 0, "The index to start dumping") flag.Parse() if *from == "" { log.Fatal("Must provide -data-dir flag.") } if *snapfile != "" && *index != 0 { log.Fatal("start-snap and start-index flags cannot be used together.") } var ( walsnap walpb.Snapshot snapshot *raftpb.Snapshot err error ) isIndex := *index != 0 if isIndex { fmt.Printf("Start dumping log entries from index %d.\n", *index) walsnap.Index = *index } else { if *snapfile == "" { ss := snap.New(snapDir(*from)) snapshot, err = ss.Load() } else { snapshot, err = snap.Read(path.Join(snapDir(*from), *snapfile)) } switch err { case nil: walsnap.Index, walsnap.Term = snapshot.Metadata.Index, snapshot.Metadata.Term nodes := genIDSlice(snapshot.Metadata.ConfState.Nodes) fmt.Printf("Snapshot:\nterm=%d index=%d nodes=%s\n", walsnap.Term, walsnap.Index, nodes) case snap.ErrNoSnapshot: fmt.Printf("Snapshot:\nempty\n") default: log.Fatalf("Failed loading snapshot: %v", err) } fmt.Println("Start dupmping log entries from snapshot.") } w, err := wal.OpenForRead(walDir(*from), walsnap) if err != nil { log.Fatalf("Failed opening WAL: %v", err) } wmetadata, state, ents, err := w.ReadAll() w.Close() if err != nil && (!isIndex || err != wal.ErrSnapshotNotFound) { log.Fatalf("Failed reading WAL: %v", err) } id, cid := parseWALMetadata(wmetadata) vid := types.ID(state.Vote) fmt.Printf("WAL metadata:\nnodeID=%s clusterID=%s term=%d commitIndex=%d vote=%s\n", id, cid, state.Term, state.Commit, vid) fmt.Printf("WAL entries:\n") fmt.Printf("lastIndex=%d\n", ents[len(ents)-1].Index) fmt.Printf("%4s\t%10s\ttype\tdata\n", "term", "index") for _, e := range ents { msg := fmt.Sprintf("%4d\t%10d", e.Term, e.Index) switch e.Type { case raftpb.EntryNormal: msg = fmt.Sprintf("%s\tnorm", msg) var rr etcdserverpb.InternalRaftRequest if err := rr.Unmarshal(e.Data); err == nil { msg = fmt.Sprintf("%s\t%s", msg, rr.String()) break } var r etcdserverpb.Request if err := r.Unmarshal(e.Data); err == nil { switch r.Method { case "": msg = fmt.Sprintf("%s\tnoop", msg) case "SYNC": msg = fmt.Sprintf("%s\tmethod=SYNC time=%q", msg, time.Unix(0, r.Time)) case "QGET", "DELETE": msg = fmt.Sprintf("%s\tmethod=%s path=%s", msg, r.Method, excerpt(r.Path, 64, 64)) default: msg = fmt.Sprintf("%s\tmethod=%s path=%s val=%s", msg, r.Method, excerpt(r.Path, 64, 64), excerpt(r.Val, 128, 0)) } break } msg = fmt.Sprintf("%s\t???", msg) case raftpb.EntryConfChange: msg = fmt.Sprintf("%s\tconf", msg) var r raftpb.ConfChange if err := r.Unmarshal(e.Data); err != nil { msg = fmt.Sprintf("%s\t???", msg) } else { msg = fmt.Sprintf("%s\tmethod=%s id=%s", msg, r.Type, types.ID(r.NodeID)) } } fmt.Println(msg) } }