Compare commits

...

450 Commits

Author SHA1 Message Date
innov a1fa8b22de ADD file via upload 2022-03-09 16:19:43 +08:00
bandl a9fac2572b fix(doc): fix redme image err 2022-02-23 18:08:05 +08:00
bandl 57caa66ef8
!103 更新文档
Merge pull request !103 from bandl/feat-doc-update
2022-02-23 05:40:30 +00:00
bandl d254a71560 feat(doc): update doc 2022-02-23 13:39:27 +08:00
bandl 07dd0f8874
!102 修复 dao 的测试错误
Merge pull request !102 from bandl/fix-dao-test
2022-02-23 05:36:52 +00:00
bandl dafffdde2c fix(dao): fix dao test err 2022-02-23 13:34:10 +08:00
bandl c6b14ced27 !101 feat-channex
Merge pull request !101 from bandl/feat-storage-channelx
2021-11-30 10:55:07 +00:00
bandl b87799a88e feat(README): update Readme 2021-11-30 18:54:32 +08:00
bandl dcfae2353b test(dao-channelX): add dao channelX test 2021-11-30 18:54:32 +08:00
bandl bf0c03a77f feat(dao-channelx): add dao channelx 2021-11-30 18:54:32 +08:00
bandl a57eab1184 test(channex): add channelx test 2021-11-30 18:54:32 +08:00
bandl ef4cbb0cee f 2021-11-30 18:54:32 +08:00
bandl f62a59b551 feat(structure): add channelx 2021-11-29 23:35:18 +08:00
bandl a949ab2edc chore(mock): update mock 2021-11-29 23:34:14 +08:00
bandl 7ac9651ef3 fix(lru): add key update length 2021-11-29 16:11:28 +08:00
bandl 19e1bb59a3 test(channelx): add channelx test 2021-11-29 00:16:17 +08:00
bandl c381c57374 feat(structure-channelx): add channelx 2021-11-29 00:16:04 +08:00
bandl 3f337dba9b chore(dao-service): update dao service 2021-11-28 20:11:21 +08:00
bandl a37097b3dd !100 修复 stringx 的一些 bug
Merge pull request !100 from bandl/fix-dao-stringx
2021-11-28 11:50:29 +00:00
bandl d90c05296a test(dao-stringx): update GetSet 2021-11-28 19:47:23 +08:00
bandl 2a556a9db6 fix(structure-stringx): fix GetSet set init nil key 2021-11-28 19:47:08 +08:00
bandl c0da22ef6f test(dao-stringx): add test TestDao_GetRange 2021-11-28 19:33:25 +08:00
bandl cf4b24ea86 fix(value): add fix value get range slice 2021-11-28 19:32:59 +08:00
bandl 953daca82c !99 修复 Stringx 的测试中的 warning
Merge pull request !99 from Pyroo/dao-stringx-test
2021-11-27 11:23:49 +00:00
Pyroo 5974dadd3e fix(storage-stringx): fix warning 2021-11-25 20:50:57 +08:00
bandl 1baac521fa !98 添加 Stringx 的测试
Merge pull request !98 from Pyroo/test-dao-stringx
2021-11-25 12:37:25 +00:00
Pyroo d6792444a7 test(storage-stringx): add stringx test 2021-11-25 20:28:53 +08:00
bandl 64a02b642e !97 完成 setx 测试
Merge pull request !97 from bandl/feat-dao-setx
2021-11-21 15:11:37 +00:00
bandl a5ef559e14 feat(dao-external): add external mock 2021-11-21 23:10:14 +08:00
bandl 0c8a17b21d test(setx): add setx test 2021-11-21 23:09:55 +08:00
bandl 0207878507 fix(setx): fix make cap 2021-11-21 23:09:40 +08:00
bandl 813b48b650 !96 添加 hashx 测试
Merge pull request !96 from bandl/test-dao-hashx
2021-11-18 11:03:32 +00:00
bandl cdd26736a5 feat(dao-hashx): add dao hashx test 2021-11-18 18:59:15 +08:00
bandl 40afd8057d fix(hashx): fix HIncrBy err catch 2021-11-18 18:58:35 +08:00
bandl 08bc1892df chore(proto): update proto 2021-11-18 17:05:03 +08:00
bandl 5e89f37e40 !95 add dao test stringx
Merge pull request !95 from bandl/test-dao-mock
2021-11-18 07:36:48 +00:00
bandl 6b2f3fb3be test(dao-stringx): add dao stringx test 2021-11-18 15:35:21 +08:00
bandl 499322c080 chore(mock): update mock 2021-11-18 14:54:42 +08:00
bandl e5f217b3b0 teat(storage-gateway): add gateway mock 2021-11-18 14:54:27 +08:00
bandl 113185d17c feat(storage-gateway): add storage gateway mock 2021-11-18 14:54:03 +08:00
bandl 981a3341ef !94 添加 setx 接口
Merge pull request !94 from bandl/feat-storage-setx
2021-11-16 06:44:29 +00:00
bandl af6426f83b feay(storage-dao): add setx type dao 2021-11-16 00:19:18 +08:00
bandl d68209c94c feat(external-gateway): add external gateway call 2021-11-16 00:19:18 +08:00
bandl 60cf8f5eb1 test(structure-hashx): add hashx range test 2021-11-16 00:19:18 +08:00
bandl 594f8acf32 feat(structure-hashx): add hashx range 2021-11-16 00:19:18 +08:00
bandl 366793d955 chore(proto): update proto 2021-11-16 00:19:18 +08:00
bandl 5105a62bca test(hashx): add unsafe.Point test 2021-11-13 20:04:21 +08:00
bandl 400d620aa4 test(lru-worker): update lru worker test 2021-11-11 23:00:21 +08:00
bandl 25be4a1509 test(hash-endpoint): update hash endpoint test 2021-11-11 23:00:04 +08:00
bandl 60de1a6ae9 chore(service): update service 2021-11-11 22:46:39 +08:00
bandl 55204575d7 feat(temp): update service temp to event2 2021-11-11 22:46:20 +08:00
bandl 2f81eab981 feat(lru, single service): update event2 2021-11-11 22:39:50 +08:00
bandl 3eb515325d feat(lru): update lru event2 2021-11-11 22:32:14 +08:00
bandl 3f3b208db1 test(event2): add event2 test 2021-11-11 22:24:28 +08:00
bandl 8b8fd58c09 feat(event2): add event2 2021-11-11 22:24:17 +08:00
bandl 62d3105273 doc(event): add event2.0 doc 2021-11-10 17:38:20 +08:00
bandl 51bd9b242f fix(hash-endpoint): tranport to endpoint 2021-11-07 21:57:22 +08:00
bandl f6eaae71b9 chore(service): update service 2021-11-07 21:49:34 +08:00
bandl 921078c61d chore(proto): update proto 2021-11-07 20:46:22 +08:00
bandl c8ef4c6e46 !93 doc(storage): update storage
Merge pull request !93 from bandl/auto-5261189-master-1636186822154
2021-11-06 08:20:46 +00:00
bandl c6273d084e doc(storage): update storage 2021-11-06 16:20:15 +08:00
bandl fd605d125f !92 doc(storage): add storage icon
Merge pull request !92 from bandl/auto-5261189-master-1636177701995
2021-11-06 05:49:01 +00:00
bandl c9dcb41cad doc(storage): add storage icon 2021-11-06 13:48:17 +08:00
bandl f7bb695e82 !91 doc(storage): fix url
Merge pull request !91 from bandl/auto-5261189-master-1636124592092
2021-11-05 15:03:34 +00:00
bandl 4e6c2ed22a doc(storage): fix url 2021-11-05 23:03:08 +08:00
bandl 0c08e40667 !90 doc(Redeme): fix url !
Merge pull request !90 from bandl/auto-5261189-master-1636124488904
2021-11-05 15:01:51 +00:00
bandl 7fa66abbf0 doc(Redeme): fix url ! 2021-11-05 23:01:24 +08:00
bandl a910e4af21 !89 添加开发者文档
Merge pull request !89 from bandl/doc-developer-doc
2021-11-05 14:59:50 +00:00
bandl 51914aea8a doc(storage): add developer doc 2021-11-05 22:58:59 +08:00
bandl bbfd32cebc !88 完成
Merge pull request !88 from bandl/feat-structure-hashx
2021-11-05 12:51:13 +00:00
bandl 44bd5bc7cd doc(readme): over hashx 2021-11-05 20:48:34 +08:00
bandl fcdb2310fe feat(storage-dao): add hashx 2021-11-05 20:44:09 +08:00
bandl 222bcc4eea chore(service): update service 2021-11-05 20:43:56 +08:00
bandl c3cff03b2b test(structure-hashx): add hashx test 2021-11-05 16:36:18 +08:00
bandl 06baf3993d feat(hashx-interface): add hash interface 2021-11-05 16:36:00 +08:00
bandl 976215ee10 feat(structure-hashx): add hashx 2021-11-05 16:34:50 +08:00
bandl 778d5152c8 perf(incr): option incr to values 2021-11-05 14:41:39 +08:00
bandl 5ce350f115 fix(linces): update license 2021-11-04 21:35:09 +08:00
bandl 047c910278 chore(service): update service 2021-11-04 20:36:42 +08:00
bandl dcada2f2fe feat(shell): add parse proto map 2021-11-04 20:33:37 +08:00
bandl 88774daede chore(proto): update proto 2021-11-04 20:28:42 +08:00
bandl 344c136586 feat(yaml): add hashx yaml 2021-11-04 19:18:56 +08:00
bandl 4c9ab82123 !87 test(structure-val): add perf test
Merge pull request !87 from bandl/auto-5261189-master-1636014762802
2021-11-04 08:33:07 +00:00
bandl 2ed75832ba test(structure-val): add perf test 2021-11-04 16:32:17 +08:00
bandl 0f1142d434 perf(structure-value): perf set bit 2021-11-04 16:31:55 +08:00
bandl b6dedfa384 !86 添加 docker 安装,以及描述
Merge pull request !86 from bandl/docker-build
2021-11-03 16:03:03 +00:00
bandl 0f2b73e932 doc(readme): add v1 readme 2021-11-04 00:01:14 +08:00
bandl 2f46dfaa2e feat(icon): add icon 2021-11-04 00:01:14 +08:00
bandl c867665b60 feat(conf): update conf 2021-11-04 00:01:14 +08:00
bandl b91966709b feat(dockerfile): add docker file
f
2021-11-04 00:00:17 +08:00
bandl 47cdf0859b !85 fix(proto): fix proto key err
Merge pull request !85 from bandl/auto-5261189-master-1635925021767
2021-11-03 07:37:57 +00:00
bandl 0b9230094a fix(proto): fix proto key err 2021-11-03 15:36:55 +08:00
bandl eccfd6a439 !84 aof
Merge pull request !84 from bandl/feat-recover-aof
2021-11-03 04:42:21 +00:00
bandl f5c3b0e1db fat(ttl): add permanent storage 2021-11-03 12:40:58 +08:00
bandl 5ee502021d feat(eooorx): update errorx key base 2021-11-02 21:34:23 +08:00
bandl 9fed552380 feat(storage): recver lru by aof 2021-11-02 21:19:35 +08:00
bandl 7d9081ce8e chore(service): updater dao service 2021-11-02 20:35:45 +08:00
bandl 4ca09febb4 feat(shell): add recover aof 2021-11-02 20:35:28 +08:00
bandl be528cbb6d !83 更新 mod 号为 wheat-os
Merge pull request !83 from bandl/refactor-mod
2021-11-02 06:46:09 +00:00
bandl 70b23849bc refactor(mod): gitee.com/wheat-os 2021-11-02 14:45:08 +08:00
bandl 99133bf7ea !82 fix-aof
Merge pull request !82 from bandl/fix-aof-nil
2021-11-02 05:03:07 +00:00
bandl 1ca43cde6c fix(aof): fix aof is nil 2021-11-02 13:02:02 +08:00
bandl de59f13234 !81 add-AOF
Merge pull request !81 from bandl/feat-storage-aof
2021-11-01 16:00:57 +00:00
bandl 72add38cee chore(service): update service 2021-11-01 23:55:12 +08:00
bandl 3b61f55fe3 feat(service): add aof service 2021-11-01 23:48:48 +08:00
bandl 6fc2417de2 feat(conf): add aof conf 2021-11-01 23:48:09 +08:00
bandl 7aa39979f0 test(aof): update test 2021-11-01 22:51:43 +08:00
bandl 4ffa91ac6a feat(aof): add aof log 2021-11-01 22:51:43 +08:00
bandl 170ba44d2d chore(aof): update aof codec 2021-11-01 21:55:50 +08:00
bandl ce888a1d0e test(aof): add codec test 2021-11-01 17:38:54 +08:00
bandl 787003d95a chore(service): update gen service 2021-11-01 17:36:35 +08:00
bandl 27542cf898 feat(shell): add gen aof codec 2021-11-01 17:35:59 +08:00
bandl 3bcd154177 feat(proto): add new key base 2021-11-01 15:28:52 +08:00
bandl bed3f1893a !80 修复 skiplist 的 bug
Merge pull request !80 from bandl/fix-skiplist
2021-10-28 06:52:59 +00:00
bandl 200623bd29 test(client): add storage client 2021-10-28 12:00:08 +08:00
bandl dce8739514 fix(work): storage worker 2021-10-28 12:00:08 +08:00
bandl 686c032f34 fix(lru-worker, skiplist): fix skiplist insert err, perf lru 2021-10-28 12:00:08 +08:00
bandl 41e282de5d !79 feat-storage-template
Merge pull request !79 from bandl/feat-make-service
2021-10-27 16:28:58 +00:00
bandl 23b13afc86 doc(storage): update upgrate storage doc 2021-10-28 00:24:39 +08:00
bandl b4c3cc5a86 test(dao): remove dao test 2021-10-27 23:55:36 +08:00
bandl 54520cb033 fix(storage): fix storage service 2021-10-27 23:53:25 +08:00
bandl c67e0c863c feat(shell): add gen service shell 2021-10-27 23:51:54 +08:00
bandl ea8e10fcbf feat(single-service): add single service 2021-10-27 23:51:17 +08:00
bandl 19a0259f58 feat(listx): update dao listx 2021-10-27 23:30:45 +08:00
bandl 511a66bd98 feat(dao): add interface 2021-10-27 23:15:48 +08:00
bandl 5642a00f61 feat(stringx): update dao stringx 2021-10-27 23:15:26 +08:00
bandl 1f85847243 feat(dao): update interface 2021-10-27 23:15:07 +08:00
bandl dab21a4ebc feat(dao): add dao template 2021-10-27 21:38:31 +08:00
bandl 14c52da1ed feat(dao): add gen dao interface tools 2021-10-27 21:38:21 +08:00
bandl 5f188eaddf feat(dao): update dao interface 2021-10-27 21:38:01 +08:00
bandl bbc4c27027 !78 优化 事件驱动
Merge pull request !78 from bandl/perf-event
2021-10-26 09:13:08 +00:00
bandl b6348f5992 feat(test): update lru test 2021-10-26 16:35:14 +08:00
bandl 404dc1fbbc feat(event): update event 2021-10-26 16:01:11 +08:00
bandl db615609cd feat(lru-worker): event recovery 2021-10-26 15:41:16 +08:00
bandl 46b029b339 test(event): add poll test 2021-10-26 14:39:50 +08:00
bandl ac4fdd7309 feat(event): add event poll 2021-10-26 14:39:34 +08:00
bandl bff937700e feat(event-pool): add event poll 2021-10-26 09:29:39 +08:00
bandl 2a69f393e5 !77 ppeof
Merge pull request !77 from bandl/feat-pporf-plugins
2021-10-25 07:49:21 +00:00
bandl 417ddf1ccf feat(plugins): add plugins 2021-10-25 15:48:21 +08:00
bandl d78cb874ed feat(conf): add conf 2021-10-25 15:47:21 +08:00
bandl 06042b778c feat(conf): ones load conf 2021-10-25 15:34:23 +08:00
bandl 19562221f9 chore(pluigin): init pluugins 2021-10-25 15:24:34 +08:00
bandl 5d7df024e4 !76 修复 内存计算错误问题
Merge pull request !76 from bandl/fix-length
2021-10-25 03:21:05 +00:00
bandl 9298b77c7c fix(lru): fix length byte 2021-10-25 11:08:18 +08:00
bandl 3f4607fb58 !75 gateway 添加 一致性 hash 环算法实现 分布式集群
Merge pull request !75 from bandl/feat-gateway-transpoart
2021-10-24 12:07:30 +00:00
bandl 09730e9ebf feat(gateway): add hash ring gateway 2021-10-24 20:03:35 +08:00
bandl cd1ba29f42 feat(conf): update conf 2021-10-24 20:03:14 +08:00
bandl cf9dc1da38 feat(conf): add target addr 2021-10-24 19:50:59 +08:00
bandl fc60b2a779 test(transport): add test hash 2021-10-24 19:12:26 +08:00
bandl e81124c7e6 feat(transport): add hash transport 2021-10-24 19:12:07 +08:00
bandl ebfa948421 !74 ref
Merge pull request !74 from bandl/refactor-struct-proto
2021-10-23 16:42:16 +00:00
bandl b32606ee15 chore(proto): update proto 2021-10-24 00:39:07 +08:00
bandl 3c8d4fd89b fix(shell): update gen proto 2021-10-24 00:35:26 +08:00
bandl 9a1f1fe0ee fix(storage): fix storage method name 2021-10-24 00:35:26 +08:00
bandl e894734418 chore(proto): update proto 2021-10-24 00:35:26 +08:00
bandl e404f670a0 feat(shell): update const gen 2021-10-24 00:35:16 +08:00
bandl 4459beba61 feat(sturcture temp): update temp 2021-10-23 23:31:42 +08:00
bandl ab277fb66e !73 storage 的 listx
Merge pull request !73 from bandl/feat-listx-option
2021-10-23 08:19:41 +00:00
bandl 0b781a178e feat(listx): add storage listx option 2021-10-23 16:17:29 +08:00
bandl e96f21399c chore(proto): update proto 2021-10-23 16:04:35 +08:00
bandl 6a63bdca84 fix(stringx): ctx 2021-10-23 16:02:52 +08:00
bandl f15792032a feat(dao): add listx dao 2021-10-23 15:18:21 +08:00
bandl 7ce1a55d0e test(listx): add listx remove 2021-10-23 15:18:10 +08:00
bandl 4f6fb64ecc feat(listx): add listx 2021-10-23 15:17:57 +08:00
bandl 74e42e78ac test(listx): test range 2021-10-22 22:01:58 +08:00
bandl 8883abd461 feat(listx): add range func 2021-10-22 22:01:48 +08:00
bandl 8c5c594ac5 feat(proto): update proto 2021-10-22 18:15:26 +08:00
bandl 77988052ee doc(make): add make doc 2021-10-22 16:26:17 +08:00
bandl e6eb86de05 doc(middle): update doc 2021-10-22 16:12:13 +08:00
bandl f022ae9cbe doc(structure): add doc 2021-10-22 16:11:59 +08:00
bandl d42b01ff77 feat(structure): update interface view 2021-10-22 15:56:44 +08:00
bandl a9dbb5169c test(listx): add listx test 2021-10-22 15:37:25 +08:00
bandl 15e1bb06af feat(listx): add listx structure 2021-10-22 15:36:25 +08:00
bandl 41ef546d95 test(stringx): val test 2021-10-22 15:35:48 +08:00
bandl 70a246f84c feat(listx): add listx interface 2021-10-21 16:18:30 +08:00
bandl 2295fbcf40 chore(proto): update proto 2021-10-21 15:57:31 +08:00
bandl 3a4fc48f46 !72 feat-stringx-option
Merge pull request !72 from bandl/feat-stringx-option
2021-10-20 13:45:46 +00:00
bandl 5b0a636e02 test(stringx): test Getrange 2021-10-20 21:42:58 +08:00
bandl fe096c9054 feat(storage): add storage opt 2021-10-20 21:35:56 +08:00
bandl a374638758 feat(dao): add dao 2021-10-20 21:35:27 +08:00
bandl 56d69f63af feat(string): add stringx option 2021-10-20 21:35:15 +08:00
bandl aed507fc9a feat(proto): update proto 2021-10-20 20:30:51 +08:00
bandl 739cb56243 feat(stringx): add string option 2021-10-20 20:30:02 +08:00
bandl 1a884ce9f0 !71 feat-middle-worker
Merge pull request !71 from bandl/feat-middle-worker
2021-10-19 08:40:06 +00:00
bandl 576a7bbd41 test(middle): add test worker 2021-10-19 16:38:31 +08:00
bandl 623373f7ac feat(middle-msg): update push middle-msg 2021-10-19 16:38:07 +08:00
bandl 4413ee6f92 feat(conf): update conf 2021-10-19 16:34:32 +08:00
bandl 4a887b0e58 feat(logx): update send msg mode 2021-10-19 16:05:24 +08:00
bandl 74a85e518d feat(conf): update conf 2021-10-19 16:02:05 +08:00
bandl cb1e555986 feat(plugins): update gen plugins 2021-10-19 15:33:03 +08:00
bandl 780cf7d276 feat(middle-msg): update middle msg 2021-10-19 15:17:43 +08:00
bandl e94a41ec73 test(client): update client test 2021-10-19 14:52:23 +08:00
bandl 6ef4654c63 !61 middle_msg
Merge pull request !61 from Sodesnei/feat-plugin-install
2021-10-19 06:52:06 +00:00
bandl 6bd16eec06 !70 优化 lru
Merge pull request !70 from bandl/perf-lru
2021-10-18 16:25:35 +00:00
bandl 21cac4639c fear(dao): update dao api 2021-10-19 00:24:36 +08:00
bandl d17f8e243c perf(lru): perf lru keybase err 2021-10-19 00:24:16 +08:00
bandl 95d3fdbd17 test(skiplist, ttl): update ttl 2021-10-19 00:06:42 +08:00
bandl ac8f748356 perf(skiplist): perf list pop left, pop range 2021-10-18 23:58:11 +08:00
bandl 064ef3e50e !69 doc-init
Merge pull request !69 from bandl/doc-tidy-up
2021-10-17 13:08:16 +00:00
bandl eb0014437b doc(init-doc): refactor doc 2021-10-17 21:06:24 +08:00
bandl 310e11c65b !68 feat-dao-test
Merge pull request !68 from bandl/feat-alone-storage
2021-10-17 12:14:08 +00:00
bandl 019322eb8f fix(stringx): fix reduce float 2021-10-17 20:04:26 +08:00
bandl a00f10c70e test(dao): add dao test 2021-10-17 20:03:13 +08:00
bandl 3c68787ff4 test(client): add client 2021-10-17 20:02:48 +08:00
bandl 57e84b6dee feat(gateway): add gateway refault 2021-10-17 19:27:00 +08:00
bandl 5fe201ca32 feat(client): add cache client 2021-10-17 17:20:01 +08:00
bandl aade8e8edb test(gateway): remove test 2021-10-17 14:49:55 +08:00
bandl 6fdf250833 !66 gateway 添加 keybase 检查
Merge pull request !66 from bandl/fix-lru-panic
2021-10-17 02:52:41 +00:00
bandl d963c06576 test(dao): add set test dao 2021-10-17 10:50:13 +08:00
bandl d6f1631d7b feat(gateway): add get keybase ctx 2021-10-17 10:49:14 +08:00
bandl 477613f0de feat(mod): update mod 2021-10-17 08:23:14 +08:00
bandl bd0e598f1a feat(makefile): add no-print-directory 2021-10-16 23:54:17 +08:00
bandl 98787c8f03 !65 更新包名
Merge pull request !65 from bandl/fix-package-name
2021-10-16 15:27:37 +00:00
bandl 1e4d611c77 feat(pro): update package name in upper 2021-10-16 23:25:34 +08:00
bandl b97edc4cf1 !64 添加 实现 网关的转发功能
Merge pull request !64 from bandl/feat-getway
2021-10-16 14:55:54 +00:00
bandl 91d93bf5be test(gateway): add gateway test 2021-10-16 22:53:27 +08:00
bandl ebdc5bd5b0 feat(gateway-reset): add director mock 2021-10-16 22:53:11 +08:00
bandl 43392236b6 feat(gateway): add gateway root 2021-10-16 22:52:37 +08:00
bandl 52c9b166f3 feat(storage): update storage 2021-10-16 22:51:51 +08:00
bandl 40374333fa feat(uitl): grace exit 2021-10-16 22:51:28 +08:00
bandl 3adeac539b chore(conf): update conf and makefule 2021-10-16 22:50:38 +08:00
bandl ec8a126581 doc(feat-gateway-doc): add gateway doc 2021-10-16 20:44:27 +08:00
bandl 4e78d08e2c feat(conf): addgateway conf 2021-10-16 18:29:31 +08:00
bandl 2c854deb52 feat(gateway): add a forwarding rules to gateway 2021-10-16 16:54:35 +08:00
bandl 62eaa8edd0 feat(gateway-codce): update codce option 2021-10-16 16:53:21 +08:00
bandl cbf7ba1933 feat(gateway): add codec mode 2021-10-15 22:36:49 +08:00
bandl 32936576d3 feat(gateway): update gateway cmd 2021-10-15 22:36:29 +08:00
bandl 57a655a708 feat(storage): update conf 2021-10-15 22:35:16 +08:00
bandl 554f7feef9 chore(proto): update proto 2021-10-12 21:22:46 +08:00
bandl 101059126c fix(single-server): fix timeOut 2021-10-12 21:22:46 +08:00
bandl ccf7179713 doc(getway): add getway doc 2021-10-12 21:22:46 +08:00
bandl 5934e88e03 test(storage): add single server test 2021-10-12 21:22:46 +08:00
bandl f7d4cee102 feat(getway): init getway 2021-10-12 21:22:46 +08:00
bandl ef5c088a49 !63 完成 全部 single lru
Merge pull request !63 from bandl/feat-lru-ttl
2021-10-12 13:18:32 +00:00
bandl c8f23d1357 test(lru): add lru test process 2021-10-12 21:15:21 +08:00
bandl 85e9a3b5f8 chore(proto): update proto 2021-10-12 21:15:21 +08:00
bandl 02bd151381 test(lru): test ttl and worker 2021-10-12 21:15:21 +08:00
bandl 758f1bfec2 feat(lru): update lru ttl and worker 2021-10-12 21:15:09 +08:00
bandl e3c7546023 fix(middle): fix middleware name msg 2021-10-12 15:10:53 +08:00
bandl b61794d74b test(util): test skiplist 2021-10-12 15:10:10 +08:00
bandl 5776e0ba6e feat(util): add skiplist 2021-10-12 15:10:00 +08:00
bandl c4161e77d0 doc(config): update wheat-cache.yaml 2021-10-12 15:09:12 +08:00
bandl e826ff4569 !62 增加清理事件
Merge pull request !62 from K-on/add-Clear-Event
2021-10-11 12:40:42 +00:00
K-on d2866256dd update pkg/lru/define.go. 2021-10-11 11:19:11 +00:00
K-on 5459c7710c 删除文件 pkg/lru/cleanwork.go 2021-10-11 11:09:59 +00:00
HuangJiaLuo aebab3b3d7 Merge remote-tracking branch 'origin/add-Clear-Event' into add-Clear-Event
# Conflicts:
#	pkg/lru/define.go
#	pkg/lru/lru.go
2021-10-11 19:06:48 +08:00
HuangJiaLuo b39899e5d6 feat(middle-msg): update lru msg 2021-10-11 19:02:01 +08:00
HuangJiaLuo 922fae0f78 feat(lru): update lru clean work 2021-10-11 19:01:24 +08:00
Sodesnei 44dbb04f0b feat(middle-msg): add PluginsInfo msg 2021-10-10 22:28:00 +08:00
Sodesnei e2f00fa2ae feat(middle-msg): add SendMiddleMsg function 2021-10-10 22:28:00 +08:00
Sodesnei ec8cea59a4 feat(doc): middleware doc 2021-10-10 22:28:00 +08:00
bandl ab257b2009 !60 日志
Merge pull request !60 from 黎白南/feat-logx-middle
2021-10-10 13:23:43 +00:00
黎白南 e5ac4d1cf9 feat(logx) add print without format, color print 2021-10-10 21:07:23 +08:00
黎白南 51517da519 feat(logx) add print without format 2021-10-10 21:07:23 +08:00
HuangJiaLuo 73e91b3ff0 test 2021-10-10 20:54:17 +08:00
HuangJiaLuo dcce00a32d feat(lru): feat the function of launching the cleanWorkFunc to driver 2021-10-10 20:54:17 +08:00
HuangJiaLuo 2500251699 feat(lru): feat the function of cleanEvent 2021-10-10 20:54:17 +08:00
HuangJiaLuo 29b9c8f3b6 feat(event): feat the function of getting the queue length 2021-10-10 20:54:17 +08:00
HuangJiaLuo f119557eec feat(errorx): feat the LruNotWorkFuncEvent error 2021-10-10 20:54:17 +08:00
HuangJiaLuo 5275be2b8e feat(event): feat the io of judgement function 2021-10-10 20:54:17 +08:00
HuangJiaLuo 83bf49ec17 feat(event): feat the get the io length 2021-10-10 20:54:17 +08:00
HuangJiaLuo cf1c90442b feat(worker): feat get the io 2021-10-10 20:54:16 +08:00
Sodesnei aac12f93f4 !58 middle driver
Merge pull request !58 from Sodesnei/fix-middleware-driver
2021-10-10 06:14:02 +00:00
Sodesnei debde8a66a feat(middle): update middle define var 2021-10-10 14:10:21 +08:00
Sodesnei 95f165fb55 feat(middle): update middle driver 2021-10-10 14:09:09 +08:00
Sodesnei febd5501c4 feat(conf): updata conf test 2021-10-10 14:05:01 +08:00
HuangJiaLuo 8a6db79fd6 feat(lru): feat the function of launching the cleanWorkFunc to driver 2021-10-09 22:08:09 +08:00
HuangJiaLuo 64b38044c8 feat(lru): feat the function of cleanEvent 2021-10-09 22:06:38 +08:00
HuangJiaLuo 843fcd27ca feat(event): feat the function of getting the queue length 2021-10-09 22:05:39 +08:00
HuangJiaLuo a251cdb844 feat(errorx): feat the LruNotWorkFuncEvent error 2021-10-09 22:04:47 +08:00
Sodesnei 4d9558c21f feat(conf): add conf single test 2021-10-09 21:56:43 +08:00
Sodesnei b182d7602d feat(plugins): updata plugins 2021-10-09 21:55:39 +08:00
Sodesnei 99c3c56a5b feat(middle-msg): add pluginsInfo 2021-10-09 21:55:16 +08:00
Sodesnei 81d3bb8434 feat(middle-msg): update base parameter 2021-10-09 21:54:26 +08:00
Sodesnei ce8f72040b feat(middleware): add middleware work function 2021-10-09 21:51:52 +08:00
Sodesnei 329513bd98 feat(middle-msg): updatae logx 2021-10-09 21:49:55 +08:00
Sodesnei 2e04517066 feat(conf): update wheat-cache.yaml 2021-10-09 21:49:16 +08:00
HuangJiaLuo f1d2cbb0ee feat(event): feat the io of judgement function 2021-10-09 10:55:12 +08:00
HuangJiaLuo c45c2682e0 feat(event): feat the get the io length 2021-10-09 10:47:17 +08:00
HuangJiaLuo 929f931cd6 feat(worker): feat get the io 2021-10-09 10:35:42 +08:00
黎白南 b168eecbb4 !56 日志
Merge pull request !56 from 黎白南/feat-logx-middle
2021-10-08 13:35:19 +00:00
黎白南 e98731c1b3 fix(log) fix produce msg, remove more route 2021-10-08 21:19:04 +08:00
黎白南 77d4b88c71 fix(log) fix produce msg, remove more route 2021-10-08 21:04:54 +08:00
Sodesnei 1540651864 !55 修改middle代码自动生成模板
Merge pull request !55 from Sodesnei/middle-template
2021-10-08 12:14:07 +00:00
Sodesnei 166d1f20c1 fix(middle-template): update middle template 2021-10-08 20:11:13 +08:00
bandl 96c8a6d53e !53 更新driver, 重构了worker
Merge pull request !53 from K-on/fix-driver
2021-10-07 08:35:26 +00:00
HuangJiaLuo 83febdd482 refactor(worker): refactor 2021-10-07 16:31:46 +08:00
HuangJiaLuo e3171a8b3e feat(event): Add SetResultErr func 2021-10-07 16:31:46 +08:00
bandl 60abd336b1 !52 增加了根据key删除value, 将key的类型修改成 KeyBase
Merge pull request !52 from K-on/feat-Lru-delete-key
2021-10-06 12:47:04 +00:00
HuangJiaLuo 428a8fa8f8 feat(worker): change string to proto.KeyBase 2021-10-06 20:39:52 +08:00
HuangJiaLuo 97833ed150 feat(single): change string to proto.KeyBase 2021-10-06 20:39:38 +08:00
HuangJiaLuo f17cab2016 feat(dao): change string to proto.KeyBase 2021-10-06 20:39:20 +08:00
HuangJiaLuo d4d93a0e51 feat(lru): change string to proto.KeyBase 2021-10-06 20:39:07 +08:00
HuangJiaLuo f9ad4d914e feat(lru): change string to proto.KeyBase 2021-10-06 20:38:56 +08:00
HuangJiaLuo d08e50f4ce feat(lru): change string to proto.KeyBase 2021-10-06 20:38:37 +08:00
HuangJiaLuo 90b021bee2 feat(lru): del by key 2021-10-06 19:56:32 +08:00
bandl 63bd44da44 !50 日志
Merge pull request !50 from 黎白南/feat-logx-middle
2021-10-06 11:14:52 +00:00
黎白南 d8dc56d95a fix(log) fix panic, remove fmt.Print 2021-10-06 19:14:16 +08:00
bandl c36659da26 !51 增加了开始的提示
Merge pull request !51 from K-on/fix-conf-test
2021-10-06 11:09:51 +00:00
黎白南 87ada5f981 doc(doc) add log param 2021-10-06 19:02:37 +08:00
黎白南 880aba64d0 test(log) add text func 2021-10-06 19:01:15 +08:00
黎白南 34dd0fe94f feat(doc) add panic, init 2021-10-06 19:00:48 +08:00
HuangJiaLuo 36e8efd682 fix(conf): add warning about the file when we want to use the yaml 2021-10-06 18:55:23 +08:00
黎白南 692ad28380 fix(doc) logx to log 2021-10-06 14:54:52 +08:00
黎白南 0e2db14d32 fix(log) fix log with context 2021-10-06 14:47:58 +08:00
黎白南 5061b2e3da feat(middle-msg) make log msg standard 2021-10-05 21:36:57 +08:00
黎白南 b75aa1d141 feat(logx) make struct without new 2021-10-05 21:36:06 +08:00
黎白南 a706d57370 feat(logx) add log function 2021-10-05 20:53:11 +08:00
bandl 5292163b14 !48 feat-storage-server-v2
Merge pull request !48 from bandl/fix-storage-structure
2021-10-05 10:24:11 +00:00
bandl c9cfa04725 test(lru): update worker 2021-10-05 16:53:28 +08:00
bandl 4afe3dabb6 feat(lru): update lru 2021-10-05 16:53:16 +08:00
bandl 212e025b23 feat(storage): update single storage 2021-10-05 16:41:17 +08:00
bandl 125b137ef6 feat(dao): add dao server 2021-10-05 16:40:29 +08:00
bandl 67da63ac03 feat(errorx): add err 2021-10-05 16:39:31 +08:00
bandl 74ab13c756 feat(shell): update proto 2021-10-05 16:39:00 +08:00
bandl 26226eca28 f 2021-10-04 22:37:21 +08:00
bandl 1de8e1b141 feat(lru): update sizebyte 2021-10-04 22:37:04 +08:00
bandl 8bcac6f739 test(lru): rename SingleCache 2021-10-04 22:20:58 +08:00
bandl e6987546ae test(stringx): update stringx test 2021-10-04 21:56:49 +08:00
bandl 8e6f18f887 chore(proto): update dcgen 2021-10-04 21:20:03 +08:00
bandl 30c34cf30f feat(structure): update structure stringx 2021-10-04 21:20:03 +08:00
bandl c27328ced4 feat(shell): update shell storage 2021-10-04 21:20:03 +08:00
Sodesnei 7c6c26c5fa !44 update middlewareFile name
Merge pull request !44 from Sodesnei/feat-middleware-python
2021-10-04 13:17:28 +00:00
Sodesnei 49496cf63c fix(middle): fix middle.template 2021-10-04 21:15:30 +08:00
Sodesnei bd804e7105 fix(middle): update define 2021-10-04 21:15:30 +08:00
Sodesnei 1c9c437a0f fix(middleware): add middlewareInterface function 2021-10-04 21:15:30 +08:00
Sodesnei 0bdbe06376 fix(middle): update middleware 2021-10-04 21:15:30 +08:00
Sodesnei ea36d370a7 fix(middle-driver): update file name 2021-10-04 21:15:30 +08:00
Sodesnei 373de8b282 fix(middle): rollback 2021-10-04 21:15:30 +08:00
K-on 15cede5780 !45 fix util
Merge pull request !45 from K-on/fix-util
2021-10-04 13:14:27 +00:00
HuangJiaLuo e637cccaed fix(util): fix the bug of memory 2021-10-04 21:06:40 +08:00
bandl f7508d67a3 !42 lru fix bug
Merge pull request !42 from K-on/feat-lru-driver
2021-10-04 12:48:25 +00:00
HuangJiaLuo b95fb85ad6 perf(util): use switch to change size 2021-10-04 20:33:38 +08:00
HuangJiaLuo 1774c9f230 feat(makefile): add init-conf 2021-10-04 20:32:55 +08:00
HuangJiaLuo 477adec1bb fix(lru): fix the bug of lru 2021-10-04 20:32:20 +08:00
HuangJiaLuo ca04ba1686 test(lru): add the test of worker 2021-10-04 16:25:52 +08:00
HuangJiaLuo 71ddeb4772 perf(lru): add the sync.Once to define 2021-10-04 16:25:09 +08:00
HuangJiaLuo 75e1251d22 feat(lru): feat the init cache 2021-10-04 16:23:37 +08:00
HuangJiaLuo dbc0467de4 fix(util): fix the bug of ParseSizeToBit 2021-10-04 16:21:48 +08:00
HuangJiaLuo 29c5aca40d test(lru): update test 2021-10-04 11:22:35 +08:00
HuangJiaLuo 99dd878bb3 feat(shell): add init_conf and update makefile 2021-10-04 11:22:34 +08:00
HuangJiaLuo 96d5a9acc9 feat(lru): fix lru function and memory function 2021-10-04 11:22:34 +08:00
HuangJiaLuo 47a49b1fdb feat(lru): update lru function 2021-10-04 11:22:34 +08:00
HuangJiaLuo 768f3df70e lru driver-test 2021-10-04 11:22:34 +08:00
bandl a556840f9b !43 修复 degen 错误问题
Merge pull request !43 from bandl/fix-structure-gen
2021-10-04 01:22:38 +00:00
bandl 2c11d500fd fix(gen-proto): update gen-proto shell 2021-10-03 16:22:34 +08:00
bandl a323f7e8a9 fix(template): update template 2021-10-03 16:22:06 +08:00
bandl 5888e2e15a !41 fix-middle-tools
Merge pull request !41 from bandl/fix-middle-tools
2021-09-29 13:23:39 +00:00
bandl 57bdec3c1d feat(middleware): update middleware 2021-09-29 21:21:45 +08:00
bandl ae5a0531d8 chore(middleware): update middle 2021-09-29 21:18:00 +08:00
bandl 04cb2a1ed1 !40 中间件自动化生成代码
Merge pull request !40 from Sodesnei/feat-middleware-python
2021-09-29 13:12:43 +00:00
Sodesnei 2c6a6a6848 fix(middleware):add middleware format 2021-09-29 20:25:06 +08:00
Sodesnei 488d84580e feat(middle): Automated code generation 2021-09-29 20:25:06 +08:00
bandl 26f3f9f663 !39 修改 lru的define文件
Merge pull request !39 from Sodesnei/fix-lru-single-work
2021-09-29 08:31:38 +00:00
Sodesnei 82e358e268 fix(lru):delete function SingleworkFunc 2021-09-29 13:38:25 +08:00
bandl c11d10d6e2 !38 feat-storage-template
Merge pull request !38 from bandl/feat-storage-tempalte
2021-09-28 15:07:49 +00:00
bandl 600ecb644e chore(structure): update structure 2021-09-28 23:00:22 +08:00
bandl 187280bc2c feat(shell): add storage shell 2021-09-28 23:00:22 +08:00
bandl ad0cdedba9 feat(conf): update const conf 2021-09-28 23:00:22 +08:00
bandl 0903477c22 !35 方案分支
Merge pull request !35 from bandl/fd-middle-tools
2021-09-28 14:58:15 +00:00
bandl 0677c56492 !36 修复 event 的一些 bug
Merge pull request !36 from bandl/fix-event-bug
2021-09-28 13:09:40 +00:00
bandl f53eea9c22 doc(event): update event doc 2021-09-28 20:59:54 +08:00
bandl 0b8e2a104f test(event): update test 2021-09-28 20:55:26 +08:00
bandl 748f61830b feat(event): fix event wait err 2021-09-28 20:55:09 +08:00
bandl 05bd410900 feat(errorx): add time out err 2021-09-28 20:29:57 +08:00
bandl d4a73b93d3 awd 2021-09-27 09:52:27 +08:00
bandl 70319ae2b1 !34 add middleware interface
Merge pull request !34 from Sodesnei/feat-middle-tools-interface
2021-09-27 01:22:31 +00:00
Sodesnei ea9a660740 feat(middleware): add middleware interface 2021-09-26 22:22:40 +08:00
bandl 0458ed3d21 !32 feat-stringx-struct
Merge pull request !32 from bandl/feat-stringx-struct
2021-09-26 12:46:24 +00:00
bandl f4327aa5b6 !33 添加 事件驱动文档
Merge pull request !33 from bandl/doc-event
2021-09-26 12:46:11 +00:00
bandl 8dd5879b2a doc(event): add event doc 2021-09-26 20:01:41 +08:00
bandl 060c1d2bfb test(structure): test stringx type 2021-09-26 16:48:13 +08:00
bandl 8d663fe920 feat(structure): add stringx type 2021-09-26 16:47:54 +08:00
bandl a8bbbc70a4 chore(structure): update template 2021-09-25 23:38:19 +08:00
bandl 175bddf527 feat(shell): update shell 2021-09-25 23:37:24 +08:00
bandl eb53a976e2 test(value): add test value 2021-09-25 16:22:33 +08:00
bandl bcacc83df6 feat(value): update value 2021-09-25 16:21:28 +08:00
bandl 3d7df7149a !31 更新 模板, 添加基础类型
Merge pull request !31 from bandl/feat-gen-storage
2021-09-25 07:43:12 +00:00
bandl ec9d3a1a71 chore(structure): update model 2021-09-25 14:52:42 +08:00
bandl f0835b3344 test(structure): test base value 2021-09-24 22:48:41 +08:00
bandl fc47f3eca0 feat(structure): add base value 2021-09-24 22:48:08 +08:00
bandl 98ef750a67 !30 feat-event-driver
Merge pull request !30 from bandl/feat-event-manage
2021-09-23 11:19:12 +00:00
bandl d1113821c9 test(event): add test event 2021-09-23 11:06:20 +08:00
bandl 6d26969cae feat(event): add event driver tools 2021-09-23 11:05:51 +08:00
bandl 36d18c1368 feat(errorx): add errorx 2021-09-23 10:11:54 +08:00
bandl ea83b319de feat(makefile): update makefile 2021-09-23 10:11:18 +08:00
bandl 24d0ef2611 !29 更新了LRU设计文档
Merge pull request !29 from K-on/update-doc
2021-09-22 03:50:39 +00:00
HuangJiaLuo 5d66e47e74 fix(gen): fix gen-interface
Update(doc): update LUR设计.md
2021-09-22 11:44:53 +08:00
bandl 6637f4c77e !28 创建 storage 模板
Merge pull request !28 from bandl/refactor-master
2021-09-21 14:23:04 +00:00
bandl cc57179c11 feat(storage): update server 2021-09-21 20:59:48 +08:00
bandl a9ab92c16a refactor(structure): refactor struct interface gen 2021-09-21 20:59:19 +08:00
bandl ddd7a8a5ed refactor(structure, shell): update shell, structure 2021-09-21 20:16:08 +08:00
bandl e3acfcd0fe refactor(proto-structure): update shell 2021-09-21 19:37:53 +08:00
bandl 6eec180306 refactor(proto-file): resume file 2021-09-21 19:28:14 +08:00
bandl 76c203c37a !25 update proto auto tool
Merge pull request !25 from 百里酚蓝/feat-stringx
2021-09-21 03:31:05 +00:00
yu_lang f3e894a068 feat(proto):update proto auto tool 2021-09-21 11:26:12 +08:00
yu_lang 53fe26db48 feat(proto):add proto auto_tool 2021-09-21 11:14:28 +08:00
yu_lang f410738b27 feat(proto):add proto auto tool 2021-09-21 11:14:28 +08:00
bandl b9060a64d5 fix(gen-struct): add struct 2021-09-21 11:14:19 +08:00
yu_lang cf4b5cd63c feat(proto):add proto auto_tool 2021-09-21 11:13:37 +08:00
yu_lang 8bc30d3b85 feat(proto):add proto auto tool 2021-09-21 11:13:28 +08:00
bandl 2e9216d894 !24 修复自动生成interface脚本
Merge pull request !24 from K-on/fix-gen-interface
2021-09-21 02:51:59 +00:00
HuangJiaLuo 77cab55402 fix(gen): fix gen-interface 2021-09-21 10:44:27 +08:00
bandl 23baebe2d7 !23 自动生成interface脚本
Merge pull request !23 from K-on/feat-update-tamplate
2021-09-21 02:14:41 +00:00
HuangJiaLuo 09b8907085 自动生成Interface 2021-09-20 20:51:56 +08:00
bandl b03d096b53 feat(structure-temp): add interface-temp 2021-09-20 18:44:56 +08:00
bandl 20b2272e7c !22 修复 gen-structure
Merge pull request !22 from bandl/fix-gen-struct
2021-09-20 08:39:11 +00:00
bandl 4b27125092 fix(gen-struct): add struct 2021-09-20 16:36:47 +08:00
bandl 63d6f66770 !21 增加proto的自动生成工具
Merge pull request !21 from 百里酚蓝/feat-stringx
2021-09-20 07:58:35 +00:00
yu_lang 1de6231a17 Merge branch 'feat-stringx' of https://gitee.com/timedb/wheat-cache into feat-stringx 2021-09-20 14:07:10 +08:00
yu_lang 27fbb69034 feat(proto):add proto 自动化生成工具 2021-09-20 14:01:15 +08:00
HuangJiaLuo d9a9da6dee 自动生成代码脚本 2021-09-20 14:00:11 +08:00
bandl fa2c67d140 !20 web doc update
Merge pull request !20 from 百里酚蓝/web-update
2021-09-20 03:41:21 +00:00
bandl 81f85009ab feat(stringx): add gen template 2021-09-19 11:53:17 +08:00
bandl c1ca0a499f feat(structure): add gen-tools 2021-09-19 10:38:21 +08:00
yu_lang 4653e6f27c doc(web-update):update web doc 2021-09-18 21:23:43 +08:00
bandl 8714fc8b8f !19 fix-storage-proto
Merge pull request !19 from bandl/fix-storage-proto
2021-09-18 08:25:01 +00:00
bandl 9b9ece8f54 fix(storage): fix porot 2021-09-18 16:23:12 +08:00
bandl 9cbd06227d !18 chore-git-vscode
Merge pull request !18 from bandl/chore-git-commit
2021-09-18 07:33:04 +00:00
bandl 7837edb92e chore(git commot del .vscode) 2021-09-18 15:31:21 +08:00
bandl f910e2c503 !17 结构体模板化
Merge pull request !17 from bandl/feat-struct-strings
2021-09-18 07:28:31 +00:00
bandl 4405512540 feat(structure-pkg): add storage pkg 2021-09-18 15:27:45 +08:00
bandl 221dbdd6d4 doc(make): update makefile doc 2021-09-18 14:39:29 +08:00
bandl b902c8cc1f feat(structure-tools): add structure tools 2021-09-17 20:33:42 +08:00
bandl 40dd0dd91a feat(stringx): add stringx init interface 2021-09-16 13:58:17 +08:00
bandl 414cd6d9a7 !15 添加 配置文件的使用
Merge pull request !15 from bandl/feat-project-conf
2021-09-09 03:13:22 +00:00
bandl c84873208b chore(project): add conf 2021-09-05 21:27:08 +08:00
bandl 8cfed8b325 doc(struct): add doc 2021-09-05 17:50:38 +08:00
bandl aadb43cfd9 feat(storage): add conf addr 2021-09-05 17:08:35 +08:00
bandl 6b80b30f31 feat(conf): test conf 2021-09-05 17:08:13 +08:00
bandl 0b88178df0 feat(conf): add conf 2021-09-05 17:07:34 +08:00
bandl 136fc48206 chore(storage): del init conf 2021-09-05 15:00:39 +08:00
bandl fd80e3ddde chore(git): setting 2021-09-01 23:00:55 +08:00
bandl 6817eccff6 !14 创建 storage server
Merge pull request !14 from bandl/feat-storage-server
2021-09-01 01:01:29 +00:00
bandl 30e182d018 feat(storage): add storage server 2021-08-31 23:31:31 +08:00
bandl 8c114bcb9a chore(project): add comm proto 2021-08-31 23:30:55 +08:00
bandl 6453b2a0ce doc(project): update project build file doc 2021-08-31 23:30:29 +08:00
bandl a5a01b8e33 chore(project): update project build file 2021-08-31 23:30:14 +08:00
bandl 13a3291e9e chore(project): rm .idea 2021-08-31 23:25:14 +08:00
bandl 781fc4b6b7 feat(struct): init struct interface 2021-08-29 22:18:07 +08:00
bandl 087bec4861 !13 增加前端文档
Merge pull request !13 from 百里酚蓝/yulang_add
2021-08-29 12:50:27 +00:00
yu_lang c321d6865d doc(yulang_add):add doc 2021-08-28 20:05:19 +08:00
yu_lang 78ee204877 test(test_by_yulang):add test 2021-08-22 16:57:42 +08:00
yu_lang 9fd9be29a3 feat(test_by_yulang):add test func 2021-08-22 16:57:18 +08:00
bandl f768f361c1 !7 添加文档
Merge pull request !7 from bandl/doc-pro-git-doc
2021-08-19 14:21:38 +00:00
bandl c699fa0527 merge(pro-doc): doc-pro 2021-08-19 22:20:41 +08:00
bandl 2c9e6784b1 doc(pro-git-doc): init doc 2021-08-19 22:16:29 +08:00
bandl 9262c6e8c5 doc(pro-git-doc): init doc 2021-08-19 22:09:49 +08:00
bandl 7e8108bc73 !6 test
Merge pull request !6 from bandl/test
2021-08-18 15:26:30 +00:00
bandl 2c0eeb89df awd 2021-08-18 23:20:47 +08:00
156 changed files with 23255 additions and 133 deletions

