funcs.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. /*
  2. *
  3. * Copyright 2018 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. // Package channelz defines APIs for enabling channelz service, entry
  19. // registration/deletion, and accessing channelz data. It also defines channelz
  20. // metric struct formats.
  21. //
  22. // All APIs in this package are experimental.
  23. package channelz
  24. import (
  25. "sort"
  26. "sync"
  27. "sync/atomic"
  28. "time"
  29. "google.golang.org/grpc/grpclog"
  30. )
  31. const (
  32. defaultMaxTraceEntry int32 = 30
  33. )
  34. var (
  35. db dbWrapper
  36. idGen idGenerator
  37. // EntryPerPage defines the number of channelz entries to be shown on a web page.
  38. EntryPerPage = 50
  39. curState int32
  40. maxTraceEntry = defaultMaxTraceEntry
  41. )
  42. // TurnOn turns on channelz data collection.
  43. func TurnOn() {
  44. if !IsOn() {
  45. NewChannelzStorage()
  46. atomic.StoreInt32(&curState, 1)
  47. }
  48. }
  49. // IsOn returns whether channelz data collection is on.
  50. func IsOn() bool {
  51. return atomic.CompareAndSwapInt32(&curState, 1, 1)
  52. }
  53. // SetMaxTraceEntry sets maximum number of trace entry per entity (i.e. channel/subchannel).
  54. // Setting it to 0 will disable channel tracing.
  55. func SetMaxTraceEntry(i int32) {
  56. atomic.StoreInt32(&maxTraceEntry, i)
  57. }
  58. // ResetMaxTraceEntryToDefault resets the maximum number of trace entry per entity to default.
  59. func ResetMaxTraceEntryToDefault() {
  60. atomic.StoreInt32(&maxTraceEntry, defaultMaxTraceEntry)
  61. }
  62. func getMaxTraceEntry() int {
  63. i := atomic.LoadInt32(&maxTraceEntry)
  64. return int(i)
  65. }
  66. // dbWarpper wraps around a reference to internal channelz data storage, and
  67. // provide synchronized functionality to set and get the reference.
  68. type dbWrapper struct {
  69. mu sync.RWMutex
  70. DB *channelMap
  71. }
  72. func (d *dbWrapper) set(db *channelMap) {
  73. d.mu.Lock()
  74. d.DB = db
  75. d.mu.Unlock()
  76. }
  77. func (d *dbWrapper) get() *channelMap {
  78. d.mu.RLock()
  79. defer d.mu.RUnlock()
  80. return d.DB
  81. }
  82. // NewChannelzStorage initializes channelz data storage and id generator.
  83. //
  84. // Note: This function is exported for testing purpose only. User should not call
  85. // it in most cases.
  86. func NewChannelzStorage() {
  87. db.set(&channelMap{
  88. topLevelChannels: make(map[int64]struct{}),
  89. channels: make(map[int64]*channel),
  90. listenSockets: make(map[int64]*listenSocket),
  91. normalSockets: make(map[int64]*normalSocket),
  92. servers: make(map[int64]*server),
  93. subChannels: make(map[int64]*subChannel),
  94. })
  95. idGen.reset()
  96. }
  97. // GetTopChannels returns a slice of top channel's ChannelMetric, along with a
  98. // boolean indicating whether there's more top channels to be queried for.
  99. //
  100. // The arg id specifies that only top channel with id at or above it will be included
  101. // in the result. The returned slice is up to a length of EntryPerPage, and is
  102. // sorted in ascending id order.
  103. func GetTopChannels(id int64) ([]*ChannelMetric, bool) {
  104. return db.get().GetTopChannels(id)
  105. }
  106. // GetServers returns a slice of server's ServerMetric, along with a
  107. // boolean indicating whether there's more servers to be queried for.
  108. //
  109. // The arg id specifies that only server with id at or above it will be included
  110. // in the result. The returned slice is up to a length of EntryPerPage, and is
  111. // sorted in ascending id order.
  112. func GetServers(id int64) ([]*ServerMetric, bool) {
  113. return db.get().GetServers(id)
  114. }
  115. // GetServerSockets returns a slice of server's (identified by id) normal socket's
  116. // SocketMetric, along with a boolean indicating whether there's more sockets to
  117. // be queried for.
  118. //
  119. // The arg startID specifies that only sockets with id at or above it will be
  120. // included in the result. The returned slice is up to a length of EntryPerPage,
  121. // and is sorted in ascending id order.
  122. func GetServerSockets(id int64, startID int64) ([]*SocketMetric, bool) {
  123. return db.get().GetServerSockets(id, startID)
  124. }
  125. // GetChannel returns the ChannelMetric for the channel (identified by id).
  126. func GetChannel(id int64) *ChannelMetric {
  127. return db.get().GetChannel(id)
  128. }
  129. // GetSubChannel returns the SubChannelMetric for the subchannel (identified by id).
  130. func GetSubChannel(id int64) *SubChannelMetric {
  131. return db.get().GetSubChannel(id)
  132. }
  133. // GetSocket returns the SocketInternalMetric for the socket (identified by id).
  134. func GetSocket(id int64) *SocketMetric {
  135. return db.get().GetSocket(id)
  136. }
  137. // RegisterChannel registers the given channel c in channelz database with ref
  138. // as its reference name, and add it to the child list of its parent (identified
  139. // by pid). pid = 0 means no parent. It returns the unique channelz tracking id
  140. // assigned to this channel.
  141. func RegisterChannel(c Channel, pid int64, ref string) int64 {
  142. id := idGen.genID()
  143. cn := &channel{
  144. refName: ref,
  145. c: c,
  146. subChans: make(map[int64]string),
  147. nestedChans: make(map[int64]string),
  148. id: id,
  149. pid: pid,
  150. trace: &channelTrace{createdTime: time.Now(), events: make([]*TraceEvent, 0, getMaxTraceEntry())},
  151. }
  152. if pid == 0 {
  153. db.get().addChannel(id, cn, true, pid, ref)
  154. } else {
  155. db.get().addChannel(id, cn, false, pid, ref)
  156. }
  157. return id
  158. }
  159. // RegisterSubChannel registers the given channel c in channelz database with ref
  160. // as its reference name, and add it to the child list of its parent (identified
  161. // by pid). It returns the unique channelz tracking id assigned to this subchannel.
  162. func RegisterSubChannel(c Channel, pid int64, ref string) int64 {
  163. if pid == 0 {
  164. grpclog.Error("a SubChannel's parent id cannot be 0")
  165. return 0
  166. }
  167. id := idGen.genID()
  168. sc := &subChannel{
  169. refName: ref,
  170. c: c,
  171. sockets: make(map[int64]string),
  172. id: id,
  173. pid: pid,
  174. trace: &channelTrace{createdTime: time.Now(), events: make([]*TraceEvent, 0, getMaxTraceEntry())},
  175. }
  176. db.get().addSubChannel(id, sc, pid, ref)
  177. return id
  178. }
  179. // RegisterServer registers the given server s in channelz database. It returns
  180. // the unique channelz tracking id assigned to this server.
  181. func RegisterServer(s Server, ref string) int64 {
  182. id := idGen.genID()
  183. svr := &server{
  184. refName: ref,
  185. s: s,
  186. sockets: make(map[int64]string),
  187. listenSockets: make(map[int64]string),
  188. id: id,
  189. }
  190. db.get().addServer(id, svr)
  191. return id
  192. }
  193. // RegisterListenSocket registers the given listen socket s in channelz database
  194. // with ref as its reference name, and add it to the child list of its parent
  195. // (identified by pid). It returns the unique channelz tracking id assigned to
  196. // this listen socket.
  197. func RegisterListenSocket(s Socket, pid int64, ref string) int64 {
  198. if pid == 0 {
  199. grpclog.Error("a ListenSocket's parent id cannot be 0")
  200. return 0
  201. }
  202. id := idGen.genID()
  203. ls := &listenSocket{refName: ref, s: s, id: id, pid: pid}
  204. db.get().addListenSocket(id, ls, pid, ref)
  205. return id
  206. }
  207. // RegisterNormalSocket registers the given normal socket s in channelz database
  208. // with ref as its reference name, and add it to the child list of its parent
  209. // (identified by pid). It returns the unique channelz tracking id assigned to
  210. // this normal socket.
  211. func RegisterNormalSocket(s Socket, pid int64, ref string) int64 {
  212. if pid == 0 {
  213. grpclog.Error("a NormalSocket's parent id cannot be 0")
  214. return 0
  215. }
  216. id := idGen.genID()
  217. ns := &normalSocket{refName: ref, s: s, id: id, pid: pid}
  218. db.get().addNormalSocket(id, ns, pid, ref)
  219. return id
  220. }
  221. // RemoveEntry removes an entry with unique channelz trakcing id to be id from
  222. // channelz database.
  223. func RemoveEntry(id int64) {
  224. db.get().removeEntry(id)
  225. }
  226. // TraceEventDesc is what the caller of AddTraceEvent should provide to describe the event to be added
  227. // to the channel trace.
  228. // The Parent field is optional. It is used for event that will be recorded in the entity's parent
  229. // trace also.
  230. type TraceEventDesc struct {
  231. Desc string
  232. Severity Severity
  233. Parent *TraceEventDesc
  234. }
  235. // AddTraceEvent adds trace related to the entity with specified id, using the provided TraceEventDesc.
  236. func AddTraceEvent(id int64, desc *TraceEventDesc) {
  237. if getMaxTraceEntry() == 0 {
  238. return
  239. }
  240. db.get().traceEvent(id, desc)
  241. }
  242. // channelMap is the storage data structure for channelz.
  243. // Methods of channelMap can be divided in two two categories with respect to locking.
  244. // 1. Methods acquire the global lock.
  245. // 2. Methods that can only be called when global lock is held.
  246. // A second type of method need always to be called inside a first type of method.
  247. type channelMap struct {
  248. mu sync.RWMutex
  249. topLevelChannels map[int64]struct{}
  250. servers map[int64]*server
  251. channels map[int64]*channel
  252. subChannels map[int64]*subChannel
  253. listenSockets map[int64]*listenSocket
  254. normalSockets map[int64]*normalSocket
  255. }
  256. func (c *channelMap) addServer(id int64, s *server) {
  257. c.mu.Lock()
  258. s.cm = c
  259. c.servers[id] = s
  260. c.mu.Unlock()
  261. }
  262. func (c *channelMap) addChannel(id int64, cn *channel, isTopChannel bool, pid int64, ref string) {
  263. c.mu.Lock()
  264. cn.cm = c
  265. cn.trace.cm = c
  266. c.channels[id] = cn
  267. if isTopChannel {
  268. c.topLevelChannels[id] = struct{}{}
  269. } else {
  270. c.findEntry(pid).addChild(id, cn)
  271. }
  272. c.mu.Unlock()
  273. }
  274. func (c *channelMap) addSubChannel(id int64, sc *subChannel, pid int64, ref string) {
  275. c.mu.Lock()
  276. sc.cm = c
  277. sc.trace.cm = c
  278. c.subChannels[id] = sc
  279. c.findEntry(pid).addChild(id, sc)
  280. c.mu.Unlock()
  281. }
  282. func (c *channelMap) addListenSocket(id int64, ls *listenSocket, pid int64, ref string) {
  283. c.mu.Lock()
  284. ls.cm = c
  285. c.listenSockets[id] = ls
  286. c.findEntry(pid).addChild(id, ls)
  287. c.mu.Unlock()
  288. }
  289. func (c *channelMap) addNormalSocket(id int64, ns *normalSocket, pid int64, ref string) {
  290. c.mu.Lock()
  291. ns.cm = c
  292. c.normalSockets[id] = ns
  293. c.findEntry(pid).addChild(id, ns)
  294. c.mu.Unlock()
  295. }
  296. // removeEntry triggers the removal of an entry, which may not indeed delete the entry, if it has to
  297. // wait on the deletion of its children and until no other entity's channel trace references it.
  298. // It may lead to a chain of entry deletion. For example, deleting the last socket of a gracefully
  299. // shutting down server will lead to the server being also deleted.
  300. func (c *channelMap) removeEntry(id int64) {
  301. c.mu.Lock()
  302. c.findEntry(id).triggerDelete()
  303. c.mu.Unlock()
  304. }
  305. // c.mu must be held by the caller
  306. func (c *channelMap) decrTraceRefCount(id int64) {
  307. e := c.findEntry(id)
  308. if v, ok := e.(tracedChannel); ok {
  309. v.decrTraceRefCount()
  310. e.deleteSelfIfReady()
  311. }
  312. }
  313. // c.mu must be held by the caller.
  314. func (c *channelMap) findEntry(id int64) entry {
  315. var v entry
  316. var ok bool
  317. if v, ok = c.channels[id]; ok {
  318. return v
  319. }
  320. if v, ok = c.subChannels[id]; ok {
  321. return v
  322. }
  323. if v, ok = c.servers[id]; ok {
  324. return v
  325. }
  326. if v, ok = c.listenSockets[id]; ok {
  327. return v
  328. }
  329. if v, ok = c.normalSockets[id]; ok {
  330. return v
  331. }
  332. return &dummyEntry{idNotFound: id}
  333. }
  334. // c.mu must be held by the caller
  335. // deleteEntry simply deletes an entry from the channelMap. Before calling this
  336. // method, caller must check this entry is ready to be deleted, i.e removeEntry()
  337. // has been called on it, and no children still exist.
  338. // Conditionals are ordered by the expected frequency of deletion of each entity
  339. // type, in order to optimize performance.
  340. func (c *channelMap) deleteEntry(id int64) {
  341. var ok bool
  342. if _, ok = c.normalSockets[id]; ok {
  343. delete(c.normalSockets, id)
  344. return
  345. }
  346. if _, ok = c.subChannels[id]; ok {
  347. delete(c.subChannels, id)
  348. return
  349. }
  350. if _, ok = c.channels[id]; ok {
  351. delete(c.channels, id)
  352. delete(c.topLevelChannels, id)
  353. return
  354. }
  355. if _, ok = c.listenSockets[id]; ok {
  356. delete(c.listenSockets, id)
  357. return
  358. }
  359. if _, ok = c.servers[id]; ok {
  360. delete(c.servers, id)
  361. return
  362. }
  363. }
  364. func (c *channelMap) traceEvent(id int64, desc *TraceEventDesc) {
  365. c.mu.Lock()
  366. child := c.findEntry(id)
  367. childTC, ok := child.(tracedChannel)
  368. if !ok {
  369. c.mu.Unlock()
  370. return
  371. }
  372. childTC.getChannelTrace().append(&TraceEvent{Desc: desc.Desc, Severity: desc.Severity, Timestamp: time.Now()})
  373. if desc.Parent != nil {
  374. parent := c.findEntry(child.getParentID())
  375. var chanType RefChannelType
  376. switch child.(type) {
  377. case *channel:
  378. chanType = RefChannel
  379. case *subChannel:
  380. chanType = RefSubChannel
  381. }
  382. if parentTC, ok := parent.(tracedChannel); ok {
  383. parentTC.getChannelTrace().append(&TraceEvent{
  384. Desc: desc.Parent.Desc,
  385. Severity: desc.Parent.Severity,
  386. Timestamp: time.Now(),
  387. RefID: id,
  388. RefName: childTC.getRefName(),
  389. RefType: chanType,
  390. })
  391. childTC.incrTraceRefCount()
  392. }
  393. }
  394. c.mu.Unlock()
  395. }
  396. type int64Slice []int64
  397. func (s int64Slice) Len() int { return len(s) }
  398. func (s int64Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
  399. func (s int64Slice) Less(i, j int) bool { return s[i] < s[j] }
  400. func copyMap(m map[int64]string) map[int64]string {
  401. n := make(map[int64]string)
  402. for k, v := range m {
  403. n[k] = v
  404. }
  405. return n
  406. }
  407. func min(a, b int) int {
  408. if a < b {
  409. return a
  410. }
  411. return b
  412. }
  413. func (c *channelMap) GetTopChannels(id int64) ([]*ChannelMetric, bool) {
  414. c.mu.RLock()
  415. l := len(c.topLevelChannels)
  416. ids := make([]int64, 0, l)
  417. cns := make([]*channel, 0, min(l, EntryPerPage))
  418. for k := range c.topLevelChannels {
  419. ids = append(ids, k)
  420. }
  421. sort.Sort(int64Slice(ids))
  422. idx := sort.Search(len(ids), func(i int) bool { return ids[i] >= id })
  423. count := 0
  424. var end bool
  425. var t []*ChannelMetric
  426. for i, v := range ids[idx:] {
  427. if count == EntryPerPage {
  428. break
  429. }
  430. if cn, ok := c.channels[v]; ok {
  431. cns = append(cns, cn)
  432. t = append(t, &ChannelMetric{
  433. NestedChans: copyMap(cn.nestedChans),
  434. SubChans: copyMap(cn.subChans),
  435. })
  436. count++
  437. }
  438. if i == len(ids[idx:])-1 {
  439. end = true
  440. break
  441. }
  442. }
  443. c.mu.RUnlock()
  444. if count == 0 {
  445. end = true
  446. }
  447. for i, cn := range cns {
  448. t[i].ChannelData = cn.c.ChannelzMetric()
  449. t[i].ID = cn.id
  450. t[i].RefName = cn.refName
  451. t[i].Trace = cn.trace.dumpData()
  452. }
  453. return t, end
  454. }
  455. func (c *channelMap) GetServers(id int64) ([]*ServerMetric, bool) {
  456. c.mu.RLock()
  457. l := len(c.servers)
  458. ids := make([]int64, 0, l)
  459. ss := make([]*server, 0, min(l, EntryPerPage))
  460. for k := range c.servers {
  461. ids = append(ids, k)
  462. }
  463. sort.Sort(int64Slice(ids))
  464. idx := sort.Search(len(ids), func(i int) bool { return ids[i] >= id })
  465. count := 0
  466. var end bool
  467. var s []*ServerMetric
  468. for i, v := range ids[idx:] {
  469. if count == EntryPerPage {
  470. break
  471. }
  472. if svr, ok := c.servers[v]; ok {
  473. ss = append(ss, svr)
  474. s = append(s, &ServerMetric{
  475. ListenSockets: copyMap(svr.listenSockets),
  476. })
  477. count++
  478. }
  479. if i == len(ids[idx:])-1 {
  480. end = true
  481. break
  482. }
  483. }
  484. c.mu.RUnlock()
  485. if count == 0 {
  486. end = true
  487. }
  488. for i, svr := range ss {
  489. s[i].ServerData = svr.s.ChannelzMetric()
  490. s[i].ID = svr.id
  491. s[i].RefName = svr.refName
  492. }
  493. return s, end
  494. }
  495. func (c *channelMap) GetServerSockets(id int64, startID int64) ([]*SocketMetric, bool) {
  496. var svr *server
  497. var ok bool
  498. c.mu.RLock()
  499. if svr, ok = c.servers[id]; !ok {
  500. // server with id doesn't exist.
  501. c.mu.RUnlock()
  502. return nil, true
  503. }
  504. svrskts := svr.sockets
  505. l := len(svrskts)
  506. ids := make([]int64, 0, l)
  507. sks := make([]*normalSocket, 0, min(l, EntryPerPage))
  508. for k := range svrskts {
  509. ids = append(ids, k)
  510. }
  511. sort.Sort(int64Slice(ids))
  512. idx := sort.Search(len(ids), func(i int) bool { return ids[i] >= startID })
  513. count := 0
  514. var end bool
  515. for i, v := range ids[idx:] {
  516. if count == EntryPerPage {
  517. break
  518. }
  519. if ns, ok := c.normalSockets[v]; ok {
  520. sks = append(sks, ns)
  521. count++
  522. }
  523. if i == len(ids[idx:])-1 {
  524. end = true
  525. break
  526. }
  527. }
  528. c.mu.RUnlock()
  529. if count == 0 {
  530. end = true
  531. }
  532. var s []*SocketMetric
  533. for _, ns := range sks {
  534. sm := &SocketMetric{}
  535. sm.SocketData = ns.s.ChannelzMetric()
  536. sm.ID = ns.id
  537. sm.RefName = ns.refName
  538. s = append(s, sm)
  539. }
  540. return s, end
  541. }
  542. func (c *channelMap) GetChannel(id int64) *ChannelMetric {
  543. cm := &ChannelMetric{}
  544. var cn *channel
  545. var ok bool
  546. c.mu.RLock()
  547. if cn, ok = c.channels[id]; !ok {
  548. // channel with id doesn't exist.
  549. c.mu.RUnlock()
  550. return nil
  551. }
  552. cm.NestedChans = copyMap(cn.nestedChans)
  553. cm.SubChans = copyMap(cn.subChans)
  554. // cn.c can be set to &dummyChannel{} when deleteSelfFromMap is called. Save a copy of cn.c when
  555. // holding the lock to prevent potential data race.
  556. chanCopy := cn.c
  557. c.mu.RUnlock()
  558. cm.ChannelData = chanCopy.ChannelzMetric()
  559. cm.ID = cn.id
  560. cm.RefName = cn.refName
  561. cm.Trace = cn.trace.dumpData()
  562. return cm
  563. }
  564. func (c *channelMap) GetSubChannel(id int64) *SubChannelMetric {
  565. cm := &SubChannelMetric{}
  566. var sc *subChannel
  567. var ok bool
  568. c.mu.RLock()
  569. if sc, ok = c.subChannels[id]; !ok {
  570. // subchannel with id doesn't exist.
  571. c.mu.RUnlock()
  572. return nil
  573. }
  574. cm.Sockets = copyMap(sc.sockets)
  575. // sc.c can be set to &dummyChannel{} when deleteSelfFromMap is called. Save a copy of sc.c when
  576. // holding the lock to prevent potential data race.
  577. chanCopy := sc.c
  578. c.mu.RUnlock()
  579. cm.ChannelData = chanCopy.ChannelzMetric()
  580. cm.ID = sc.id
  581. cm.RefName = sc.refName
  582. cm.Trace = sc.trace.dumpData()
  583. return cm
  584. }
  585. func (c *channelMap) GetSocket(id int64) *SocketMetric {
  586. sm := &SocketMetric{}
  587. c.mu.RLock()
  588. if ls, ok := c.listenSockets[id]; ok {
  589. c.mu.RUnlock()
  590. sm.SocketData = ls.s.ChannelzMetric()
  591. sm.ID = ls.id
  592. sm.RefName = ls.refName
  593. return sm
  594. }
  595. if ns, ok := c.normalSockets[id]; ok {
  596. c.mu.RUnlock()
  597. sm.SocketData = ns.s.ChannelzMetric()
  598. sm.ID = ns.id
  599. sm.RefName = ns.refName
  600. return sm
  601. }
  602. c.mu.RUnlock()
  603. return nil
  604. }
  605. type idGenerator struct {
  606. id int64
  607. }
  608. func (i *idGenerator) reset() {
  609. atomic.StoreInt64(&i.id, 0)
  610. }
  611. func (i *idGenerator) genID() int64 {
  612. return atomic.AddInt64(&i.id, 1)
  613. }