@@ -33,6 +33,7 @@ import (
33
33
"log"
34
34
"math"
35
35
"net"
36
+ "sync"
36
37
"time"
37
38
38
39
"golang.org/x/net/context"
55
56
)
56
57
57
58
type routeGuideServer struct {
58
- savedFeatures []* pb.Feature
59
- routeNotes map [string ][]* pb.RouteNote
59
+ savedFeatures []* pb.Feature // read-only after initialized
60
+
61
+ mu sync.Mutex // protects routeNotes
62
+ routeNotes map [string ][]* pb.RouteNote
60
63
}
61
64
62
65
// GetFeature returns the feature at the given point.
@@ -130,12 +133,17 @@ func (s *routeGuideServer) RouteChat(stream pb.RouteGuide_RouteChatServer) error
130
133
return err
131
134
}
132
135
key := serialize (in .Location )
133
- if _ , present := s .routeNotes [key ]; ! present {
134
- s .routeNotes [key ] = []* pb.RouteNote {in }
135
- } else {
136
- s .routeNotes [key ] = append (s .routeNotes [key ], in )
137
- }
138
- for _ , note := range s .routeNotes [key ] {
136
+
137
+ s .mu .Lock ()
138
+ s .routeNotes [key ] = append (s .routeNotes [key ], in )
139
+ // Note: this copy prevents blocking other clients while serving this one.
140
+ // We don't need to do a deep copy, because elements in the slice are
141
+ // insert-only and never modified.
142
+ rn := make ([]* pb.RouteNote , len (s .routeNotes [key ]))
143
+ copy (rn , s .routeNotes [key ])
144
+ s .mu .Unlock ()
145
+
146
+ for _ , note := range rn {
139
147
if err := stream .Send (note ); err != nil {
140
148
return err
141
149
}
@@ -201,9 +209,8 @@ func serialize(point *pb.Point) string {
201
209
}
202
210
203
211
func newServer () * routeGuideServer {
204
- s := new ( routeGuideServer )
212
+ s := & routeGuideServer { routeNotes : make ( map [ string ][] * pb. RouteNote )}
205
213
s .loadFeatures (* jsonDBFile )
206
- s .routeNotes = make (map [string ][]* pb.RouteNote )
207
214
return s
208
215
}
209
216
0 commit comments