column_charge.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. package charge
  2. import (
  3. "bytes"
  4. "context"
  5. "fmt"
  6. "strconv"
  7. "time"
  8. model "go-common/app/job/main/growup/model/charge"
  9. task "go-common/app/job/main/growup/service"
  10. "go-common/library/log"
  11. xtime "go-common/library/time"
  12. "golang.org/x/sync/errgroup"
  13. )
  14. func (s *Service) columnCharges(c context.Context, date time.Time, ch chan []*model.Column) (err error) {
  15. defer func() {
  16. close(ch)
  17. }()
  18. var id int64
  19. for {
  20. var charges []*model.Column
  21. charges, err = s.dao.ColumnCharge(c, date, id, _limitSize, "column_daily_charge")
  22. if err != nil {
  23. return
  24. }
  25. ch <- charges
  26. if len(charges) < _limitSize {
  27. break
  28. }
  29. id = charges[len(charges)-1].ID
  30. }
  31. return
  32. }
  33. func (s *Service) handleColumn(c context.Context, date time.Time,
  34. dailyChannel chan []*model.Column) (weeklyMap, monthlyMap map[int64]*model.Column, statisMap map[int64]*model.ColumnStatis, err error) {
  35. var eg errgroup.Group
  36. weeklyMap = make(map[int64]*model.Column)
  37. monthlyMap = make(map[int64]*model.Column)
  38. statisMap = make(map[int64]*model.ColumnStatis)
  39. eg.Go(func() (err error) {
  40. weekly, err := s.getColumnCharge(c, getStartWeeklyDate(date), "column_weekly_charge")
  41. if err != nil {
  42. log.Error("s.GetColumnCharge(column_weekly_charge) error(%v)", err)
  43. return
  44. }
  45. for _, cm := range weekly {
  46. weeklyMap[cm.AID] = cm
  47. }
  48. return
  49. })
  50. eg.Go(func() (err error) {
  51. monthly, err := s.getColumnCharge(c, getStartMonthlyDate(date), "column_monthly_charge")
  52. if err != nil {
  53. log.Error("s.GetColumnCharge(column_monthly_charge) error(%v)", err)
  54. return
  55. }
  56. for _, cm := range monthly {
  57. monthlyMap[cm.AID] = cm
  58. }
  59. return
  60. })
  61. eg.Go(func() (err error) {
  62. statis, err := s.getCmStatisMap(c)
  63. if err != nil {
  64. log.Error("s.getCmStatisMap error(%v)", err)
  65. }
  66. for _, cm := range statis {
  67. statisMap[cm.AID] = cm
  68. }
  69. return
  70. })
  71. if err = eg.Wait(); err != nil {
  72. log.Error("handleColumn eg.Wait error(%v)", err)
  73. return
  74. }
  75. s.calColumns(date, weeklyMap, monthlyMap, statisMap, dailyChannel)
  76. return
  77. }
  78. func (s *Service) calColumns(date time.Time, weeklyMap, monthlyMap map[int64]*model.Column, statisMap map[int64]*model.ColumnStatis, dailyChannel chan []*model.Column) {
  79. for daily := range dailyChannel {
  80. s.calColumn(date, daily, weeklyMap, monthlyMap, statisMap)
  81. }
  82. }
  83. func (s *Service) calColumn(date time.Time, daily []*model.Column, weeklyMap, monthlyMap map[int64]*model.Column, statisMap map[int64]*model.ColumnStatis) {
  84. for _, charge := range daily {
  85. if weekly, ok := weeklyMap[charge.AID]; ok {
  86. updateColumnCharge(weekly, charge)
  87. } else {
  88. weeklyMap[charge.AID] = addColumnCharge(charge, startWeeklyDate)
  89. }
  90. if monthly, ok := monthlyMap[charge.AID]; ok {
  91. updateColumnCharge(monthly, charge)
  92. } else {
  93. monthlyMap[charge.AID] = addColumnCharge(charge, startMonthlyDate)
  94. }
  95. if statis, ok := statisMap[charge.AID]; ok {
  96. updateColumnStatis(statis, charge)
  97. } else {
  98. statisMap[charge.AID] = addColumnStatis(charge)
  99. }
  100. }
  101. }
  102. func addColumnCharge(daily *model.Column, fixDate time.Time) *model.Column {
  103. return &model.Column{
  104. AID: daily.AID,
  105. MID: daily.MID,
  106. Title: daily.Title,
  107. TagID: daily.TagID,
  108. Words: daily.Words,
  109. UploadTime: daily.UploadTime,
  110. IncCharge: daily.IncCharge,
  111. Date: xtime.Time(fixDate.Unix()),
  112. DBState: _dbInsert,
  113. }
  114. }
  115. func updateColumnCharge(origin, daily *model.Column) {
  116. origin.IncCharge += daily.IncCharge
  117. origin.DBState = _dbUpdate
  118. }
  119. func addColumnStatis(daily *model.Column) *model.ColumnStatis {
  120. return &model.ColumnStatis{
  121. AID: daily.AID,
  122. MID: daily.MID,
  123. Title: daily.Title,
  124. TagID: daily.TagID,
  125. UploadTime: daily.UploadTime,
  126. TotalCharge: daily.IncCharge,
  127. DBState: _dbInsert,
  128. }
  129. }
  130. func updateColumnStatis(statis *model.ColumnStatis, daily *model.Column) {
  131. statis.TotalCharge += daily.IncCharge
  132. statis.DBState = _dbUpdate
  133. }
  134. func (s *Service) getColumnCharge(c context.Context, date time.Time, table string) (cms []*model.Column, err error) {
  135. cms = make([]*model.Column, 0)
  136. var id int64
  137. for {
  138. var cm []*model.Column
  139. cm, err = s.dao.ColumnCharge(c, date, id, _limitSize, table)
  140. if err != nil {
  141. return
  142. }
  143. cms = append(cms, cm...)
  144. if len(cm) < _limitSize {
  145. break
  146. }
  147. id = cm[len(cm)-1].ID
  148. }
  149. return
  150. }
  151. func (s *Service) getCmStatisMap(c context.Context) (cms []*model.ColumnStatis, err error) {
  152. cms = make([]*model.ColumnStatis, 0)
  153. var id int64
  154. for {
  155. var cm []*model.ColumnStatis
  156. cm, err = s.dao.CmStatis(c, id, _limitSize)
  157. if err != nil {
  158. return
  159. }
  160. cms = append(cms, cm...)
  161. if len(cm) < _limitSize {
  162. break
  163. }
  164. id = cm[len(cm)-1].ID
  165. }
  166. return
  167. }
  168. func (s *Service) cmDBStore(c context.Context, table string, cmMap map[int64]*model.Column) error {
  169. insert, update := make([]*model.Column, _batchSize), make([]*model.Column, _batchSize)
  170. insertIndex, updateIndex := 0, 0
  171. for _, charge := range cmMap {
  172. if charge.DBState == _dbInsert {
  173. insert[insertIndex] = charge
  174. insertIndex++
  175. } else if charge.DBState == _dbUpdate {
  176. update[updateIndex] = charge
  177. updateIndex++
  178. }
  179. if insertIndex >= _batchSize {
  180. _, err := s.cmBatchInsert(c, insert[:insertIndex], table)
  181. if err != nil {
  182. log.Error("s.cmBatchInsert error(%v)", err)
  183. return err
  184. }
  185. insertIndex = 0
  186. }
  187. if updateIndex >= _batchSize {
  188. _, err := s.cmBatchInsert(c, update[:updateIndex], table)
  189. if err != nil {
  190. log.Error("s.cmBatchInsert error(%v)", err)
  191. return err
  192. }
  193. updateIndex = 0
  194. }
  195. }
  196. if insertIndex > 0 {
  197. _, err := s.cmBatchInsert(c, insert[:insertIndex], table)
  198. if err != nil {
  199. log.Error("s.cmBatchInsert error(%v)", err)
  200. return err
  201. }
  202. }
  203. if updateIndex > 0 {
  204. _, err := s.cmBatchInsert(c, update[:updateIndex], table)
  205. if err != nil {
  206. log.Error("s.cmBatchInsert error(%v)", err)
  207. return err
  208. }
  209. }
  210. return nil
  211. }
  212. func assembleCmCharge(charges []*model.Column) (vals string) {
  213. var buf bytes.Buffer
  214. for _, row := range charges {
  215. buf.WriteString("(")
  216. buf.WriteString(strconv.FormatInt(row.AID, 10))
  217. buf.WriteByte(',')
  218. buf.WriteString(strconv.FormatInt(row.MID, 10))
  219. buf.WriteByte(',')
  220. buf.WriteString(strconv.FormatInt(row.TagID, 10))
  221. buf.WriteByte(',')
  222. buf.WriteString(strconv.FormatInt(row.IncCharge, 10))
  223. buf.WriteByte(',')
  224. buf.WriteString("'" + row.Date.Time().Format(_layout) + "'")
  225. buf.WriteByte(',')
  226. buf.WriteString(strconv.FormatInt(row.UploadTime, 10))
  227. buf.WriteString(")")
  228. buf.WriteByte(',')
  229. }
  230. if buf.Len() > 0 {
  231. buf.Truncate(buf.Len() - 1)
  232. }
  233. vals = buf.String()
  234. buf.Reset()
  235. return
  236. }
  237. func (s *Service) cmBatchInsert(c context.Context, charges []*model.Column, table string) (rows int64, err error) {
  238. vals := assembleCmCharge(charges)
  239. rows, err = s.dao.InsertCmChargeTable(c, vals, table)
  240. return
  241. }
  242. func (s *Service) cmStatisDBStore(c context.Context, statisMap map[int64]*model.ColumnStatis) error {
  243. insert, update := make([]*model.ColumnStatis, _batchSize), make([]*model.ColumnStatis, _batchSize)
  244. insertIndex, updateIndex := 0, 0
  245. for _, charge := range statisMap {
  246. if charge.DBState == _dbInsert {
  247. insert[insertIndex] = charge
  248. insertIndex++
  249. } else if charge.DBState == _dbUpdate {
  250. update[updateIndex] = charge
  251. updateIndex++
  252. }
  253. if insertIndex >= _batchSize {
  254. _, err := s.cmStatisBatchInsert(c, insert[:insertIndex])
  255. if err != nil {
  256. log.Error("s.cmStatisBatchInsert error(%v)", err)
  257. return err
  258. }
  259. insertIndex = 0
  260. }
  261. if updateIndex >= _batchSize {
  262. _, err := s.cmStatisBatchInsert(c, update[:updateIndex])
  263. if err != nil {
  264. log.Error("s.cmStatisBatchInsert error(%v)", err)
  265. return err
  266. }
  267. updateIndex = 0
  268. }
  269. }
  270. if insertIndex > 0 {
  271. _, err := s.cmStatisBatchInsert(c, insert[:insertIndex])
  272. if err != nil {
  273. log.Error("s.cmStatisBatchInsert error(%v)", err)
  274. return err
  275. }
  276. }
  277. if updateIndex > 0 {
  278. _, err := s.cmStatisBatchInsert(c, update[:updateIndex])
  279. if err != nil {
  280. log.Error("s.cmStatisBatchInsert error(%v)", err)
  281. return err
  282. }
  283. }
  284. return nil
  285. }
  286. func assembleCmStatis(statis []*model.ColumnStatis) (vals string) {
  287. var buf bytes.Buffer
  288. for _, row := range statis {
  289. buf.WriteString("(")
  290. buf.WriteString(strconv.FormatInt(row.AID, 10))
  291. buf.WriteByte(',')
  292. buf.WriteString(strconv.FormatInt(row.MID, 10))
  293. buf.WriteByte(',')
  294. buf.WriteString(strconv.FormatInt(row.TagID, 10))
  295. buf.WriteByte(',')
  296. buf.WriteString(strconv.FormatInt(row.TotalCharge, 10))
  297. buf.WriteByte(',')
  298. buf.WriteString("'" + time.Unix(row.UploadTime, 0).Format(_layoutSec) + "'")
  299. buf.WriteString(")")
  300. buf.WriteByte(',')
  301. }
  302. if buf.Len() > 0 {
  303. buf.Truncate(buf.Len() - 1)
  304. }
  305. vals = buf.String()
  306. buf.Reset()
  307. return
  308. }
  309. func (s *Service) cmStatisBatchInsert(c context.Context, statis []*model.ColumnStatis) (rows int64, err error) {
  310. vals := assembleCmStatis(statis)
  311. rows, err = s.dao.InsertCmStatisBatch(c, vals)
  312. return
  313. }
  314. // CheckTaskColumn check column count by date
  315. func (s *Service) CheckTaskColumn(c context.Context, date string) (err error) {
  316. defer func() {
  317. task.GetTaskService().SetTaskStatus(c, task.TaskCmCharge, date, err)
  318. }()
  319. count, err := s.dao.CountCmDailyCharge(c, date)
  320. if count == 0 {
  321. err = fmt.Errorf("date(%s) column_daily_charge = 0", date)
  322. }
  323. return
  324. }