@@ -132,6 +132,20 @@ func generateMemberID(clientID string, instanceID *string) string {
132132// GROUPS //
133133////////////
134134
135+ func (gs * groups ) newGroup (name string ) * group {
136+ return & group {
137+ c : gs .c ,
138+ gs : gs ,
139+ name : name ,
140+ members : make (map [string ]* groupMember ),
141+ pending : make (map [string ]* groupMember ),
142+ protocols : make (map [string ]int ),
143+ reqCh : make (chan * clientReq ),
144+ controlCh : make (chan func ()),
145+ quitCh : make (chan struct {}),
146+ }
147+ }
148+
135149// handleJoin completely hijacks the incoming request.
136150func (gs * groups ) handleJoin (creq * clientReq ) {
137151 if gs .gs == nil {
@@ -141,17 +155,7 @@ func (gs *groups) handleJoin(creq *clientReq) {
141155start:
142156 g := gs .gs [req .Group ]
143157 if g == nil {
144- g = & group {
145- c : gs .c ,
146- gs : gs ,
147- name : req .Group ,
148- members : make (map [string ]* groupMember ),
149- pending : make (map [string ]* groupMember ),
150- protocols : make (map [string ]int ),
151- reqCh : make (chan * clientReq ),
152- controlCh : make (chan func ()),
153- quitCh : make (chan struct {}),
154- }
158+ g = gs .newGroup (req .Group )
155159 waitJoin := make (chan struct {})
156160 gs .gs [req .Group ] = g
157161 go g .manage (func () { close (waitJoin ) })
@@ -194,8 +198,25 @@ func (gs *groups) handleLeave(creq *clientReq) bool {
194198 return gs .handleHijack (creq .kreq .(* kmsg.LeaveGroupRequest ).Group , creq )
195199}
196200
197- func (gs * groups ) handleOffsetCommit (creq * clientReq ) bool {
198- return gs .handleHijack (creq .kreq .(* kmsg.OffsetCommitRequest ).Group , creq )
201+ func (gs * groups ) handleOffsetCommit (creq * clientReq ) {
202+ if gs .gs == nil {
203+ gs .gs = make (map [string ]* group )
204+ }
205+ req := creq .kreq .(* kmsg.OffsetCommitRequest )
206+ start:
207+ g := gs .gs [req .Group ]
208+ if g == nil {
209+ g = gs .newGroup (req .Group )
210+ waitCommit := make (chan struct {})
211+ gs .gs [req .Group ] = g
212+ go g .manage (func () { close (waitCommit ) })
213+ defer func () { <- waitCommit }()
214+ }
215+ select {
216+ case g .reqCh <- creq :
217+ case <- g .quitCh :
218+ goto start
219+ }
199220}
200221
201222func (gs * groups ) handleOffsetDelete (creq * clientReq ) bool {
@@ -551,7 +572,9 @@ func (g *group) manage(detachNew func()) {
551572 case * kmsg.LeaveGroupRequest :
552573 kresp = g .handleLeave (creq )
553574 case * kmsg.OffsetCommitRequest :
554- kresp = g .handleOffsetCommit (creq )
575+ var ok bool
576+ kresp , ok = g .handleOffsetCommit (creq )
577+ firstJoin (ok )
555578 case * kmsg.OffsetDeleteRequest :
556579 kresp = g .handleOffsetDelete (creq )
557580 }
@@ -807,34 +830,60 @@ func fillOffsetCommit(req *kmsg.OffsetCommitRequest, resp *kmsg.OffsetCommitResp
807830}
808831
809832// Handles a commit.
810- func (g * group ) handleOffsetCommit (creq * clientReq ) * kmsg.OffsetCommitResponse {
833+ func (g * group ) handleOffsetCommit (creq * clientReq ) ( * kmsg.OffsetCommitResponse , bool ) {
811834 req := creq .kreq .(* kmsg.OffsetCommitRequest )
812835 resp := req .ResponseKind ().(* kmsg.OffsetCommitResponse )
813836
814837 if kerr := g .c .validateGroup (creq , req .Group ); kerr != nil {
815838 fillOffsetCommit (req , resp , kerr .Code )
816- return resp
839+ return resp , false
817840 }
818841 if req .InstanceID != nil {
819842 fillOffsetCommit (req , resp , kerr .InvalidGroupID .Code )
820- return resp
821- }
822- m , ok := g .members [req .MemberID ]
823- if ! ok {
824- fillOffsetCommit (req , resp , kerr .UnknownMemberID .Code )
825- return resp
843+ return resp , false
826844 }
827- if req .Generation != g .generation {
828- fillOffsetCommit (req , resp , kerr .IllegalGeneration .Code )
829- return resp
845+
846+ var m * groupMember
847+ if len (g .members ) > 0 {
848+ var ok bool
849+ m , ok = g .members [req .MemberID ]
850+ if ! ok {
851+ fillOffsetCommit (req , resp , kerr .UnknownMemberID .Code )
852+ return resp , false
853+ }
854+ if req .Generation != g .generation {
855+ fillOffsetCommit (req , resp , kerr .IllegalGeneration .Code )
856+ return resp , false
857+ }
858+ } else {
859+ if req .MemberID != "" {
860+ fillOffsetCommit (req , resp , kerr .UnknownMemberID .Code )
861+ return resp , false
862+ }
863+ if req .Generation != - 1 {
864+ fillOffsetCommit (req , resp , kerr .IllegalGeneration .Code )
865+ return resp , false
866+ }
867+ if g .state != groupEmpty {
868+ panic ("invalid state: no members, but group not empty" )
869+ }
830870 }
831871
832872 switch g .state {
833873 default :
834874 fillOffsetCommit (req , resp , kerr .GroupIDNotFound .Code )
835- return resp
875+ return resp , true
836876 case groupEmpty :
837- // for when we support empty group commits
877+ for _ , t := range req .Topics {
878+ for _ , p := range t .Partitions {
879+ g .commits .set (t .Topic , p .Partition , offsetCommit {
880+ offset : p .Offset ,
881+ leaderEpoch : p .LeaderEpoch ,
882+ metadata : p .Metadata ,
883+ })
884+ }
885+ }
886+ fillOffsetCommit (req , resp , 0 )
838887 case groupPreparingRebalance , groupStable :
839888 for _ , t := range req .Topics {
840889 for _ , p := range t .Partitions {
@@ -851,7 +900,7 @@ func (g *group) handleOffsetCommit(creq *clientReq) *kmsg.OffsetCommitResponse {
851900 fillOffsetCommit (req , resp , kerr .RebalanceInProgress .Code )
852901 g .updateHeartbeat (m )
853902 }
854- return resp
903+ return resp , true
855904}
856905
857906// Transitions the group to the preparing rebalance state. We first need to
0 commit comments