task.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "log"
  6. mu "mfw/util"
  7. "qfw/util"
  8. "regexp"
  9. "strings"
  10. "sync"
  11. "time"
  12. "github.com/robfig/cron"
  13. "go.mongodb.org/mongo-driver/bson/primitive"
  14. )
  15. /**
  16. 任务入口
  17. 全量、增量合并
  18. 更新、插入,内存清理
  19. 转换成info对象
  20. **/
  21. //项目合并对象
  22. type ProjectTask struct {
  23. InitMinTime int64 //最小时间,小于0的处理一次
  24. name string
  25. thread int //线程数
  26. //查找锁
  27. findLock sync.Mutex
  28. wg sync.WaitGroup
  29. //map锁
  30. AllIdsMapLock sync.Mutex
  31. //对应的id
  32. AllIdsMap map[string]*ID
  33. //采购单位、项目名称、项目编号
  34. mapPb, mapPn, mapPc map[string]*Key
  35. // mapPbLock, mapPnLock, mapPcLock sync.Mutex
  36. //更新或新增通道
  37. updatePool chan []map[string]interface{}
  38. savePool chan map[string]interface{}
  39. saveSign, updateSign chan bool
  40. //表名
  41. coll string
  42. //当前状态是全量还是增量
  43. currentType string //当前是跑全量还是跑增量
  44. //
  45. clearContimes int
  46. //当前时间
  47. currentTime int64
  48. //保存长度
  49. saveSize int
  50. pici int64
  51. validTime int64
  52. // LockPool chan *sync.Mutex
  53. // LockPoolLock sync.Mutex
  54. // m1, m23, m4 map[int]int
  55. // l1, l23, l4 map[int]*sync.Mutex
  56. }
  57. func NewPT() *ProjectTask {
  58. p := &ProjectTask{
  59. InitMinTime: int64(1325347200),
  60. name: "全/增量对象",
  61. thread: 4,
  62. updatePool: make(chan []map[string]interface{}, 5000),
  63. //savePool: make(chan map[string]interface{}, 2000),
  64. wg: sync.WaitGroup{},
  65. AllIdsMap: make(map[string]*ID, 5000000),
  66. mapPb: make(map[string]*Key, 1500000),
  67. mapPn: make(map[string]*Key, 5000000),
  68. mapPc: make(map[string]*Key, 5000000),
  69. saveSize: 400,
  70. saveSign: make(chan bool, 1),
  71. updateSign: make(chan bool, 1),
  72. coll: ProjectColl,
  73. validTime: int64(util.IntAllDef(Sysconfig["validdays"], 150) * 86400),
  74. }
  75. return p
  76. }
  77. var P_QL *ProjectTask
  78. //初始化全量合并对象
  79. func init() {
  80. P_QL = NewPT()
  81. go P_QL.updateAllQueue()
  82. go P_QL.clearMem()
  83. }
  84. func (p *ProjectTask) updateAllQueue() {
  85. arru := make([][]map[string]interface{}, p.saveSize)
  86. indexu := 0
  87. sp := make(chan bool, 5)
  88. for {
  89. select {
  90. case v := <-p.updatePool:
  91. arru[indexu] = v
  92. indexu++
  93. if indexu == p.saveSize {
  94. sp <- true
  95. go func(arru [][]map[string]interface{}) {
  96. defer func() {
  97. <-sp
  98. }()
  99. MongoTool.UpSertBulk(p.coll, arru...)
  100. }(arru)
  101. arru = make([][]map[string]interface{}, p.saveSize)
  102. indexu = 0
  103. }
  104. case <-time.After(1000 * time.Millisecond):
  105. if indexu > 0 {
  106. sp <- true
  107. go func(arru [][]map[string]interface{}) {
  108. defer func() {
  109. <-sp
  110. }()
  111. MongoTool.UpSertBulk(p.coll, arru...)
  112. }(arru[:indexu])
  113. arru = make([][]map[string]interface{}, p.saveSize)
  114. indexu = 0
  115. }
  116. }
  117. }
  118. }
  119. //项目合并内存更新
  120. func (p *ProjectTask) clearMem() {
  121. c := cron.New()
  122. //在内存中保留最近6个月的信息
  123. //跑全量时每4分钟跑一次,跑增量时400分钟跑一次
  124. c.AddFunc("50 0/15 * * * *", func() {
  125. if p.currentType == "ql" || p.clearContimes >= 60 {
  126. //跳过的次数清零
  127. p.clearContimes = 0
  128. //信息进入查找对比全局锁
  129. p.findLock.Lock()
  130. //defer p.findLock.Unlock()
  131. //合并进行的任务都完成
  132. p.wg.Wait()
  133. //遍历id
  134. //所有内存中的项目信息
  135. p.AllIdsMapLock.Lock()
  136. //清除计数
  137. clearNum := 0
  138. for k, v := range p.AllIdsMap {
  139. if p.currentTime-v.P.LastTime > p.validTime {
  140. clearNum++
  141. //删除id的map
  142. delete(p.AllIdsMap, k)
  143. //删除pb
  144. if v.P.Buyer != "" {
  145. ids := p.mapPb[v.P.Buyer]
  146. if ids != nil {
  147. ids.Lock.Lock()
  148. ids.Arr = deleteSlice(ids.Arr, k)
  149. if len(ids.Arr) == 0 {
  150. delete(p.mapPb, v.P.Buyer)
  151. }
  152. ids.Lock.Unlock()
  153. }
  154. }
  155. //删除mapPn
  156. for _, vn := range append([]string{v.P.ProjectName}, v.P.MPN...) {
  157. if vn != "" {
  158. ids := p.mapPn[vn]
  159. if ids != nil {
  160. ids.Lock.Lock()
  161. ids.Arr = deleteSlice(ids.Arr, k)
  162. if len(ids.Arr) == 0 {
  163. delete(p.mapPn, vn)
  164. }
  165. ids.Lock.Unlock()
  166. }
  167. }
  168. }
  169. //删除mapPc
  170. for _, vn := range append([]string{v.P.ProjectCode}, v.P.MPC...) {
  171. if vn != "" {
  172. ids := p.mapPc[vn]
  173. if ids != nil {
  174. ids.Lock.Lock()
  175. ids.Arr = deleteSlice(ids.Arr, k)
  176. if len(ids.Arr) == 0 {
  177. delete(p.mapPc, vn)
  178. }
  179. ids.Lock.Unlock()
  180. }
  181. }
  182. }
  183. v = nil
  184. }
  185. }
  186. p.AllIdsMapLock.Unlock()
  187. p.findLock.Unlock()
  188. log.Println("清除完成:", clearNum, len(p.AllIdsMap), len(p.mapPn), len(p.mapPc), len(p.mapPb))
  189. } else {
  190. p.clearContimes++
  191. }
  192. })
  193. c.Start()
  194. select {}
  195. }
  196. //全量合并
  197. func (p *ProjectTask) taskQl(udpInfo map[string]interface{}) {
  198. defer util.Catch()
  199. //1、检查pubilshtime索引
  200. db, _ := udpInfo["db"].(string)
  201. if db == "" {
  202. db = MongoTool.DbName
  203. }
  204. coll, _ := udpInfo["coll"].(string)
  205. if coll == "" {
  206. coll = ExtractColl
  207. }
  208. thread := util.IntAllDef(udpInfo["thread"], 4)
  209. if thread > 0 {
  210. p.thread = thread
  211. }
  212. q, _ := udpInfo["query"].(map[string]interface{})
  213. if q == nil {
  214. q = map[string]interface{}{}
  215. lteid, _ := udpInfo["lteid"].(string)
  216. var idmap map[string]interface{}
  217. if len(lteid) > 15 {
  218. idmap = map[string]interface{}{
  219. "$lte": StringTOBsonId(lteid),
  220. }
  221. }
  222. gtid, _ := udpInfo["gtid"].(string)
  223. if len(gtid) > 15 {
  224. if idmap == nil {
  225. idmap = map[string]interface{}{}
  226. }
  227. idmap["$gt"] = StringTOBsonId(gtid)
  228. }
  229. if idmap != nil {
  230. q["_id"] = idmap
  231. }
  232. }
  233. //生成查询语句执行
  234. log.Println("查询语句:", q)
  235. p.enter(db, coll, q)
  236. }
  237. //增量合并
  238. func (p *ProjectTask) taskZl(udpInfo map[string]interface{}) {
  239. defer util.Catch()
  240. //1、检查pubilshtime索引
  241. db, _ := udpInfo["db"].(string)
  242. if db == "" {
  243. db = MongoTool.DbName
  244. }
  245. coll, _ := udpInfo["coll"].(string)
  246. if coll == "" {
  247. coll = ExtractColl
  248. }
  249. thread := util.IntAllDef(udpInfo["thread"], 4)
  250. if thread > 0 {
  251. p.thread = thread
  252. }
  253. //开始id和结束id
  254. q, _ := udpInfo["query"].(map[string]interface{})
  255. gtid := udpInfo["gtid"].(string)
  256. lteid := udpInfo["lteid"].(string)
  257. if q == nil {
  258. q = map[string]interface{}{
  259. "_id": map[string]interface{}{
  260. "$gt": StringTOBsonId(gtid),
  261. "$lte": StringTOBsonId(lteid),
  262. },
  263. }
  264. }
  265. if q != nil {
  266. //生成查询语句执行
  267. p.enter(db, coll, q)
  268. }
  269. if udpInfo["stop"] == nil {
  270. nextNode(udpInfo, p.pici)
  271. }
  272. }
  273. func StringTOBsonId(id string) primitive.ObjectID {
  274. objectId, _ := primitive.ObjectIDFromHex(id)
  275. return objectId
  276. }
  277. //通知下个节点nextNode
  278. func nextNode(mapInfo map[string]interface{}, pici int64) {
  279. mapInfo["stype"] = "project"
  280. mapInfo["query"] = map[string]interface{}{
  281. "pici": pici,
  282. }
  283. for n, to := range toaddr {
  284. key := fmt.Sprintf("%d-%s-%d", pici, "project", n)
  285. mapInfo["key"] = key
  286. datas, _ := json.Marshal(mapInfo)
  287. node := &udpNode{datas, to, time.Now().Unix(), 0}
  288. udptaskmap.Store(key, node)
  289. udpclient.WriteUdp(datas, mu.OP_TYPE_DATA, to)
  290. }
  291. }
  292. func (p *ProjectTask) enter(db, coll string, q map[string]interface{}) {
  293. defer util.Catch()
  294. count, taskcount := 0, 0
  295. pool := make(chan bool, p.thread)
  296. log.Println("start project", q)
  297. sess := MongoTool.GetMgoConn()
  298. defer MongoTool.DestoryMongoConn(sess)
  299. infoPool := make(chan map[string]interface{}, 2000)
  300. over := make(chan bool)
  301. go func() {
  302. L:
  303. for {
  304. select {
  305. case tmp := <-infoPool:
  306. pool <- true
  307. taskcount++
  308. go func(tmp map[string]interface{}) {
  309. defer func() {
  310. <-pool
  311. }()
  312. if util.IntAll(tmp["repeat"]) == 0 {
  313. info := ParseInfo(tmp)
  314. if info != nil && !((info.pnbval == 1 && info.Buyer != "") || info.pnbval == 0) {
  315. p.currentTime = info.Publishtime
  316. p.startProjectMerge(info, tmp)
  317. }
  318. } else {
  319. //信息错误,进行更新
  320. }
  321. }(tmp)
  322. case <-over:
  323. break L
  324. }
  325. }
  326. }()
  327. ms := sess.DB(db).C(coll).Find(q).Sort("publishtime")
  328. if Sysconfig["hints"] != nil {
  329. ms.Hint(Sysconfig["hints"])
  330. }
  331. query := ms.Iter()
  332. //
  333. var lastid interface{}
  334. L:
  335. for {
  336. select {
  337. case <-queryClose:
  338. log.Println("receive interrupt sign")
  339. log.Println("close iter..", lastid, query.Cursor.Close(nil))
  340. queryCloseOver <- true
  341. break L
  342. default:
  343. tmp := make(map[string]interface{})
  344. if query.Next(&tmp) {
  345. lastid = tmp["_id"]
  346. if count%2000 == 0 {
  347. log.Println("current", count, lastid)
  348. }
  349. infoPool <- tmp
  350. count++
  351. } else {
  352. break L
  353. }
  354. }
  355. }
  356. time.Sleep(5 * time.Second)
  357. over <- true
  358. //阻塞
  359. for n := 0; n < p.thread; n++ {
  360. pool <- true
  361. }
  362. log.Println("所有线程执行完成...", count, taskcount)
  363. }
  364. var (
  365. //从标题获取项目编号
  366. titleGetPc = regexp.MustCompile("^([-0-9a-zA-Z第号采招政询电审竞#]{8,}[-0-9a-zA-Z#]+)")
  367. titleGetPc1 = regexp.MustCompile("[\\[【((](.{0,6}(编号|编码|项号|包号|代码|标段?号)[::为])?([-0-9a-zA-Z第号采招政询电审竞#]{5,}([\\[\\]()()][-0-9a-zA-Z第号采招审竞#]+[\\[\\]()()][-0-9a-zA-Z第号采招审竞#]+)?)[\\]】))]")
  368. titleGetPc2 = regexp.MustCompile("([-0-9a-zA-Z第号采政招询电审竞#]{8,}[-0-9a-zA-Z#]+)(.{0,5}公告)?$")
  369. //项目编号过滤
  370. pcReplace = regexp.MustCompile("([\\[【((〖〔《{﹝{](重|第?[二三四再]次.{0,4})[\\]】))〗〕》}﹞}])$|[\\[\\]【】()()〖〗〔〕《》{}﹝﹞-;{}–  ]+|(号|重|第?[二三四五再]次(招标)?)$|[ __]+|((采购)?项目|采购(项目)?)$")
  371. //项目编号只是数字或只是字母4个以下
  372. StrOrNum = regexp.MustCompile("^[0-9_-]{1,4}$|^[a-zA-Z_-]{1,4}$")
  373. //纯数字或纯字母
  374. StrOrNum2 = regexp.MustCompile("^[0-9_-]+$|^[a-zA-Z_-]+$")
  375. )
  376. func ParseInfo(tmp map[string]interface{}) (info *Info) {
  377. bys, _ := json.Marshal(tmp)
  378. var thisinfo *Info
  379. json.Unmarshal(bys, &thisinfo)
  380. if thisinfo == nil {
  381. return nil
  382. }
  383. if len(thisinfo.Topscopeclass) == 0 {
  384. thisinfo.Topscopeclass = []string{}
  385. }
  386. if len(thisinfo.Subscopeclass) == 0 {
  387. thisinfo.Subscopeclass = []string{}
  388. }
  389. //从标题中查找项目编号
  390. res := titleGetPc.FindStringSubmatch(thisinfo.Title)
  391. if len(res) > 1 && len(res[1]) > 6 && thisinfo.ProjectCode != res[1] && !numCheckPc.MatchString(res[1]) && !_zimureg1.MatchString(res[1]) {
  392. thisinfo.PTC = res[1]
  393. } else {
  394. res = titleGetPc1.FindStringSubmatch(thisinfo.Title)
  395. if len(res) > 3 && len(res[3]) > 6 && thisinfo.ProjectCode != res[3] && !numCheckPc.MatchString(res[3]) && !_zimureg1.MatchString(res[3]) {
  396. thisinfo.PTC = res[3]
  397. } else {
  398. res = titleGetPc2.FindStringSubmatch(thisinfo.Title)
  399. if len(res) > 1 && len(res[1]) > 6 && thisinfo.ProjectCode != res[1] && !numCheckPc.MatchString(res[1]) && !_zimureg1.MatchString(res[1]) {
  400. thisinfo.PTC = res[1]
  401. }
  402. }
  403. }
  404. if thisinfo.ProjectName != "" && len([]rune(thisinfo.ProjectName)) > 0 {
  405. thisinfo.ProjectName = pcReplace.ReplaceAllString(thisinfo.ProjectName, "")
  406. if thisinfo.ProjectName != "" {
  407. thisinfo.pnbval++
  408. }
  409. }
  410. if thisinfo.ProjectCode != "" || thisinfo.PTC != "" {
  411. if thisinfo.ProjectCode != "" {
  412. thisinfo.ProjectCode = pcReplace.ReplaceAllString(thisinfo.ProjectCode, "")
  413. if thisinfo.pnbval == 0 && len([]rune(thisinfo.ProjectCode)) < 5 {
  414. thisinfo.ProjectCode = StrOrNum.ReplaceAllString(thisinfo.ProjectCode, "")
  415. }
  416. } else {
  417. thisinfo.PTC = pcReplace.ReplaceAllString(thisinfo.PTC, "")
  418. if thisinfo.pnbval == 0 && len([]rune(thisinfo.PTC)) < 5 {
  419. thisinfo.PTC = StrOrNum.ReplaceAllString(thisinfo.PTC, "")
  420. }
  421. }
  422. if thisinfo.ProjectCode != "" || thisinfo.PTC != "" {
  423. thisinfo.pnbval++
  424. }
  425. }
  426. if thisinfo.ProjectCode == thisinfo.PTC || strings.Index(thisinfo.ProjectCode, thisinfo.PTC) > -1 {
  427. thisinfo.PTC = ""
  428. }
  429. if thisinfo.Buyer != "" && len([]rune(thisinfo.Buyer)) > 2 {
  430. thisinfo.pnbval++
  431. } else {
  432. thisinfo.Buyer = ""
  433. }
  434. //winners整理
  435. winner, _ := tmp["winner"].(string)
  436. m1 := map[string]bool{}
  437. winners := []string{}
  438. if winner != "" {
  439. m1[winner] = true
  440. winners = append(winners, winner)
  441. }
  442. packageM, _ := tmp["package"].(map[string]interface{})
  443. if packageM != nil {
  444. thisinfo.HasPackage = true
  445. for _, p := range packageM {
  446. pm, _ := p.(map[string]interface{})
  447. pw, _ := pm["winner"].(string)
  448. if pw != "" && !m1[pw] {
  449. m1[pw] = true
  450. winners = append(winners, pw)
  451. }
  452. }
  453. }
  454. thisinfo.Winners = winners
  455. thisinfo.LenPC = len([]rune(thisinfo.ProjectCode))
  456. thisinfo.LenPTC = len([]rune(thisinfo.PTC))
  457. thisinfo.LenPN = len([]rune(thisinfo.ProjectName))
  458. return thisinfo
  459. }
  460. //从数组中删除元素
  461. func deleteSlice(arr []string, v string) []string {
  462. for k, v1 := range arr {
  463. if v1 == v {
  464. return append(arr[:k], arr[k+1:]...)
  465. }
  466. }
  467. return arr
  468. }
  469. // if taskcount > 0 && taskcount%50000 == 0 { //歇歇
  470. // log.Println("pause start..", taskcount)
  471. // for n := 0; n < p.thread; n++ {
  472. // pool <- true
  473. // }
  474. // for n := 0; n < p.thread; n++ {
  475. // <-pool
  476. // }
  477. // log.Println("pause over..")
  478. // }
  479. //lastid = tmp["_id"]
  480. //tmp = make(map[string]interface{})
  481. // if count > 40000 {
  482. // query.Close()
  483. // break
  484. // }
  485. //over++
  486. //func (p *ProjectTask) saveQueue() {
  487. // arr := make([]map[string]interface{}, p.saveSize)
  488. // indexs := 0
  489. // for {
  490. // select {
  491. // case <-p.saveSign:
  492. // if indexs > 0 {
  493. // MongoTool.SaveBulk(p.coll, arr[:indexs]...)
  494. // arr = make([]map[string]interface{}, p.saveSize)
  495. // indexs = 0
  496. // }
  497. // p.updateSign <- true
  498. // case v := <-p.savePool:
  499. // arr[indexs] = v
  500. // indexs++
  501. // if indexs == p.saveSize {
  502. // MongoTool.SaveBulk(p.coll, arr...)
  503. // arr = make([]map[string]interface{}, p.saveSize)
  504. // indexs = 0
  505. // }
  506. // case <-time.After(100 * time.Millisecond):
  507. // if indexs > 0 {
  508. // MongoTool.SaveBulk(p.coll, arr[:indexs]...)
  509. // arr = make([]map[string]interface{}, p.saveSize)
  510. // indexs = 0
  511. // }
  512. // }
  513. // }
  514. //}
  515. ////项目保存和更新通道
  516. //func (p *ProjectTask) updateQueue() {
  517. // arru := make([][]map[string]interface{}, p.saveSize)
  518. // indexu := 0
  519. // for {
  520. // select {
  521. // case v := <-p.updatePool:
  522. // arru[indexu] = v
  523. // indexu++
  524. // if indexu == p.saveSize {
  525. // //更新之前先保存
  526. // p.saveSign <- true
  527. // <-p.updateSign
  528. // MongoTool.UpdateBulk(p.coll, arru...)
  529. // arru = make([][]map[string]interface{}, p.saveSize)
  530. // indexu = 0
  531. // }
  532. // case <-time.After(100 * time.Millisecond):
  533. // if indexu > 0 {
  534. // p.saveSign <- true
  535. // <-p.updateSign
  536. // MongoTool.UpdateBulk(p.coll, arru[:indexu]...)
  537. // arru = make([][]map[string]interface{}, p.saveSize)
  538. // indexu = 0
  539. // }
  540. // }
  541. // }
  542. //}
  543. //func (p *ProjectTask) ConCurrentLock(n1, n2, n3, n4 int) {
  544. // var lock *sync.Mutex
  545. // p.LockPoolLock.Lock()
  546. // if p.m1[n1] > 0 || p.m23[n2] > 0 || p.m23[n3] > 0 || p.m4[n4] > 0 {
  547. // if p.l1[n1] != nil {
  548. // lock = p.l1[n1]
  549. // } else if p.l23[n2] != nil {
  550. // lock = p.l23[n2]
  551. // } else if p.l23[n3] != nil {
  552. // lock = p.l23[n3]
  553. // } else if p.l4[n4] != nil {
  554. // lock = p.l4[n4]
  555. // }
  556. // } else {
  557. // lock = <-p.LockPool
  558. // }
  559. // if n1 > 0 {
  560. // p.m1[n1]++
  561. // p.l1[n1] = lock
  562. // }
  563. // if n2 > 0 {
  564. // p.m23[n2]++
  565. // p.l23[n2] = lock
  566. // }
  567. // if n3 > 0 {
  568. // p.m23[n3]++
  569. // p.l23[n3] = lock
  570. // }
  571. // if n4 > 0 {
  572. // p.m4[n4]++
  573. // p.l4[n4] = lock
  574. // }
  575. // p.LockPoolLock.Unlock()
  576. // lock.Lock()
  577. //}
  578. //func (p *ProjectTask) ConCurrentUnLock(n1, n2, n3, n4 int) {
  579. // var lock1 *sync.Mutex
  580. // p.LockPoolLock.Lock()
  581. // if p.l1[n1] != nil {
  582. // lock1 = p.l1[n1]
  583. // } else if p.l23[n2] != nil {
  584. // lock1 = p.l23[n2]
  585. // } else if p.l23[n3] != nil {
  586. // lock1 = p.l23[n3]
  587. // } else if p.l4[n4] != nil {
  588. // lock1 = p.l4[n4]
  589. // }
  590. // if p.m1[n1] > 0 {
  591. // p.m1[n1]--
  592. // if p.m1[n1] == 0 {
  593. // p.l1[n1] = nil
  594. // }
  595. // }
  596. // if p.m23[n2] > 0 {
  597. // p.m23[n2]--
  598. // if p.m23[n2] == 0 {
  599. // p.l23[n2] = nil
  600. // }
  601. // }
  602. // if p.m23[n3] > 0 {
  603. // p.m23[n3]--
  604. // if p.m23[n3] == 0 {
  605. // p.l23[n3] = nil
  606. // }
  607. // }
  608. // if p.m4[n4] > 0 {
  609. // p.m4[n4]--
  610. // if p.m4[n4] == 0 {
  611. // p.l4[n4] = nil
  612. // }
  613. // }
  614. // p.LockPoolLock.Unlock()
  615. // lock1.Unlock()
  616. //}