examples: fix concurrent map accesses in route_guide server (#1752)

This commit is contained in:
dfawley 2017-12-18 10:21:30 -08:00 committed by GitHub
parent 4e393e0b21
commit 45088c2971
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 17 additions and 10 deletions

View File

@ -33,6 +33,7 @@ import (
"log" "log"
"math" "math"
"net" "net"
"sync"
"time" "time"
"golang.org/x/net/context" "golang.org/x/net/context"
@ -55,8 +56,10 @@ var (
) )
type routeGuideServer struct { type routeGuideServer struct {
savedFeatures []*pb.Feature savedFeatures []*pb.Feature // read-only after initialized
routeNotes map[string][]*pb.RouteNote
mu sync.Mutex // protects routeNotes
routeNotes map[string][]*pb.RouteNote
} }
// GetFeature returns the feature at the given point. // GetFeature returns the feature at the given point.
@ -130,12 +133,17 @@ func (s *routeGuideServer) RouteChat(stream pb.RouteGuide_RouteChatServer) error
return err return err
} }
key := serialize(in.Location) key := serialize(in.Location)
if _, present := s.routeNotes[key]; !present {
s.routeNotes[key] = []*pb.RouteNote{in} s.mu.Lock()
} else { s.routeNotes[key] = append(s.routeNotes[key], in)
s.routeNotes[key] = append(s.routeNotes[key], in) // Note: this copy prevents blocking other clients while serving this one.
} // We don't need to do a deep copy, because elements in the slice are
for _, note := range s.routeNotes[key] { // insert-only and never modified.
rn := make([]*pb.RouteNote, len(s.routeNotes[key]))
copy(rn, s.routeNotes[key])
s.mu.Unlock()
for _, note := range rn {
if err := stream.Send(note); err != nil { if err := stream.Send(note); err != nil {
return err return err
} }
@ -201,9 +209,8 @@ func serialize(point *pb.Point) string {
} }
func newServer() *routeGuideServer { func newServer() *routeGuideServer {
s := new(routeGuideServer) s := &routeGuideServer{routeNotes: make(map[string][]*pb.RouteNote)}
s.loadFeatures(*jsonDBFile) s.loadFeatures(*jsonDBFile)
s.routeNotes = make(map[string][]*pb.RouteNote)
return s return s
} }