View File

@ -7,7 +7,7 @@
### 描述(做了什么,变更了什么)
### 测试用例(新增、改动、可能影响的功能)
### 影响到的模块

9
.gitignore vendored
View File

@ -5,8 +5,17 @@
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
.idea
.vscode
# build file
/bin/storage
/bin/gateway

8
.idea/.gitignore vendored
View File

@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/wheat-cache.iml" filepath="$PROJECT_DIR$/.idea/wheat-cache.iml" />
</modules>
</component>
</project>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

7
Dockerfile Normal file
View File

@ -0,0 +1,7 @@
FROM ubuntu:18.04
WORKDIR /home/src/gitee.com/wheat-os/wheat-cache
ADD . /home/src/gitee.com/wheat-os/wheat-cache
RUN mkdir /etc/wheat-cache
RUN mv /home/src/gitee.com/wheat-os/wheat-cache/conf/wheat-cache.yaml /etc/wheat-cache/

Binary file not shown.

147
README.md

File diff suppressed because one or more lines are too long

22
client/client.go Normal file
View File

@ -0,0 +1,22 @@
package client
import (
"gitee.com/wheat-os/wheatCache/client/middle"
"gitee.com/wheat-os/wheatCache/pkg/proto"
"google.golang.org/grpc"
)
func newWheatClient(targer string, opt ...middle.ClientMiddle) (proto.CommServerClient, error) {
interceptor := middle.GetUnaryInterceptor(opt...)
comm, err := grpc.Dial(targer, grpc.WithInsecure(), grpc.WithUnaryInterceptor(interceptor))
if err != nil {
return nil, err
}
return proto.NewCommServerClient(comm), nil
}
func NewWheatClient(targer string, opt ...middle.ClientMiddle) (proto.CommServerClient, error) {
return newWheatClient(targer, opt...)
}

47
client/client_test.go Normal file
View File

@ -0,0 +1,47 @@
package client
import (
"context"
"testing"
"gitee.com/wheat-os/wheatCache/client/middle"
"gitee.com/wheat-os/wheatCache/pkg/proto"
"github.com/stretchr/testify/require"
)
func TestClient(t *testing.T) {
cli, err := NewWheatClient("127.0.0.1:5891", middle.WithUnaryColonyClient)
require.NoError(t, err)
ctx := context.Background()
bKey := proto.NewBaseKey("apple")
resp, err := cli.Set(ctx, &proto.SetRequest{
Key: bKey,
Val: "yyyy",
})
require.NoError(t, err)
require.Equal(t, resp.Result, "yyyy")
getResp, err := cli.Get(ctx, &proto.GetRequest{
Key: bKey,
})
require.NoError(t, err)
require.Equal(t, getResp.Result, "yyyy")
}
func TestClientGet(t *testing.T) {
cli, err := NewWheatClient("127.0.0.1:5891", middle.WithUnaryColonyClient)
require.NoError(t, err)
ctx := context.Background()
bKey := &proto.BaseKey{
Key: "apple",
}
getResp, err := cli.Get(ctx, &proto.GetRequest{
Key: bKey,
})
require.NoError(t, err)
require.Equal(t, getResp.Result, "yyyy")
}

6
client/middle/define.go Normal file
View File

@ -0,0 +1,6 @@
package middle
import "context"
// type UnaryClientInterceptor func(ctx context.Context, method string, req, reply interface{}, cc *ClientConn, invoker UnaryInvoker, opts ...CallOption) error
type ClientMiddle func(ctx context.Context, method string, req, reply interface{}, header map[string]string) error

53
client/middle/middle.go Normal file
View File

@ -0,0 +1,53 @@
package middle
import (
"context"
"gitee.com/wheat-os/wheatCache/pkg/proto"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
func WithUnaryColonyClient(ctx context.Context, method string, req, reply interface{}, header map[string]string) error {
key, ok := req.(proto.GetKeyBaseInterface)
if !ok {
return status.Errorf(codes.Unknown, "key base err")
}
if header == nil {
return nil
}
// meta 解析会出现 全部小写问题
header[proto.BaseKeyMethodKey] = key.GetKey().Key
return nil
}
func getKeyByKeyMapvalue(m map[string]string) []string {
l := make([]string, 0)
for key, value := range m {
l = append(l, key, value)
}
return l
}
func GetUnaryInterceptor(middleOpts ...ClientMiddle) grpc.UnaryClientInterceptor {
return func(ctx context.Context, method string, req, reply interface{},
cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
// 加载中间件
header := make(map[string]string)
for _, mid := range middleOpts {
err := mid(ctx, method, req, reply, header)
if err != nil {
return err
}
}
lm := getKeyByKeyMapvalue(header)
headerData := metadata.Pairs(lm...)
ctxH := metadata.NewOutgoingContext(ctx, headerData)
return invoker(ctxH, method, req, reply, cc, opts...)
}
}

56
conf/public_conf.go Normal file
View File

@ -0,0 +1,56 @@
package conf
import (
"log"
"sync"
"github.com/spf13/viper"
)
const (
linuxPath = "/etc/wheat-cache/"
)
var confLock sync.Once
func init() {
confLock.Do(func() {
setDefaultConfValue()
err := LoadConf("")
switch err.(type) {
case nil:
case viper.ConfigFileNotFoundError:
formatPath := []string{linuxPath}
log.Fatalf("the profile could not be read, read path:%v", formatPath)
default:
log.Fatalf("the resolution of the profile failed, err: %v", err)
}
},
)
}
func setDefaultConfValue() {
// 设置一些默认值
viper.SetDefault("version", "base-01")
defaultStorage()
}
func LoadConf(path string) error {
if path != "" {
viper.AddConfigPath(path)
}
viper.SetConfigName("wheat-cache")
// 添加默认读取地址
// linux
viper.AddConfigPath(linuxPath)
viper.SetConfigType("yaml")
err := viper.ReadInConfig()
if err != nil {
return err
}
return nil
}

35
conf/public_conf_test.go Normal file
View File

@ -0,0 +1,35 @@
package conf
import (
"testing"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
)
func TestConf(t *testing.T) {
// 外部导入 conf.yaml 需要导入 conf 包
// 每次迁移文件时, 使用 sudo make init-conf来将yam文件迁移到指定的文件夹下
// get 使用, 读取 public_conf 配置文件
h := viper.Get("storage.host")
require.Equal(t, h, "127.0.0.1")
h = viper.Get("env")
require.Equal(t, h, "dev")
// set 使用
viper.Set("host", "1222")
host := viper.GetString("host")
require.Equal(t, host, "1222")
}
func TestMiddleConf(t *testing.T) {
ct := viper.GetStringSlice("plugins-control.logcontext")
require.Equal(t, ct, []string{"logMiddle"})
d := viper.GetInt("middleware-driver.driverCount")
require.Equal(t, d, 1000)
c := viper.GetInt("middleware-driver.middleConsumerCount")
require.Equal(t, c, 5)
}

11
conf/storage.go Normal file
View File

@ -0,0 +1,11 @@
package conf
import "github.com/spf13/viper"
func defaultStorage() {
// aof
viper.SetDefault("storage.aof-path", "/etc/wheat-cache/wheat.aof")
viper.SetDefault("storage.aof-flush-time", 5)
viper.SetDefault("storage.aof-check-time", 1)
viper.SetDefault("storage.aof-check-freq", 20)
}

60
conf/wheat-cache.yaml Normal file
View File

@ -0,0 +1,60 @@
version: 'v1.0'
env: 'dev'
storage:
host: '0.0.0.0'
port: 5890
timeOut: 2 # second
aof-codec: "b16" # 目前只实现了 b16 编码方案。
aof-path: "/etc/wheat-cache/wheat.aof"
aof-flush-time: 5 # second , 每 5 秒刷新缓冲区的内容到磁盘。
aof-check-time: 1 # 每 1 second 执行一次 io 检查
aof-check-freq: 20 # 在一个 aof-check-time 周期内,出现超过 aof-check-freq 的 IO 操作会刷新磁盘
# clearSize and maxSize must be Int
lruCache:
clearSize: "512mb"
maxSize: "1GB"
eventDriverSize: 2000
workTime: 1
detachNum: 300
logPrint:
stath: ["error"]
middleware-driver:
driverCount: 1000
middleConsumerCount: 5
# Register the message push type
# 在这里注册消息推送类型,
plugins-control:
# log-context: Logs generated by storage or gateway are pushed through this message
# log-context: storage 或者 gateway 产生的日志通过这个消息推送
log-context: [ "mock-plugins" ]
# lru-clean-context: Lru is pushed through this message when data cleansing occurs
# lru-clean-context: Lru 发生数据清理时通过这个消息推送
lru-clean-context: ["mock-plugins"]
# lru-ttl-context: Lru is pushed through this message when data expires
# lru-ttl-context: Lru 发生数据过期时通过这个消息推送
lru-ttl-context: ["mock-plugins"]
# plugins-info-contextAll plugins information for the current project
# plugins-info-context: 当前项目全部的插件信息
plugins-infos-context: ["mock-plugins"]
gateway:
host: '0.0.0.0'
port: 5891
target: ["127.0.0.1:5890"]
mock-plugin:
pprof-addr: "127.0.0.1:8000"

2
doc/_icon/alf.svg Normal file
View File

@ -0,0 +1,2 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="94" height="20" role="img" aria-label="license: AFL3.0"><title>license: AFL3.0</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="94" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="47" height="20" fill="#555"/><rect x="47" width="47" height="20" fill="#97ca00"/><rect width="94" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="245" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="370">license</text><text x="245" y="140" transform="scale(.1)" fill="#fff" textLength="370">license</text><text aria-hidden="true" x="695" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="370">AFL3.0</text><text x="695" y="140" transform="scale(.1)" fill="#fff" textLength="370">AFL3.0</text></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 37 KiB

2
doc/_icon/cache.svg Normal file
View File

@ -0,0 +1,2 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="88" height="20" role="img" aria-label="Wheat: Cache"><title>Wheat: Cache</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="88" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="45" height="20" fill="#555"/><rect x="45" width="43" height="20" fill="#a4a61d"/><rect width="88" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="235" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="350">Wheat</text><text x="235" y="140" transform="scale(.1)" fill="#fff" textLength="350">Wheat</text><text aria-hidden="true" x="655" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="330">Cache</text><text x="655" y="140" transform="scale(.1)" fill="#fff" textLength="330">Cache</text></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

3
doc/_icon/event.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.9 KiB

2
doc/_icon/version.svg Normal file
View File

@ -0,0 +1,2 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="86" height="20" role="img" aria-label="version: v1.1"><title>version: v1.1</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="86" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="51" height="20" fill="#555"/><rect x="51" width="35" height="20" fill="#007ec6"/><rect width="86" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="265" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="410">version</text><text x="265" y="140" transform="scale(.1)" fill="#fff" textLength="410">version</text><text aria-hidden="true" x="675" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="250">v1.1</text><text x="675" y="140" transform="scale(.1)" fill="#fff" textLength="250">v1.1</text></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,11 @@
### Cache 分布式方案-Getway
![getway方案](https://gitee.com/timedb/img/raw/master/images/getway方案.svg)
1. single 集群分布式方案中,使用 getway 方向代理客户端的 grpc 请求, 通过 hash 环实现 分布式。
2. 集群模式中, 通过主从来 实现 cache 的备份问题,提高容灾性。

32
doc/make.md Normal file
View File

@ -0,0 +1,32 @@
### 构建工具文档
#### dcgen
1. 根据结构体接口模板生成 proto 文件
2. 迁移 proto 到 pkg/proto 下
3. 更新结构体常量
>PS : 开发一个 storage 的新接口时一般有以下步骤
>1. 修改 storage 接口配置文件
>2. make dcgen
>3. 修改生成的 proto 文件
>4. make dcgen
>5. 添加 storage 的操作接口
#### build-storage
编译并且生成 /bin/storage
#### build-gateway
编译并且生成 /bin/gateway
#### install
1. 安装项目,需要 sudo
#### storage
根据配置文件启动 storage
#### gateway
根据配置文件启动 gateway
#### init-conf
根据配置文件文档初始化配置文件到 /etc/wheat-cache/wheat-cache.yaml

View File

@ -0,0 +1,13 @@
### 事件驱动 2.0
### event 1.0 存在的问题
事件驱动 1.0 在 相互关联访问时,会发生 死锁问题, 导致一个事件执行周期失败
### event 2.0 新特性
- 异步事件支持
- 挂起操作
### event 2.0 设计图
![](../../_icon/event.svg)

View File

@ -0,0 +1,150 @@
### 事件驱动使用文档
- 包目录: pkg/event
- 使用场景, 异步推送数据
#### 事件驱动基本概念
- event
event 是事件驱动的事件部分, 主要负责一些信息的传递, 一共分为,有等待和无等待的事件, 无等待事件 consumer 消费事件后,不会给 produce 回复, 有等待事件, 支持事件消费后, 向 produce 发送一个回复。
- driver
driver 是事件的驱动, 主要复制连接 produce 以及 consumer 其中维护了一个 event 的队列。
- produce
produce 主要负责 推送 事件, 每个 produce 都需要维护一个 事件驱动通过 driver 来进行数据的推送。
- consumer
consumer 负责接收事件, 每个 consumer 都需要注册一个 事件驱动 来获取 event。
####
#### 应用场景
事件驱动主要用于 异步消息的推送(目前的实现也支持 同步的消息实现), 一般来说 produce 发送 event 后 event 被消费过程会完全于 produce 无关。
#### 无返回 event 使用例子
我们使用 借书为例子使用, 假设 A 要把 书 S 交还给 B 他们约定, A 把书 S 放到图书馆, B 在空闲时去图书馆取出书 S。
```go
func TestNewConsumer(t *testing.T) {
// 定义一个图书馆
type Library struct {
driver DriverInterface
}
library := &Library{
driver: NewDriver(100),
}
ctx := context.Background()
// 定义 A
type A struct {
produce ProduceInterface
}
a := &A{
produce: NewProduce(library.driver),
}
// 定义 B
type B struct {
consumer ConsumerInterface
}
b := &B{
consumer: NewConsumer(library.driver),
}
// 定义书 S 并且添加一些描述
book := NewEvent("S")
book.SetMsg("title", "hello world")
book.SetCtxValue("pages", 120)
// A 把书 S 放到图书馆
go func() {
a.produce.Call(ctx, book)
}()
// 模拟 B 去图书馆拿书
book = b.consumer.Receive(ctx)
fmt.Println(book.GetMsg("title"))
}
```
#### 有返回event的使用例子
在上述流程的情景下, 我们添加一些条件, B 拿到书以后检查书是否损坏,如果损坏, 需要告诉 A 书损坏情况。
```go
func TestNewConsumer(t *testing.T) {
// 定义一个图书馆
type Library struct {
driver DriverInterface
}
library := &Library{
driver: NewDriver(100),
}
ctx := context.Background()
// 定义 A
type A struct {
produce ProduceInterface
}
a := &A{
produce: NewProduce(library.driver),
}
// 定义 B
type B struct {
consumer ConsumerInterface
}
b := &B{
consumer: NewConsumer(library.driver),
}
// 定义书 S 并且添加一些描述
book := NewEvent("S")
book.SetMsg("title", "hello world")
book.SetValue("pages", 120)
// A 把书 S 放到图书馆
go func() {
book.InitWaitEvent()
a.produce.Call(ctx, book)
// A 等待 B 的回复, 但是他最多只会等待 B 2个小时
res, err := book.StartWaitEvent(2 * time.Hour)
require.NoError(t, err)
fmt.Println(res)
}()
// 模拟 B 去图书馆拿书
book = b.consumer.Receive(ctx)
fmt.Println(book.GetMsg("title"))
// 书完好
book.ExecWorkAndSendResult(func() (interface{}, error) {
// b 检查书
return "OK", nil
})
time.Sleep(50 * time.Millisecond)
}
```

7
doc/pkg/lru/LRU设计.md Normal file
View File

@ -0,0 +1,7 @@
![](https://gitee.com/HuangJiaLuo/imgbed/raw/master/LRUdesign.svg)
EventP : 生产事件
EventQ : 事件队列
Event CP : 清理事件

View File

@ -0,0 +1,5 @@
### RDB + AOF 的事务解决方案
![事务RDB方案](https://gitee.com/timedb/img/raw/master/images/事务RDB方案.svg)

47
doc/pkg/middle/middle.md Normal file
View File

@ -0,0 +1,47 @@
### 中间件调用
### 创建事件
event := event.NewEvent("logcontext")
### 创建驱动
middleware := NewMiddleWare()
### 将事件推入驱动
middleware.eventProduce.Call(ctx, event)
### 获取驱动的事件
middleware.eventConsumer.Reciver(ctx)
### 插件接口
type MiddleToolsInterface interface {
Init() // 初始化
Exec(interface{}) (interface{}, error) // 处理用户发送事件
Name() string // 获取中间件名称
Describe() string // 描述
}
### 插件的New方法规定为 NewMiddleWare()
每个插件都要定义 NewMiddleWare()
### 将插件名 “logMiddle” 注册到配置文件wheat-cache.yaml,其他插件注册
plugins-control:
logcontext: ["logMiddle"]

View File

@ -0,0 +1,60 @@
### 结构体开发文档
#### 基础结构体开发
- 基础结构体放到 /pkg/structure。
- 每个结构 类型都以 x 结尾,如 listx stringx。
- 在 pkg/structure/define.go 文件中添加对应结构体的接口,主要为 了保证项目可以扩展线程安全结构体, 以及结构体接口的实现, 目前 lru 采用 single 模式, 可以只开发 single 的结构体,如 stringxSingle。
- 请在结构体包中 补充单元测试。
#### 目前实现结构体接口说明
> ps: 所有的详细用法都可以查看单元测试文件。
```go
// stringx
type StringXInterface interface {
KeyBaseInterface
// 重新设置一个 值
Set(string) (string, UpdateLength)
// 获取值的 string 形式
Get() string
// 值自动增加 一个值,只对 float 和 string 有效
Add(int32) (string, error)
// 值自动增加 减少值,只对 float 和 string 有效
Reduce(int32) (string, error)
// 使用位图类型
Setbit(int32, bool) UpdateLength
Getbit(int32) (bool, error)
// 获取字符串的切片
Getrange(start, end int32) (string, error)
GetLength() int
}
// listx
type ListXInterface interface {
KeyBaseInterface
LPush(...string) UpdateLength
RPush(...string) UpdateLength
LPop(int) ([]string, UpdateLength)
RPop(int) ([]string, UpdateLength)
Index(int) (string, error)
// 插入一组数据, bool 类型表示是否右插尾插false 时采用左插(头插)
Insert(int, bool, ...string) (UpdateLength, error)
Length() int
// 切片, O(n)复杂度
Slice(start, end int) (UpdateLength, error)
}
```
### structure.Value 类型
- 结构体的数据区域全部使用 structure.Value 类型存储。
- structure.Value 主要实现了 sting, int64, float64 的存储接口。
- structure.Value 非常容易计算内存占用。
- structure.UpdateLength 指的是在进行某一个操作以后,内存大小的变化。
- 为了保证 lru 的存储效率lru 不会去遍历全部的 key 来重新计算大小,而是根据 UpdateLength 来动态更新 lru 的大小,具体实现在 dao 中。
- structure.Value 类型的使用方法可以在 pkg/structure/value_test.go 中获取。

46
doc/storage/storage.md Normal file
View File

@ -0,0 +1,46 @@
### 快速进行 storage 开发
#### 开发环境
- ubuntu18, 可以使用 wsl
- go1.15+, python3
- jinja2
- go mod
- protobuf 3.17.3
- protoc-gen-go v1.26.0
#### storage 执行流程
![](../_icon/storage-dao.svg)
#### 分层,简介
```sh
.
├── cmd # storage 启动函数
│ └── root.go
├── dao # 实际处理层,接口实现全部再 dao 层里实现
│ ├── dao.go
│ ├── dao_test.go
│ ├── interface.gen.go
│ ├── listx.go # listx 相关功能
│ └── stringx.go
├── main.go
├── service # 接口层,由 gen-service 自动生成
│ ├── define.go
│ ├── single.go
│ └── single_service.gen.go
└── temp # 开发模板层
├── const.gen.go
├── const.template
├── dao.template
├── service.template
└── tem.yaml
```
#### 快速开发接口
> [快速开发视频 blibli](https://www.bilibili.com/video/BV1HL4y1v7ps)
1. 修改 temp/tem.yaml 文件,添加新接口
2. 在项目根目录执行 `make dcgen` 生成 proto 原始结构
3. 修改对应新添加接口的 proto 文件,再次执行 `make dcgen` 完成 proto 迁移
4. 执行 `make gen-service` 生成 dao 接口
5. 完成 新 dao 层接口, 根据需要添加单元测试。
6. 使用 make install 编译并且安装项目

6
doc/前端文档.md Normal file
View File

@ -0,0 +1,6 @@
### 前端技术选择
- react框架
- 组件antd或React-bootstrap或其他css组件
- 图表库BizCharts
- protobufjs
- grafana

View File

@ -0,0 +1,54 @@
### 单元测试文档
#### 样例
```go
package dao
import (
"testing"
_ "gitee.com/wheat-os/wheatCache/conf"
"gitee.com/wheat-os/wheatCache/pkg/lru"
"gitee.com/wheat-os/wheatCache/pkg/proto"
"github.com/stretchr/testify/require"
)
// 规范1. 每个 package 应该都至少有一个单测
// 规范2. 包里有公用的 mock 数据应该分离出来。
func mockData(t *testing.T, d *Dao) {
values := []string{"1", "1.3", "abcdefg"}
for _, val := range values {
key := &proto.BaseKey{
Key: val,
}
_, err := d.Set(key, val)
// 规范3. 使用 require 包来完成单测
require.NoError(t, err)
}
}
// 规范4. 单元测试应该尽可能覆盖全部情况,不要使用依赖注入。
func TestDao_Reduce(t *testing.T) {
lruCache := lru.NewLRUCache()
dao := NewDao(lruCache)
mockData(t, dao)
resp, err := dao.Reduce(&proto.BaseKey{Key: "1"}, 2)
require.NoError(t, err)
require.Equal(t, resp, "-1")
resp, err = dao.Reduce(&proto.BaseKey{Key: "1.3"}, 2)
require.NoError(t, err)
require.Equal(t, resp, "-0.70")
_, err = dao.Reduce(&proto.BaseKey{Key: "abcdefg"}, 2)
require.Error(t, err)
}
```

View File

@ -0,0 +1,119 @@
### 开发流程
- 拉取 master 到本地
```
git fetch origin master && git rebase origin/master
```
- 查看本地更改 commit
```
git log
```
- 添加分支
```sh
# name-(feat, fix, doc)-(mode)-(task)
git checkout -b doc-pro-git-doc
```
- do task
- 提交 检查
```
git push origin doc-pro-git-doc
```
- 监听文件
```
git add .
```
- 添加 commit
```
git commit -m "init doc"
```
>**commit message格式**
>
>```text
><type>(<scope>): <subject>
>```
>
>**type(必须)**
>
>用于说明git commit的类别只允许使用下面的标识。
>
>feat新功能feature
>
>fix修复bug可以是QA发现的BUG也可以是研发自己发现的BUG。
>
>doc文档documentation
>
>style格式不影响代码运行的变动
>
>refactor重构即不是新增功能也不是修改bug的代码变动
>
>perf优化相关比如提升性能、体验。
>
>test增加测试。
>
>chore构建过程或辅助工具的变动。
>
>revert回滚到上一个版本。
>
>merge代码合并。
- 提交PR (remove)
```
添加描述, 提交PR
```
- 解决问题
- 整理 commit
- 整理
```shell
git rebase -i origin/master
f:
# 回调
git rebase --abort
# 继续
```
- 强行推送
```
git push -f origin doc-pro-git-doc
```
- 重做
```sh
git log
# 7e8108bc7347ef6e2f01d6bc1d1f249afc82a486
git reset 7e8108bc7347ef6e2f01d6bc1d1f249afc82a486
```
- 合并冲突
```sh
# B 分支名称
git pull origin B
```
-

69
gateway/cmd/root.go Normal file
View File

@ -0,0 +1,69 @@
package cmd
import (
"fmt"
"net"
_ "gitee.com/wheat-os/wheatCache/conf"
wheatCodec "gitee.com/wheat-os/wheatCache/gateway/codec"
"gitee.com/wheat-os/wheatCache/gateway/endpoint"
"gitee.com/wheat-os/wheatCache/gateway/proxy"
"gitee.com/wheat-os/wheatCache/pkg/logx"
"gitee.com/wheat-os/wheatCache/pkg/util/server"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"google.golang.org/grpc"
)
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "getway",
Short: "getway",
Long: `start getway server`,
Run: func(cmd *cobra.Command, args []string) {
host := viper.GetString("gateway.host")
port := viper.GetInt("gateway.port")
tcpAddr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", host, port))
if err != nil {
logx.Panic("get gateway addr err:%v", err)
}
listen, err := net.ListenTCP("tcp", tcpAddr)
if err != nil {
logx.Panic("get gateway tcp conn err:%v", err)
}
gatewayServer := GetGatewayServer()
server.ElegantExitServer(gatewayServer)
logx.Info("start gateway in addr: %s", tcpAddr.String())
if err := gatewayServer.Serve(listen); err != nil {
logx.Errorln(err)
}
},
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
cobra.CheckErr(rootCmd.Execute())
}
func GetGatewayServer() *grpc.Server {
targets := viper.GetStringSlice("gateway.target")
logx.Debug("service target in %v", targets)
stream := proxy.GetDirectorByServiceHash()
endpoint := endpoint.NewHashEndpoint(endpoint.HashReplicasDefault, nil, targets...)
opts := make([]grpc.ServerOption, 0)
opts = append(
opts,
grpc.ForceServerCodec(wheatCodec.Codec()),
grpc.UnknownServiceHandler(proxy.TransparentHandler(stream, endpoint)),
)
return grpc.NewServer(opts...)
}

60
gateway/codec/codce.go Normal file
View File

@ -0,0 +1,60 @@
package codec
import (
"google.golang.org/grpc/encoding"
"google.golang.org/protobuf/proto"
)
// protoCodec 用于 gateway 解析全部的 grpc 类型的消息
type protoCodec struct{}
func (protoCodec) Name() string {
return "wheat-cache-proto"
}
func (protoCodec) Marshal(v interface{}) ([]byte, error) {
return proto.Marshal(v.(proto.Message))
}
func (protoCodec) Unmarshal(data []byte, v interface{}) error {
return proto.Unmarshal(data, v.(proto.Message))
}
type Frame struct {
payload []byte
}
type proxyCodec struct {
baseCodec encoding.Codec
}
func (p *proxyCodec) Name() string {
return "wheat-cache-proxy"
}
func (p *proxyCodec) Marshal(v interface{}) ([]byte, error) {
out, ok := v.(*Frame)
if !ok {
return p.Marshal(v)
}
return out.payload, nil
}
func (p *proxyCodec) Unmarshal(data []byte, v interface{}) error {
dst, ok := v.(*Frame)
if !ok {
return p.Unmarshal(data, v)
}
dst.payload = data
return nil
}
// CodeWithParent 生成基于 proto 的解码器
func CodeWithParent(parent encoding.Codec) encoding.Codec {
return &proxyCodec{parent}
}
func Codec() encoding.Codec {
return CodeWithParent(protoCodec{})
}

View File

@ -0,0 +1,11 @@
package endpoint
type EndpointInterface interface {
GetTargetAddr(...string) (string, error)
IsEmpty() bool
AddTarget(targets ...string)
}
const (
HashReplicasDefault = 3
)

85
gateway/endpoint/hash.go Normal file
View File

@ -0,0 +1,85 @@
package endpoint
import (
"hash/crc32"
"sort"
"strconv"
"gitee.com/wheat-os/wheatCache/pkg/errorx"
)
type HashFunc func(data []byte) uint32
// 实现 sort
type UInt32Slice []uint32
func (s UInt32Slice) Len() int {
return len(s)
}
func (s UInt32Slice) Less(i, j int) bool {
return s[i] < s[j]
}
func (s UInt32Slice) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
type HashEndpoint struct {
hash HashFunc
replicas int // 复制因子
keys UInt32Slice
hashMap map[uint32]string // taraget 隐射
}
func NewHashEndpoint(replicas int, fn HashFunc, target ...string) EndpointInterface {
endpoint := &HashEndpoint{
replicas: replicas,
hash: fn,
hashMap: make(map[uint32]string, len(target)),
}
if endpoint.hash == nil {
endpoint.hash = crc32.ChecksumIEEE // 默认使用 CRC32 算法
}
endpoint.AddTarget(target...)
return endpoint
}
func (h *HashEndpoint) IsEmpty() bool {
return len(h.keys) == 0
}
func (h *HashEndpoint) AddTarget(targets ...string) {
for _, tar := range targets {
for i := 0; i < h.replicas; i++ {
hash := h.hash([]byte(strconv.Itoa(i) + tar))
h.keys = append(h.keys, hash)
h.hashMap[hash] = tar
}
}
// 虚拟值排序,方便查找
sort.Sort(h.keys)
}
func (h *HashEndpoint) GetTargetAddr(str ...string) (string, error) {
if h.IsEmpty() {
return "", errorx.New("gateway not register transport")
}
if len(str) != 1 {
return "", errorx.New("must give key")
}
hash := h.hash([]byte(str[0]))
idx := sort.Search(len(h.keys), func(i int) bool { return h.keys[i] >= hash })
if idx == len(h.keys) {
return h.hashMap[h.keys[0]], nil
}
return h.hashMap[h.keys[idx]], nil
}

View File

@ -0,0 +1,17 @@
package endpoint
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestHashTransport_GetTargetAddr(t *testing.T) {
tran := NewHashEndpoint(3, nil, "127.0.0.1:5581", "127.0.0.1:5582", "127.0.0.1:5583")
key := "test"
target, err := tran.GetTargetAddr(key)
require.NoError(t, err)
require.Equal(t, target, "127.0.0.1:5582")
}

7
gateway/main.go Normal file
View File

@ -0,0 +1,7 @@
package main
import "gitee.com/wheat-os/wheatCache/gateway/cmd"
func main() {
cmd.Execute()
}

17
gateway/proxy/define.go Normal file
View File

@ -0,0 +1,17 @@
package proxy
import (
"context"
"gitee.com/wheat-os/wheatCache/gateway/endpoint"
"google.golang.org/grpc"
)
type StreamDirector func(ctx context.Context, fullMethodName string, endpoint endpoint.EndpointInterface) (context.Context, *grpc.ClientConn, error)
var (
clientStreamDescForProxying = &grpc.StreamDesc{
ServerStreams: true,
ClientStreams: true,
}
)

37
gateway/proxy/director.go Normal file
View File

@ -0,0 +1,37 @@
package proxy
import (
"context"
"gitee.com/wheat-os/wheatCache/gateway/codec"
"gitee.com/wheat-os/wheatCache/gateway/endpoint"
"gitee.com/wheat-os/wheatCache/pkg/proto"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
func GetDirectorByServiceHash() StreamDirector {
return func(ctx context.Context, fullMethodName string, endpoint endpoint.EndpointInterface) (context.Context, *grpc.ClientConn, error) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, nil, status.Errorf(codes.Unknown, "from FromIncomingContext err")
}
baseKey, ok := md[proto.BaseKeyMethodKey]
if !ok {
return nil, nil, status.Errorf(codes.Unknown,
"grpc header is not found %s, please check the client interceptor", proto.BaseKeyMethodKey)
}
target, err := endpoint.GetTargetAddr(baseKey...)
if err != nil {
return nil, nil, status.Errorf(codes.Unknown, "get transport err, err:%v", err)
}
cli, err := grpc.DialContext(ctx, target, grpc.WithInsecure(), grpc.WithDefaultCallOptions(grpc.ForceCodec(codec.Codec())))
return ctx, cli, err
}
}

131
gateway/proxy/proxy.go Normal file
View File

@ -0,0 +1,131 @@
package proxy
import (
"context"
"io"
wheatCodec "gitee.com/wheat-os/wheatCache/gateway/codec"
"gitee.com/wheat-os/wheatCache/gateway/endpoint"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// TransparentHandler returns a handler that attempts to proxy all requests that are not registered in the server.
// The indented use here is as a transparent proxy, where the server doesn't know about the services implemented by the
// backends. It should be used as a `grpc.UnknownServiceHandler`.
//
// This can *only* be used if the `server` also uses grpcproxy.CodecForServer() ServerOption.
func TransparentHandler(director StreamDirector, endpoint endpoint.EndpointInterface) grpc.StreamHandler {
streamer := &handler{
director,
endpoint,
}
return streamer.handler
}
type handler struct {
director StreamDirector
endpoint endpoint.EndpointInterface
}
// handler is where the real magic of proxying happens.
// It is invoked like any gRPC server stream and uses the gRPC server framing to get and receive bytes from the wire,
// forwarding it to a ClientStream established against the relevant ClientConn.
func (s *handler) handler(srv interface{}, serverStream grpc.ServerStream) error {
fullMethodName, ok := grpc.MethodFromServerStream(serverStream)
if !ok {
return status.Errorf(codes.Internal, "lowLevelServerStream not exists in context")
}
outgoingCtx, backendConn, err := s.director(serverStream.Context(), fullMethodName, s.endpoint)
if err != nil {
return err
}
clientCtx, clientCancel := context.WithCancel(outgoingCtx)
defer clientCancel()
clientStream, err := grpc.NewClientStream(clientCtx, clientStreamDescForProxying, backendConn, fullMethodName)
if err != nil {
return err
}
s2cErrChan := s.forwardServerToClient(serverStream, clientStream)
c2sErrChan := s.forwardClientToServer(clientStream, serverStream)
for i := 0; i < 2; i++ {
select {
case s2cErr := <-s2cErrChan:
if s2cErr == io.EOF {
// 客户端流发送完毕正常关闭结束, Proxy 关闭对 Backend 的连接
clientStream.CloseSend()
break
}
clientCancel()
return status.Errorf(codes.Internal, "failed proxying s2c: %v", s2cErr)
case c2sErr := <-c2sErrChan:
// 服务的没用在提供数据触发这个分支
serverStream.SetTrailer(clientStream.Trailer())
if c2sErr != io.EOF {
return c2sErr
}
return nil
}
}
return status.Errorf(codes.Internal, "gRPC proxying should never reach this stage.")
}
func (s *handler) forwardClientToServer(src grpc.ClientStream, dst grpc.ServerStream) chan error {
ret := make(chan error, 1)
go func() {
f := &wheatCodec.Frame{}
for i := 0; ; i++ {
if err := src.RecvMsg(f); err != nil {
ret <- err // this can be io.EOF which is happy case
break
}
if i == 0 {
// This is a bit of a hack, but client to server headers are only readable after first client msg is
// received but must be written to server stream before the first msg is flushed.
// This is the only place to do it nicely.
md, err := src.Header()
if err != nil {
ret <- err
break
}
if err := dst.SendHeader(md); err != nil {
ret <- err
break
}
}
if err := dst.SendMsg(f); err != nil {
ret <- err
break
}
}
}()
return ret
}
func (s *handler) forwardServerToClient(src grpc.ServerStream, dst grpc.ClientStream) chan error {
ret := make(chan error, 1)
go func() {
f := &wheatCodec.Frame{}
for i := 0; ; i++ {
if err := src.RecvMsg(f); err != nil {
ret <- err // this can be io.EOF which is happy case
break
}
if err := dst.SendMsg(f); err != nil {
ret <- err
break
}
}
}()
return ret
}

6
go.mod
View File

@ -1,8 +1,12 @@
module gitee.com/timedb/wheatCache
module gitee.com/wheat-os/wheatCache
go 1.16
require (
github.com/golang/mock v1.5.0
github.com/spf13/cobra v1.2.1
github.com/spf13/viper v1.8.1
github.com/stretchr/testify v1.7.0
google.golang.org/grpc v1.41.0
google.golang.org/protobuf v1.26.0
)

13
go.sum
View File

@ -46,6 +46,7 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@ -53,6 +54,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
@ -65,6 +67,7 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
@ -86,6 +89,7 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -103,6 +107,7 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@ -116,6 +121,7 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@ -250,6 +256,7 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
@ -330,6 +337,7 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -462,6 +470,7 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@ -532,6 +541,7 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
@ -553,6 +563,8 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E=
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -564,6 +576,7 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=

View File

@ -0,0 +1,58 @@
BASE_PATH = $(shell pwd)
STORAGE_PATH = $(BASE_PATH)/storage
BASE_OUT = $(BASE_PATH)/bin
MAKEFLAGS+= --no-print-directory
dcgen:
@python3 ./shell/gen_protobuf.py
@python3 ./shell/proto.py
@python3 ./shell/make-struct.py
.PHONY: build-storage
build-storage:
@cd storage && go build -o $(BASE_OUT)/storage
.PHONY: build-gateway
build-gateway:
@cd gateway && go build -o $(BASE_OUT)/gateway
.PHONY: install
install:
@make gen-middleware
@make build-storage
@make build-gateway
@sudo python3 ./shell/init_conf.py
.PHONY: storage
storage:
@./bin/storage storage
.PHONY: gateway
gateway:
@./bin/gateway gateway
.PHONY: gen-struct
gen-struct:
@python3 ./shell/make-struct.py
.PHONY: gen-protobuf
gen-protobuf:
@python3 ./shell/gen_protobuf.py
.PHONY: gen-middleware
gen-middleware:
@python3 ./shell/gen_middleware.py
.PHONY: init-conf
init-conf:
@python3 ./shell/init_conf.py
.PHONY: gen-service
gen-service:
@python3 ./shell/make_service.py
.PHONY: gen-mock
gen-mock:
@mockgen -source=./pkg/proto/storage.pb.go CommServerClient > ./mock/storage/mock_client.gen.go

File diff suppressed because it is too large Load Diff

9
pkg/errorx/dao.go Normal file
View File

@ -0,0 +1,9 @@
package errorx
func DaoTypeErr(typ string) error {
return New("the type is not: %s", typ)
}
func NotKeyErr(key string) error {
return New("the key is not exist, key:%s", key)
}

12
pkg/errorx/err.go Normal file
View File

@ -0,0 +1,12 @@
package errorx
import (
"errors"
"fmt"
)
// New TODO 添加链路追踪等 @bandl @lgq
func New(msg string, format ...interface{}) error {
msg = fmt.Sprintf(msg, format...)
return errors.New(msg)
}

5
pkg/errorx/event.go Normal file
View File

@ -0,0 +1,5 @@
package errorx
func EventRecoveryErr() error {
return New("this event has been recycled")
}

9
pkg/errorx/lru.go Normal file
View File

@ -0,0 +1,9 @@
package errorx
func LruNotWorkFuncEventErr() error {
return New("the event haven't work of function")
}
func KeyBaseIsNilErr() error {
return New("key base can't be nil")
}

5
pkg/errorx/time.go Normal file
View File

@ -0,0 +1,5 @@
package errorx
func TimeOutErr() error {
return New("time out err")
}

25
pkg/event/consumer.go Normal file
View File

@ -0,0 +1,25 @@
package event
import "context"
type Consumer struct {
driver DriverInterface
}
func (c *Consumer) Receive(ctx context.Context) *event {
return c.driver.Get()
}
func (c *Consumer) NewEvent(name string) *event {
return c.driver.NewEvent(name)
}
func (c *Consumer) Recovery(e *event) {
c.driver.Recovery(e)
}
func NewConsumer(driver DriverInterface) ConsumerInterface {
return &Consumer{
driver: driver,
}
}

33
pkg/event/define.go Normal file
View File

@ -0,0 +1,33 @@
package event
import (
"context"
)
const (
defaultEventState = int32(iota) //默认情况下的状态
waitEventState // 等待状态
workEventState //工作状态
closeEventState //事件关闭状态
)
type EventWorkFunc func() (interface{}, error)
type DriverInterface interface {
Get() *event
Put(*event)
GetLength() int
NewEvent(string) *event
Recovery(*event)
}
type ProduceInterface interface {
Call(context.Context, *event)
NewEvent(string) *event
Recovery(*event)
}
type ConsumerInterface interface {
Receive(ctx context.Context) *event
Recovery(*event)
}

189
pkg/event/driver.go Normal file
View File

@ -0,0 +1,189 @@
package event
import (
"sync/atomic"
"time"
"gitee.com/wheat-os/wheatCache/pkg/errorx"
)
// 事件 poll 降低 new 对象的频率
type eventPoll struct {
poll chan *event
maxSize int32
nowSize *int32
}
func (e *eventPoll) getEvent() *event {
issSize := atomic.LoadInt32(e.nowSize)
if issSize < e.maxSize {
atomic.AddInt32(e.nowSize, 1)
return newEvent()
}
return <-e.poll
}
func (e *eventPoll) recovery(rEvent *event) {
rEvent.Reset()
e.poll <- rEvent
}
func newEventPoll(maxSize int) *eventPoll {
return &eventPoll{
poll: make(chan *event, maxSize),
maxSize: int32(maxSize),
nowSize: new(int32),
}
}
type event struct {
msgCtx map[string]interface{}
eventName string
msg map[string]string // 消息
waitResult chan interface{} // 等待返回
err error
eventStatus *int32
ttlManage *time.Timer
}
func newEvent() *event {
status := defaultEventState
return &event{
eventStatus: &status,
}
}
func (e *event) Reset() {
if e.ttlManage != nil {
e.ttlManage.Stop()
}
e.err = nil
atomic.SwapInt32(e.eventStatus, defaultEventState)
}
func (e *event) SetMsg(key string, val string) {
if e.msg == nil {
e.msg = make(map[string]string)
}
e.msg[key] = val
}
func (e *event) GetMsg(key string) string {
return e.msg[key]
}
func (e *event) GetEventName() string {
return e.eventName
}
// SetValue 写入 ctx 传递用参数
func (e *event) SetValue(key string, value interface{}) {
if e.msgCtx == nil {
e.msgCtx = make(map[string]interface{})
}
e.msgCtx[key] = value
}
func (e *event) GetValue(key string) (interface{}, bool) {
val, ok := e.msgCtx[key]
return val, ok
}
// InitWaitEvent 初始化 wait event 必须调用才拥有等待特性
func (e *event) InitWaitEvent() {
if e.waitResult == nil || len(e.waitResult) > 0 {
e.waitResult = make(chan interface{})
}
// 清理残留
if e.ttlManage == nil {
e.ttlManage = time.NewTimer(0)
}
e.ttlManage.Stop()
if len(e.ttlManage.C) > 0 {
<-e.ttlManage.C
}
atomic.CompareAndSwapInt32(e.eventStatus, defaultEventState, waitEventState)
}
// StartWaitEvent 开始一个等待任务
func (e *event) StartWaitEvent(ttl time.Duration) (interface{}, error) {
e.ttlManage.Reset(ttl)
for {
select {
case <-e.ttlManage.C:
if atomic.CompareAndSwapInt32(e.eventStatus, waitEventState, closeEventState) {
return nil, errorx.TimeOutErr()
}
continue
case result := <-e.waitResult:
atomic.CompareAndSwapInt32(e.eventStatus, workEventState, closeEventState)
return result, e.err
}
}
}
func (e *event) ExecWorkAndSendResult(work EventWorkFunc) (interface{}, error) {
if !atomic.CompareAndSwapInt32(e.eventStatus, waitEventState, workEventState) {
return nil, errorx.New("not wait status, exec err")
}
res, err := work()
e.err = err
e.waitResult <- res
return res, err
}
func (e *event) SetResultErr(err error) {
if !atomic.CompareAndSwapInt32(e.eventStatus, waitEventState, workEventState) {
return
}
e.err = err
e.waitResult <- nil
}
type Driver struct {
maxQueueSize int
queue chan *event
poll *eventPoll
}
// Get 获取驱动
func (d *Driver) Get() *event {
return <-d.queue
}
func (d *Driver) Put(event *event) {
d.queue <- event
}
func (d *Driver) GetLength() int {
return len(d.queue)
}
func (d *Driver) NewEvent(name string) *event {
event := d.poll.getEvent()
event.eventName = name
return event
}
// 任何时候回收事件都应该由 最后使用者回收
func (d *Driver) Recovery(e *event) {
d.poll.recovery(e)
}
// NewDriver 新建 Driver
func NewDriver(maxSize int) DriverInterface {
return &Driver{
maxQueueSize: maxSize,
queue: make(chan *event, maxSize),
poll: newEventPoll(maxSize),
}
}

89
pkg/event/event_test.go Normal file
View File

@ -0,0 +1,89 @@
package event
import (
"context"
"fmt"
"strconv"
"sync"
"testing"
"time"
"github.com/stretchr/testify/require"
)
const testEvent = "1001"
const waitTestEvent = "1002"
// 简单的 单向 event 使用
func Test_EventDriver(t *testing.T) {
driver := NewDriver(2000)
produce := NewProduce(driver)
consumer := NewConsumer(driver)
ctx := context.Background()
wait := sync.WaitGroup{}
wait.Add(30000)
go func() {
for i := 0; i < 30000; i++ {
event := produce.NewEvent(testEvent)
event.SetMsg("k", strconv.Itoa(i))
produce.Call(ctx, event)
}
}()
go func() {
for {
event := consumer.Receive(ctx)
fmt.Println(event.GetMsg("k"))
consumer.Recovery(event)
wait.Done()
}
}()
wait.Wait()
fmt.Println(*driver.(*Driver).poll.nowSize)
}
// 双向 event
func Test_WaitEventDriver(t *testing.T) {
driver := NewDriver(200)
produce := NewProduce(driver)
consumer := NewConsumer(driver)
ctx := context.Background()
wait := sync.WaitGroup{}
wait.Add(300000)
go func() {
for i := 0; i < 300000; i++ {
event := produce.NewEvent(testEvent)
event.SetMsg("k", strconv.Itoa(i))
event.InitWaitEvent()
produce.Call(ctx, event)
val, err := event.StartWaitEvent(2 * time.Second)
require.NoError(t, err)
fmt.Println(val)
produce.Recovery(event)
wait.Done()
}
}()
go func() {
for {
event := consumer.Receive(ctx)
event.ExecWorkAndSendResult(func() (interface{}, error) {
msg := event.GetMsg("k")
return "hello: " + msg, nil
})
}
}()
wait.Wait()
fmt.Println(*driver.(*Driver).poll.nowSize)
}

25
pkg/event/produce.go Normal file
View File

@ -0,0 +1,25 @@
package event
import "context"
type Produce struct {
driver DriverInterface
}
func (p *Produce) NewEvent(name string) *event {
return p.driver.NewEvent(name)
}
func (p *Produce) Recovery(e *event) {
p.driver.Recovery(e)
}
func (p *Produce) Call(ctx context.Context, e *event) {
p.driver.Put(e)
}
func NewProduce(driver DriverInterface) ProduceInterface {
return &Produce{
driver: driver,
}
}

21
pkg/event2/consumer.go Normal file
View File

@ -0,0 +1,21 @@
package event2
import "context"
type Consumer struct {
driver DriverInterface
}
func (c *Consumer) Receive(ctx context.Context) *event {
return c.driver.Get()
}
func (c *Consumer) NewEvent(name string) *event {
return c.driver.NewEvent(name)
}
func NewConsumer(driver DriverInterface) ConsumerInterface {
return &Consumer{
driver: driver,
}
}

49
pkg/event2/define.go Normal file
View File

@ -0,0 +1,49 @@
package event2
import (
"context"
)
const (
initEventState = int32(iota) // 初始化状态
waitEventState // 等待状态
workEventState // 工作状态
closeEventState // 事件关闭状态
recoveryEventState // 事件回收状态
)
const (
awaitThread = 3
)
const (
WorkFuncEventKey = "workFunc"
)
// 线程安全
type EventWorkFunc func() (interface{}, error)
// 挂起事件, 线程不安全
type EventAwaitFunc func() (interface{}, error)
// 实际操作
type awaitFunc func() (*event, interface{}, error)
type DriverInterface interface {
Get() *event
Put(*event)
GetLength() int
NewEvent(string) *event
await(awaitFunc)
recovery(e *event)
}
type ProduceInterface interface {
Call(context.Context, *event)
NewEvent(string) *event
}
type ConsumerInterface interface {
Receive(ctx context.Context) *event
}

221
pkg/event2/driver.go Normal file
View File

@ -0,0 +1,221 @@
package event2
import (
"sync/atomic"
"time"
"gitee.com/wheat-os/wheatCache/pkg/errorx"
)
type event struct {
msgCtx map[string]interface{}
eventName string
msg map[string]string // 消息
waitResult chan interface{} // 等待返回
err error
eventStatus int32
ttlManage *time.Timer
parentDriver DriverInterface
}
func (e *event) reset() {
if e.ttlManage != nil {
e.ttlManage.Stop()
if len(e.ttlManage.C) > 0 {
<-e.ttlManage.C
}
}
e.err = nil
// 清空结果
if len(e.waitResult) != 0 {
<-e.waitResult
}
}
func (e *event) Recovery() {
e.parentDriver.recovery(e)
}
func (e *event) SetMsg(key string, val string) {
if e.msg == nil {
e.msg = make(map[string]string)
}
e.msg[key] = val
}
func (e *event) GetMsg(key string) string {
if e.msg == nil {
return ""
}
return e.msg[key]
}
func (e *event) GetEventName() string {
return e.eventName
}
// SetValue 写入 ctx 传递用参数
func (e *event) SetValue(key string, value interface{}) {
if e.msgCtx == nil {
e.msgCtx = make(map[string]interface{})
}
e.msgCtx[key] = value
}
func (e *event) GetValue(key string) (interface{}, bool) {
if e.msgCtx == nil {
return nil, false
}
val, ok := e.msgCtx[key]
return val, ok
}
func (e *event) InitWaitEvent() {
e.reset()
if e.waitResult == nil {
e.waitResult = make(chan interface{})
}
atomic.SwapInt32(&e.eventStatus, waitEventState)
}
func (e *event) SetResultErr(err error) {
if !atomic.CompareAndSwapInt32(&e.eventStatus, waitEventState, workEventState) {
return
}
e.err = err
e.waitResult <- nil
}
// StartWaitEvent 开始一个等待任务
func (e *event) StartWaitEvent(ttl time.Duration) (interface{}, error) {
if e.ttlManage == nil {
e.ttlManage = time.NewTimer(ttl)
} else {
e.ttlManage.Reset(ttl)
}
for {
select {
case <-e.ttlManage.C:
if atomic.CompareAndSwapInt32(&e.eventStatus, waitEventState, closeEventState) {
return nil, errorx.TimeOutErr()
}
continue
case result := <-e.waitResult:
atomic.SwapInt32(&e.eventStatus, closeEventState)
return result, e.err
}
}
}
// 实际执行推送
func (e *event) execWorker(res interface{}, err error) {
switch work := res.(type) {
case EventAwaitFunc:
await := func() (*event, interface{}, error) {
result, err := work()
return e, result, err
}
e.parentDriver.await(await)
case EventWorkFunc:
e.InitWaitEvent()
e.SetValue(WorkFuncEventKey, work)
e.parentDriver.Put(e)
default:
e.err = err
e.waitResult <- res
}
}
func (e *event) ExecWorkAndSendResult(work EventWorkFunc) (interface{}, error) {
if !atomic.CompareAndSwapInt32(&e.eventStatus, waitEventState, workEventState) {
return nil, errorx.New("not wait status, exec err")
}
res, err := work()
e.execWorker(res, err)
return res, err
}
type driver struct {
waitQueue chan awaitFunc
eventQueue chan *event
levelQueue chan *event
// event 池的实现
poll chan *event
maxPoolSize int32
nowPoolSize int32
}
func NewDriver(maxSize int) DriverInterface {
d := &driver{
// pool
maxPoolSize: int32(maxSize),
nowPoolSize: 0,
poll: make(chan *event, maxSize),
// waitQueue 1/3 的挂起指标
waitQueue: make(chan awaitFunc, maxSize/3),
levelQueue: make(chan *event, maxSize/3),
eventQueue: make(chan *event, maxSize),
}
d.awaitWorker()
return d
}
func (d *driver) NewEvent(name string) *event {
issSize := atomic.LoadInt32(&d.nowPoolSize)
if issSize < d.maxPoolSize {
atomic.AddInt32(&d.nowPoolSize, 1)
return d.newEvent(name)
}
e := <-d.poll
e.eventName = name
return e
}
func (d *driver) newEvent(name string) *event {
status := initEventState
return &event{
eventStatus: status,
parentDriver: d,
eventName: name,
}
}
// 先尝试 level
func (d *driver) Get() *event {
if len(d.levelQueue) > 0 {
return <-d.levelQueue
}
return <-d.eventQueue
}
func (d *driver) Put(e *event) {
d.eventQueue <- e
}
func (d *driver) GetLength() int {
return len(d.eventQueue) + len(d.levelQueue)
}
func (d *driver) recovery(e *event) {
atomic.SwapInt32(&e.eventStatus, recoveryEventState)
e.reset()
d.poll <- e
}
// 挂起操作相关
func (d *driver) await(a awaitFunc) {
d.waitQueue <- a
}

152
pkg/event2/driver_test.go Normal file
View File

@ -0,0 +1,152 @@
package event2
import (
"context"
"fmt"
"strconv"
"sync"
"testing"
"time"
"github.com/stretchr/testify/require"
)
const testEvent = "1001"
const waitTestEvent = "1002"
// 简单的 单向 event 使用
func Test_EventDriver(t *testing.T) {
driver := NewDriver(2000)
produce := NewProduce(driver)
consumer := NewConsumer(driver)
ctx := context.Background()
wait := sync.WaitGroup{}
wait.Add(30000)
go func() {
for i := 0; i < 30000; i++ {
event := produce.NewEvent(testEvent)
event.SetMsg("k", strconv.Itoa(i))
produce.Call(ctx, event)
}
}()
go func() {
for {
event := consumer.Receive(ctx)
fmt.Println(event.GetMsg("k"))
event.Recovery()
wait.Done()
}
}()
wait.Wait()
}
// 双向 event
func Test_EventDriver_Tow_way(t *testing.T) {
ctx := context.Background()
driver := NewDriver(2000)
produce := NewProduce(driver)
consumer := NewConsumer(driver)
go func() {
for {
event := consumer.Receive(ctx)
work, ok := event.GetValue(WorkFuncEventKey)
if !ok {
panic("get work key err")
}
workFunc, ok := work.(EventWorkFunc)
if !ok {
panic("work func err")
}
_, err := event.ExecWorkAndSendResult(workFunc)
require.NoError(t, err)
}
}()
// 一般的 two-way 模式
for i := 0; i < 10000; i++ {
event := produce.NewEvent(waitTestEvent)
event.InitWaitEvent()
event.SetValue(WorkFuncEventKey, EventWorkFunc(func() (interface{}, error) {
return i + 1, nil
}))
produce.Call(ctx, event)
res, err := event.StartWaitEvent(2 * time.Second)
require.NoError(t, err)
require.Equal(t, res, i+1)
event.Recovery()
}
// 挂起模式2 秒左右的执行时间
group := sync.WaitGroup{}
group.Add(5)
for i := 0; i < 5; i++ {
go func(i int) {
event := produce.NewEvent(waitTestEvent)
event.InitWaitEvent()
event.SetValue(WorkFuncEventKey, EventWorkFunc(func() (interface{}, error) {
// 访问 await Work 来发起一个 异步请求操作
return EventAwaitFunc(func() (interface{}, error) {
time.Sleep(time.Second)
return i + 1, nil
}), nil
}))
produce.Call(ctx, event)
res, err := event.StartWaitEvent(2 * time.Second)
require.NoError(t, err)
require.Equal(t, res, i+1)
event.Recovery()
group.Done()
}(i)
}
// 挂起成功不发生超时
for i := 0; i < 10000; i++ {
event := produce.NewEvent(waitTestEvent)
event.InitWaitEvent()
event.SetValue(WorkFuncEventKey, EventWorkFunc(func() (interface{}, error) {
return i + 1, nil
}))
produce.Call(ctx, event)
res, err := event.StartWaitEvent(500 * time.Millisecond)
require.NoError(t, err)
require.Equal(t, res, i+1)
event.Recovery()
}
group.Wait()
// 挂起一个高延迟操作, 保证局部操作还在事件中
group = sync.WaitGroup{}
group.Add(5)
for i := 0; i < 5; i++ {
event := produce.NewEvent(waitTestEvent)
event.InitWaitEvent()
event.SetValue(WorkFuncEventKey, EventWorkFunc(func() (interface{}, error) {
return EventAwaitFunc(func() (interface{}, error) {
// 返回值为 EventWorkFunc 时, 会重新加入末端队列
return EventWorkFunc(func() (interface{}, error) {
return i + 1, nil
}), nil
}), nil
}))
produce.Call(ctx, event)
res, err := event.StartWaitEvent(2 * time.Second)
require.NoError(t, err)
require.Equal(t, res, i+1)
event.Recovery()
group.Done()
fmt.Println(i)
}
group.Wait()
}

21
pkg/event2/produce.go Normal file
View File

@ -0,0 +1,21 @@
package event2
import "context"
type Produce struct {
driver DriverInterface
}
func (p *Produce) NewEvent(name string) *event {
return p.driver.NewEvent(name)
}
func (p *Produce) Call(ctx context.Context, e *event) {
p.driver.Put(e)
}
func NewProduce(driver DriverInterface) ProduceInterface {
return &Produce{
driver: driver,
}
}

13
pkg/event2/worker.go Normal file
View File

@ -0,0 +1,13 @@
package event2
func (d *driver) awaitWorker() {
for i := 0; i < awaitThread; i++ {
go func() {
for {
awaitFunc := <-d.waitQueue
e, res, err := awaitFunc()
e.execWorker(res, err)
}
}()
}
}

View File

@ -1 +0,0 @@
package define

43
pkg/logx/define.go Normal file
View File

@ -0,0 +1,43 @@
package logx
import (
"context"
"sync"
"gitee.com/wheat-os/wheatCache/pkg/event"
"github.com/spf13/viper"
)
type LogLevelState int8
var (
once sync.Once
stath []string
)
type upLogger struct {
ctx context.Context
produce event.ProduceInterface
}
func init() {
once.Do(func() {
stath = viper.GetStringSlice("logPrint.stath")
})
}
type logInterface interface {
Debug(format string, msg ...interface{})
Info(format string, msg ...interface{})
Warn(format string, msg ...interface{})
Error(format string, msg ...interface{})
Panic(format string, msg ...interface{})
Debugln(msg ...interface{})
Infoln(msg ...interface{})
Warnln(msg ...interface{})
Errorln(msg ...interface{})
Panicln(msg ...interface{})
Print(level string, format string, msg ...interface{})
}

161
pkg/logx/logx.go Normal file
View File

@ -0,0 +1,161 @@
package logx
import (
"context"
"fmt"
"os"
"runtime"
"strings"
"time"
"gitee.com/wheat-os/wheatCache/pkg/event"
middleMsg "gitee.com/wheat-os/wheatCache/pkg/middle-msg"
)
func With(ctx context.Context, p event.ProduceInterface) *upLogger {
return &upLogger{
ctx: ctx,
produce: p,
}
}
func (l *upLogger) Debug(format string, msg ...interface{}) {
l.Print("DEBUG", format, msg...)
}
func (l *upLogger) Info(format string, msg ...interface{}) {
l.Print("INFO", format, msg...)
}
func (l *upLogger) Warn(format string, msg ...interface{}) {
l.Print("WARN", format, msg...)
}
func (l *upLogger) Error(format string, msg ...interface{}) {
l.Print("ERROR", format, msg...)
}
func (l *upLogger) Panic(format string, msg ...interface{}) {
l.Print("ERROR", format, msg...)
os.Exit(-1)
}
func (l *upLogger) Print(level string, format string, msg ...interface{}) {
logPrint(4, level, format, msg...)
sendMsg := &middleMsg.LogContext{
Level: level,
Data: time.Now(),
Msg: fmt.Sprintf(format, msg...),
Route: findPlace(4),
}
middleMsg.SendMiddleMsg(l.ctx, l.produce, sendMsg)
}
func (l *upLogger) Debugln(msg ...interface{}) {
l.Print("DEBUG", "%s", format(msg...))
}
func (l *upLogger) Infoln(msg ...interface{}) {
l.Print("INFO", "%s", format(msg...))
}
func (l *upLogger) Warnln(msg ...interface{}) {
l.Print("WARN", "%s", format(msg...))
}
func (l *upLogger) Errorln(msg ...interface{}) {
l.Print("ERROR", "%s", format(msg...))
}
func (l *upLogger) Panicln(msg ...interface{}) {
l.Print("ERROR", "%s", format(msg...))
os.Exit(-1)
}
func Debug(format string, msg ...interface{}) {
logPrint(3, "DEBUG", format, msg...)
}
func Info(format string, msg ...interface{}) {
logPrint(3, "INFO", format, msg...)
}
func Warn(format string, msg ...interface{}) {
logPrint(3, "WARN", format, msg...)
}
func Error(format string, msg ...interface{}) {
logPrint(3, "ERROR", format, msg...)
}
func Panic(format string, msg ...interface{}) {
logPrint(3, "PANIC", format, msg...)
os.Exit(-1)
}
func Debugln(msg ...interface{}) {
logPrint(3, "DEBUG", "%s", format(msg...))
}
func Infoln(msg ...interface{}) {
logPrint(3, "INFO", "%s", format(msg...))
}
func Warnln(msg ...interface{}) {
logPrint(3, "WARN", "%s", format(msg...))
}
func Errorln(msg ...interface{}) {
logPrint(3, "ERROR", "%s", format(msg...))
}
func Panicln(msg ...interface{}) {
logPrint(3, "PANIC", "%s", format(msg...))
os.Exit(-1)
}
func logPrint(floor int, level string, format string, msg ...interface{}) {
place := findPlace(floor)
datetime := fmt.Sprintf("%s", time.Now())[0:19]
switch level {
case "DEBUG":
fmt.Printf("\033[1;37;40m")
case "INFO":
fmt.Printf("\033[1;32;40m")
case "WARN":
fmt.Printf("\033[1;33;40m")
default:
fmt.Printf("\033[1;31;40m")
}
//fmt.Println(level, datetime, fmt.Sprintf(format, msg...))
fmt.Printf("%s\t%v\t%s\n", level, datetime, fmt.Sprintf(format, msg...))
for _, lv := range stath {
if strings.ToUpper(lv) == strings.ToUpper(level) {
fmt.Println(place)
break
}
}
}
func findPlace(floor int) string {
var (
place string
i = floor
)
for {
_, file, line, _ := runtime.Caller(i)
if line == 0 {
break
}
i++
place = fmt.Sprintf("%s:%d\n%s", file, line, place)
}
return place
}
func format(message ...interface{}) (context string) {
for _, msg := range message {
context = fmt.Sprintf("%s\t%v", context, msg)
}
return context
}

38
pkg/logx/logx_test.go Normal file
View File

@ -0,0 +1,38 @@
package logx
import (
"context"
"testing"
_ "gitee.com/wheat-os/wheatCache/conf"
"gitee.com/wheat-os/wheatCache/pkg/event"
)
func TestStd(t *testing.T) {
Info("%d%s", 11, "Info")
Debug("%d%s", 11, "Debug")
Warn("%d%s", 11, "Warn")
Error("%d%s", 11, "Error")
Infoln(1321, "dwad", 0x9812933)
Debugln(1321, "dwad", 0x9812933)
Warnln(1321, "dwad", 0x9812933)
Errorln(1321, "dwad", 0x9812933)
//Panic("%d%s", 11, "Panic")
logger := With(context.Background(),
event.NewProduce(event.NewDriver(100)))
logger.Info("%d%s", 11, "Info")
logger.Debug("%d%s", 11, "Debug")
logger.Warn("%d%s", 11, "Warn")
logger.Error("%d%s", 11, "Error")
//logger.Panic("%d%s", 11, "Panic")
logger.Infoln(11, "Info")
logger.Debugln(11, "Debug")
logger.Warnln(11, "Warn")
logger.Errorln(11, "Error")
}

46
pkg/lru/define.go Normal file
View File

@ -0,0 +1,46 @@
package lru
import (
"sync"
"time"
"gitee.com/wheat-os/wheatCache/pkg/proto"
"gitee.com/wheat-os/wheatCache/pkg/structure"
)
type SingleWorkFunc func() interface{}
const (
OptionEventName = "operateEvent"
CleanEventName = "clearEvent"
TtlEventName = "ttlEvent"
)
var (
lruCacheOnce sync.Once
lruCache *SingleCache
)
const (
defaultLruMaxSize = 1 * 1024 * 1024 * 1024
defaultLruClearSize = 0.5 * 1024 * 1024 * 1024
defaultLruEventDriver = 2000
)
const (
defaultWaitTime = 20 * time.Minute
)
type CacheInterface interface {
Del() error
Get(key *proto.BaseKey) (structure.KeyBaseInterface, bool)
Add(key *proto.BaseKey, val structure.KeyBaseInterface) error
UpdateLruSize(length structure.UpdateLength)
DelByKey(key *proto.BaseKey) error
DelToClearSize() error
}
// TTL
const (
defaultDetachNum = 300
defaultTtlMaxLevel = 18
)

View File

@ -1,3 +0,0 @@
package define
// define

225
pkg/lru/lru.go Normal file
View File

@ -0,0 +1,225 @@
package lru
import (
"container/list"
"sync/atomic"
_ "gitee.com/wheat-os/wheatCache/conf"
"gitee.com/wheat-os/wheatCache/pkg/errorx"
"gitee.com/wheat-os/wheatCache/pkg/event"
"gitee.com/wheat-os/wheatCache/pkg/event2"
"gitee.com/wheat-os/wheatCache/pkg/middle"
"gitee.com/wheat-os/wheatCache/pkg/proto"
"gitee.com/wheat-os/wheatCache/pkg/structure"
"gitee.com/wheat-os/wheatCache/pkg/util"
"github.com/spf13/viper"
)
type keyBaseValue struct {
key string
val structure.KeyBaseInterface
expire int64 // 过期时间戳
}
type SingleCache struct {
maxsize int64 //最大的长度
clearSize int64 // 清理长度
nowSize int64 // 现在的长度
li *list.List
lruMap map[string]*list.Element
lruMaxDiverSize int
lruTtlManage *lruTTl // 定时清理器
lruDriver event2.DriverInterface
lruConsumer event2.ConsumerInterface
lruCleanProduce event2.ProduceInterface // 发送清理事件
middleProduce event.ProduceInterface // 中间件驱动
}
// UpdateLruSize 更新现在的长度
func (lru *SingleCache) UpdateLruSize(length structure.UpdateLength) {
atomic.AddInt64(&lru.nowSize, int64(length))
}
func cacheInit() (int64, int64, int, int) {
maxSize := viper.GetString("lruCache.maxSize")
retMaxSize, maxErr := util.ParseSizeToBit(maxSize)
if maxErr != nil {
return 0, 0, 0, 0
}
if retMaxSize == 0 {
retMaxSize = defaultLruMaxSize
}
clearSize := viper.GetString("lruCache.clearSize")
retClearSize, clearErr := util.ParseSizeToBit(clearSize)
if clearErr != nil {
return 0, 0, 0, 0
}
if retClearSize == 0 {
retClearSize = defaultLruClearSize
}
maxDriver := viper.GetInt("lruCache.eventDriverSize")
if maxDriver == 0 {
maxDriver = defaultLruEventDriver
}
detachNum := viper.GetInt("lruCache.detachNum")
if detachNum == 0 {
detachNum = defaultDetachNum
}
return retMaxSize, retClearSize, maxDriver, detachNum
}
// NewLRUCache lru初始化
func NewLRUCache() *SingleCache {
maxSize, clearSize, maxDriverSize, detachNum := cacheInit()
lruDriver := event2.NewDriver(maxDriverSize)
lruCacheOnce.Do(func() {
lru := &SingleCache{
maxsize: maxSize,
clearSize: clearSize,
nowSize: 0,
li: list.New(),
lruMap: make(map[string]*list.Element),
lruMaxDiverSize: maxDriverSize,
lruDriver: lruDriver,
lruConsumer: event2.NewConsumer(lruDriver),
lruCleanProduce: event2.NewProduce(lruDriver),
middleProduce: event.NewProduce(middle.NewMiddleWare().GetEventDriver()),
lruTtlManage: newLruTTl(detachNum),
}
lruCache = lru
// 启动 lru 事件驱动
go lru.lruSingleWork()
go lru.lruTtlWork()
go lru.cleanWork()
})
return lruCache
}
// GetDriver 获取驱动
func (lru *SingleCache) GetDriver() event2.DriverInterface {
return lru.lruDriver
}
//Add 增加
func (lru *SingleCache) Add(key *proto.BaseKey, val structure.KeyBaseInterface) error {
if key == nil {
return errorx.KeyBaseIsNilErr()
}
exp := lru.lruTtlManage.setKeys(key)
keyBaseVal := &keyBaseValue{
key: key.Key,
val: val,
expire: exp,
}
if elVal, ok := lru.lruMap[key.Key]; ok {
lru.li.MoveToFront(elVal)
oldSize := elVal.Value.(structure.KeyBaseInterface).SizeByte()
lru.UpdateLruSize(structure.UpdateLength(val.SizeByte() - oldSize))
elVal.Value = keyBaseVal
return nil
}
valEl := lru.li.PushFront(keyBaseVal)
lru.lruMap[key.Key] = valEl
//增加大小
lru.UpdateLruSize(structure.UpdateLength(valEl.Value.(*keyBaseValue).val.SizeByte()))
return nil
}
// Get 查找key对应的value
func (lru *SingleCache) Get(key *proto.BaseKey) (structure.KeyBaseInterface, bool) {
if key == nil {
return nil, false
}
if elVal, ok := lru.lruMap[key.Key]; ok {
lru.li.MoveToFront(elVal)
return elVal.Value.(*keyBaseValue).val, true
}
return nil, false
}
//Del 删除机制
func (lru *SingleCache) Del() error {
if lru.lruMap == nil {
return errorx.New("lru is nil")
}
data := lru.li.Back()
delete(lru.lruMap, data.Value.(*keyBaseValue).key)
//删除大小
lru.UpdateLruSize(structure.UpdateLength(-1 * data.Value.(*keyBaseValue).val.SizeByte()))
lru.li.Remove(data)
return nil
}
//DelByKey 根据key删除
func (lru *SingleCache) DelByKey(key *proto.BaseKey) error {
if key == nil {
return errorx.KeyBaseIsNilErr()
}
if lru.lruMap == nil {
return errorx.New("lru is nil")
}
if el, ok := lru.lruMap[key.Key]; ok {
delete(lru.lruMap, key.Key)
lru.li.Remove(el)
lru.UpdateLruSize(structure.UpdateLength(-1 * el.Value.(*keyBaseValue).val.SizeByte()))
return nil
}
return errorx.New("lru no this key")
}
//DelByKeyAndExTtl 根据key(string)删除已经过期的 key
func (lru *SingleCache) delByKeyAndExTtl(key string, beforeTime int64) {
if elVal, ok := lru.lruMap[key]; ok {
exp := elVal.Value.(*keyBaseValue).expire
if exp <= beforeTime {
delete(lru.lruMap, key)
lru.li.Remove(elVal)
lru.UpdateLruSize(structure.UpdateLength(-1 * elVal.Value.(*keyBaseValue).val.SizeByte()))
}
}
}
func (lru *SingleCache) DelToClearSize() error {
if lru.lruMap == nil {
return errorx.New("lru is nil")
}
for lru.nowSize > lru.clearSize {
//del自动给nowSize进行大小的改变
err := lru.Del()
if err != nil {
return err
}
}
return nil
}
// 更新过期时间
func (lru *SingleCache) UpdateTTl(key *proto.BaseKey) error {
if key == nil {
return errorx.KeyBaseIsNilErr()
}
if elVal, ok := lru.lruMap[key.Key]; ok {
expire := lru.lruTtlManage.setKeys(key)
elVal.Value.(*keyBaseValue).expire = expire
}
return errorx.New("the key is not in lru cache, key:%s", key.Key)
}

103
pkg/lru/lru_test.go Normal file
View File

@ -0,0 +1,103 @@
package lru
import (
"fmt"
"testing"
"time"
"gitee.com/wheat-os/wheatCache/pkg/proto"
"gitee.com/wheat-os/wheatCache/pkg/structure/stringx"
"github.com/stretchr/testify/require"
)
func TestNewLRUCache(t *testing.T) {
cache := NewLRUCache()
v1 := stringx.NewStringSingle()
v2 := stringx.NewStringSingle()
v3 := stringx.NewStringSingle()
key1 := proto.BaseKey{
Key: "1",
}
key2 := proto.BaseKey{
Key: "2",
}
key3 := proto.BaseKey{
Key: "3",
}
cache.Add(&key1, v1)
cache.Add(&key2, v2)
cache.Add(&key3, v3)
cache.Add(&key1, v1)
fmt.Println(cache.nowSize)
cache.Del()
fmt.Println(cache.nowSize)
_, isTrue := cache.Get(&key1)
require.Equal(t, isTrue, true)
}
func TestNewLRUCache2(t *testing.T) {
//根据key删除
cache := NewLRUCache()
v1 := stringx.NewStringSingle()
v2 := stringx.NewStringSingle()
v3 := stringx.NewStringSingle()
key1 := proto.BaseKey{
Key: "1",
}
key2 := proto.BaseKey{
Key: "2",
}
key3 := proto.BaseKey{
Key: "3",
}
cache.Add(&key1, v1)
cache.Add(&key2, v2)
cache.Add(&key3, v3)
cache.DelByKey(&key1)
_, ok := cache.Get(&key1)
require.Equal(t, ok, false)
require.Error(t, cache.DelByKey(&key1))
}
func TestLruProcess(t *testing.T) {
lru := NewLRUCache()
lru.clearSize = 3600
for i := 100; i < 200; i++ {
lru.Add(&proto.BaseKey{
Key: fmt.Sprint(i),
Ttl: 20 << 2,
}, stringx.NewStringSingle())
}
// mock LruKey
for i := 0; i < 100; i++ {
lru.Add(&proto.BaseKey{
Key: fmt.Sprint(i),
Ttl: 4,
}, stringx.NewStringSingle())
}
require.Equal(t, lru.nowSize, int64(200*24))
// 自动清理测试
fmt.Println(lru.clearSize)
require.Equal(t, lru.li.Len(), 200)
time.Sleep(3 * time.Second)
require.Less(t, lru.nowSize, lru.clearSize+1)
// TTL 测试, 100-200 key 发生自动清理 留下 50-100 共 1000-100 + 20个 key5s 后,前 0-100的 key 过期,剩下
time.Sleep(2 * time.Second)
require.Equal(t, lru.li.Len(), 50)
// 过期全部的 Key
for i := 100; i < 200; i++ {
lru.UpdateTTl(&proto.BaseKey{
Key: fmt.Sprint(i),
Ttl: -1,
})
}
time.Sleep(2 * time.Second)
require.Equal(t, lru.nowSize, int64(0))
}

56
pkg/lru/ttl.go Normal file
View File

@ -0,0 +1,56 @@
package lru
import (
"sync"
"time"
"gitee.com/wheat-os/wheatCache/pkg/proto"
"gitee.com/wheat-os/wheatCache/pkg/util/skiplist"
)
// lru 的 ttl 管理器
type lruTTl struct {
sk *skiplist.SkipList
memoryKey chan string // 缓存过期的 key
detachNum int // 每次移除的数量
mu sync.Mutex
}
func (l *lruTTl) setKeys(key *proto.BaseKey) int64 {
l.mu.Lock()
defer l.mu.Unlock()
// 永久存储
if key.Expire == nil && key.Ttl == 0 {
return 0
}
ttlTime := time.Now().Unix()
if key.Expire != nil {
ttlTime = key.Expire.GetSeconds()
}
ttlTime += key.GetTtl()
l.sk.Insert(float64(ttlTime), key.GetKey())
return ttlTime
}
// 加载过期的 Key 到 Memory
func (l *lruTTl) ttlKeyToMemoryBySecond() {
t := time.Now()
values := l.sk.PopLeft(float64(t.Unix()))
for _, val := range values {
l.memoryKey <- val.(string)
}
}
func newLruTTl(detachNum int) *lruTTl {
return &lruTTl{
sk: skiplist.NewSkipList(defaultTtlMaxLevel),
// 默认 10000 个 Key
memoryKey: make(chan string, 10000),
detachNum: detachNum,
}
}

36
pkg/lru/ttl_test.go Normal file
View File

@ -0,0 +1,36 @@
package lru
import (
"fmt"
"testing"
"time"
"gitee.com/wheat-os/wheatCache/pkg/proto"
"gitee.com/wheat-os/wheatCache/pkg/structure/stringx"
"github.com/stretchr/testify/require"
)
func TestTTlCup(t *testing.T) {
k := make([]string, 100, 3000)
fmt.Println(cap(k))
p := k[:50]
fmt.Println(cap(p))
}
func Test_LruTTl(t *testing.T) {
lru := NewLRUCache()
s := stringx.NewStringSingle()
lru.Add(&proto.BaseKey{
Key: "k8s",
Ttl: 1,
}, s)
lru.Add(&proto.BaseKey{
Key: "990",
Ttl: 10,
}, s)
require.Equal(t, lru.nowSize, int64(48))
time.Sleep(4 * time.Second)
require.Equal(t, lru.nowSize, int64(24))
}

62
pkg/lru/woker_test.go Normal file
View File

@ -0,0 +1,62 @@
package lru
import (
"context"
"testing"
"time"
"gitee.com/wheat-os/wheatCache/pkg/event2"
"gitee.com/wheat-os/wheatCache/pkg/logx"
"gitee.com/wheat-os/wheatCache/pkg/proto"
"gitee.com/wheat-os/wheatCache/pkg/structure/stringx"
"github.com/stretchr/testify/require"
)
func TestWorker(t *testing.T) {
ctx := context.Background()
lru := NewLRUCache()
produce := event2.NewProduce(lru.GetDriver())
workEvent := produce.NewEvent(OptionEventName)
workEvent.SetValue(event2.WorkFuncEventKey, event2.EventWorkFunc(func() (interface{}, error) {
v1 := stringx.NewStringSingle()
key := proto.BaseKey{
Key: "v1",
}
res, _ := v1.Set("123")
lru.Add(&key, v1)
return res, nil
}))
workEvent.InitWaitEvent()
produce.Call(ctx, workEvent)
res, err := workEvent.StartWaitEvent(2 * time.Second)
require.NoError(t, err)
require.Equal(t, res, "123")
}
func TestSingleCache_DelToClearSize(t *testing.T) {
ctx := context.Background()
lru := NewLRUCache()
produce := event2.NewProduce(lru.GetDriver())
for i := int32(20000); i > 0; i-- {
workEvent := produce.NewEvent(OptionEventName)
workEvent.SetValue(event2.WorkFuncEventKey, event2.EventWorkFunc(func() (interface{}, error) {
v1 := stringx.NewStringSingle()
key := proto.BaseKey{
Key: string(i),
Ttl: 1,
}
u := v1.Setbit(i, true)
lru.Add(&key, v1)
return u, nil
}))
workEvent.InitWaitEvent()
produce.Call(ctx, workEvent)
workEvent.StartWaitEvent(2 * time.Second)
workEvent.Recovery()
}
logx.Info("start size is %d", lru.nowSize)
time.Sleep(10 * time.Second)
logx.Info("end size is %d", lru.nowSize)
}

135
pkg/lru/worker.go Normal file
View File

@ -0,0 +1,135 @@
package lru
import (
"context"
"time"
"gitee.com/wheat-os/wheatCache/pkg/errorx"
"gitee.com/wheat-os/wheatCache/pkg/event"
"gitee.com/wheat-os/wheatCache/pkg/event2"
"gitee.com/wheat-os/wheatCache/pkg/logx"
mMsg "gitee.com/wheat-os/wheatCache/pkg/middle-msg"
)
func (lru *SingleCache) lruSingleWork() {
ctx := context.Background()
for {
workEvent := lru.lruConsumer.Receive(ctx)
workFunc, ok := workEvent.GetValue(event2.WorkFuncEventKey)
if !ok {
workEvent.SetResultErr(errorx.LruNotWorkFuncEventErr())
continue
}
switch workEvent.GetEventName() {
case OptionEventName:
if work, ok := workFunc.(event2.EventWorkFunc); ok {
workEvent.ExecWorkAndSendResult(work)
}
case CleanEventName:
// 对当前的io数量进行判断
ioNum := lru.GetDriver().GetLength()
if ioNum > lru.lruMaxDiverSize/2 {
lru.lruCleanProduce.Call(ctx, workEvent)
continue
}
if work, ok := workFunc.(event2.EventWorkFunc); ok {
workEvent.ExecWorkAndSendResult(work)
}
case TtlEventName:
if work, ok := workFunc.(event2.EventWorkFunc); ok {
workEvent.ExecWorkAndSendResult(work)
}
}
}
}
// 执行过期事件
func (lru *SingleCache) lruTtlWork() {
ctx := context.Background()
// 清理事件
go func() {
work := event2.EventWorkFunc(func() (interface{}, error) {
beforeTime := time.Now().Unix()
cle := lru.lruTtlManage.detachNum
if cle > len(lru.lruTtlManage.memoryKey) {
cle = len(lru.lruTtlManage.memoryKey)
}
keys := make([]string, 0)
for i := 0; i < cle; i++ {
key := <-lru.lruTtlManage.memoryKey
keys = append(keys, key)
lru.delByKeyAndExTtl(key, beforeTime)
}
return keys, nil
})
cleanTTlTicker := time.NewTicker(500 * time.Millisecond)
defer cleanTTlTicker.Stop()
for {
// 清理事件
<-cleanTTlTicker.C
if len(lru.lruTtlManage.memoryKey) == 0 {
continue
}
ttlEvent := lru.lruCleanProduce.NewEvent(TtlEventName)
ttlEvent.SetValue(event2.WorkFuncEventKey, work)
ttlEvent.InitWaitEvent()
lru.lruCleanProduce.Call(ctx, ttlEvent)
keys, err := ttlEvent.StartWaitEvent(time.Second * 2)
ttlEvent.Recovery()
mMsg.SendMiddleMsg(ctx, lru.middleProduce, mMsg.LruTTlContext{
Keys: keys.([]string),
CleanTime: time.Now(),
})
if err != nil {
logx.With(ctx, lru.middleProduce).Errorln(err)
}
}
}()
// 收集事件
for {
time.Sleep(1 * time.Second)
lru.lruTtlManage.ttlKeyToMemoryBySecond()
}
}
func (lru *SingleCache) cleanWork() {
cxt := context.Background()
work := event.EventWorkFunc(func() (interface{}, error) {
err := lru.DelToClearSize()
return nil, err
})
for {
time.Sleep(2 * time.Second)
if lru.clearSize < lru.nowSize {
lruCleanEvent := lru.lruCleanProduce.NewEvent(CleanEventName)
lruCleanEvent.SetValue(event2.WorkFuncEventKey, work)
lruCleanEvent.InitWaitEvent()
lru.lruCleanProduce.Call(cxt, lruCleanEvent)
_, err := lruCleanEvent.StartWaitEvent(defaultWaitTime)
if err != nil {
logx.With(cxt, lru.middleProduce).Errorln(err)
}
// 归还
lruCleanEvent.Recovery()
}
}
}

40
pkg/middle-msg/define.go Normal file
View File

@ -0,0 +1,40 @@
package middlemsg
import (
"context"
"gitee.com/wheat-os/wheatCache/pkg/errorx"
"gitee.com/wheat-os/wheatCache/pkg/event"
)
const (
MiddleMsgKey = "middleMsgKey"
)
func SendMiddleMsg(
ctx context.Context,
middleProduce event.ProduceInterface,
val interface{},
) error {
if middleProduce == nil {
return errorx.New("middleProduce not is nil")
}
var eventName string
switch val.(type) {
case *LogContext:
eventName = LogContextName
case *LruCleanContext:
eventName = LruCleanContextName
case *LruTTlContext:
eventName = LruTTlContextName
case *PulginsInfos:
eventName = PulginsInfosName
}
msgEvent := middleProduce.NewEvent(eventName)
msgEvent.SetValue(MiddleMsgKey, val)
middleProduce.Call(ctx, msgEvent)
return nil
}

14
pkg/middle-msg/logx.go Normal file
View File

@ -0,0 +1,14 @@
package middlemsg
import "time"
var (
LogContextName = "log-context"
)
type LogContext struct {
Level string
Data time.Time
Msg string
Route string
}

21
pkg/middle-msg/lru.go Normal file
View File

@ -0,0 +1,21 @@
package middlemsg
import "time"
const LruCleanContextName = "lru-clean-context"
type LruCleanContext struct {
Keys []string
BeforeCleanSize int64
BehindCleanSize int64
StartTime time.Time
EndTime time.Time
}
const LruTTlContextName = "lru-ttl-context"
type LruTTlContext struct {
Keys []string
CleanTime time.Time
}

21
pkg/middle-msg/plugins.go Normal file
View File

@ -0,0 +1,21 @@
package middlemsg
import (
"time"
)
const (
PulginsInfosName = "plugins-infos-context"
)
type PulginsInfo struct {
Version string
Desc string
Name string
Statux string
Time time.Duration
}
type PulginsInfos struct {
Infos []*PulginsInfo
}

15
pkg/middle/define.go Normal file
View File

@ -0,0 +1,15 @@
package middle
import (
"sync"
)
var (
oneMiddle sync.Once
middleWareDriver *MiddleWare
)
const (
defaultConsumerCount = 5
defaultDriverCount = 1000
)

View File

@ -1 +0,0 @@
package define

74
pkg/middle/middleware.go Normal file
View File

@ -0,0 +1,74 @@
package middle
import (
_ "gitee.com/wheat-os/wheatCache/conf"
"gitee.com/wheat-os/wheatCache/pkg/event"
"gitee.com/wheat-os/wheatCache/plugins"
"gitee.com/wheat-os/wheatCache/plugins/config"
"github.com/spf13/viper"
)
type MiddleWare struct {
eventDriver event.DriverInterface
eventConsumer event.ConsumerInterface
eventProduce event.ProduceInterface
plugins map[string][]plugins.PluginInterface
consumerCount int
driverCount int
}
func NewMiddleWare() *MiddleWare {
oneMiddle.Do(func() {
consumerCount, driverCount := loadConfigAndDefault()
driver := event.NewDriver(driverCount)
middleWareDriver = &MiddleWare{
eventDriver: driver,
eventConsumer: event.NewConsumer(driver),
eventProduce: event.NewProduce(driver),
driverCount: driverCount,
consumerCount: consumerCount,
}
middleWareDriver.loadPlugins()
// 多消费 middle
middleWareDriver.startWork()
})
return middleWareDriver
}
func (m *MiddleWare) GetEventDriver() event.DriverInterface {
return m.eventDriver
}
func (m *MiddleWare) loadPlugins() {
plug := viper.GetStringMapStringSlice("plugins-control")
pluginsMap := config.GetMiddlewareMap()
pluginsContext := make(map[string][]plugins.PluginInterface)
for msg, pluNames := range plug {
pulgSingle := make([]plugins.PluginInterface, 0)
for _, name := range pluNames {
pulgSingle = append(pulgSingle, pluginsMap[name])
}
pluginsContext[msg] = pulgSingle
}
m.plugins = pluginsContext
}
func loadConfigAndDefault() (int, int) {
// 加载 consumerCount
consumerCount := viper.GetInt("middle-driver.middleConsumerCount")
if consumerCount == 0 {
consumerCount = defaultConsumerCount
}
driverCount := viper.GetInt("middle-driver.driverCount")
if driverCount == 0 {
driverCount = defaultDriverCount
}
return consumerCount, driverCount
}

36
pkg/middle/worker.go Normal file
View File

@ -0,0 +1,36 @@
package middle
import (
"context"
"gitee.com/wheat-os/wheatCache/pkg/logx"
middleMsg "gitee.com/wheat-os/wheatCache/pkg/middle-msg"
)
func (m *MiddleWare) startWork() {
for i := 0; i < m.consumerCount; i++ {
go func() {
ctx := context.Background()
for {
workEvent := m.eventConsumer.Receive(ctx)
plugs := m.plugins[workEvent.GetEventName()]
msg, ok := workEvent.GetValue(middleMsg.MiddleMsgKey)
m.eventConsumer.Recovery(workEvent)
if !ok {
logx.With(ctx, m.eventProduce).Error("get event value errnot key:%s", middleMsg.MiddleMsgKey)
continue
}
// 发送事件到 全部的 plugs 里
for _, val := range plugs {
_, err := val.Exec(msg)
if err != nil {
logx.With(ctx, m.eventProduce).Errorln(err)
}
}
}
}()
}
}

42
pkg/middle/worker_test.go Normal file
View File

@ -0,0 +1,42 @@
package middle
import (
"context"
"fmt"
"testing"
"time"
"gitee.com/wheat-os/wheatCache/pkg/event"
middleMsg "gitee.com/wheat-os/wheatCache/pkg/middle-msg"
)
func Test_middleware_loadPlugins(t *testing.T) {
m := NewMiddleWare()
m.loadPlugins()
fmt.Println(m.plugins)
}
func TestWorker(t *testing.T) {
ctx := context.Background()
m := NewMiddleWare()
product := event.NewProduce(m.GetEventDriver())
middleMsg.SendMiddleMsg(ctx, product, &middleMsg.LogContext{
Msg: "debug msg",
})
middleMsg.SendMiddleMsg(ctx, product, &middleMsg.PulginsInfos{
Infos: []*middleMsg.PulginsInfo{
{
Desc: "miss",
},
},
})
middleMsg.SendMiddleMsg(ctx, product, &middleMsg.LruTTlContext{
Keys: []string{"1", "2", "3"},
})
time.Sleep(1 * time.Second)
}

218
pkg/proto/base.pb.go Normal file
View File

@ -0,0 +1,218 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.17.3
// source: base.proto
package proto
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type BaseKey struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Ttl int64 `protobuf:"varint,2,opt,name=ttl,proto3" json:"ttl,omitempty"`
Expire *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=expire,proto3" json:"expire,omitempty"`
}
func (x *BaseKey) Reset() {
*x = BaseKey{}
if protoimpl.UnsafeEnabled {
mi := &file_base_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *BaseKey) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*BaseKey) ProtoMessage() {}
func (x *BaseKey) ProtoReflect() protoreflect.Message {
mi := &file_base_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use BaseKey.ProtoReflect.Descriptor instead.
func (*BaseKey) Descriptor() ([]byte, []int) {
return file_base_proto_rawDescGZIP(), []int{0}
}
func (x *BaseKey) GetKey() string {
if x != nil {
return x.Key
}
return ""
}
func (x *BaseKey) GetTtl() int64 {
if x != nil {
return x.Ttl
}
return 0
}
func (x *BaseKey) GetExpire() *timestamppb.Timestamp {
if x != nil {
return x.Expire
}
return nil
}
type External struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *External) Reset() {
*x = External{}
if protoimpl.UnsafeEnabled {
mi := &file_base_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *External) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*External) ProtoMessage() {}
func (x *External) ProtoReflect() protoreflect.Message {
mi := &file_base_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use External.ProtoReflect.Descriptor instead.
func (*External) Descriptor() ([]byte, []int) {
return file_base_proto_rawDescGZIP(), []int{1}
}
var File_base_proto protoreflect.FileDescriptor
var file_base_proto_rawDesc = []byte{
0x0a, 0x0a, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x61, 0x0a,
0x07, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x74, 0x74,
0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x74, 0x74, 0x6c, 0x12, 0x32, 0x0a, 0x06,
0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x06, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65,
0x22, 0x0a, 0x0a, 0x08, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x42, 0x0b, 0x5a, 0x09,
0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x33,
}
var (
file_base_proto_rawDescOnce sync.Once
file_base_proto_rawDescData = file_base_proto_rawDesc
)
func file_base_proto_rawDescGZIP() []byte {
file_base_proto_rawDescOnce.Do(func() {
file_base_proto_rawDescData = protoimpl.X.CompressGZIP(file_base_proto_rawDescData)
})
return file_base_proto_rawDescData
}
var file_base_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_base_proto_goTypes = []interface{}{
(*BaseKey)(nil), // 0: BaseKey
(*External)(nil), // 1: External
(*timestamppb.Timestamp)(nil), // 2: google.protobuf.Timestamp
}
var file_base_proto_depIdxs = []int32{
2, // 0: BaseKey.expire:type_name -> google.protobuf.Timestamp
1, // [1:1] is the sub-list for method output_type
1, // [1:1] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
1, // [1:1] is the sub-list for extension extendee
0, // [0:1] is the sub-list for field type_name
}
func init() { file_base_proto_init() }
func file_base_proto_init() {
if File_base_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_base_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BaseKey); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_base_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*External); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_base_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_base_proto_goTypes,
DependencyIndexes: file_base_proto_depIdxs,
MessageInfos: file_base_proto_msgTypes,
}.Build()
File_base_proto = out.File
file_base_proto_rawDesc = nil
file_base_proto_goTypes = nil
file_base_proto_depIdxs = nil
}

733
pkg/proto/channelx.pb.go Normal file
View File

@ -0,0 +1,733 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.26.0
// protoc v3.17.3
// source: channelx.proto
package proto
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type CPushRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Key *BaseKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Value []string `protobuf:"bytes,2,rep,name=value,proto3" json:"value,omitempty"`
}
func (x *CPushRequest) Reset() {
*x = CPushRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_channelx_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CPushRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CPushRequest) ProtoMessage() {}
func (x *CPushRequest) ProtoReflect() protoreflect.Message {
mi := &file_channelx_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CPushRequest.ProtoReflect.Descriptor instead.
func (*CPushRequest) Descriptor() ([]byte, []int) {
return file_channelx_proto_rawDescGZIP(), []int{0}
}
func (x *CPushRequest) GetKey() *BaseKey {
if x != nil {
return x.Key
}
return nil
}
func (x *CPushRequest) GetValue() []string {
if x != nil {
return x.Value
}
return nil
}
type CPushResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
E *External `protobuf:"bytes,1,opt,name=e,proto3" json:"e,omitempty"`
}
func (x *CPushResponse) Reset() {
*x = CPushResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_channelx_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CPushResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CPushResponse) ProtoMessage() {}
func (x *CPushResponse) ProtoReflect() protoreflect.Message {
mi := &file_channelx_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CPushResponse.ProtoReflect.Descriptor instead.
func (*CPushResponse) Descriptor() ([]byte, []int) {
return file_channelx_proto_rawDescGZIP(), []int{1}
}
func (x *CPushResponse) GetE() *External {
if x != nil {
return x.E
}
return nil
}
type CPopRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Key *BaseKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Count int32 `protobuf:"varint,2,opt,name=count,proto3" json:"count,omitempty"`
}
func (x *CPopRequest) Reset() {
*x = CPopRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_channelx_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CPopRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CPopRequest) ProtoMessage() {}
func (x *CPopRequest) ProtoReflect() protoreflect.Message {
mi := &file_channelx_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CPopRequest.ProtoReflect.Descriptor instead.
func (*CPopRequest) Descriptor() ([]byte, []int) {
return file_channelx_proto_rawDescGZIP(), []int{2}
}
func (x *CPopRequest) GetKey() *BaseKey {
if x != nil {
return x.Key
}
return nil
}
func (x *CPopRequest) GetCount() int32 {
if x != nil {
return x.Count
}
return 0
}
type CPopResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
E *External `protobuf:"bytes,1,opt,name=e,proto3" json:"e,omitempty"`
Result []string `protobuf:"bytes,2,rep,name=result,proto3" json:"result,omitempty"`
}
func (x *CPopResponse) Reset() {
*x = CPopResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_channelx_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CPopResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CPopResponse) ProtoMessage() {}
func (x *CPopResponse) ProtoReflect() protoreflect.Message {
mi := &file_channelx_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CPopResponse.ProtoReflect.Descriptor instead.
func (*CPopResponse) Descriptor() ([]byte, []int) {
return file_channelx_proto_rawDescGZIP(), []int{3}
}
func (x *CPopResponse) GetE() *External {
if x != nil {
return x.E
}
return nil
}
func (x *CPopResponse) GetResult() []string {
if x != nil {
return x.Result
}
return nil
}
type CMakeRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Key *BaseKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
Length int32 `protobuf:"varint,2,opt,name=length,proto3" json:"length,omitempty"`
}
func (x *CMakeRequest) Reset() {
*x = CMakeRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_channelx_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CMakeRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CMakeRequest) ProtoMessage() {}
func (x *CMakeRequest) ProtoReflect() protoreflect.Message {
mi := &file_channelx_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CMakeRequest.ProtoReflect.Descriptor instead.
func (*CMakeRequest) Descriptor() ([]byte, []int) {
return file_channelx_proto_rawDescGZIP(), []int{4}
}
func (x *CMakeRequest) GetKey() *BaseKey {
if x != nil {
return x.Key
}
return nil
}
func (x *CMakeRequest) GetLength() int32 {
if x != nil {
return x.Length
}
return 0
}
type CMakeResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *CMakeResponse) Reset() {
*x = CMakeResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_channelx_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CMakeResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CMakeResponse) ProtoMessage() {}
func (x *CMakeResponse) ProtoReflect() protoreflect.Message {
mi := &file_channelx_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CMakeResponse.ProtoReflect.Descriptor instead.
func (*CMakeResponse) Descriptor() ([]byte, []int) {
return file_channelx_proto_rawDescGZIP(), []int{5}
}
type CLenRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Key *BaseKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
}
func (x *CLenRequest) Reset() {
*x = CLenRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_channelx_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CLenRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CLenRequest) ProtoMessage() {}
func (x *CLenRequest) ProtoReflect() protoreflect.Message {
mi := &file_channelx_proto_msgTypes[6]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CLenRequest.ProtoReflect.Descriptor instead.
func (*CLenRequest) Descriptor() ([]byte, []int) {
return file_channelx_proto_rawDescGZIP(), []int{6}
}
func (x *CLenRequest) GetKey() *BaseKey {
if x != nil {
return x.Key
}
return nil
}
type CLenResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Length int32 `protobuf:"varint,2,opt,name=length,proto3" json:"length,omitempty"`
}
func (x *CLenResponse) Reset() {
*x = CLenResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_channelx_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CLenResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CLenResponse) ProtoMessage() {}
func (x *CLenResponse) ProtoReflect() protoreflect.Message {
mi := &file_channelx_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CLenResponse.ProtoReflect.Descriptor instead.
func (*CLenResponse) Descriptor() ([]byte, []int) {
return file_channelx_proto_rawDescGZIP(), []int{7}
}
func (x *CLenResponse) GetLength() int32 {
if x != nil {
return x.Length
}
return 0
}
type CCleanRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Key *BaseKey `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
}
func (x *CCleanRequest) Reset() {
*x = CCleanRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_channelx_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CCleanRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CCleanRequest) ProtoMessage() {}
func (x *CCleanRequest) ProtoReflect() protoreflect.Message {
mi := &file_channelx_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CCleanRequest.ProtoReflect.Descriptor instead.
func (*CCleanRequest) Descriptor() ([]byte, []int) {
return file_channelx_proto_rawDescGZIP(), []int{8}
}
func (x *CCleanRequest) GetKey() *BaseKey {
if x != nil {
return x.Key
}
return nil
}
type CCleanResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
}
func (x *CCleanResponse) Reset() {
*x = CCleanResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_channelx_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CCleanResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CCleanResponse) ProtoMessage() {}
func (x *CCleanResponse) ProtoReflect() protoreflect.Message {
mi := &file_channelx_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CCleanResponse.ProtoReflect.Descriptor instead.
func (*CCleanResponse) Descriptor() ([]byte, []int) {
return file_channelx_proto_rawDescGZIP(), []int{9}
}
var File_channelx_proto protoreflect.FileDescriptor
var file_channelx_proto_rawDesc = []byte{
0x0a, 0x0e, 0x63, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x1a, 0x0a, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x40, 0x0a, 0x0c,
0x43, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x03,
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x42, 0x61, 0x73, 0x65,
0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x28,
0x0a, 0x0d, 0x43, 0x50, 0x75, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x17, 0x0a, 0x01, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x45, 0x78, 0x74,
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x52, 0x01, 0x65, 0x22, 0x3f, 0x0a, 0x0b, 0x43, 0x50, 0x6f, 0x70,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03,
0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01,
0x28, 0x05, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3f, 0x0a, 0x0c, 0x43, 0x50, 0x6f,
0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x17, 0x0a, 0x01, 0x65, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x52,
0x01, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x03,
0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x42, 0x0a, 0x0c, 0x43, 0x4d,
0x61, 0x6b, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x03, 0x6b, 0x65,
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65,
0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68,
0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0x0f,
0x0a, 0x0d, 0x43, 0x4d, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x29, 0x0a, 0x0b, 0x43, 0x4c, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a,
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x42, 0x61,
0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x26, 0x0a, 0x0c, 0x43, 0x4c,
0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65,
0x6e, 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67,
0x74, 0x68, 0x22, 0x2b, 0x0a, 0x0d, 0x43, 0x43, 0x6c, 0x65, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x08, 0x2e, 0x42, 0x61, 0x73, 0x65, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22,
0x10, 0x0a, 0x0e, 0x43, 0x43, 0x6c, 0x65, 0x61, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x42, 0x0b, 0x5a, 0x09, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_channelx_proto_rawDescOnce sync.Once
file_channelx_proto_rawDescData = file_channelx_proto_rawDesc
)
func file_channelx_proto_rawDescGZIP() []byte {
file_channelx_proto_rawDescOnce.Do(func() {
file_channelx_proto_rawDescData = protoimpl.X.CompressGZIP(file_channelx_proto_rawDescData)
})
return file_channelx_proto_rawDescData
}
var file_channelx_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
var file_channelx_proto_goTypes = []interface{}{
(*CPushRequest)(nil), // 0: CPushRequest
(*CPushResponse)(nil), // 1: CPushResponse
(*CPopRequest)(nil), // 2: CPopRequest
(*CPopResponse)(nil), // 3: CPopResponse
(*CMakeRequest)(nil), // 4: CMakeRequest
(*CMakeResponse)(nil), // 5: CMakeResponse
(*CLenRequest)(nil), // 6: CLenRequest
(*CLenResponse)(nil), // 7: CLenResponse
(*CCleanRequest)(nil), // 8: CCleanRequest
(*CCleanResponse)(nil), // 9: CCleanResponse
(*BaseKey)(nil), // 10: BaseKey
(*External)(nil), // 11: External
}
var file_channelx_proto_depIdxs = []int32{
10, // 0: CPushRequest.key:type_name -> BaseKey
11, // 1: CPushResponse.e:type_name -> External
10, // 2: CPopRequest.key:type_name -> BaseKey
11, // 3: CPopResponse.e:type_name -> External
10, // 4: CMakeRequest.key:type_name -> BaseKey
10, // 5: CLenRequest.key:type_name -> BaseKey
10, // 6: CCleanRequest.key:type_name -> BaseKey
7, // [7:7] is the sub-list for method output_type
7, // [7:7] is the sub-list for method input_type
7, // [7:7] is the sub-list for extension type_name
7, // [7:7] is the sub-list for extension extendee
0, // [0:7] is the sub-list for field type_name
}
func init() { file_channelx_proto_init() }
func file_channelx_proto_init() {
if File_channelx_proto != nil {
return
}
file_base_proto_init()
if !protoimpl.UnsafeEnabled {
file_channelx_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CPushRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_channelx_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CPushResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_channelx_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CPopRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_channelx_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CPopResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_channelx_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CMakeRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_channelx_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CMakeResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_channelx_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CLenRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_channelx_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CLenResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_channelx_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CCleanRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_channelx_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CCleanResponse); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_channelx_proto_rawDesc,
NumEnums: 0,
NumMessages: 10,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_channelx_proto_goTypes,
DependencyIndexes: file_channelx_proto_depIdxs,
MessageInfos: file_channelx_proto_msgTypes,
}.Build()
File_channelx_proto = out.File
file_channelx_proto_rawDesc = nil
file_channelx_proto_goTypes = nil
file_channelx_proto_depIdxs = nil
}

35
pkg/proto/define.go Normal file
View File

@ -0,0 +1,35 @@
package proto
import (
"google.golang.org/protobuf/types/known/timestamppb"
)
type GetKeyBaseInterface interface {
GetKey() *BaseKey
}
const (
BaseKeyMethodKey = "basekey"
)
// NewBaseKey
// keyttlexpire
func NewBaseKey(key string, t ...int64) *BaseKey {
var expire *timestamppb.Timestamp = nil
var ttl int64
if len(t) > 1 {
expire = &timestamppb.Timestamp{
Seconds: t[1],
}
ttl = t[0]
} else if len(t) == 1 {
ttl = t[0]
}
return &BaseKey{
Key: key,
Expire: expire,
Ttl: ttl,
}
}

1301
pkg/proto/hashx.pb.go Normal file

File diff suppressed because it is too large Load Diff

1676
pkg/proto/listx.pb.go Normal file

File diff suppressed because it is too large Load Diff

1913
pkg/proto/setx.pb.go Normal file

File diff suppressed because it is too large Load Diff

2210
pkg/proto/storage.pb.go Normal file

File diff suppressed because it is too large Load Diff

1416
pkg/proto/stringx.pb.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,66 @@
package channelx
import (
"sync/atomic"
"gitee.com/wheat-os/wheatCache/pkg/structure"
)
type ChannelX struct {
channel chan *structure.Value
sizeByte int64
}
func MakeChannelX(length int) structure.ChannelXInterface {
return &ChannelX{
channel: make(chan *structure.Value, length),
sizeByte: 0,
}
}
func (c *ChannelX) SizeByte() int64 {
return c.sizeByte
}
// RollBack TODO 事务相关, V2 实现
func (c *ChannelX) RollBack() error {
panic("not implemented") // TODO: Implement
}
// Begin 事务相关, V2 实现
func (c *ChannelX) Begin() error {
panic("not implemented") // TODO: Implement
}
// Comment 事务相关, V2 实现
func (c *ChannelX) Comment() error {
panic("not implemented") // TODO: Implement
}
func (c *ChannelX) Encode() ([]byte, error) {
panic("not implemented") // TODO: Implement
}
func (c *ChannelX) Push(value string) structure.UpdateLength {
val := structure.NewValue(value)
up := val.GetSize()
c.channel <- val
atomic.AddInt64(&c.sizeByte, int64(up))
return structure.UpdateLength(up)
}
func (c *ChannelX) Pop() (string, structure.UpdateLength) {
val := <-c.channel
return val.ToString(), structure.UpdateLength(val.GetSize()) * -1
}
func (c *ChannelX) Length() int {
return len(c.channel)
}
func (c *ChannelX) Clean() structure.UpdateLength {
c.channel = make(chan *structure.Value, cap(c.channel))
up := c.sizeByte
c.sizeByte = 0
return structure.UpdateLength(up) * -1
}

View File

@ -0,0 +1,24 @@
package channelx
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestChannelX_Push(t *testing.T) {
c := MakeChannelX(10)
require.Equal(t, c.Length(), 0)
up := c.Push("111")
require.Equal(t, 24, int(up))
res, up := c.Pop()
require.Equal(t, -24, int(up))
require.Equal(t, res, "111")
up = c.Push("111")
c.Clean()
require.Equal(t, c.Length(), 0)
}

77
pkg/structure/define.go Normal file
View File

@ -0,0 +1,77 @@
package structure
const (
defaultLen = 8 // 默认创建的 value 大小
)
type DynamicType int8
type UpdateLength int64
const (
DynamicNull = DynamicType(iota)
DynamicInt
DynamicFloat
DynamicString
)
type KeyBaseInterface interface {
SizeByte() int64
// RollBack TODO 事务相关, V2 实现
RollBack() error
// Begin 事务相关, V2 实现
Begin() error
// Comment 事务相关, V2 实现
Comment() error
Encode() ([]byte, error)
}
type StringXInterface interface {
KeyBaseInterface
Set(string) (string, UpdateLength)
Get() string
Add(int32) (string, error)
Reduce(int32) (string, error)
Setbit(int32, bool) UpdateLength
Getbit(int32) (bool, error)
Getrange(start, end int32) (string, error)
GetLength() int
}
type ListXInterface interface {
KeyBaseInterface
LPush(...string) UpdateLength
RPush(...string) UpdateLength
LPop(int) ([]string, UpdateLength)
RPop(int) ([]string, UpdateLength)
Index(int) (string, error)
Insert(int, bool, ...string) (UpdateLength, error)
Length() int
Slice(start, end int) (UpdateLength, error) // 切片, O(n)复杂度
Range(start, end int) ([]string, error)
Remove(value string, count int) (int, UpdateLength)
}
type HashXInterface interface {
KeyBaseInterface
Set(key string, val string) UpdateLength
Get(key string) (string, error)
Del(key string) (UpdateLength, error)
Key() []string
Value() []string
Item() map[string]string
Add(renewal int, key ...string) (int, []string, error) // 访问影响成功的结果
SetX(key string, val string) (bool, UpdateLength) // 不存在才插入
Length() int
Range(consur, count int, regex string) []string
}
type ChannelXInterface interface {
KeyBaseInterface
Push(value string) UpdateLength
Pop() (string, UpdateLength)
Length() int
Clean() UpdateLength
}

View File

@ -0,0 +1,157 @@
package hashx
import (
"regexp"
"gitee.com/wheat-os/wheatCache/pkg/errorx"
"gitee.com/wheat-os/wheatCache/pkg/structure"
)
type HashX map[string]*structure.Value
func NewHashXSingle() structure.HashXInterface {
return make(HashX)
}
func (h HashX) SizeByte() int64 {
var size int
for _, val := range h {
size += val.GetSize()
}
return int64(size)
}
// RollBack TODO 事务相关, V2 实现
func (h HashX) RollBack() error {
panic("not implemented") // TODO: Implement
}
// Begin 事务相关, V2 实现
func (h HashX) Begin() error {
panic("not implemented") // TODO: Implement
}
// Comment 事务相关, V2 实现
func (h HashX) Comment() error {
panic("not implemented") // TODO: Implement
}
func (h HashX) Encode() ([]byte, error) {
panic("not implemented") // TODO: Implement
}
func (h HashX) Set(key string, val string) structure.UpdateLength {
var Length structure.UpdateLength
if v, ok := h[key]; ok {
Length -= structure.UpdateLength(v.GetSize())
}
strVal := structure.NewValue(val)
h[key] = strVal
return Length + structure.UpdateLength(strVal.GetSize())
}
func (h HashX) Get(key string) (string, error) {
if v, ok := h[key]; ok {
return v.ToString(), nil
}
return "", errorx.New("this key does not exist in hashx, key:%s", key)
}
func (h HashX) Del(key string) (structure.UpdateLength, error) {
if v, ok := h[key]; ok {
delete(h, key)
return structure.UpdateLength(v.GetSize()), nil
}
return 0, errorx.New("this key does not exist in hashx, key:%s", key)
}
func (h HashX) Key() []string {
result := make([]string, 0, len(h))
for key := range h {
result = append(result, key)
}
return result
}
func (h HashX) Value() []string {
result := make([]string, 0, len(h))
for _, val := range h {
result = append(result, val.ToString())
}
return result
}
func (h HashX) Item() map[string]string {
result := make(map[string]string, len(h))
for key, val := range h {
result[key] = val.ToString()
}
return result
}
func (h HashX) Add(renewal int, keys ...string) (count int, result []string, err error) {
for _, key := range keys {
if v, ok := h[key]; ok {
res, err := v.Incr(int32(renewal))
if err != nil {
continue
}
count += 1
result = append(result, res)
}
}
return count, result, nil
}
func (h HashX) SetX(key string, val string) (bool, structure.UpdateLength) {
if _, ok := h[key]; ok {
return false, 0
}
strVal := structure.NewValue(val)
h[key] = strVal
return true, structure.UpdateLength(strVal.GetSize())
}
func (h HashX) Length() int {
return len(h)
}
func (h HashX) Range(consur, count int, regex string) []string {
var reComp *regexp.Regexp
if regex == "" {
reComp = nil
} else {
reComp = regexp.MustCompile(regex)
}
result := make([]string, 0)
for _, val := range h {
if consur > 0 {
consur--
continue
}
if count == 0 && count != -1 {
break
}
s := val.ToString()
if reComp == nil {
count--
result = append(result, s)
continue
}
if reComp.MatchString(s) {
count--
result = append(result, s)
}
}
return result
}

View File

@ -0,0 +1,113 @@
package hashx
import (
"fmt"
"reflect"
"regexp"
"testing"
"unsafe"
"github.com/stretchr/testify/require"
)
func TestHashX_Set_SetX(t *testing.T) {
h := NewHashXSingle()
h.Set("key", "opq")
res, err := h.Get("key")
require.NoError(t, err)
require.Equal(t, res, "opq")
b, _ := h.SetX("key", "opq")
require.Equal(t, b, false)
b, _ = h.SetX("key1", "opq")
require.Equal(t, b, true)
res, err = h.Get("key1")
require.NoError(t, err)
require.Equal(t, res, "opq")
}
func TestHashX_Del(t *testing.T) {
h := NewHashXSingle()
up := h.Set("key", "opq")
upu, err := h.Del("key")
require.NoError(t, err)
require.Equal(t, up, upu)
}
func TestHashX_Key(t *testing.T) {
h := NewHashXSingle()
h.Set("key", "opq")
h.Set("key1", "opq")
h.Set("key2", "opq")
require.Equal(t, h.Key(), []string{"key", "key1", "key2"})
}
func TestHashX_Value(t *testing.T) {
h := NewHashXSingle()
h.Set("key", "opq")
h.Set("key1", "opq")
h.Set("key2", "opq")
require.Equal(t, h.Value(), []string{"opq", "opq", "opq"})
}
func TestHashX_Add(t *testing.T) {
h := NewHashXSingle()
h.Set("1", "1")
c, res, err := h.Add(1, "1")
require.NoError(t, err)
require.Equal(t, c, 1)
require.Equal(t, res, []string{"2"})
s, err := h.Get("1")
require.NoError(t, err)
require.Equal(t, s, "2")
}
func Test_Pointer(t *testing.T) {
s := make([]int, 9, 20)
lens := *(*int)(unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + uintptr(8)))
fmt.Println(lens, len(s))
mp := make(map[string]int)
mp["qcrao"] = 100
mp["stefno"] = 18
count := **(**uint8)(unsafe.Pointer(uintptr(unsafe.Pointer(&mp)) + uintptr(16)))
fmt.Println(count, len(mp)) // 2
}
func string2bytes(s string) []byte {
stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))
result := reflect.SliceHeader{
Data: stringHeader.Data,
Len: stringHeader.Len,
Cap: stringHeader.Len,
}
return *(*[]byte)(unsafe.Pointer(&result))
}
func TestHashX_Range(t *testing.T) {
reComp := regexp.MustCompile("a.+")
require.True(t, reComp.MatchString("abbs"))
h := NewHashXSingle()
h.Set("abbs", "abbs")
h.Set("ppp", "ppp")
h.Set("accs", "accs")
result := h.Range(0, 3, "")
require.Len(t, result, 3)
result = h.Range(0, -1, "")
require.Len(t, result, 3)
result = h.Range(0, -1, "a.+")
require.Len(t, result, 2)
result = h.Range(1, -1, "a.+")
require.Len(t, result, 1)
}

View File

@ -0,0 +1,428 @@
package listx
import (
"gitee.com/wheat-os/wheatCache/pkg/errorx"
"gitee.com/wheat-os/wheatCache/pkg/structure"
)
/*
1. 双向链表
2. 支持头尾操作
3. 支持索引
4. 支持切片
*/
type ListxNode struct {
next *ListxNode
pre *ListxNode
val *structure.Value
}
type Listx struct {
head *ListxNode
tail *ListxNode
length int
}
func NewListXSingle() structure.ListXInterface {
return &Listx{
head: nil,
tail: nil,
length: 0,
}
}
func (l *Listx) initByValue(val string) int {
if l.head == nil && l.length == 0 {
node := &ListxNode{
val: structure.NewValue(val),
}
l.head = node
l.tail = node
l.length = 1
return node.val.GetSize()
}
return 0
}
// 定位到 list 的元素, 支持反向索引
func (l *Listx) location(index int) (*ListxNode, error) {
// 正定位
if index >= 0 {
node := l.head
for ; index != 0 && node != nil; index -= 1 {
node = node.next
}
if node == nil {
return nil, errorx.New("index crosses the line")
}
return node, nil
}
node := l.tail
for index = (-index) - 1; index != 0 && node != nil; {
node = node.pre
index -= 1
}
if node == nil {
return nil, errorx.New("index crosses the line")
}
return node, nil
}
// 转换为左索引,负数索引
func (l *Listx) leftIndex(index int) (int, error) {
if index < 0 && l.length+index > 0 {
return index, nil
}
if index >= 0 && index < l.length {
return index - l.length, nil
}
return 0, errorx.New("the index is not valid, index:%d", index)
}
// 转换为右索引,正数索引
func (l *Listx) rightIndex(index int) (int, error) {
if index >= 0 && index < l.length {
return index, nil
}
if index < 0 && l.length+index >= 0 {
return l.length + index, nil
}
return 0, errorx.New("the index is not valid, index:%d", index)
}
func (l *Listx) remove(node *ListxNode) {
if node == nil {
return
}
l.length -= 1
if node == l.head {
l.head = node.next
node.next.pre = nil
return
}
if node == l.tail {
l.tail = node.pre
node.pre.next = nil
return
}
node.pre.next = node.next
node.next.pre = node.pre
}
func (l *Listx) SizeByte() int64 {
bytes := 0
r := l.head
for r != nil {
bytes += 16 + r.val.GetSize()
r = r.next
}
return int64(bytes)
}
// RollBack TODO 事务相关, V2 实现
func (l *Listx) RollBack() error {
panic("not implemented") // TODO: Implement
}
// Begin 事务相关, V2 实现
func (l *Listx) Begin() error {
panic("not implemented") // TODO: Implement
}
// Comment 事务相关, V2 实现
func (l *Listx) Comment() error {
panic("not implemented") // TODO: Implement
}
func (l *Listx) Encode() ([]byte, error) {
panic("not implemented") // TODO: Implement
}
func (l *Listx) LPush(valueStr ...string) structure.UpdateLength {
if len(valueStr) == 0 {
return 0
}
// 使用第一个元素尝试初始化列表
updateLength := l.initByValue(valueStr[0])
for i := 1; i < len(valueStr); i++ {
head := l.head
val := structure.NewValue(valueStr[i])
node := &ListxNode{val: val}
node.next = head
head.pre = node
l.head = node
l.length += 1
updateLength += val.GetSize()
}
return structure.UpdateLength(updateLength)
}
func (l *Listx) RPush(valueStr ...string) structure.UpdateLength {
if len(valueStr) == 0 {
return 0
}
updateLength := l.initByValue(valueStr[0])
for i := 1; i < len(valueStr); i++ {
tail := l.tail
val := structure.NewValue(valueStr[i])
node := &ListxNode{val: val}
tail.next = node
node.pre = tail
l.tail = node
l.length += 1
updateLength += val.GetSize()
}
return structure.UpdateLength(updateLength)
}
func (l *Listx) LPop(count int) ([]string, structure.UpdateLength) {
values := make([]string, 0, count)
head := l.head
// 动态变化长度
updateLength := 0
for nodePoint := 0; head != nil && nodePoint < count; nodePoint++ {
values = append(values, head.val.ToString())
updateLength += head.val.GetSize()
head = head.next
l.length -= 1
}
if head != nil {
head.pre = nil
} else {
l.tail = nil
}
l.head = head
return values, structure.UpdateLength(updateLength)
}
func (l *Listx) RPop(count int) ([]string, structure.UpdateLength) {
values := make([]string, 0, count)
tail := l.tail
updateLength := 0
for nodePoint := 0; tail != nil && nodePoint < count; nodePoint++ {
values = append(values, tail.val.ToString())
updateLength += tail.val.GetSize()
tail = tail.pre
l.length -= 1
}
if tail != nil {
tail.next = nil
} else {
l.head = nil
}
l.tail = tail
return values, structure.UpdateLength(updateLength)
}
func (l *Listx) Index(index int) (string, error) {
node, err := l.location(index)
if err != nil {
return "", nil
}
return node.val.ToString(), nil
}
// Insert, right 为 true 右添加,否则左添加
func (l *Listx) Insert(index int, right bool, valueStr ...string) (structure.UpdateLength, error) {
targetNode, err := l.location(index)
if err != nil {
return 0, err
}
updateLength := 0
for _, valStr := range valueStr {
val := structure.NewValue(valStr)
node := &ListxNode{val: val}
// 右插
if right {
node.pre = targetNode
node.next = targetNode.next
targetNode.next = node
targetNode.next.pre = node
// 更新尾部
if targetNode == l.tail {
l.tail = node
}
targetNode = node
} else {
// 左插
node.pre = targetNode.pre
targetNode.pre.next = node
node.next = targetNode
targetNode.pre = node
// 更新头部
if targetNode == l.head {
l.head = node
}
targetNode = node
}
updateLength += val.GetSize()
l.length += 1
}
return structure.UpdateLength(updateLength), nil
}
func (l *Listx) Length() int {
return l.length
}
// Slice 切片
func (l *Listx) Slice(start int, end int) (structure.UpdateLength, error) {
startOffset, err := l.rightIndex(start)
if err != nil {
return 0, err
}
endRightOffset, err := l.rightIndex(end)
if err != nil && end != l.length {
return 0, errorx.New("index overstep the boundary, index: %d", end)
}
if startOffset >= endRightOffset && endRightOffset != 0 {
return 0, errorx.New("the start index must be larger than the end index")
}
// 计算左偏移
var endOffset int
if end == l.length {
endOffset = 0
} else {
endOffset, err = l.leftIndex(end)
if err != nil {
return 0, err
}
}
updateLength := 0
// 右切片
head := l.head
for nodePoint := 0; head != nil && nodePoint < startOffset; nodePoint++ {
updateLength += head.val.GetSize()
head = head.next
l.length -= 1
}
l.head = head
head.pre = nil
tail := l.tail
for nodePoint := 0; tail != nil && nodePoint < -endOffset; nodePoint++ {
updateLength += tail.val.GetSize()
tail = tail.pre
l.length -= 1
}
l.tail = tail
tail.next = nil
return structure.UpdateLength(updateLength), nil
}
// Range 遍历
func (l *Listx) Range(start, end int) ([]string, error) {
startOffset, err := l.rightIndex(start)
if err != nil {
return nil, err
}
endRightOffset, err := l.rightIndex(end)
if err != nil && end != l.length {
return nil, errorx.New("index overstep the boundary, index: %d", end)
}
if startOffset >= endRightOffset && endRightOffset != 0 {
return nil, errorx.New("the start index must be larger than the end index")
}
head := l.head
for nodePoint := 0; head != nil && nodePoint < startOffset; nodePoint++ {
head = head.next
}
values := make([]string, 0)
for i := 0; i < endRightOffset-startOffset && head != nil; i++ {
values = append(values, head.val.ToString())
head = head.next
}
return values, nil
}
func (l *Listx) Remove(value string, count int) (int, structure.UpdateLength) {
if count == 0 {
return 0, 0
}
updateLength := 0
remCount := count
// 头删除
if count > 0 {
node := l.head
for node != nil && remCount > 0 {
if node.val.ToString() == value {
l.remove(node)
remCount--
updateLength += node.val.GetSize()
}
node = node.next
}
return count - remCount, structure.UpdateLength(updateLength)
}
// 尾删除
node := l.tail
for node != nil && remCount < 0 {
if node.val.ToString() == value {
l.remove(node)
remCount++
updateLength += node.val.GetSize()
}
node = node.pre
}
return remCount - count, structure.UpdateLength(updateLength)
}

View File

@ -0,0 +1,228 @@
package listx
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestListx_LPush_And_Pop(t *testing.T) {
list := NewListXSingle()
up := list.LPush("1", "2", "3")
require.Equal(t, list.Length(), 3)
values, updateLength := list.LPop(3)
require.Equal(t, values, []string{"3", "2", "1"})
require.Equal(t, up, updateLength)
list.LPush("1", "2", "3")
values, updateLength = list.LPop(1)
require.Equal(t, values, []string{"3"})
require.Equal(t, int(updateLength), 24)
}
func TestListx_RPush_Pop(t *testing.T) {
list := NewListXSingle()
up := list.RPush("1", "2", "3")
require.Equal(t, list.Length(), 3)
values, updateLength := list.LPop(3)
require.Equal(t, values, []string{"1", "2", "3"})
require.Equal(t, up, updateLength)
list.RPush("1", "2", "3")
values, updateLength = list.RPop(2)
require.Equal(t, values, []string{"3", "2"})
require.Equal(t, int(updateLength), 48)
}
func TestListx_location(t *testing.T) {
list := &Listx{
head: nil,
tail: nil,
length: 0,
}
list.RPush("1", "2", "3")
node, err := list.location(1)
require.NoError(t, err)
require.Equal(t, node.val.ToString(), "2")
node, err = list.location(0)
require.NoError(t, err)
require.Equal(t, node.val.ToString(), "1")
node, err = list.location(2)
require.NoError(t, err)
require.Equal(t, node.val.ToString(), "3")
_, err = list.location(3)
require.Error(t, err)
node, err = list.location(-1)
require.NoError(t, err)
require.Equal(t, node.val.ToString(), "3")
node, err = list.location(-2)
require.NoError(t, err)
require.Equal(t, node.val.ToString(), "2")
node, err = list.location(-3)
require.NoError(t, err)
require.Equal(t, node.val.ToString(), "1")
_, err = list.location(-4)
require.Error(t, err)
}
func TestListx_Insert(t *testing.T) {
list := NewListXSingle()
list.LPush("a", "b", "c", "d", "e")
val, _ := list.LPop(1)
require.Equal(t, val, []string{"e"})
res, err := list.Index(1)
require.NoError(t, err)
require.Equal(t, res, "c")
_, err = list.Insert(1, false, "1", "2", "3")
require.NoError(t, err)
// 全部取出
val, _ = list.LPop(list.Length())
require.Equal(t, val, []string{"d", "3", "2", "1", "c", "b", "a"})
list.RPush("1", "2", "3", "4", "5")
res, err = list.Index(-2)
require.NoError(t, err)
require.Equal(t, res, "4")
_, err = list.Insert(-1, true, "6", "7")
require.NoError(t, err)
val, _ = list.LPop(list.Length())
require.Equal(t, val, []string{"1", "2", "3", "4", "5", "6", "7"})
}
func TestListx_Index(t *testing.T) {
list := &Listx{
head: nil,
tail: nil,
length: 0,
}
list.RPush("a", "b", "c", "d", "e")
index := 2
leftIndex, err := list.leftIndex(index)
require.NoError(t, err)
rightIndex, err := list.rightIndex(index)
require.NoError(t, err)
v1, err := list.Index(leftIndex)
require.NoError(t, err)
v2, err := list.Index(rightIndex)
require.NoError(t, err)
require.Equal(t, v1, v2)
}
func TestListx_Slice(t *testing.T) {
list := NewListXSingle()
list.RPush("a", "b", "c", "d", "e")
// 主流程测试
list.Slice(1, 2)
values, _ := list.LPop(list.Length())
require.Equal(t, values, []string{"b"})
list2 := NewListXSingle()
list2.RPush("1", "2", "3", "4", "5")
list2.Slice(0, 4)
values, _ = list2.LPop(list2.Length())
require.Equal(t, values, []string{"1", "2", "3", "4"})
list3 := NewListXSingle()
list3.RPush("1", "2", "3", "4", "5")
list3.Slice(2, list3.Length())
values, _ = list3.LPop(list3.Length())
require.Equal(t, values, []string{"3", "4", "5"})
// 测试负数索引
list3 = NewListXSingle()
list3.RPush("1", "2", "3", "4", "5")
_, err := list3.Slice(0, -2)
require.NoError(t, err)
values, _ = list3.LPop(list3.Length())
require.Equal(t, values, []string{"1", "2", "3"})
// 测试负数双边际
list3 = NewListXSingle()
list3.RPush("1", "2", "3", "4", "5")
_, err = list3.Slice(-3, -2)
require.NoError(t, err)
values, _ = list3.LPop(list3.Length())
require.Equal(t, values, []string{"3"})
// 测试负数边际
list3 = NewListXSingle()
list3.RPush("1", "2", "3", "4", "5")
_, err = list3.Slice(-5, 4)
require.NoError(t, err)
values, _ = list3.LPop(list3.Length())
require.Equal(t, values, []string{"1", "2", "3", "4"})
}
func TestListx_Range(t *testing.T) {
list := NewListXSingle()
list.RPush("a", "b", "c", "d", "e")
val, err := list.Range(0, 2)
require.NoError(t, err)
require.Equal(t, val, []string{"a", "b"})
val, err = list.Range(0, -1)
require.NoError(t, err)
require.Equal(t, val, []string{"a", "b", "c", "d"})
val, err = list.Range(-3, 3)
require.NoError(t, err)
require.Equal(t, val, []string{"c"})
val, err = list.Range(-1, list.Length())
require.NoError(t, err)
require.Equal(t, val, []string{})
_, err = list.Range(6, -1)
require.Error(t, err)
}
func TestListx_Remove(t *testing.T) {
list := NewListXSingle()
list.RPush("a", "b", "c", "c", "e")
count, up := list.Remove("c", -2)
require.Equal(t, count, 2)
require.Equal(t, int(up), 34)
res, _ := list.LPop(list.Length())
require.Equal(t, res, []string{"a", "b", "e"})
list = NewListXSingle()
list.RPush("a", "b", "c", "c", "e")
count, up = list.Remove("b", 1)
require.Equal(t, count, 1)
require.Equal(t, int(up), 17)
res, _ = list.LPop(list.Length())
require.Equal(t, res, []string{"a", "c", "c", "e"})
}

Some files were not shown because too many files have changed in this diff Show More