Compare commits

..

162 Commits

Author SHA1 Message Date
刘祥超
b0d1f2c8ea 版本号修改为1.3.9 2024-05-20 09:51:19 +08:00
刘祥超
94de773773 修改copyright 2024-05-17 18:30:33 +08:00
刘祥超
da8d7f1437 设置文件句柄最大缓存为65535 2024-05-16 20:40:41 +08:00
刘祥超
777bbdf50b 优化代码 2024-05-11 09:23:54 +08:00
刘祥超
f5596b4f0c 增加edge-node top命令,用来调用系统的top命令并传入edge-node进程ID 2024-05-08 19:42:55 +08:00
刘祥超
480d165538 WAF区域封禁增加“允许搜索引擎”选项 2024-05-08 17:52:20 +08:00
刘祥超
870d18a5ac 搜索引擎识别增加facebook 2024-05-08 17:18:48 +08:00
刘祥超
731f213310 WAF规则集中增加“允许搜索引擎”选项,可以快速允许搜索引擎访问 2024-05-08 16:45:28 +08:00
刘祥超
f1b3a7463d 优化ttlcache相关代码 2024-05-08 11:10:56 +08:00
刘祥超
5020985b96 KV缓存索引增加内存缓存 2024-05-08 10:57:36 +08:00
刘祥超
a0ac33af5a Partial Content新创建时不对比Content-MD5 2024-05-08 10:30:47 +08:00
刘祥超
ffe3f248a9 Partial Content每次写入缓存时都检查Content-MD5是否一致 2024-05-07 20:15:47 +08:00
刘祥超
02dc42d8e0 缓存策略增加“允许读取不完整的Partial Content”选项 2024-05-07 20:06:06 +08:00
刘祥超
b68d92d506 上传IP增加失败重试 2024-05-07 17:55:28 +08:00
刘祥超
1144ca8a8b Partial Content从源站读取数据时验证本地缓存的Content-MD5是否一致 2024-05-07 17:27:10 +08:00
刘祥超
0b216090f1 修复修改后的Partial Content Range范围多1字节的问题 2024-05-07 16:32:53 +08:00
刘祥超
b1e609b2b4 优化一处注释 2024-05-07 16:21:43 +08:00
刘祥超
8de74b62e7 优化Partial Content内容缓存,现在可以使用“部分文件缓存+部分回源”的方式提供内容 2024-05-07 16:20:22 +08:00
刘祥超
02da06dffd WAF增加“请求报头最大长度”参数 2024-05-06 21:06:55 +08:00
刘祥超
bd417a3795 网站全局设置中增加“XFF中最多地址数”选项 2024-05-06 14:05:12 +08:00
刘祥超
42e1e0c3df 再次提升节点默认读写线程数限制 2024-05-05 22:12:28 +08:00
刘祥超
216dacc348 IP名单优化
* 增加IP灰名单,用于仅记录并观察IP
* 优化IP名单同步版本号管理
* WAF记录IP动作优先记录到网站和策略相关的IP名单中
2024-05-05 19:10:46 +08:00
刘祥超
968eac6046 增加默认的并发读写线程数 2024-05-03 18:03:15 +08:00
刘祥超
9a3740dc00 自动安装nftables时尝试使用apt-get 2024-05-03 15:51:08 +08:00
刘祥超
ef1626de53 优化代码 2024-05-03 15:31:40 +08:00
刘祥超
5eb122f0a3 UDP连接也检查IP名单 2024-05-03 15:11:54 +08:00
刘祥超
6e2c5aabc2 自定义页面增加是否“启用系统自定义页面”选项 2024-05-03 11:22:50 +08:00
刘祥超
1a1ae239b3 版本号修改为1.3.8.2 2024-05-03 11:22:16 +08:00
刘祥超
95f42ebd37 如果已经有足够的硬盘写入速度测试数据,则不再执行测试 2024-05-02 11:49:51 +08:00
刘祥超
7111d23f11 edge-node accesslog命令输出增加发送内容字节数、请求来源、请求UserAgent 2024-05-01 19:29:07 +08:00
刘祥超
e42c8452ff 优化并发读写相关代码 2024-05-01 15:53:49 +08:00
刘祥超
fe6e5ba5f9 优化并发读写限制 2024-05-01 12:42:35 +08:00
刘祥超
406d5de482 从内存刷新到磁盘时无需并发写限制 2024-04-30 21:23:44 +08:00
刘祥超
f66e672bb4 读取缓存时总是尝试打开文件,不受并发读的限制 2024-04-30 20:26:34 +08:00
刘祥超
7252d00c8e 版本号修改为1.3.8 2024-04-30 19:09:57 +08:00
刘祥超
7ec4656aea 可以在集群设置中修改节点最大并发读/写数 2024-04-30 19:09:40 +08:00
刘祥超
33156fed2a 延长读写线程超时时间/增加相关测试用例 2024-04-30 17:24:08 +08:00
刘祥超
e8538d4e34 bfs commit 2024-04-30 12:38:43 +08:00
刘祥超
c7d60e01b8 在请求上下文中停用统计的时候也停用对应的指标统计 2024-04-30 00:05:32 +08:00
刘祥超
bbb4b7d31a 版本修改为1.3.7 2024-04-29 23:12:12 +08:00
刘祥超
aa2467c7cf 增加读写线程限制相关测试用例 2024-04-29 23:10:02 +08:00
刘祥超
fa02713ab5 限制读写线程最小值为4,最大值为32 2024-04-29 22:51:51 +08:00
刘祥超
973324ae8f 写入和删除缓存文件时增加线程数限制 2024-04-29 22:36:26 +08:00
刘祥超
7febc6aaf3 读取文件时增加线程数限制 2024-04-29 22:01:55 +08:00
刘祥超
1cede74db3 bfs:修复并发读提示ErrClosed都问题 2024-04-28 19:02:59 +08:00
刘祥超
0dbbc12eb7 bfs:实现对FileHeader中Block数据的compaction 2024-04-28 15:38:13 +08:00
刘祥超
b272de2122 bfs:对FileHeader的压缩和解压使用Pool管理 2024-04-28 10:06:29 +08:00
刘祥超
962cbde4e9 bfs:弹出BFile的时候确保没有正在被使用 2024-04-27 20:55:04 +08:00
刘祥超
6226e31cdc bfs:实现FileHeader的lazy load 2024-04-27 20:11:50 +08:00
刘祥超
fb8c78553a bfs:同一个Hash同时只能有一个Writer,避免多线程读冲突 2024-04-27 18:27:49 +08:00
刘祥超
801f5d4525 bfs:实现maxOpenFiles 2024-04-27 17:29:12 +08:00
刘祥超
04007bf8f1 bfs: 增加读写线程限制 2024-04-27 07:09:14 +08:00
刘祥超
8c044faace bfs: bfs.FS增加锁 (experimental) 2024-04-26 19:26:22 +08:00
刘祥超
f262e76f96 bfs commit (exprimental) 2024-04-26 18:44:29 +08:00
刘祥超
ef057b106e 初步实现bfs原型(仅用于实验) 2024-04-26 17:16:32 +08:00
刘祥超
508f8cbae0 调整KV相关选项尺寸 2024-04-26 17:15:55 +08:00
刘祥超
d8e4ff3d01 增强KV字节编码安全性 2024-04-24 14:33:15 +08:00
刘祥超
f247e57e76 优化KV相关日志 2024-04-24 09:03:15 +08:00
刘祥超
3581ce3763 优化KV相关错误提示/可以从路径直接加载数据库 2024-04-23 11:56:00 +08:00
刘祥超
b66c70de66 ${requestMethod}变量增加默认值GET 2024-04-22 21:32:53 +08:00
刘祥超
d3a4f14999 版本号修改为1.3.6.1 2024-04-22 18:46:29 +08:00
刘祥超
00a7324640 增加缓存索引相关测试用例 2024-04-22 18:46:21 +08:00
刘祥超
d8ea1809dc 优化代码 2024-04-22 12:38:18 +08:00
刘祥超
7f5088958e 版本号修改为1.3.6 2024-04-22 10:51:19 +08:00
刘祥超
eff928d988 修复非80/443端口回源跟随无法正确识别地址的问题 2024-04-22 10:51:11 +08:00
刘祥超
b1e1c3ebbf 启动时判断是否处于空闲时间决定是否执行fstrim 2024-04-21 23:04:51 +08:00
刘祥超
c8f440e24c 优化测试用例 2024-04-21 19:04:31 +08:00
刘祥超
6c5f4e0705 修复HTTP Client相关测试用例 2024-04-21 15:13:45 +08:00
刘祥超
73e6b04026 下载Partial Content时,本地缓存不完整时,只要结束位置为空,就从源站下载 2024-04-21 12:51:44 +08:00
刘祥超
0b09de3378 修复从本地数据库中的第一次加载的IP可能不起作用的问题 2024-04-21 10:33:12 +08:00
刘祥超
69b1355cfe 修复IP名单中“所有IP”类型的IP不起作用的问题 2024-04-21 10:32:04 +08:00
刘祥超
459f8a8215 优化测试用例 2024-04-21 08:48:33 +08:00
刘祥超
a58b9a1fda 版本号修改为1.3.5 2024-04-20 22:39:28 +08:00
刘祥超
6cdcceda86 优化ttlcache测试用例 2024-04-20 22:39:17 +08:00
刘祥超
1cf0f13f7d 修复ttlcache可能缺失回收数据的问题 2024-04-20 22:20:44 +08:00
刘祥超
b1b450bb50 写分区加载文件时,避免单次拓展的文件尺寸太大 2024-04-20 18:59:07 +08:00
刘祥超
a7ad2cea8f 提升Partial Content的范围数据(ranges)写入效率 2024-04-20 17:44:23 +08:00
刘祥超
c9dac96366 优化代码 2024-04-20 15:51:48 +08:00
刘祥超
5b9ffe1225 当使用Range: bytes=0-访问分区文件缓存时,只有已缓存完整才会允许访问
防止有些客户端软件无法根据返回的Content-Range分段读取内容
2024-04-20 15:31:20 +08:00
刘祥超
b965080bb0 忽略一些实验性代码 2024-04-20 08:54:54 +08:00
刘祥超
ed49d74874 更新依赖库 2024-04-20 08:54:04 +08:00
刘祥超
91f817d2d2 优化xxhash和fnv相关代码 2024-04-18 18:25:33 +08:00
刘祥超
96cb816200 优化${serverName}识别相关代码 2024-04-18 17:14:56 +08:00
刘祥超
bf28505d91 请求源站时支持自动gzip回源 2024-04-18 16:18:49 +08:00
刘祥超
ad558cc0e8 硬盘TRIM增加追踪统计 2024-04-18 15:10:08 +08:00
刘祥超
0065543e96 修改空闲时间数据缓存文件名 2024-04-18 12:32:02 +08:00
刘祥超
56219d5082 改进空闲时间算法 2024-04-18 10:02:09 +08:00
刘祥超
ffac717219 优化代码 2024-04-18 08:47:05 +08:00
刘祥超
8794bf5676 回源跟随限制单次请求最大跳转次数为8 2024-04-18 08:29:52 +08:00
刘祥超
7130154bc8 修复回源跟随无法跨不同协议、不同服务器地址的问题 2024-04-17 20:38:00 +08:00
刘祥超
2b01162ab4 优化HTTP客户端管理 2024-04-17 18:24:21 +08:00
刘祥超
3ce30e36bb 增加测试用例 2024-04-17 17:18:11 +08:00
刘祥超
3e183ac824 防盗链功能增加“例外URL“和“限制URL”设置 2024-04-17 15:45:24 +08:00
刘祥超
e1d9e72df0 UA名单支持批量添加关键词 2024-04-17 15:26:33 +08:00
刘祥超
bbb71db0d0 增加三个常用文件扩展名 2024-04-17 14:06:30 +08:00
刘祥超
7310b601d6 内容压缩功能增加“例外URL“和“限制URL”设置 2024-04-17 13:56:38 +08:00
刘祥超
7220c53ced 自动在空闲时间执行定时任务 2024-04-17 13:10:55 +08:00
刘祥超
234887cc1d 内容压缩增加繁忙(busy)检测 2024-04-17 08:36:14 +08:00
刘祥超
fedc4262a0 将版本号修改为1.3.4.4 2024-04-16 13:56:34 +08:00
刘祥超
267ac99d65 再次调低内容压缩Pool的内容长度 2024-04-16 12:55:18 +08:00
刘祥超
140d3bbf59 优化内容压缩
* 取消用户设置的压缩级别,现在压缩级别通过系统自动设置
* Pool中的对象命中100万次时自动销毁,避免内存泄漏
* 降低Pool中的对象数量,避免占用太多内存
* 根据系统CPU线程数自动计算压缩级别,避免消耗太多CPU
* zstd限制解码的最大Window
* zstd使用低内存模式
2024-04-16 11:32:38 +08:00
刘祥超
ae82310b92 优化代码 2024-04-15 19:37:38 +08:00
刘祥超
484b56492b 修复DAU统计导致无法提示进程在运行的问题 2024-04-15 16:06:16 +08:00
刘祥超
167bb2df29 增加 vm.max_map_count 内核参数自动调整 2024-04-15 15:18:22 +08:00
刘祥超
a4d58ffc40 增加测试用例 2024-04-15 14:15:30 +08:00
刘祥超
64a186b0e7 优化代码 2024-04-15 12:20:31 +08:00
刘祥超
e0bed33cc5 版本号修改为1.3.4.3 2024-04-15 09:26:13 +08:00
刘祥超
5e7ea9a884 优化字节缓冲区相关代码 2024-04-15 09:26:00 +08:00
刘祥超
4bdd248f99 优化代码 2024-04-15 08:42:33 +08:00
刘祥超
0789b3d0d5 golangci中禁用tagliatelle 2024-04-14 20:00:22 +08:00
刘祥超
27c61ca0d4 改进单元测试,以便于可以使用go test ../...进行执行 2024-04-14 19:59:56 +08:00
刘祥超
7141add68e 删除一直未实现的Unix协议相关内容 2024-04-14 17:12:53 +08:00
刘祥超
7e11ee98a9 TCP和UDP也支持DAU统计 2024-04-14 16:55:35 +08:00
刘祥超
cdb6134a3b 增加DAU清理指标 2024-04-14 15:47:16 +08:00
刘祥超
3a9fec5196 CC防护增加“忽略常用文件”选项 2024-04-13 20:39:21 +08:00
刘祥超
0396cae524 上传封禁IP时同时传入原始IP值 2024-04-13 16:49:45 +08:00
刘祥超
04c503d644 WAF策略中的IP名单也应用于网站单独设置的WAF规则 2024-04-13 09:58:06 +08:00
刘祥超
f526665633 执行定时任务时自动根据负载进行延后执行 2024-04-12 21:13:19 +08:00
刘祥超
fe069762bb 增加网站每日独立IP统计 2024-04-12 20:12:09 +08:00
刘祥超
62f8ed63be 统一KV存储表命名方式 2024-04-12 13:58:57 +08:00
刘祥超
4fb1e414be 增强加密密钥兼容性 2024-04-12 13:47:07 +08:00
刘祥超
4cc6a4ff31 优化代码 2024-04-12 08:41:14 +08:00
刘祥超
6026d8c3bd 根据系统可用内存调整写入缓存到内存的阈值 2024-04-12 08:17:14 +08:00
刘祥超
dc9cff541e 人机识别验证成功后记录到Cookie,以便于在重启、切换节点时仍能恢复验证状态 2024-04-11 16:14:14 +08:00
刘祥超
b1151479e0 增强加密密钥的稳定性 2024-04-11 15:11:58 +08:00
刘祥超
7bb808c08d 增强加密密钥的稳定性 2024-04-11 14:18:32 +08:00
刘祥超
200718d7dc 提高硬盘TRIM运行时负载要求 2024-04-09 11:39:16 +08:00
刘祥超
d75afa9850 版本号修改为1.3.4.2 2024-04-09 10:05:49 +08:00
刘祥超
8d72e5fdd1 优化KV存储数据表关闭后的错误提示 2024-04-07 14:55:12 +08:00
刘祥超
1fe15d4e3c 优化WAF
* 信息加密使用struct代替map,以缩短加密后内容长度
* 拦截动作、人机识别动作增加是否尝试全局封禁选项
* JSCookie识别动作增加默认设置选项
* 人机识别中传入info参数异常时,尝试跳转到来源地址,避免直接提示invalid request
2024-04-07 14:31:22 +08:00
刘祥超
e87ea9d802 从IP名单中查询IP时增加过期时间检查,防止GC速度慢时可能有1秒延迟 2024-04-07 13:57:01 +08:00
刘祥超
b15b5cfb8f 优化IP名单相关代码 2024-04-06 15:37:14 +08:00
刘祥超
c9eb577c06 更好地支持IPv6/优化IP名单内存用量 2024-04-06 10:07:39 +08:00
刘祥超
ece596d7b9 限制硬盘TRIM只在Linux下执行 2024-04-05 11:47:54 +08:00
刘祥超
58b6d7848a 缓存写入结束时检查Content-Length是否和实际内容长度一致 2024-04-05 11:45:18 +08:00
刘祥超
c4bb92433d 优化缓存从内存刷新到硬盘程序 2024-04-05 10:59:14 +08:00
刘祥超
f6e5201cc3 上传指标数据时忽略不完整数据 2024-04-05 10:05:20 +08:00
刘祥超
b645c76a07 修复修改内存缓存策略导致缓存策略实际容量越来越少的问题 2024-04-05 09:09:31 +08:00
刘祥超
27c56119ae 硬盘TRIM周期从1周改为2天 2024-04-04 19:55:15 +08:00
刘祥超
e034c31333 增加SSD硬盘自动TRIM功能 2024-04-04 17:20:13 +08:00
刘祥超
94ada46abc 删除不需要的代码 2024-04-04 09:30:41 +08:00
刘祥超
4148681bb8 优化MMAP相关功能 2024-04-04 08:28:14 +08:00
刘祥超
e5c5234be8 使用KV存储实现指标统计 2024-04-02 19:54:04 +08:00
刘祥超
750aafdea1 修复KV存储锁无法创建的问题 2024-03-31 16:03:35 +08:00
刘祥超
4d3c214d7d Agent识别库增加KV存储 2024-03-31 15:05:07 +08:00
刘祥超
a5950cc91b 优化代码 2024-03-31 12:54:30 +08:00
刘祥超
4d88629707 优化缓存索引代码 2024-03-31 11:47:50 +08:00
刘祥超
98441ccd3a 优化过期列表管理 2024-03-31 11:47:34 +08:00
刘祥超
2a44283016 优化代码 2024-03-31 10:39:18 +08:00
刘祥超
db9463bdb1 为KV存储增加文件锁 2024-03-31 10:37:06 +08:00
刘祥超
d2e9c8c10f 使用KV数据库来管理IP名单 2024-03-31 10:08:53 +08:00
刘祥超
b4995868c9 提升IP名单性能 2024-03-30 14:42:56 +08:00
刘祥超
10319ab48f 使用MMAP提升缓存读取性能 2024-03-29 19:28:16 +08:00
刘祥超
6146a829ed 版本号修改为1.3.4.1 2024-03-29 17:08:16 +08:00
刘祥超
947ef4eb78 降低默认的CPU线程数(经测试,有约20%的性能提升) 2024-03-29 09:25:53 +08:00
刘祥超
4cfd48f0c4 优化代码 2024-03-28 17:18:00 +08:00
刘祥超
f1d0984031 优化代码 2024-03-28 17:17:34 +08:00
刘祥超
f119690ab7 优化文件句柄缓存相关代码 2024-03-28 08:52:53 +08:00
刘祥超
a77134a601 降低并发写线程数 2024-03-27 20:18:32 +08:00
刘祥超
707ed03f1e 根据系统环境动态调整内容刷入磁盘线程数 2024-03-25 16:36:29 +08:00
刘祥超
07080b13ee 默认启用KV缓存数据库 2024-03-25 11:40:19 +08:00
刘祥超
f78f9136d0 调整pebble相关参数 2024-03-25 11:40:08 +08:00
504 changed files with 12944 additions and 4239 deletions

View File

@@ -71,4 +71,6 @@ linters:
- forcetypeassert
- whitespace
- noctx
- rowserrcheck
- rowserrcheck
- tagliatelle
- protogetter

View File

@@ -11,4 +11,4 @@ go run -tags=${TAG} ../cmd/edge-node/main.go stop
# reference: https://pkg.go.dev/cmd/go/internal/test
go clean -testcache
go test -timeout 10s -tags="${TAG}" -cover ../...
go test -timeout 60s -tags="${TAG}" -cover ../...

View File

@@ -9,6 +9,7 @@ import (
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
"github.com/TeaOSLab/EdgeNode/internal/nodes"
"github.com/TeaOSLab/EdgeNode/internal/utils"
executils "github.com/TeaOSLab/EdgeNode/internal/utils/exec"
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
"github.com/iwind/TeaGo/Tea"
_ "github.com/iwind/TeaGo/bootstrap"
@@ -22,8 +23,10 @@ import (
_ "net/http/pprof"
"os"
"path/filepath"
"runtime"
"sort"
"strings"
"syscall"
"time"
)
@@ -31,7 +34,7 @@ func main() {
var app = apps.NewAppCmd().
Version(teaconst.Version).
Product(teaconst.ProductName).
Usage(teaconst.ProcessName + " [-v|start|stop|restart|status|quit|test|reload|service|daemon|config|pprof|accesslog|uninstall]").
Usage(teaconst.ProcessName + " [-v|start|stop|restart|status|quit|test|reload|service|daemon|config|pprof|top|accesslog|uninstall]").
Usage(teaconst.ProcessName + " [trackers|goman|conns|gc|bandwidth|disk|cache.garbage]").
Usage(teaconst.ProcessName + " [ip.drop|ip.reject|ip.remove|ip.close] IP")
@@ -552,7 +555,7 @@ func main() {
return
}
err = os.WriteFile(Tea.Root + "/configs/api_node.yaml", configYAML, 0666)
err = os.WriteFile(Tea.Root+"/configs/api_node.yaml", configYAML, 0666)
if err != nil {
fmt.Println("[ERROR]write config failed: " + err.Error())
return
@@ -560,6 +563,37 @@ func main() {
fmt.Println("success")
})
app.On("top", func() {
var sock = gosock.NewTmpSock(teaconst.ProcessName)
reply, err := sock.Send(&gosock.Command{Code: "pid"})
if err != nil {
fmt.Println("[ERROR]not started yet")
return
}
var pid = maps.NewMap(reply.Params).GetInt("pid")
if pid <= 0 {
fmt.Println("[ERROR]invalid pid '" + types.String(pid) + "'")
return
}
topExe, _ := executils.LookPath("top")
if len(topExe) > 0 {
if runtime.GOOS == "linux" {
err = syscall.Exec(topExe, []string{topExe, "-p", types.String(pid)}, os.Environ())
} else if runtime.GOOS == "darwin" {
err = syscall.Exec(topExe, []string{topExe, "-pid", types.String(pid)}, os.Environ())
} else {
fmt.Println("[ERROR]not supported os '" + runtime.GOOS + "'")
return
}
if err != nil {
fmt.Println("[ERROR]start failed: " + err.Error())
}
} else {
fmt.Println("[ERROR]could not found 'top' command in this system")
}
})
app.Run(func() {
var node = nodes.NewNode()
node.Start()

39
go.mod
View File

@@ -6,7 +6,6 @@ replace (
github.com/TeaOSLab/EdgeCommon => ../EdgeCommon
github.com/dchest/captcha => github.com/iwind/captcha v0.0.0-20231130092438-ae985686ed84
github.com/fsnotify/fsnotify => github.com/iwind/fsnotify v1.5.2-0.20220817040843-193be2051ff4
github.com/google/nftables => github.com/iwind/nftables v0.0.0-20230419014751-9f023a644ad4
)
require (
@@ -16,21 +15,21 @@ require (
github.com/aws/aws-sdk-go v1.44.279
github.com/baidubce/bce-sdk-go v0.9.170
github.com/biessek/golang-ico v0.0.0-20180326222316-d348d9ea4670
github.com/cespare/xxhash v1.1.0
github.com/cespare/xxhash/v2 v2.2.0
github.com/cockroachdb/pebble v1.1.0
github.com/dchest/captcha v0.0.0-00010101000000-000000000000
github.com/fsnotify/fsnotify v1.7.0
github.com/go-redis/redis/v8 v8.11.5
github.com/google/gopacket v1.1.19
github.com/google/nftables v0.1.0
github.com/google/nftables v0.2.0
github.com/huaweicloud/huaweicloud-sdk-go-obs v3.23.4+incompatible
github.com/iwind/TeaGo v0.0.0-20230630104525-161f0b32996d
github.com/iwind/TeaGo v0.0.0-20240411075713-6c1fc9aca7b6
github.com/iwind/gofcgi v0.0.0-20210528023741-a92711d45f11
github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4
github.com/iwind/gowebp v0.0.0-20240109104518-489f3429f5c5
github.com/klauspost/compress v1.17.7
github.com/klauspost/compress v1.17.8
github.com/mattn/go-sqlite3 v1.14.17
github.com/mdlayher/netlink v1.7.1
github.com/mdlayher/netlink v1.7.2
github.com/miekg/dns v1.1.43
github.com/mssola/useragent v1.0.0
github.com/pires/go-proxyproto v0.6.1
@@ -39,10 +38,10 @@ require (
github.com/shirou/gopsutil/v3 v3.22.2
github.com/tdewolff/minify/v2 v2.20.19
github.com/tencentyun/cos-go-sdk-v5 v0.7.41
golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81
golang.org/x/image v0.13.0
golang.org/x/net v0.22.0
golang.org/x/sys v0.18.0
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f
golang.org/x/image v0.15.0
golang.org/x/net v0.24.0
golang.org/x/sys v0.19.0
google.golang.org/grpc v1.62.1
google.golang.org/protobuf v1.33.0
gopkg.in/yaml.v3 v3.0.1
@@ -54,32 +53,25 @@ require (
github.com/clbanning/mxj v1.8.4 // indirect
github.com/cockroachdb/errors v1.11.1 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/pebble v1.1.0 // indirect
github.com/cockroachdb/redact v1.1.5 // indirect
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/getsentry/sentry-go v0.27.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/glog v1.2.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/flatbuffers v24.3.7+incompatible // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-querystring v1.0.0 // indirect
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/josharian/native v1.0.0 // indirect
github.com/josharian/native v1.1.0 // indirect
github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mdlayher/socket v0.4.0 // indirect
github.com/mdlayher/socket v0.5.0 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/mozillazg/go-httpheader v0.2.1 // indirect
github.com/onsi/ginkgo/v2 v2.16.0 // indirect
@@ -95,13 +87,12 @@ require (
github.com/tklauser/go-sysconf v0.3.9 // indirect
github.com/tklauser/numcpus v0.3.0 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/mock v0.4.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/mod v0.16.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.19.0 // indirect
golang.org/x/tools v0.20.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect
)

174
go.sum
View File

@@ -1,9 +1,5 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ=
github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/QcloudApi/qcloud_sign_golang v0.0.0-20141224014652-e4130a326409/go.mod h1:1pk82RBxDY/JZnPQrtqHlUFfCctgdorsd9M06fMynOM=
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
@@ -17,16 +13,12 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/biessek/golang-ico v0.0.0-20180326222316-d348d9ea4670 h1:FQPKKjDhzG0T4ew6dm6MGrXb4PRAi8ZmTuYuxcF62BM=
github.com/biessek/golang-ico v0.0.0-20180326222316-d348d9ea4670/go.mod h1:iRWAFbKXMMkVQyxZ1PfGlkBr1TjATx1zy2MRprV7A3Q=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I=
github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4=
github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU=
github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8=
github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw=
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
@@ -41,21 +33,12 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8=
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=
github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
@@ -72,34 +55,10 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68=
github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/flatbuffers v24.3.7+incompatible h1:BxGUkIQnOciBu33bd5BdvqY8Qvo0O/GR4SPhh7x9Ed0=
github.com/google/flatbuffers v24.3.7+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/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.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
@@ -108,16 +67,17 @@ github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASu
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
github.com/google/nftables v0.2.0 h1:PbJwaBmbVLzpeldoeUKGkE2RjstrjPKMl6oLrfEJ6/8=
github.com/google/nftables v0.2.0/go.mod h1:Beg6V6zZ3oEn0JuiUQ4wqwuyqqzasOltcoXPtgLbFp4=
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 h1:y3N7Bm7Y9/CtpiVkw/ZWj6lSlDF3F74SfKwfTCer72Q=
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/huaweicloud/huaweicloud-sdk-go-obs v3.23.4+incompatible h1:XRAk4HBDLCYEdPLWtKf5iZhOi7lfx17aY0oSO9+mcg8=
github.com/huaweicloud/huaweicloud-sdk-go-obs v3.23.4+incompatible/go.mod h1:l7VUhRbTKCzdOacdT4oWCwATKyvZqUOlOqr0Ous3k4s=
github.com/iwind/TeaGo v0.0.0-20230630104525-161f0b32996d h1:XnTIj781NdSipts60fVqbgZorVAKVSRaA6nqVNfBQ1g=
github.com/iwind/TeaGo v0.0.0-20230630104525-161f0b32996d/go.mod h1:fi/Pq+/5m2HZoseM+39dMF57ANXRt6w4PkGu3NXPc5s=
github.com/iwind/TeaGo v0.0.0-20240411075713-6c1fc9aca7b6 h1:dS3pTxrLlDQxdoxSUcHkHnr3LHpsBIXv8v2/xw65RN8=
github.com/iwind/TeaGo v0.0.0-20240411075713-6c1fc9aca7b6/go.mod h1:SfqVbWyIPdVflyA6lMgicZzsoGS8pyeLiTRe8/CIpGI=
github.com/iwind/captcha v0.0.0-20231130092438-ae985686ed84 h1:/RtK8t22a/YFkBWiEwxS+JWcDmxAKsu+r+p00c36K0Q=
github.com/iwind/captcha v0.0.0-20231130092438-ae985686ed84/go.mod h1:7zoElIawLp7GUMLcj54K9kbw+jEyvz2K0FDdRRYhvWo=
github.com/iwind/fsnotify v1.5.2-0.20220817040843-193be2051ff4 h1:PKtXlgNHJhdwl5ozio7KRV3n0SckMw+8ZC2NCpRSv8U=
@@ -128,26 +88,20 @@ github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4 h1:VWGsCqTzObdlbf7UUE
github.com/iwind/gosock v0.0.0-20211103081026-ee4652210ca4/go.mod h1:H5Q7SXwbx3a97ecJkaS2sD77gspzE7HFUafBO0peEyA=
github.com/iwind/gowebp v0.0.0-20240109104518-489f3429f5c5 h1:tA0HEDQJ/FM847wc7kVpSgkTfMF1LervEmd2UZQr3Po=
github.com/iwind/gowebp v0.0.0-20240109104518-489f3429f5c5/go.mod h1:AYyXDhbbD7q9N6rJff2jrE7pGupaiyvtv3YeyIAQLXk=
github.com/iwind/nftables v0.0.0-20230419014751-9f023a644ad4 h1:RPAH9Sj9l/20zH5zU5/iJGszfwPq6eLjoiC/n/asulA=
github.com/iwind/nftables v0.0.0-20230419014751-9f023a644ad4/go.mod h1:7OLL+86wZKfBnAJxNxmdcZ0ebbgdp/A28fcagx9oJqA=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTxk=
github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e h1:LvL4XsI70QxOGHed6yhQtAU34Kx3Qq2wwBzGFKY8zKk=
github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e/go.mod h1:kLgvv7o6UM+0QSf0QjAse3wReFDsb9qbZJdfexWlrQw=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -160,23 +114,18 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/mdlayher/netlink v1.7.1 h1:FdUaT/e33HjEXagwELR8R3/KL1Fq5x3G5jgHLp/BTmg=
github.com/mdlayher/netlink v1.7.1/go.mod h1:nKO5CSjE/DJjVhk/TNp6vCE1ktVxEA8VEh8drhZzxsQ=
github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw=
github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc=
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
github.com/mdlayher/socket v0.5.0 h1:ilICZmJcQz70vrWVes1MFera4jGiWNocSkykwwoy3XI=
github.com/mdlayher/socket v0.5.0/go.mod h1:WkcBFfvyG8QENs5+hfQPl1X6Jpd2yeLIYgrGFmJiJxI=
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ=
github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60=
github.com/mssola/useragent v1.0.0 h1:WRlDpXyxHDNfvZaPEut5Biveq86Ze4o4EMffyMxmH5o=
github.com/mssola/useragent v1.0.0/go.mod h1:hz9Cqz4RXusgg1EdI4Al0INR62kP7aPSRNHnpU+b85Y=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
@@ -185,6 +134,8 @@ github.com/onsi/ginkgo/v2 v2.16.0 h1:7q1w9frJDzninhXxjZd+Y/x54XNjG/UlRLIYPZafsPM
github.com/onsi/ginkgo/v2 v2.16.0/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pires/go-proxyproto v0.6.1 h1:EBupykFmo22SDjv4fQVQd2J9NOoLPmyZA/15ldOGkPw=
github.com/pires/go-proxyproto v0.6.1/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
@@ -196,7 +147,6 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos=
github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8=
github.com/prometheus/common v0.51.0 h1:vT5R9NAlW4V6k8Wruk7ikrHaHRsrPbduM/cKTOdQM/k=
@@ -212,27 +162,18 @@ github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1
github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM=
github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/shirou/gopsutil/v3 v3.22.2 h1:wCrArWFkHYIdDxx/FSfF5RB4dpJYW6t7rcp3+zL8uks=
github.com/shirou/gopsutil/v3 v3.22.2/go.mod h1:WapW1AOOPlHyXr+yOyw3uYx36enocrtSoSBy0L5vUHY=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tdewolff/minify/v2 v2.20.19 h1:tX0SR0LUrIqGoLjXnkIzRSIbKJ7PaNnSENLD4CyH6Xo=
github.com/tdewolff/minify/v2 v2.20.19/go.mod h1:ulkFoeAVWMLEyjuDz1ZIWOA31g5aWOawCFRp9R/MudM=
github.com/tdewolff/parse/v2 v2.7.12 h1:tgavkHc2ZDEQVKy1oWxwIyh5bP4F5fEh/JmBwPP/3LQ=
@@ -255,8 +196,6 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -265,51 +204,35 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f h1:3CW0unweImhOzd5FmYuRsD4Y4oQFKZIjAnKbjV4WIrw=
golang.org/x/exp v0.0.0-20240314144324-c7f7c6466f7f/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 h1:6R2FC06FonbXQ8pK11/PDFY6N6LWlf9KlzibaCapmqc=
golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
golang.org/x/image v0.13.0 h1:3cge/F/QTkNLauhf2QoE9zp+7sr+ZcL4HnoZmdwg9sg=
golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -323,10 +246,9 @@ golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -341,44 +263,21 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk=
google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
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=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -388,7 +287,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
@@ -396,5 +294,3 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -1,9 +1,8 @@
package apps
import (
"github.com/TeaOSLab/EdgeNode/internal/goman"
"github.com/TeaOSLab/EdgeNode/internal/utils"
"github.com/TeaOSLab/EdgeNode/internal/utils/sizes"
"github.com/TeaOSLab/EdgeNode/internal/utils/goman"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/files"
timeutil "github.com/iwind/TeaGo/utils/time"
@@ -41,7 +40,7 @@ func (this *LogWriter) Init() {
this.c = make(chan string, 1024)
// 异步写入文件
var maxFileSize = 128 * sizes.M // 文件最大尺寸,超出此尺寸则清空
var maxFileSize int64 = 128 << 20 // 文件最大尺寸,超出此尺寸则清空
if fp != nil {
goman.New(func() {
var totalSize int64 = 0

View File

@@ -1,4 +1,4 @@
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
// Copyright 2023 GoEdge goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package apps

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package caches

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
package caches
@@ -6,13 +6,14 @@ import "errors"
// 常用的几个错误
var (
ErrNotFound = errors.New("cache not found")
ErrFileIsWriting = errors.New("the cache file is updating")
ErrInvalidRange = errors.New("invalid range")
ErrEntityTooLarge = errors.New("entity too large")
ErrWritingUnavailable = errors.New("writing unavailable")
ErrWritingQueueFull = errors.New("writing queue full")
ErrServerIsBusy = errors.New("server is busy")
ErrNotFound = errors.New("cache not found")
ErrFileIsWriting = errors.New("the cache file is updating")
ErrInvalidRange = errors.New("invalid range")
ErrEntityTooLarge = errors.New("entity too large")
ErrWritingUnavailable = errors.New("writing unavailable")
ErrWritingQueueFull = errors.New("writing queue full")
ErrServerIsBusy = errors.New("server is busy")
ErrUnexpectedContentLength = errors.New("unexpected content length")
)
// CapacityError 容量错误
@@ -45,3 +46,16 @@ func CanIgnoreErr(err error) bool {
var capacityErr *CapacityError
return errors.As(err, &capacityErr)
}
func IsCapacityError(err error) bool {
if err == nil {
return false
}
var capacityErr *CapacityError
return errors.As(err, &capacityErr)
}
func IsBusyError(err error) bool {
return err != nil && errors.Is(err, ErrServerIsBusy)
}

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
package caches_test

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package caches

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
package caches

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
package caches_test
@@ -7,7 +7,7 @@ import (
"github.com/TeaOSLab/EdgeNode/internal/caches"
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
"github.com/TeaOSLab/EdgeNode/internal/utils/testutils"
"github.com/TeaOSLab/EdgeNode/internal/zero"
"github.com/TeaOSLab/EdgeNode/internal/utils/zero"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
"runtime"

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package caches
@@ -7,9 +7,10 @@ import (
"fmt"
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
"github.com/TeaOSLab/EdgeNode/internal/utils"
"github.com/TeaOSLab/EdgeNode/internal/utils/dbs"
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
memutils "github.com/TeaOSLab/EdgeNode/internal/utils/mem"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/types"
"net"
@@ -64,7 +65,7 @@ func (this *SQLiteFileListDB) Open(dbPath string) error {
// 动态调整Cache值
var cacheSize = 512
var memoryGB = utils.SystemMemoryGB()
var memoryGB = memutils.SystemMemoryGB()
if memoryGB >= 1 {
cacheSize = 256 * memoryGB
}
@@ -593,9 +594,9 @@ func (this *SQLiteFileListDB) shouldRecover() bool {
// 删除数据库文件
func (this *SQLiteFileListDB) deleteDB() {
_ = os.Remove(this.dbPath)
_ = os.Remove(this.dbPath + "-shm")
_ = os.Remove(this.dbPath + "-wal")
_ = fsutils.Remove(this.dbPath)
_ = fsutils.Remove(this.dbPath + "-shm")
_ = fsutils.Remove(this.dbPath + "-wal")
}
// 加载Hash列表

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package caches_test

View File

@@ -1,10 +1,10 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package caches
import (
"github.com/TeaOSLab/EdgeNode/internal/utils"
"github.com/TeaOSLab/EdgeNode/internal/zero"
memutils "github.com/TeaOSLab/EdgeNode/internal/utils/mem"
"github.com/TeaOSLab/EdgeNode/internal/utils/zero"
"math/big"
"sync"
)
@@ -46,7 +46,7 @@ func NewSQLiteFileListHashMap() *SQLiteFileListHashMap {
func (this *SQLiteFileListHashMap) Load(db *SQLiteFileListDB) error {
// 如果系统内存过小,我们不缓存
if utils.SystemMemoryGB() < 3 {
if memutils.SystemMemoryGB() < 3 {
return nil
}

View File

@@ -1,11 +1,11 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package caches_test
import (
"github.com/TeaOSLab/EdgeNode/internal/caches"
"github.com/TeaOSLab/EdgeNode/internal/utils/testutils"
"github.com/TeaOSLab/EdgeNode/internal/zero"
"github.com/TeaOSLab/EdgeNode/internal/utils/zero"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/assert"
"github.com/iwind/TeaGo/rands"

View File

@@ -4,9 +4,12 @@ package caches
import (
"fmt"
"github.com/TeaOSLab/EdgeNode/internal/goman"
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
"github.com/TeaOSLab/EdgeNode/internal/utils/fnv"
"github.com/TeaOSLab/EdgeNode/internal/utils/goman"
memutils "github.com/TeaOSLab/EdgeNode/internal/utils/mem"
"github.com/TeaOSLab/EdgeNode/internal/utils/ttlcache"
"github.com/iwind/TeaGo/types"
"strings"
"testing"
@@ -20,19 +23,31 @@ type KVFileList struct {
onAdd func(item *Item)
onRemove func(item *Item)
memCache *ttlcache.Cache[int64]
}
func NewKVFileList(dir string) *KVFileList {
var memGB = memutils.SystemMemoryGB()
if memGB <= 0 {
memGB = 1
}
var maxCachePieces = 32
var maxCacheItems = memGB << 15
var memCache = ttlcache.NewCache[int64](ttlcache.NewPiecesOption(maxCachePieces), ttlcache.NewMaxItemsOption(maxCacheItems))
dir = strings.TrimSuffix(dir, "/")
var stores = [countKVStores]*KVListFileStore{}
for i := 0; i < countKVStores; i++ {
stores[i] = NewKVListFileStore(dir + "/db-" + types.String(i) + ".store")
stores[i] = NewKVListFileStore(dir+"/db-"+types.String(i)+".store", memCache)
}
return &KVFileList{
dir: dir,
stores: stores,
dir: dir,
stores: stores,
memCache: memCache,
}
}
@@ -59,7 +74,7 @@ func (this *KVFileList) Init() error {
// Reset 重置数据
func (this *KVFileList) Reset() error {
// do nothing
this.memCache.Clean()
return nil
}
@@ -74,16 +89,31 @@ func (this *KVFileList) Add(hash string, item *Item) error {
this.onAdd(item)
}
if item.ExpiresAt > 0 {
this.memCache.Write(hash, item.HeaderSize+item.BodySize, min(item.ExpiresAt, fasttime.Now().Unix()+3600))
}
return nil
}
// Exist 检查内容是否存在
func (this *KVFileList) Exist(hash string) (bool, error) {
func (this *KVFileList) Exist(hash string) (bool, int64, error) {
// read from cache
var cacheItem = this.memCache.Read(hash)
if cacheItem != nil {
return true, cacheItem.Value, nil
}
return this.getStore(hash).ExistItem(hash)
}
// ExistQuick 快速检查内容是否存在
func (this *KVFileList) ExistQuick(hash string) (bool, error) {
// read from cache
if this.memCache.Read(hash) != nil {
return true, nil
}
return this.getStore(hash).ExistQuickItem(hash)
}
@@ -150,6 +180,9 @@ func (this *KVFileList) Remove(hash string) error {
this.onRemove(nil)
}
// remove from cache
this.memCache.Delete(hash)
return nil
}
@@ -204,6 +237,9 @@ func (this *KVFileList) CleanAll() error {
})
}
group.Wait()
this.memCache.Clean()
return lastErr
}
@@ -287,6 +323,9 @@ func (this *KVFileList) Close() error {
})
}
group.Wait()
this.memCache.Destroy()
return lastErr
}

View File

@@ -6,6 +6,7 @@ import (
"errors"
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
"github.com/TeaOSLab/EdgeNode/internal/utils/kvstore"
"github.com/TeaOSLab/EdgeNode/internal/utils/ttlcache"
"github.com/cockroachdb/pebble"
"regexp"
"strings"
@@ -20,11 +21,14 @@ type KVListFileStore struct {
itemsTable *kvstore.Table[*Item]
rawIsReady bool
memCache *ttlcache.Cache[int64]
}
func NewKVListFileStore(path string) *KVListFileStore {
func NewKVListFileStore(path string, memCache *ttlcache.Cache[int64]) *KVListFileStore {
return &KVListFileStore{
path: path,
path: path,
memCache: memCache,
}
}
@@ -90,23 +94,30 @@ func (this *KVListFileStore) AddItem(hash string, item *Item) error {
return this.itemsTable.Set(hash, item)
}
func (this *KVListFileStore) ExistItem(hash string) (bool, error) {
func (this *KVListFileStore) ExistItem(hash string) (bool, int64, error) {
if !this.isReady() {
return false, nil
return false, -1, nil
}
item, err := this.itemsTable.Get(hash)
if err != nil {
if kvstore.IsKeyNotFound(err) {
return false, nil
if kvstore.IsNotFound(err) {
return false, -1, nil
}
return false, err
return false, -1, err
}
if item == nil {
return false, nil
return false, -1, nil
}
return item.ExpiresAt >= fasttime.NewFastTime().Unix(), nil
if item.ExpiresAt <= fasttime.Now().Unix() {
return false, 0, nil
}
// write to cache
this.memCache.Write(hash, item.HeaderSize+item.BodySize, min(item.ExpiresAt, fasttime.Now().Unix()+3600))
return true, item.HeaderSize + item.BodySize, nil
}
func (this *KVListFileStore) ExistQuickItem(hash string) (bool, error) {
@@ -168,6 +179,7 @@ func (this *KVListFileStore) PurgeItems(count int, callback func(hash string) er
if deleteErr != nil {
return deleteErr
}
this.memCache.Delete(hash)
}
return nil
})
@@ -214,6 +226,7 @@ func (this *KVListFileStore) PurgeLFUItems(count int, callback func(hash string)
if deleteErr != nil {
return deleteErr
}
this.memCache.Delete(hash)
}
return nil
})
@@ -276,6 +289,9 @@ func (this *KVListFileStore) CleanItemsWithPrefix(prefix string) error {
return false, setErr
}
// remove from cache
this.memCache.Delete(item.Key)
return true, nil
})
if err != nil {
@@ -334,6 +350,9 @@ func (this *KVListFileStore) CleanItemsWithWildcardPrefix(prefix string) error {
return false, setErr
}
// remove from cache
this.memCache.Delete(item.Key)
return true, nil
})
if err != nil {
@@ -402,6 +421,9 @@ func (this *KVListFileStore) CleanItemsWithWildcardKey(key string) error {
return false, setErr
}
// remove from cache
this.memCache.Delete(item.Key)
return true, nil
})
if err != nil {

View File

@@ -18,14 +18,6 @@ import (
var testingKVList *caches.KVFileList
func TestMain(m *testing.M) {
m.Run()
if testingKVList != nil {
_ = testingKVList.Close()
}
}
func testOpenKVFileList(t *testing.T) *caches.KVFileList {
var list = caches.NewKVFileList(Tea.Root + "/data/stores/cache-stores")
err := list.Init()
@@ -38,11 +30,18 @@ func testOpenKVFileList(t *testing.T) *caches.KVFileList {
}
func TestNewKVFileList(t *testing.T) {
_ = testOpenKVFileList(t)
var list = testOpenKVFileList(t)
err := list.Close()
if err != nil {
t.Fatal(err)
}
}
func TestKVFileList_Add(t *testing.T) {
var list = testOpenKVFileList(t)
defer func() {
_ = list.Close()
}()
err := list.Add(stringutil.Md5("123456"), &caches.Item{
Type: caches.ItemTypeFile,
@@ -67,6 +66,9 @@ func TestKVFileList_Add_Many(t *testing.T) {
}
var list = testOpenKVFileList(t)
defer func() {
_ = list.Close()
}()
const start = 0
const count = 1_000_000
@@ -89,7 +91,7 @@ func TestKVFileList_Add_Many(t *testing.T) {
err := list.Add(stringutil.Md5(strconv.Itoa(i)), &caches.Item{
Type: caches.ItemTypeFile,
Key: "https://www.example.com/index.html" + strconv.Itoa(i),
ExpiresAt: time.Now().Unix() + 60,
ExpiresAt: time.Now().Unix() + 3600,
StaleAt: 0,
HeaderSize: 0,
BodySize: int64(rand.Int() % 1_000_000),
@@ -113,6 +115,9 @@ func TestKVFileList_Add_Many_Suffix(t *testing.T) {
}
var list = testOpenKVFileList(t)
defer func() {
_ = list.Close()
}()
const start = 0
const count = 1000
@@ -155,11 +160,15 @@ func TestKVFileList_Add_Many_Suffix(t *testing.T) {
func TestKVFileList_Exist(t *testing.T) {
var list = testOpenKVFileList(t)
defer func() {
_ = list.Close()
}()
for _, hash := range []string{
stringutil.Md5("123456"),
stringutil.Md5("654321"),
} {
b, err := list.Exist(hash)
b, _, err := list.Exist(hash)
if err != nil {
t.Fatal(err)
}
@@ -167,8 +176,38 @@ func TestKVFileList_Exist(t *testing.T) {
}
}
func TestKVFileList_ExistMany(t *testing.T) {
var list = testOpenKVFileList(t)
defer func() {
_ = list.Close()
}()
var countFound int
var count = 10
if testutils.IsSingleTesting() {
count = 2_000_000
}
var before = time.Now()
for i := 0; i < count; i++ {
ok, _, err := list.Exist(stringutil.Md5(strconv.Itoa(i)))
if err != nil {
t.Fatal(err)
}
if ok {
countFound++
}
}
var costSeconds = time.Since(before).Seconds()
t.Log("total:", costSeconds*1000, "ms", "found:", countFound, "qps:", fmt.Sprintf("%.2fK/s", float64(count)/costSeconds/1000), "per read:", fmt.Sprintf("%.4fms", costSeconds*1000/float64(count)))
}
func TestKVFileList_ExistQuick(t *testing.T) {
var list = testOpenKVFileList(t)
defer func() {
_ = list.Close()
}()
for _, hash := range []string{
stringutil.Md5("123456"),
stringutil.Md5("654321"),
@@ -183,6 +222,10 @@ func TestKVFileList_ExistQuick(t *testing.T) {
func TestKVFileList_Remove(t *testing.T) {
var list = testOpenKVFileList(t)
defer func() {
_ = list.Close()
}()
for _, hash := range []string{
stringutil.Md5("123456"),
stringutil.Md5("654321"),
@@ -194,8 +237,34 @@ func TestKVFileList_Remove(t *testing.T) {
}
}
func TestKVFileList_RemoveMany(t *testing.T) {
var list = testOpenKVFileList(t)
defer func() {
_ = list.Close()
}()
var count = 10
if testutils.IsSingleTesting() {
count = 2_000_000
}
var before = time.Now()
for i := 0; i < count; i++ {
err := list.Remove(stringutil.Md5(strconv.Itoa(i)))
if err != nil {
t.Fatal(err)
}
}
var costSeconds = time.Since(before).Seconds()
t.Log("total:", costSeconds*1000, "ms", "qps:", fmt.Sprintf("%.2fK/s", float64(count)/costSeconds/1000), "per delete:", fmt.Sprintf("%.4fms", costSeconds*1000/float64(count)))
}
func TestKVFileList_CleanAll(t *testing.T) {
var list = testOpenKVFileList(t)
defer func() {
_ = list.Close()
}()
err := list.CleanAll()
if err != nil {
t.Fatal(err)
@@ -208,6 +277,10 @@ func TestKVFileList_Inspect(t *testing.T) {
}
var list = testOpenKVFileList(t)
defer func() {
_ = list.Close()
}()
err := list.TestInspect(t)
if err != nil {
t.Fatal(err)
@@ -216,6 +289,10 @@ func TestKVFileList_Inspect(t *testing.T) {
func TestKVFileList_Purge(t *testing.T) {
var list = testOpenKVFileList(t)
defer func() {
_ = list.Close()
}()
var before = time.Now()
count, err := list.Purge(4_000, func(hash string) error {
//t.Log("hash:", hash)
@@ -229,6 +306,10 @@ func TestKVFileList_Purge(t *testing.T) {
func TestKVFileList_PurgeLFU(t *testing.T) {
var list = testOpenKVFileList(t)
defer func() {
_ = list.Close()
}()
var before = time.Now()
err := list.PurgeLFU(20000, func(hash string) error {
t.Log("hash:", hash)
@@ -242,6 +323,10 @@ func TestKVFileList_PurgeLFU(t *testing.T) {
func TestKVFileList_Count(t *testing.T) {
var list = testOpenKVFileList(t)
defer func() {
_ = list.Close()
}()
var before = time.Now()
count, err := list.Count()
if err != nil {
@@ -252,6 +337,10 @@ func TestKVFileList_Count(t *testing.T) {
func TestKVFileList_Stat(t *testing.T) {
var list = testOpenKVFileList(t)
defer func() {
_ = list.Close()
}()
var before = time.Now()
stat, err := list.Stat(func(hash string) bool {
return true
@@ -264,6 +353,10 @@ func TestKVFileList_Stat(t *testing.T) {
func TestKVFileList_CleanPrefix(t *testing.T) {
var list = testOpenKVFileList(t)
defer func() {
_ = list.Close()
}()
var before = time.Now()
defer func() {
@@ -279,6 +372,10 @@ func TestKVFileList_CleanPrefix(t *testing.T) {
func TestKVFileList_CleanMatchPrefix(t *testing.T) {
var list = testOpenKVFileList(t)
defer func() {
_ = list.Close()
}()
var before = time.Now()
defer func() {
@@ -294,6 +391,10 @@ func TestKVFileList_CleanMatchPrefix(t *testing.T) {
func TestKVFileList_CleanMatchKey(t *testing.T) {
var list = testOpenKVFileList(t)
defer func() {
_ = list.Close()
}()
var before = time.Now()
defer func() {
@@ -322,7 +423,7 @@ func BenchmarkKVFileList_Exist(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, existErr := list.Exist(stringutil.Md5(strconv.Itoa(rand.Int() % 2_000_000)))
_, _, existErr := list.Exist(stringutil.Md5(strconv.Itoa(rand.Int() % 2_000_000)))
if existErr != nil {
b.Fatal(existErr)
}

View File

@@ -1,17 +1,18 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
package caches
import (
"database/sql"
"errors"
"github.com/TeaOSLab/EdgeNode/internal/goman"
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
"github.com/TeaOSLab/EdgeNode/internal/ttlcache"
"github.com/TeaOSLab/EdgeNode/internal/utils/dbs"
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
"github.com/TeaOSLab/EdgeNode/internal/utils/fnv"
"github.com/TeaOSLab/EdgeNode/internal/zero"
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
"github.com/TeaOSLab/EdgeNode/internal/utils/goman"
"github.com/TeaOSLab/EdgeNode/internal/utils/ttlcache"
"github.com/TeaOSLab/EdgeNode/internal/utils/zero"
"github.com/iwind/TeaGo/types"
"os"
"strings"
@@ -130,26 +131,26 @@ func (this *SQLiteFileList) Add(hash string, item *Item) error {
return nil
}
func (this *SQLiteFileList) Exist(hash string) (bool, error) {
func (this *SQLiteFileList) Exist(hash string) (bool, int64, error) {
var db = this.GetDB(hash)
if !db.IsReady() {
return false, nil
return false, -1, nil
}
// 如果Hash列表里不存在那么必然不存在
if !db.hashMap.Exist(hash) {
return false, nil
return false, -1, nil
}
var item = this.memoryCache.Read(hash)
if item != nil {
return true, nil
return true, -1, nil
}
var row = db.existsByHashStmt.QueryRow(hash, time.Now().Unix())
if row.Err() != nil {
return false, nil
return false, -1, nil
}
var expiredAt int64
@@ -158,15 +159,15 @@ func (this *SQLiteFileList) Exist(hash string) (bool, error) {
if errors.Is(err, sql.ErrNoRows) {
err = nil
}
return false, err
return false, -1, err
}
if expiredAt < fasttime.Now().Unix() {
return false, nil
if expiredAt <= fasttime.Now().Unix() {
return false, -1, nil
}
this.memoryCache.Write(hash, zero.Zero{}, this.maxExpiresAtForMemoryCache(expiredAt))
return true, nil
return true, -1, nil
}
func (this *SQLiteFileList) ExistQuick(hash string) (isReady bool, found bool) {
@@ -486,7 +487,7 @@ func (this *SQLiteFileList) UpgradeV3(oldDir string, brokenOnError bool) error {
remotelogs.Println("CACHE", "upgrading local database from '"+oldDir+"' ...")
defer func() {
_ = os.Remove(indexDBPath)
_ = fsutils.Remove(indexDBPath)
remotelogs.Println("CACHE", "upgrading local database finished")
}()

View File

@@ -1,10 +1,10 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
package caches_test
import (
"github.com/TeaOSLab/EdgeNode/internal/caches"
"github.com/TeaOSLab/EdgeNode/internal/goman"
"github.com/TeaOSLab/EdgeNode/internal/utils/goman"
"github.com/TeaOSLab/EdgeNode/internal/utils/testutils"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/rands"
@@ -140,7 +140,7 @@ func TestFileList_Exist(t *testing.T) {
}()
{
var hash = stringutil.Md5("123456")
exists, err := list.Exist(hash)
exists, _, err := list.Exist(hash)
if err != nil {
t.Fatal(err)
}
@@ -148,7 +148,7 @@ func TestFileList_Exist(t *testing.T) {
}
{
var hash = stringutil.Md5("http://edge.teaos.cn/1234561")
exists, err := list.Exist(hash)
exists, _, err := list.Exist(hash)
if err != nil {
t.Fatal(err)
}
@@ -208,7 +208,7 @@ func TestFileList_Exist_Many_DB(t *testing.T) {
countLocker.Unlock()
var list = listSlice[rands.Int(0, len(listSlice)-1)]
_, _ = list.Exist(hash)
_, _, _ = list.Exist(hash)
default:
return
}
@@ -442,6 +442,6 @@ func BenchmarkFileList_Exist(b *testing.B) {
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = list.Exist("f0eb5b87e0b0041f3917002c0707475f" + types.String(i))
_, _, _ = list.Exist("f0eb5b87e0b0041f3917002c0707475f" + types.String(i))
}
}

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
package caches
@@ -13,7 +13,7 @@ type ListInterface interface {
Add(hash string, item *Item) error
// Exist 检查内容是否存在
Exist(hash string) (bool, error)
Exist(hash string) (ok bool, size int64, err error)
// CleanPrefix 清除某个前缀的缓存
CleanPrefix(prefix string) error

View File

@@ -89,21 +89,21 @@ func (this *MemoryList) Add(hash string, item *Item) error {
return nil
}
func (this *MemoryList) Exist(hash string) (bool, error) {
func (this *MemoryList) Exist(hash string) (bool, int64, error) {
this.locker.RLock()
defer this.locker.RUnlock()
prefix := this.prefix(hash)
itemMap, ok := this.itemMaps[prefix]
if !ok {
return false, nil
return false, -1, nil
}
item, ok := itemMap[hash]
if !ok {
return false, nil
return false, -1, nil
}
return !item.IsExpired(), nil
return !item.IsExpired(), -1, nil
}
// CleanPrefix 根据前缀进行清除

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"github.com/TeaOSLab/EdgeNode/internal/caches"
"github.com/TeaOSLab/EdgeNode/internal/utils/testutils"
"github.com/cespare/xxhash"
"github.com/cespare/xxhash/v2"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
@@ -317,7 +317,7 @@ func BenchmarkMemoryList(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_, _ = list.Exist(types.String("a" + types.String(rands.Int(1, 10000))))
_, _, _ = list.Exist(types.String("a" + types.String(rands.Int(1, 10000))))
_ = list.Add("a"+types.String(rands.Int(1, 100000)), &caches.Item{})
_, _ = list.Purge(1000, func(hash string) error {
return nil

View File

@@ -7,7 +7,7 @@ import (
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
"github.com/TeaOSLab/EdgeNode/internal/events"
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
"github.com/TeaOSLab/EdgeNode/internal/utils"
memutils "github.com/TeaOSLab/EdgeNode/internal/utils/mem"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/types"
"golang.org/x/sys/unix"
@@ -149,7 +149,7 @@ func (this *Manager) UpdatePolicies(newPolicies []*serverconfigs.HTTPCachePolicy
}
this.CountFileStorages = 0
this.CountFileStorages = 0
this.CountMemoryStorages = 0
for _, storage := range this.storageMap {
_, isFileStorage := storage.(*FileStorage)
this.CountMemoryStorages++
@@ -299,7 +299,7 @@ func (this *Manager) MaxSystemMemoryBytesPerStorage() int64 {
count = 1
}
var resultBytes = int64(utils.SystemMemoryBytes()) / 3 / int64(count) // 1/3 of the system memory
var resultBytes = int64(memutils.SystemMemoryBytes()) / 3 / int64(count) // 1/3 of the system memory
if resultBytes < 1<<30 {
resultBytes = 1 << 30
}

View File

@@ -1,375 +0,0 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package caches
import (
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
"github.com/TeaOSLab/EdgeNode/internal/goman"
"github.com/TeaOSLab/EdgeNode/internal/utils"
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
"github.com/iwind/TeaGo/logs"
"os"
"sync"
"sync/atomic"
"time"
)
const (
enableFragmentPool = false
minMemoryFragmentPoolItemSize = 8 << 10
maxMemoryFragmentPoolItemSize = 128 << 20
maxItemsInMemoryFragmentPoolBucket = 1024
memoryFragmentPoolBucketSegmentSize = 512 << 10
maxMemoryFragmentPoolItemAgeSeconds = 60
)
var SharedFragmentMemoryPool *MemoryFragmentPool
func init() {
if !teaconst.IsMain {
return
}
SharedFragmentMemoryPool = NewMemoryFragmentPool()
goman.New(func() {
var ticker = time.NewTicker(200 * time.Millisecond)
for range ticker.C {
for i := 0; i < 10; i++ { // skip N empty buckets
var isEmpty = SharedFragmentMemoryPool.GCNextBucket()
if !isEmpty {
break
}
}
}
})
}
type MemoryFragmentPoolItem struct {
Bytes []byte
size int64
createdAt int64
Refs int32
}
func (this *MemoryFragmentPoolItem) IsExpired() bool {
return this.createdAt < fasttime.Now().Unix()-maxMemoryFragmentPoolItemAgeSeconds
}
func (this *MemoryFragmentPoolItem) Reset() {
this.Bytes = nil
}
func (this *MemoryFragmentPoolItem) IsAvailable() bool {
return atomic.AddInt32(&this.Refs, 1) == 1
}
// MemoryFragmentPool memory fragments management
type MemoryFragmentPool struct {
bucketMaps []map[uint64]*MemoryFragmentPoolItem // [ { id => Zero }, ... ]
countBuckets int
gcBucketIndex int
mu sync.RWMutex
id uint64
totalMemory int64
isOk bool
capacity int64
debugMode bool
countGet uint64
countNew uint64
}
// NewMemoryFragmentPool create new fragment memory pool
func NewMemoryFragmentPool() *MemoryFragmentPool {
var pool = &MemoryFragmentPool{}
pool.init()
return pool
}
func (this *MemoryFragmentPool) init() {
var capacity = int64(utils.SystemMemoryGB()) << 30 / 16
if capacity > 256<<20 {
this.isOk = true
this.capacity = capacity
this.bucketMaps = []map[uint64]*MemoryFragmentPoolItem{}
for i := 0; i < maxMemoryFragmentPoolItemSize/memoryFragmentPoolBucketSegmentSize+1; i++ {
this.bucketMaps = append(this.bucketMaps, map[uint64]*MemoryFragmentPoolItem{})
}
this.countBuckets = len(this.bucketMaps)
}
// print statistics for debug
if len(os.Getenv("GOEDGE_DEBUG_MEMORY_FRAGMENT_POOL")) > 0 {
this.debugMode = true
go func() {
var maxRounds = 10_000
var ticker = time.NewTicker(10 * time.Second)
for range ticker.C {
logs.Println("reused:", this.countGet, "created:", this.countNew, "fragments:", this.Len(), "memory:", this.totalMemory>>20, "MB")
maxRounds--
if maxRounds <= 0 {
break
}
}
}()
}
}
// Get try to get a bytes object
func (this *MemoryFragmentPool) Get(expectSize int64) (resultBytes []byte, ok bool) {
if !this.isOk {
return
}
if expectSize <= 0 {
return
}
// DO NOT check min segment size
this.mu.RLock()
var bucketIndex = this.bucketIndexForSize(expectSize)
var resultItemId uint64
const maxSearchingBuckets = 20
for i := bucketIndex; i <= bucketIndex+maxSearchingBuckets; i++ {
resultBytes, resultItemId, ok = this.findItemInMap(this.bucketMaps[i], expectSize)
if ok {
this.mu.RUnlock()
// remove from bucket
this.mu.Lock()
delete(this.bucketMaps[i], resultItemId)
this.mu.Unlock()
return
}
if i >= this.countBuckets {
break
}
}
this.mu.RUnlock()
return
}
// Put a bytes object to specified bucket
func (this *MemoryFragmentPool) Put(data []byte) (ok bool) {
if !this.isOk {
return
}
var l = int64(cap(data)) // MUST be 'cap' instead of 'len'
if l < minMemoryFragmentPoolItemSize || l > maxMemoryFragmentPoolItemSize {
return
}
if atomic.LoadInt64(&this.totalMemory) >= this.capacity {
return
}
var itemId = atomic.AddUint64(&this.id, 1)
this.mu.Lock()
defer this.mu.Unlock()
var bucketMap = this.bucketMaps[this.bucketIndexForSize(l)]
if len(bucketMap) >= maxItemsInMemoryFragmentPoolBucket {
return
}
atomic.AddInt64(&this.totalMemory, l)
bucketMap[itemId] = &MemoryFragmentPoolItem{
Bytes: data,
size: l,
createdAt: fasttime.Now().Unix(),
}
return true
}
// GC fully GC
func (this *MemoryFragmentPool) GC() {
if !this.isOk {
return
}
var totalMemory = atomic.LoadInt64(&this.totalMemory)
if totalMemory < this.capacity {
return
}
this.mu.Lock()
defer this.mu.Unlock()
var garbageSize = totalMemory * 1 / 10 // 10%
// remove expired
for _, bucketMap := range this.bucketMaps {
for itemId, item := range bucketMap {
if item.IsExpired() {
delete(bucketMap, itemId)
item.Reset()
atomic.AddInt64(&this.totalMemory, -item.size)
garbageSize -= item.size
}
}
}
// remove others
if garbageSize > 0 {
for _, bucketMap := range this.bucketMaps {
for itemId, item := range bucketMap {
delete(bucketMap, itemId)
item.Reset()
atomic.AddInt64(&this.totalMemory, -item.size)
garbageSize -= item.size
if garbageSize <= 0 {
break
}
}
}
}
}
// GCNextBucket gc one bucket
func (this *MemoryFragmentPool) GCNextBucket() (isEmpty bool) {
if !this.isOk {
return
}
var itemIds = []uint64{}
// find
this.mu.RLock()
var bucketIndex = this.gcBucketIndex
var bucketMap = this.bucketMaps[bucketIndex]
isEmpty = len(bucketMap) == 0
if isEmpty {
this.mu.RUnlock()
// move to next bucket index
bucketIndex++
if bucketIndex >= this.countBuckets {
bucketIndex = 0
}
this.gcBucketIndex = bucketIndex
return
}
for itemId, item := range bucketMap {
if item.IsExpired() {
itemIds = append(itemIds, itemId)
}
}
this.mu.RUnlock()
// remove
if len(itemIds) > 0 {
this.mu.Lock()
for _, itemId := range itemIds {
item, ok := bucketMap[itemId]
if !ok {
continue
}
if !item.IsAvailable() {
continue
}
delete(bucketMap, itemId)
item.Reset()
atomic.AddInt64(&this.totalMemory, -item.size)
}
this.mu.Unlock()
}
// move to next bucket index
bucketIndex++
if bucketIndex >= this.countBuckets {
bucketIndex = 0
}
this.gcBucketIndex = bucketIndex
return
}
func (this *MemoryFragmentPool) SetCapacity(capacity int64) {
this.capacity = capacity
}
func (this *MemoryFragmentPool) TotalSize() int64 {
return atomic.LoadInt64(&this.totalMemory)
}
func (this *MemoryFragmentPool) Len() int {
this.mu.Lock()
defer this.mu.Unlock()
var count = 0
for _, bucketMap := range this.bucketMaps {
count += len(bucketMap)
}
return count
}
func (this *MemoryFragmentPool) IncreaseNew() {
if this.isOk && this.debugMode {
atomic.AddUint64(&this.countNew, 1)
}
}
func (this *MemoryFragmentPool) bucketIndexForSize(size int64) int {
return int(size / memoryFragmentPoolBucketSegmentSize)
}
func (this *MemoryFragmentPool) findItemInMap(bucketMap map[uint64]*MemoryFragmentPoolItem, expectSize int64) (resultBytes []byte, resultItemId uint64, ok bool) {
if len(bucketMap) == 0 {
return
}
for itemId, item := range bucketMap {
if item.size >= expectSize {
// check if is referred
if !item.IsAvailable() {
continue
}
// return result
if item.size != expectSize {
resultBytes = item.Bytes[:expectSize]
} else {
resultBytes = item.Bytes
}
// reset old item
item.Reset()
atomic.AddInt64(&this.totalMemory, -item.size)
resultItemId = itemId
if this.debugMode {
atomic.AddUint64(&this.countGet, 1)
}
ok = true
return
}
}
return
}

View File

@@ -1,313 +0,0 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package caches_test
import (
"bytes"
"github.com/TeaOSLab/EdgeNode/internal/caches"
"github.com/TeaOSLab/EdgeNode/internal/utils/testutils"
"github.com/iwind/TeaGo/assert"
"github.com/iwind/TeaGo/rands"
timeutil "github.com/iwind/TeaGo/utils/time"
"runtime"
"sync"
"sync/atomic"
"testing"
"time"
)
func TestNewMemoryFragmentPool(t *testing.T) {
var a = assert.NewAssertion(t)
var pool = caches.NewMemoryFragmentPool()
for i := 0; i < 3000; i++ {
ok := pool.Put(make([]byte, 2<<20))
if !ok {
t.Log("finished at", i)
break
}
}
t.Log(pool.TotalSize()>>20, "MB", pool.Len(), "items")
{
r, ok := pool.Get(1 << 20)
a.IsTrue(ok)
a.IsTrue(len(r) == 1<<20)
}
{
r, ok := pool.Get(2 << 20)
a.IsTrue(ok)
a.IsTrue(len(r) == 2<<20)
}
{
r, ok := pool.Get(4 << 20)
a.IsFalse(ok)
a.IsTrue(len(r) == 0)
}
t.Log(pool.TotalSize()>>20, "MB", pool.Len(), "items")
}
func TestNewMemoryFragmentPool_LargeBucket(t *testing.T) {
var a = assert.NewAssertion(t)
var pool = caches.NewMemoryFragmentPool()
{
pool.Put(make([]byte, 128<<20+1))
a.IsTrue(pool.Len() == 0)
}
{
pool.Put(make([]byte, 128<<20))
a.IsTrue(pool.Len() == 1)
pool.Get(118 << 20)
a.IsTrue(pool.Len() == 0)
}
{
pool.Put(make([]byte, 128<<20))
a.IsTrue(pool.Len() == 1)
pool.Get(110 << 20)
a.IsTrue(pool.Len() == 1)
}
}
func TestMemoryFragmentPool_Get_Exactly(t *testing.T) {
var a = assert.NewAssertion(t)
var pool = caches.NewMemoryFragmentPool()
{
pool.Put(make([]byte, 129<<20))
a.IsTrue(pool.Len() == 0)
}
{
pool.Put(make([]byte, 4<<20))
a.IsTrue(pool.Len() == 1)
}
{
pool.Get(4 << 20)
a.IsTrue(pool.Len() == 0)
}
}
func TestMemoryFragmentPool_Get_Round(t *testing.T) {
var a = assert.NewAssertion(t)
var pool = caches.NewMemoryFragmentPool()
{
pool.Put(make([]byte, 8<<20))
pool.Put(make([]byte, 8<<20))
pool.Put(make([]byte, 8<<20))
a.IsTrue(pool.Len() == 3)
}
{
resultBytes, ok := pool.Get(3 << 20)
a.IsTrue(pool.Len() == 2)
if ok {
pool.Put(resultBytes)
}
}
{
pool.Get(2 << 20)
a.IsTrue(pool.Len() == 2)
}
{
pool.Get(1 << 20)
a.IsTrue(pool.Len() == 1)
}
}
func TestMemoryFragmentPool_GC(t *testing.T) {
var pool = caches.NewMemoryFragmentPool()
pool.SetCapacity(32 << 20)
for i := 0; i < 16; i++ {
pool.Put(make([]byte, 4<<20))
}
var before = time.Now()
pool.GC()
t.Log(time.Since(before).Seconds()*1000, "ms")
t.Log(pool.Len())
}
func TestMemoryFragmentPool_Memory(t *testing.T) {
if !testutils.IsSingleTesting() {
return
}
var pool = caches.NewMemoryFragmentPool()
testutils.StartMemoryStats(t, func() {
t.Log(pool.Len(), "items")
})
var sampleData = bytes.Repeat([]byte{'A'}, 16<<20)
var countNew = 0
for i := 0; i < 1000; i++ {
cacheData, ok := pool.Get(16 << 20)
if ok {
copy(cacheData, sampleData)
pool.Put(cacheData)
} else {
countNew++
var data = make([]byte, 16<<20)
copy(data, sampleData)
pool.Put(data)
}
}
t.Log("count new:", countNew)
t.Log("count remains:", pool.Len())
time.Sleep(10 * time.Minute)
}
func TestMemoryFragmentPool_GCNextBucket(t *testing.T) {
if !testutils.IsSingleTesting() {
return
}
var pool = caches.NewMemoryFragmentPool()
for i := 0; i < 1000; i++ {
pool.Put(make([]byte, rands.Int(0, 100)<<20))
}
var lastLen int
for {
pool.GCNextBucket()
var currentLen = pool.Len()
if lastLen == currentLen {
continue
}
lastLen = currentLen
t.Log(currentLen, "items", pool.TotalSize(), "bytes", timeutil.Format("H:i:s"))
time.Sleep(100 * time.Millisecond)
if currentLen == 0 {
break
}
}
}
func TestMemoryFragmentPoolItem(t *testing.T) {
var a = assert.NewAssertion(t)
var m = map[int]*caches.MemoryFragmentPoolItem{}
m[1] = &caches.MemoryFragmentPoolItem{
Refs: 0,
}
var item = m[1]
a.IsTrue(item.Refs == 0)
a.IsTrue(atomic.AddInt32(&item.Refs, 1) == 1)
for _, item2 := range m {
t.Log(item2)
a.IsTrue(atomic.AddInt32(&item2.Refs, 1) == 2)
}
t.Log(m)
}
func BenchmarkMemoryFragmentPool_Get_HIT(b *testing.B) {
runtime.GOMAXPROCS(4)
var pool = caches.NewMemoryFragmentPool()
for i := 0; i < 3000; i++ {
ok := pool.Put(make([]byte, 2<<20))
if !ok {
break
}
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
data, ok := pool.Get(2 << 20)
if ok {
pool.Put(data)
}
}
})
}
func BenchmarkMemoryFragmentPool_Get_TOTALLY_MISSING(b *testing.B) {
runtime.GOMAXPROCS(4)
var pool = caches.NewMemoryFragmentPool()
for i := 0; i < 3000; i++ {
ok := pool.Put(make([]byte, 2<<20+100))
if !ok {
break
}
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
data, ok := pool.Get(2<<20 + 200)
if ok {
pool.Put(data)
}
}
})
}
func BenchmarkMemoryPool_Get_HIT_MISSING(b *testing.B) {
runtime.GOMAXPROCS(4)
var pool = caches.NewMemoryFragmentPool()
for i := 0; i < 3000; i++ {
ok := pool.Put(make([]byte, rands.Int(2, 32)<<20))
if !ok {
break
}
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
data, ok := pool.Get(4 << 20)
if ok {
pool.Put(data)
}
}
})
}
func BenchmarkMemoryFragmentPool_GC(b *testing.B) {
runtime.GOMAXPROCS(4)
var pool = caches.NewMemoryFragmentPool()
pool.SetCapacity(1 << 30)
for i := 0; i < 2_000; i++ {
pool.Put(make([]byte, 1<<20))
}
var mu = sync.Mutex{}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
mu.Lock()
for i := 0; i < 100; i++ {
pool.GCNextBucket()
}
mu.Unlock()
}
})
}

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package caches

View File

@@ -1,12 +1,12 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package caches
import (
"fmt"
"github.com/TeaOSLab/EdgeNode/internal/goman"
"github.com/TeaOSLab/EdgeNode/internal/utils"
"github.com/TeaOSLab/EdgeNode/internal/utils/goman"
"github.com/TeaOSLab/EdgeNode/internal/utils/linkedlist"
memutils "github.com/TeaOSLab/EdgeNode/internal/utils/mem"
"github.com/fsnotify/fsnotify"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/types"
@@ -38,12 +38,15 @@ func NewOpenFileCache(maxCount int) (*OpenFileCache, error) {
if maxCount <= 0 {
maxCount = 16384
}
if maxCount > 65535 {
maxCount = 65535
}
var cache = &OpenFileCache{
maxCount: maxCount,
poolMap: map[string]*OpenFilePool{},
poolList: linkedlist.NewList[*OpenFilePool](),
capacitySize: (int64(utils.SystemMemoryGB()) << 30) / 16,
capacitySize: (int64(memutils.SystemMemoryGB()) << 30) / 16,
}
watcher, err := fsnotify.NewWatcher()
@@ -64,6 +67,8 @@ func NewOpenFileCache(maxCount int) (*OpenFileCache, error) {
}
func (this *OpenFileCache) Get(filename string) *OpenFile {
filename = filepath.Clean(filename)
this.locker.RLock()
pool, ok := this.poolMap[filename]
this.locker.RUnlock()
@@ -85,6 +90,8 @@ func (this *OpenFileCache) Get(filename string) *OpenFile {
}
func (this *OpenFileCache) Put(filename string, file *OpenFile) {
filename = filepath.Clean(filename)
if file.size > maxOpenFileSize {
return
}
@@ -119,6 +126,8 @@ func (this *OpenFileCache) Put(filename string, file *OpenFile) {
}
func (this *OpenFileCache) Close(filename string) {
filename = filepath.Clean(filename)
this.locker.Lock()
pool, ok := this.poolMap[filename]

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package caches_test

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package caches

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package caches_test

View File

@@ -1,27 +1,28 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package caches
import (
"bytes"
"encoding/json"
rangeutils "github.com/TeaOSLab/EdgeNode/internal/utils/ranges"
"github.com/iwind/TeaGo/types"
"os"
"strconv"
)
// PartialRanges 内容分区范围定义
type PartialRanges struct {
Version int `json:"version"` // 版本号
Ranges [][2]int64 `json:"ranges"` // 范围
BodySize int64 `json:"bodySize"` // 总长度
Version int `json:"version"` // 版本号
Ranges [][2]int64 `json:"ranges"` // 范围
BodySize int64 `json:"bodySize"` // 总长度
ContentMD5 string `json:"contentMD5"` // 内容md5
}
// NewPartialRanges 获取新对象
func NewPartialRanges(expiresAt int64) *PartialRanges {
return &PartialRanges{
Ranges: [][2]int64{},
Version: 1,
Version: 2,
}
}
@@ -46,6 +47,8 @@ func NewPartialRangesFromData(data []byte) (*PartialRanges, error) {
if commaIndex > 0 {
rs.Ranges = append(rs.Ranges, [2]int64{types.Int64(line[colonIndex+1 : commaIndex]), types.Int64(line[commaIndex+1:])})
}
case "m": // Content-MD5
rs.ContentMD5 = string(line[colonIndex+1:])
}
}
data = data[index+1:]
@@ -70,7 +73,7 @@ func NewPartialRangesFromJSON(data []byte) (*PartialRanges, error) {
// NewPartialRangesFromFile 从文件中加载范围信息
func NewPartialRangesFromFile(path string) (*PartialRanges, error) {
data, err := os.ReadFile(path)
data, err := SharedPartialRangesQueue.Get(path)
if err != nil {
return nil, err
}
@@ -102,7 +105,6 @@ func (this *PartialRanges) Add(begin int64, end int64) {
}
// insert
// TODO 将来使用二分法改进
var index = -1
for i, r := range this.Ranges {
if r[0] > begin || (r[0] == begin && r[1] >= end) {
@@ -128,7 +130,6 @@ func (this *PartialRanges) Contains(begin int64, end int64) bool {
return false
}
// TODO 使用二分法查找改进性能
for _, r2 := range this.Ranges {
if r2[0] <= begin && r2[1] >= end {
return true
@@ -144,7 +145,6 @@ func (this *PartialRanges) Nearest(begin int64, end int64) (r [2]int64, ok bool)
return
}
// TODO 使用二分法查找改进性能
for _, r2 := range this.Ranges {
if r2[0] <= begin && r2[1] > begin {
r = [2]int64{begin, this.min(end, r2[1])}
@@ -155,10 +155,28 @@ func (this *PartialRanges) Nearest(begin int64, end int64) (r [2]int64, ok bool)
return
}
// FindRangeAtPosition 查找在某个位置上的范围
func (this *PartialRanges) FindRangeAtPosition(position int64) (r rangeutils.Range, ok bool) {
if len(this.Ranges) == 0 || position < 0 {
return
}
for _, r2 := range this.Ranges {
if r2[0] <= position && r2[1] > position {
return [2]int64{position, r2[1]}, true
}
}
return
}
// 转换为字符串
func (this *PartialRanges) String() string {
var s = "v:" + strconv.Itoa(this.Version) + "\n" + // version
"b:" + this.formatInt64(this.BodySize) + "\n" // bodySize
if len(this.ContentMD5) > 0 {
s += "m:" + this.ContentMD5 + "\n" // Content-MD5
}
for _, r := range this.Ranges {
s += "r:" + this.formatInt64(r[0]) + "," + this.formatInt64(r[1]) + "\n" // range
}
@@ -172,7 +190,8 @@ func (this *PartialRanges) Bytes() []byte {
// WriteToFile 写入到文件中
func (this *PartialRanges) WriteToFile(path string) error {
return os.WriteFile(path, this.Bytes(), 0666)
SharedPartialRangesQueue.Put(path, this.Bytes())
return nil
}
// Max 获取最大位置
@@ -188,6 +207,11 @@ func (this *PartialRanges) Reset() {
this.Ranges = [][2]int64{}
}
// IsCompleted 是否已下载完整
func (this *PartialRanges) IsCompleted() bool {
return len(this.Ranges) == 1 && this.Ranges[0][0] == 0 && this.Ranges[0][1] == this.BodySize-1
}
func (this *PartialRanges) merge(index int) {
// forward
var lastIndex = index

View File

@@ -0,0 +1,144 @@
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package caches
import (
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
"github.com/TeaOSLab/EdgeNode/internal/utils/fnv"
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
"github.com/TeaOSLab/EdgeNode/internal/utils/goman"
memutils "github.com/TeaOSLab/EdgeNode/internal/utils/mem"
"sync"
)
var SharedPartialRangesQueue = NewPartialRangesQueue()
func init() {
if !teaconst.IsMain {
return
}
SharedPartialRangesQueue.Start()
}
const partialRangesQueueSharding = 8
// PartialRangesQueue ranges file writing queue
type PartialRangesQueue struct {
m [partialRangesQueueSharding]map[string][]byte // { filename => data, ... }
c chan string // filename1, ...
mu [partialRangesQueueSharding]*sync.RWMutex
}
// NewPartialRangesQueue Create new queue
func NewPartialRangesQueue() *PartialRangesQueue {
var queueSize = 512
var memGB = memutils.SystemMemoryGB()
if memGB > 16 {
queueSize = 8 << 10
} else if memGB > 8 {
queueSize = 4 << 10
} else if memGB > 4 {
queueSize = 2 << 10
} else if memGB > 2 {
queueSize = 1 << 10
}
var m = [partialRangesQueueSharding]map[string][]byte{}
var muList = [partialRangesQueueSharding]*sync.RWMutex{}
for i := 0; i < partialRangesQueueSharding; i++ {
muList[i] = &sync.RWMutex{}
m[i] = map[string][]byte{}
}
return &PartialRangesQueue{
mu: muList,
m: m,
c: make(chan string, queueSize),
}
}
// Start the queue
func (this *PartialRangesQueue) Start() {
goman.New(func() {
this.Dump()
})
}
// Put ranges data to filename
func (this *PartialRangesQueue) Put(filename string, data []byte) {
var index = this.indexForKey(filename)
this.mu[index].Lock()
this.m[index][filename] = data
this.mu[index].Unlock()
// always wait to finish
this.c <- filename
}
// Get ranges data from filename
func (this *PartialRangesQueue) Get(filename string) ([]byte, error) {
var index = this.indexForKey(filename)
this.mu[index].RLock()
data, ok := this.m[index][filename]
this.mu[index].RUnlock()
if ok {
return data, nil
}
return fsutils.ReadFile(filename)
}
// Delete ranges filename
func (this *PartialRangesQueue) Delete(filename string) {
var index = this.indexForKey(filename)
this.mu[index].Lock()
delete(this.m[index], filename)
this.mu[index].Unlock()
}
// Dump ranges to filename from memory
func (this *PartialRangesQueue) Dump() {
for filename := range this.c {
var index = this.indexForKey(filename)
this.mu[index].Lock()
data, ok := this.m[index][filename]
if ok {
delete(this.m[index], filename)
}
this.mu[index].Unlock()
if !ok || len(data) == 0 {
continue
}
err := fsutils.WriteFile(filename, data, 0666)
if err != nil {
remotelogs.Println("PARTIAL_RANGES_QUEUE", "write file '"+filename+"' failed: "+err.Error())
}
}
}
// Len count all files
func (this *PartialRangesQueue) Len() int {
var count int
for i := 0; i < partialRangesQueueSharding; i++ {
this.mu[i].RLock()
count += len(this.m[i])
this.mu[i].RUnlock()
}
return count
}
func (this *PartialRangesQueue) indexForKey(filename string) int {
return int(fnv.HashString(filename) % partialRangesQueueSharding)
}

View File

@@ -0,0 +1,31 @@
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package caches_test
import (
"github.com/TeaOSLab/EdgeNode/internal/caches"
"github.com/iwind/TeaGo/assert"
"testing"
)
func TestNewPartialRangesQueue(t *testing.T) {
var a = assert.NewAssertion(t)
var queue = caches.NewPartialRangesQueue()
queue.Put("a", []byte{1, 2, 3})
t.Log("add 'a':", queue.Len())
t.Log(queue.Get("a"))
a.IsTrue(queue.Len() == 1)
queue.Put("a", nil)
t.Log("add 'a':", queue.Len())
a.IsTrue(queue.Len() == 1)
queue.Put("b", nil)
t.Log("add 'b':", queue.Len())
a.IsTrue(queue.Len() == 2)
queue.Delete("a")
t.Log("delete 'a':", queue.Len())
a.IsTrue(queue.Len() == 1)
}

View File

@@ -1,8 +1,10 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package caches_test
import (
"crypto/md5"
"encoding/base64"
"encoding/json"
"github.com/TeaOSLab/EdgeNode/internal/caches"
"github.com/iwind/TeaGo/assert"
@@ -167,8 +169,13 @@ func TestPartialRanges_Encode_String(t *testing.T) {
for i := 0; i < 10; i++ {
r.Ranges = append(r.Ranges, [2]int64{int64(i * 100), int64(i*100 + 100)})
}
var sum = md5.Sum([]byte("123456"))
r.ContentMD5 = base64.StdEncoding.EncodeToString(sum[:])
var before = time.Now()
var data = r.String()
t.Log(data)
t.Log(time.Since(before).Seconds()*1000, "ms")
t.Log(len(data))

View File

@@ -1,6 +1,9 @@
package caches
import "github.com/TeaOSLab/EdgeNode/internal/utils/ranges"
import (
"github.com/TeaOSLab/EdgeNode/internal/utils/ranges"
"io"
)
type ReaderFunc func(n int) (goNext bool, err error)
@@ -41,6 +44,9 @@ type Reader interface {
// ContainsRange 是否包含某个区间内容
ContainsRange(r rangeutils.Range) (r2 rangeutils.Range, ok bool)
// SetNextReader 设置下一个内容Reader
SetNextReader(nextReader io.ReadCloser)
// Close 关闭
Close() error
}

View File

@@ -0,0 +1,14 @@
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package caches
import "io"
type BaseReader struct {
nextReader io.ReadCloser
}
// SetNextReader 设置下一个内容Reader
func (this *BaseReader) SetNextReader(nextReader io.ReadCloser) {
this.nextReader = nextReader
}

View File

@@ -3,6 +3,7 @@ package caches
import (
"encoding/binary"
"errors"
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
rangeutils "github.com/TeaOSLab/EdgeNode/internal/utils/ranges"
"github.com/iwind/TeaGo/types"
"io"
@@ -10,7 +11,9 @@ import (
)
type FileReader struct {
fp *os.File
BaseReader
fp *fsutils.File
openFile *OpenFile
openFileCache *OpenFileCache
@@ -28,7 +31,7 @@ type FileReader struct {
isClosed bool
}
func NewFileReader(fp *os.File) *FileReader {
func NewFileReader(fp *fsutils.File) *FileReader {
return &FileReader{fp: fp}
}
@@ -305,7 +308,8 @@ func (this *FileReader) ReadBodyRange(buf []byte, start int64, end int64, callba
}
for {
n, err := this.fp.Read(buf)
var n int
n, err = this.fp.Read(buf)
if n > 0 {
var n2 = int(end-offset) + 1
if n2 <= n {
@@ -341,6 +345,33 @@ func (this *FileReader) ReadBodyRange(buf []byte, start int64, end int64, callba
isOk = true
// 读取下一个Reader
if this.nextReader != nil {
defer func() {
_ = this.nextReader.Close()
}()
for {
var n int
n, err = this.nextReader.Read(buf)
if n > 0 {
goNext, writeErr := callback(n)
if writeErr != nil {
return writeErr
}
if !goNext {
break
}
}
if err != nil {
if err != io.EOF {
return err
}
break
}
}
}
return nil
}
@@ -351,7 +382,7 @@ func (this *FileReader) ContainsRange(r rangeutils.Range) (r2 rangeutils.Range,
// FP 原始的文件句柄
func (this *FileReader) FP() *os.File {
return this.fp
return this.fp.Raw()
}
func (this *FileReader) Close() error {
@@ -366,7 +397,7 @@ func (this *FileReader) Close() error {
} else {
var cacheMeta = make([]byte, len(this.meta))
copy(cacheMeta, this.meta)
this.openFileCache.Put(this.fp.Name(), NewOpenFile(this.fp, cacheMeta, this.header, this.LastModified(), this.bodySize))
this.openFileCache.Put(this.fp.Name(), NewOpenFile(this.fp.Raw(), cacheMeta, this.header, this.LastModified(), this.bodySize))
}
return nil
}
@@ -374,7 +405,7 @@ func (this *FileReader) Close() error {
return this.fp.Close()
}
func (this *FileReader) readToBuff(fp *os.File, buf []byte) (ok bool, err error) {
func (this *FileReader) readToBuff(fp *fsutils.File, buf []byte) (ok bool, err error) {
n, err := fp.Read(buf)
if err != nil {
return false, err
@@ -393,5 +424,5 @@ func (this *FileReader) discard() error {
}
// remove file
return os.Remove(this.fp.Name())
return fsutils.Remove(this.fp.Name())
}

View File

@@ -0,0 +1,18 @@
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !plus
package caches
import (
"errors"
"io"
)
type MMAPFileReader struct {
FileReader
}
func (this *MMAPFileReader) CopyBodyTo(writer io.Writer) (int, error) {
// stub
return 0, errors.New("not implemented")
}

View File

@@ -2,6 +2,7 @@ package caches
import (
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
"github.com/iwind/TeaGo/Tea"
"os"
"testing"
@@ -36,7 +37,7 @@ func TestFileReader(t *testing.T) {
defer func() {
_ = fp.Close()
}()
reader := NewFileReader(fp)
reader := NewFileReader(fsutils.NewFile(fp, fsutils.FlagRead))
err = reader.Init()
if err != nil {
t.Fatal(err)
@@ -75,7 +76,7 @@ func TestFileReader_ReadHeader(t *testing.T) {
defer func() {
_ = fp.Close()
}()
var reader = NewFileReader(fp)
var reader = NewFileReader(fsutils.NewFile(fp, fsutils.FlagRead))
err = reader.Init()
if err != nil {
if os.IsNotExist(err) {
@@ -138,7 +139,7 @@ func TestFileReader_Range(t *testing.T) {
defer func() {
_ = fp.Close()
}()
reader := NewFileReader(fp)
reader := NewFileReader(fsutils.NewFile(fp, fsutils.FlagRead))
err = reader.Init()
if err != nil {
t.Fatal(err)

View File

@@ -7,6 +7,8 @@ import (
)
type MemoryReader struct {
BaseReader
item *MemoryItem
offset int

View File

@@ -4,10 +4,10 @@ import (
"encoding/binary"
"errors"
"fmt"
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
rangeutils "github.com/TeaOSLab/EdgeNode/internal/utils/ranges"
"github.com/iwind/TeaGo/types"
"io"
"os"
)
type PartialFileReader struct {
@@ -17,7 +17,7 @@ type PartialFileReader struct {
rangePath string
}
func NewPartialFileReader(fp *os.File) *PartialFileReader {
func NewPartialFileReader(fp *fsutils.File) *PartialFileReader {
return &PartialFileReader{
FileReader: NewFileReader(fp),
rangePath: PartialRangesFilePath(fp.Name()),
@@ -34,7 +34,7 @@ func (this *PartialFileReader) InitAutoDiscard(autoDiscard bool) error {
this.header = this.openFile.header
}
isOk := false
var isOk = false
if autoDiscard {
defer func() {
@@ -54,9 +54,9 @@ func (this *PartialFileReader) InitAutoDiscard(autoDiscard bool) error {
var buf = this.meta
if len(buf) == 0 {
buf = make([]byte, SizeMeta)
ok, err := this.readToBuff(this.fp, buf)
if err != nil {
return err
ok, readErr := this.readToBuff(this.fp, buf)
if readErr != nil {
return readErr
}
if !ok {
return ErrNotFound
@@ -73,10 +73,10 @@ func (this *PartialFileReader) InitAutoDiscard(autoDiscard bool) error {
this.status = status
// URL
urlLength := binary.BigEndian.Uint32(buf[SizeExpiresAt+SizeStatus : SizeExpiresAt+SizeStatus+SizeURLLength])
var urlLength = binary.BigEndian.Uint32(buf[SizeExpiresAt+SizeStatus : SizeExpiresAt+SizeStatus+SizeURLLength])
// header
headerSize := int(binary.BigEndian.Uint32(buf[SizeExpiresAt+SizeStatus+SizeURLLength : SizeExpiresAt+SizeStatus+SizeURLLength+SizeHeaderLength]))
var headerSize = int(binary.BigEndian.Uint32(buf[SizeExpiresAt+SizeStatus+SizeURLLength : SizeExpiresAt+SizeStatus+SizeURLLength+SizeHeaderLength]))
if headerSize == 0 {
return nil
}
@@ -96,7 +96,7 @@ func (this *PartialFileReader) InitAutoDiscard(autoDiscard bool) error {
if this.openFileCache != nil && len(this.header) == 0 {
if headerSize > 0 && headerSize <= 512 {
this.header = make([]byte, headerSize)
_, err := this.fp.Seek(this.headerOffset, io.SeekStart)
_, err = this.fp.Seek(this.headerOffset, io.SeekStart)
if err != nil {
return err
}
@@ -140,7 +140,13 @@ func (this *PartialFileReader) Ranges() *PartialRanges {
return this.ranges
}
func (this *PartialFileReader) IsCompleted() bool {
return this.ranges != nil && this.ranges.IsCompleted()
}
func (this *PartialFileReader) discard() error {
_ = os.Remove(this.rangePath)
SharedPartialRangesQueue.Delete(this.rangePath)
_ = fsutils.Remove(this.rangePath)
return this.FileReader.discard()
}

View File

@@ -10,15 +10,16 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
"github.com/TeaOSLab/EdgeNode/internal/events"
"github.com/TeaOSLab/EdgeNode/internal/goman"
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
"github.com/TeaOSLab/EdgeNode/internal/trackers"
"github.com/TeaOSLab/EdgeNode/internal/utils"
"github.com/TeaOSLab/EdgeNode/internal/utils/bytepool"
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
"github.com/TeaOSLab/EdgeNode/internal/utils/goman"
memutils "github.com/TeaOSLab/EdgeNode/internal/utils/mem"
setutils "github.com/TeaOSLab/EdgeNode/internal/utils/sets"
"github.com/TeaOSLab/EdgeNode/internal/utils/sizes"
"github.com/TeaOSLab/EdgeNode/internal/zero"
"github.com/TeaOSLab/EdgeNode/internal/utils/trackers"
"github.com/TeaOSLab/EdgeNode/internal/utils/zero"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/rands"
"github.com/iwind/TeaGo/types"
@@ -54,16 +55,30 @@ const (
)
const (
FileStorageMaxIgnoreKeys = 32768 // 最大可忽略的键值数(尺寸过大的键值)
HotItemSize = 1024 // 热点数据数量
HotItemLifeSeconds int64 = 3600 // 热点数据生命周期
FileToMemoryMaxSize = 32 * sizes.M // 可以从文件写入到内存的最大文件尺寸
FileStorageMaxIgnoreKeys = 32768 // 最大可忽略的键值数(尺寸过大的键值)
HotItemSize = 1024 // 热点数据数量
HotItemLifeSeconds int64 = 3600 // 热点数据生命周期
FileTmpSuffix = ".tmp"
DefaultMinDiskFreeSpace uint64 = 5 << 30 // 当前磁盘最小剩余空间
DefaultStaleCacheSeconds = 1200 // 过时缓存留存时间
HashKeyLength = 32
)
var FileToMemoryMaxSize int64 = 32 << 20 // 可以从文件写入到内存的最大文件尺寸
func init() {
var availableMemoryGB = memutils.AvailableMemoryGB()
if availableMemoryGB > 64 {
FileToMemoryMaxSize = 512 << 20
} else if availableMemoryGB > 32 {
FileToMemoryMaxSize = 256 << 20
} else if availableMemoryGB > 16 {
FileToMemoryMaxSize = 128 << 20
} else if availableMemoryGB > 8 {
FileToMemoryMaxSize = 64 << 20
}
}
var sharedWritingFileKeyMap = map[string]zero.Zero{} // key => bool
var sharedWritingFileKeyLocker = sync.Mutex{}
@@ -125,7 +140,7 @@ func (this *FileStorage) CanUpdatePolicy(newPolicy *serverconfigs.HTTPCachePolic
if err != nil {
return false
}
var oldOptions = &serverconfigs.HTTPFileCacheStorage{}
var oldOptions = serverconfigs.NewHTTPFileCacheStorage()
err = json.Unmarshal(oldOptionsJSON, oldOptions)
if err != nil {
return false
@@ -135,7 +150,7 @@ func (this *FileStorage) CanUpdatePolicy(newPolicy *serverconfigs.HTTPCachePolic
if err != nil {
return false
}
var newOptions = &serverconfigs.HTTPFileCacheStorage{}
var newOptions = serverconfigs.NewHTTPFileCacheStorage()
err = json.Unmarshal(newOptionsJSON, newOptions)
if err != nil {
return false
@@ -158,7 +173,7 @@ func (this *FileStorage) UpdatePolicy(newPolicy *serverconfigs.HTTPCachePolicy)
if err != nil {
return
}
var newOptions = &serverconfigs.HTTPFileCacheStorage{}
var newOptions = serverconfigs.NewHTTPFileCacheStorage()
err = json.Unmarshal(newOptionsJSON, newOptions)
if err != nil {
remotelogs.Error("CACHE", "update policy '"+types.String(this.policy.Id)+"' failed: decode options failed: "+err.Error())
@@ -223,7 +238,7 @@ func (this *FileStorage) Init() error {
var before = time.Now()
// 配置
var options = &serverconfigs.HTTPFileCacheStorage{}
var options = serverconfigs.NewHTTPFileCacheStorage()
optionsJSON, err := json.Marshal(this.policy.Options)
if err != nil {
return err
@@ -297,14 +312,19 @@ func (this *FileStorage) Init() error {
var totalSize = this.TotalDiskSize()
var cost = time.Since(before).Seconds() * 1000
var sizeMB = types.String(totalSize) + " Bytes"
if totalSize > 1*sizes.G {
sizeMB = fmt.Sprintf("%.3f G", float64(totalSize)/float64(sizes.G))
} else if totalSize > 1*sizes.M {
sizeMB = fmt.Sprintf("%.3f M", float64(totalSize)/float64(sizes.M))
} else if totalSize > 1*sizes.K {
sizeMB = fmt.Sprintf("%.3f K", float64(totalSize)/float64(sizes.K))
if totalSize > (1 << 30) {
sizeMB = fmt.Sprintf("%.3f GiB", float64(totalSize)/(1<<30))
} else if totalSize > (1 << 20) {
sizeMB = fmt.Sprintf("%.3f MiB", float64(totalSize)/(1<<20))
} else if totalSize > (1 << 10) {
sizeMB = fmt.Sprintf("%.3f KiB", float64(totalSize)/(1<<10))
}
remotelogs.Println("CACHE", "init policy "+types.String(this.policy.Id)+" from '"+this.options.Dir+"', cost: "+fmt.Sprintf("%.2f", cost)+" ms, size: "+sizeMB)
var mmapTag = "disabled"
if this.options.EnableMMAP {
mmapTag = "enabled"
}
remotelogs.Println("CACHE", "init policy "+types.String(this.policy.Id)+" from '"+this.options.Dir+"', cost: "+fmt.Sprintf("%.2f", cost)+" ms, size: "+sizeMB+", mmap: "+mmapTag)
}()
// 初始化list
@@ -360,17 +380,31 @@ func (this *FileStorage) openReader(key string, allowMemory bool, useStale bool,
hash, path, _ := this.keyPath(key)
// 检查文件记录是否已过期
var estimatedSize int64
var existInList bool
if !useStale {
exists, err := this.list.Exist(hash)
exists, filesize, err := this.list.Exist(hash)
if err != nil {
return nil, err
}
if !exists {
return nil, ErrNotFound
}
estimatedSize = filesize
existInList = true
}
// 尝试通过MMAP读取
if estimatedSize > 0 {
reader, err := this.tryMMAPReader(isPartial, estimatedSize, path)
if err != nil {
return nil, err
}
if reader != nil {
return reader, nil
}
}
// TODO 尝试使用mmap加快读取速度
var isOk = false
var openFile *OpenFile
var openFileCache = this.openFileCache // 因为中间可能有修改,所以先赋值再获取
@@ -378,9 +412,16 @@ func (this *FileStorage) openReader(key string, allowMemory bool, useStale bool,
openFile = openFileCache.Get(path)
}
var fp *os.File
var err error
if openFile == nil {
if existInList {
fsutils.ReaderLimiter.Ack()
}
fp, err = os.OpenFile(path, os.O_RDONLY, 0444)
if existInList {
fsutils.ReaderLimiter.Release()
}
if err != nil {
if !os.IsNotExist(err) {
return nil, err
@@ -399,16 +440,17 @@ func (this *FileStorage) openReader(key string, allowMemory bool, useStale bool,
var reader Reader
if isPartial {
var partialFileReader = NewPartialFileReader(fp)
var partialFileReader = NewPartialFileReader(fsutils.NewFile(fp, fsutils.FlagRead))
partialFileReader.openFile = openFile
partialFileReader.openFileCache = openFileCache
reader = partialFileReader
} else {
var fileReader = NewFileReader(fp)
var fileReader = NewFileReader(fsutils.NewFile(fp, fsutils.FlagRead))
fileReader.openFile = openFile
fileReader.openFileCache = openFileCache
reader = fileReader
}
err = reader.Init()
if err != nil {
return nil, err
@@ -459,7 +501,7 @@ func (this *FileStorage) openWriter(key string, expiredAt int64, status int, hea
maxMemorySize = maxSize
}
var memoryStorage = this.memoryStorage
if !fsutils.DiskIsExtremelyFast() && !isFlushing && !isPartial && memoryStorage != nil && ((bodySize > 0 && bodySize < maxMemorySize) || bodySize < 0) {
if !isFlushing && !isPartial && memoryStorage != nil && ((bodySize > 0 && bodySize < maxMemorySize) || bodySize < 0) {
writer, err := memoryStorage.OpenWriter(key, expiredAt, status, headerSize, bodySize, maxMemorySize, false)
if err == nil {
return writer, nil
@@ -469,6 +511,10 @@ func (this *FileStorage) openWriter(key string, expiredAt int64, status int, hea
if errors.Is(err, ErrWritingQueueFull) {
return nil, err
}
if IsCapacityError(err) && bodySize > 0 && memoryStorage.totalDirtySize > (128<<20) {
return nil, err
}
}
// 是否正在写入
@@ -480,11 +526,6 @@ func (this *FileStorage) openWriter(key string, expiredAt int64, status int, hea
return nil, fmt.Errorf("%w(001)", ErrFileIsWriting)
}
if !isFlushing && !fsutils.WriteReady() {
sharedWritingFileKeyLocker.Unlock()
return nil, ErrServerIsBusy
}
sharedWritingFileKeyMap[key] = zero.New()
sharedWritingFileKeyLocker.Unlock()
defer func() {
@@ -549,11 +590,11 @@ func (this *FileStorage) openWriter(key string, expiredAt int64, status int, hea
var partialRanges *PartialRanges
if isPartial {
// 数据库中是否存在
existsCacheItem, _ := this.list.Exist(hash)
existsCacheItem, _, _ := this.list.Exist(hash)
if existsCacheItem {
readerFp, err := os.OpenFile(tmpPath, os.O_RDONLY, 0444)
readerFp, err := fsutils.OpenFile(tmpPath, os.O_RDONLY, 0444)
if err == nil {
var partialReader = NewPartialFileReader(readerFp)
var partialReader = NewPartialFileReader(fsutils.NewFile(readerFp, fsutils.FlagRead))
err = partialReader.Init()
_ = partialReader.Close()
if err == nil && partialReader.bodyOffset > 0 {
@@ -584,22 +625,31 @@ func (this *FileStorage) openWriter(key string, expiredAt int64, status int, hea
if isNewCreated && existsFile {
flags |= os.O_TRUNC
}
fsutils.WriteBegin()
writer, err := os.OpenFile(tmpPath, flags, 0666)
fsutils.WriteEnd()
if !isFlushing {
if !fsutils.WriterLimiter.TryAck() {
return nil, ErrServerIsBusy
}
}
fp, err := os.OpenFile(tmpPath, flags, 0666)
if !isFlushing {
fsutils.WriterLimiter.Release()
}
if err != nil {
// TODO 检查在各个系统中的稳定性
if os.IsNotExist(err) {
_ = os.MkdirAll(dir, 0777)
// open file again
writer, err = os.OpenFile(tmpPath, flags, 0666)
fsutils.WriterLimiter.Ack()
fp, err = os.OpenFile(tmpPath, flags, 0666)
fsutils.WriterLimiter.Release()
}
if err != nil {
return nil, err
}
}
var writer = fsutils.NewFile(fp, fsutils.FlagWrite)
var removeOnFailure = true
defer func() {
if err != nil {
@@ -610,18 +660,25 @@ func (this *FileStorage) openWriter(key string, expiredAt int64, status int, hea
if !isOk {
_ = writer.Close()
if removeOnFailure {
_ = os.Remove(tmpPath)
_ = fsutils.Remove(tmpPath)
}
}
}()
// 尝试锁定,如果锁定失败,则直接返回
fsutils.WriterLimiter.Ack()
err = syscall.Flock(int(writer.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
fsutils.WriterLimiter.Release()
if err != nil {
removeOnFailure = false
return nil, fmt.Errorf("%w (003)", ErrFileIsWriting)
}
// 关闭
if openFileCache != nil {
openFileCache.Close(cachePath)
}
var metaBodySize int64 = -1
var metaHeaderSize = -1
if isNewCreated {
@@ -648,9 +705,7 @@ func (this *FileStorage) openWriter(key string, expiredAt int64, status int, hea
metaBodySize = bodySize
}
fsutils.WriteBegin()
_, err = writer.Write(metaBytes)
fsutils.WriteEnd()
if err != nil {
return nil, err
}
@@ -949,6 +1004,11 @@ func (this *FileStorage) CanSendfile() bool {
return this.options.EnableSendfile
}
// Options 获取当前缓存存储的选项
func (this *FileStorage) Options() *serverconfigs.HTTPFileCacheStorage {
return this.options
}
// 获取Key对应的文件路径
func (this *FileStorage) keyPath(key string) (hash string, path string, diskIsFull bool) {
hash = stringutil.Md5(key)
@@ -1103,9 +1163,7 @@ func (this *FileStorage) purgeLoop() {
for i := 0; i < times; i++ {
countFound, err := this.list.Purge(purgeCount, func(hash string) error {
path, _ := this.hashPath(hash)
fsutils.WriteBegin()
err := this.removeCacheFile(path)
fsutils.WriteEnd()
if err != nil && !os.IsNotExist(err) {
remotelogs.Error("CACHE", "purge '"+path+"' error: "+err.Error())
}
@@ -1162,9 +1220,7 @@ func (this *FileStorage) purgeLoop() {
var before = time.Now()
err := this.list.PurgeLFU(count, func(hash string) error {
path, _ := this.hashPath(hash)
fsutils.WriteBegin()
err := this.removeCacheFile(path)
fsutils.WriteEnd()
if err != nil && !os.IsNotExist(err) {
remotelogs.Error("CACHE", "purge '"+path+"' error: "+err.Error())
}
@@ -1235,8 +1291,9 @@ func (this *FileStorage) hotLoop() {
size = len(result) / 10
}
var buf = utils.BytePool16k.Get()
defer utils.BytePool16k.Put(buf)
var buf = bytepool.Pool16k.Get()
defer bytepool.Pool16k.Put(buf)
for _, item := range result[:size] {
reader, err := this.openReader(item.Key, false, false, false)
if err != nil {
@@ -1277,8 +1334,8 @@ func (this *FileStorage) hotLoop() {
continue
}
err = reader.ReadHeader(buf, func(n int) (goNext bool, err error) {
_, err = writer.WriteHeader(buf[:n])
err = reader.ReadHeader(buf.Bytes, func(n int) (goNext bool, err error) {
_, err = writer.WriteHeader(buf.Bytes[:n])
return
})
if err != nil {
@@ -1287,10 +1344,10 @@ func (this *FileStorage) hotLoop() {
continue
}
err = reader.ReadBody(buf, func(n int) (goNext bool, err error) {
err = reader.ReadBody(buf.Bytes, func(n int) (goNext bool, err error) {
goNext = true
if n > 0 {
_, err = writer.Write(buf[:n])
_, err = writer.Write(buf.Bytes[:n])
if err != nil {
goNext = false
}
@@ -1398,7 +1455,7 @@ func (this *FileStorage) increaseHit(key string, hash string, reader Reader) {
// 增加到热点
// 这里不收录缓存尺寸过大的文件
if memoryStorage != nil && reader.BodySize() > 0 && reader.BodySize() < 128*sizes.M {
if memoryStorage != nil && reader.BodySize() > 0 && reader.BodySize() < (128<<20) {
this.hotMapLocker.Lock()
hotItem, ok := this.hotMap[key]
@@ -1431,7 +1488,7 @@ func (this *FileStorage) removeCacheFile(path string) error {
openFileCache.Close(path)
}
var err = os.Remove(path)
var err = fsutils.Remove(path)
if err == nil || os.IsNotExist(err) {
err = nil
@@ -1443,7 +1500,8 @@ func (this *FileStorage) removeCacheFile(path string) error {
_, statErr := os.Stat(partialPath)
if statErr == nil {
_ = os.Remove(partialPath)
_ = fsutils.Remove(partialPath)
SharedPartialRangesQueue.Delete(partialPath)
}
}
return err

View File

@@ -0,0 +1,9 @@
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build !plus
package caches
func (this *FileStorage) tryMMAPReader(isPartial bool, estimatedSize int64, path string) (Reader, error) {
// stub
return nil, nil
}

View File

@@ -664,7 +664,7 @@ func TestFileStorage_ScanGarbageCaches(t *testing.T) {
func BenchmarkFileStorage_Read(b *testing.B) {
runtime.GOMAXPROCS(1)
_ = utils.SetRLimit(1024 * 1024)
_ = utils.SetRLimit(1 << 20)
var storage = NewFileStorage(&serverconfigs.HTTPCachePolicy{
Id: 1,

View File

@@ -3,15 +3,16 @@ package caches
import (
"fmt"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeNode/internal/goman"
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
"github.com/TeaOSLab/EdgeNode/internal/trackers"
"github.com/TeaOSLab/EdgeNode/internal/utils"
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
"github.com/TeaOSLab/EdgeNode/internal/utils/goman"
memutils "github.com/TeaOSLab/EdgeNode/internal/utils/mem"
setutils "github.com/TeaOSLab/EdgeNode/internal/utils/sets"
"github.com/TeaOSLab/EdgeNode/internal/zero"
"github.com/cespare/xxhash"
"github.com/TeaOSLab/EdgeNode/internal/utils/trackers"
"github.com/TeaOSLab/EdgeNode/internal/utils/zero"
"github.com/cespare/xxhash/v2"
"github.com/iwind/TeaGo/types"
"math"
"runtime"
@@ -54,7 +55,9 @@ type MemoryStorage struct {
purgeTicker *utils.Ticker
usedSize int64
usedSize int64
totalDirtySize int64
writingKeyMap map[string]zero.Zero // key => bool
ignoreKeys *setutils.FixedSet
@@ -66,7 +69,7 @@ func NewMemoryStorage(policy *serverconfigs.HTTPCachePolicy, parentStorage Stora
if parentStorage != nil {
if queueSize <= 0 {
queueSize = utils.SystemMemoryGB() * 100_000
queueSize = memutils.SystemMemoryGB() * 100_000
}
dirtyChan = make(chan string, queueSize)
@@ -99,10 +102,19 @@ func (this *MemoryStorage) Init() error {
// 启动定时Flush memory to disk任务
if this.parentStorage != nil {
// TODO 应该根据磁盘性能决定线程数
// TODO 线程数应该可以在缓存策略和节点中设定
var threads = runtime.NumCPU()
var threads = 2
var numCPU = runtime.NumCPU()
if fsutils.DiskIsExtremelyFast() {
if numCPU >= 8 {
threads = 8
} else {
threads = 4
}
} else if fsutils.DiskIsFast() {
if numCPU >= 4 {
threads = 4
}
}
for i := 0; i < threads; i++ {
goman.New(func() {
this.startFlush()
@@ -118,7 +130,7 @@ func (this *MemoryStorage) OpenReader(key string, useStale bool, isPartial bool)
var hash = this.hash(key)
// check if exists in list
exists, _ := this.list.Exist(types.String(hash))
exists, _, _ := this.list.Exist(types.String(hash))
if !exists {
return nil, ErrNotFound
}
@@ -177,7 +189,7 @@ func (this *MemoryStorage) openWriter(key string, expiresAt int64, status int, h
if isDirty &&
this.parentStorage != nil &&
this.dirtyQueueSize > 0 &&
len(this.dirtyChan) >= this.dirtyQueueSize-int(fsutils.DiskMaxWrites) /** delta **/ { // 缓存时间过长
len(this.dirtyChan) >= this.dirtyQueueSize-64 /** delta **/ { // 缓存时间过长
return nil, ErrWritingQueueFull
}
@@ -202,7 +214,7 @@ func (this *MemoryStorage) openWriter(key string, expiresAt int64, status int, h
item, ok := this.valuesMap[hash]
if ok && !item.IsExpired() {
var hashString = types.String(hash)
exists, _ := this.list.Exist(hashString)
exists, _, _ := this.list.Exist(hashString)
if !exists {
// remove from values map
delete(this.valuesMap, hash)
@@ -330,6 +342,9 @@ func (this *MemoryStorage) Stop() {
close(this.dirtyChan)
}
this.usedSize = 0
this.totalDirtySize = 0
_ = this.list.Close()
this.locker.Unlock()
@@ -496,14 +511,20 @@ func (this *MemoryStorage) startFlush() {
if fsutils.IsInExtremelyHighLoad {
time.Sleep(1 * time.Second)
} else if fsutils.IsInHighLoad {
time.Sleep(100 * time.Millisecond)
}
}
}
// 单次Flush任务
func (this *MemoryStorage) flushItem(key string) {
func (this *MemoryStorage) flushItem(fullKey string) {
sizeString, key, found := strings.Cut(fullKey, "@")
if !found {
return
}
defer func() {
atomic.AddInt64(&this.totalDirtySize, -types.Int64(sizeString))
}()
if this.parentStorage == nil {
return
}
@@ -516,11 +537,6 @@ func (this *MemoryStorage) flushItem(key string) {
// 从内存中移除,并确保无论如何都会执行
defer func() {
_ = this.Delete(key)
// 重用内存,前提是确保内存不再被引用
if enableFragmentPool && ok && item.IsDone && !item.isReferring && len(item.BodyValue) > 0 {
SharedFragmentMemoryPool.Put(item.BodyValue)
}
}()
if !ok {
@@ -536,13 +552,28 @@ func (this *MemoryStorage) flushItem(key string) {
}
// 检查是否在列表中防止未加入列表时就开始flush
isInList, err := this.list.Exist(types.String(hash))
isInList, _, err := this.list.Exist(types.String(hash))
if err != nil {
remotelogs.Error("CACHE", "flush items failed: "+err.Error())
return
}
if !isInList {
time.Sleep(1 * time.Second)
for i := 0; i < 1000; i++ {
isInList, _, err = this.list.Exist(types.String(hash))
if err != nil {
remotelogs.Error("CACHE", "flush items failed: "+err.Error())
time.Sleep(1 * time.Second)
continue
}
if isInList {
break
}
time.Sleep(1 * time.Millisecond)
}
if !isInList {
// discard
return
}
}
writer, err := this.parentStorage.OpenFlushWriter(key, item.ExpiresAt, item.Status, len(item.HeaderValue), int64(len(item.BodyValue)))

View File

@@ -6,6 +6,7 @@ import (
"github.com/TeaOSLab/EdgeNode/internal/utils/testutils"
"github.com/iwind/TeaGo/logs"
"github.com/iwind/TeaGo/rands"
"math/rand"
"runtime"
"runtime/debug"
"strconv"
@@ -381,3 +382,31 @@ func BenchmarkValuesMap(b *testing.B) {
}
})
}
func BenchmarkNewMemoryStorage(b *testing.B) {
var storage = NewMemoryStorage(&serverconfigs.HTTPCachePolicy{}, nil)
var data = bytes.Repeat([]byte{'A'}, 1024)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
func() {
writer, err := storage.OpenWriter("abc"+strconv.Itoa(rand.Int()), time.Now().Unix()+60, 200, -1, -1, -1, false)
if err != nil {
b.Fatal(err)
}
if err != nil {
b.Fatal(err)
}
_, _ = writer.WriteHeader([]byte("Header"))
_, _ = writer.Write(data)
err = writer.Close()
if err != nil {
b.Fatal(err)
}
}()
}
})
}

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package caches

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package caches

View File

@@ -1,11 +1,11 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package caches_test
import (
"fmt"
"github.com/TeaOSLab/EdgeNode/internal/caches"
"github.com/cespare/xxhash"
"github.com/cespare/xxhash/v2"
"github.com/iwind/TeaGo/types"
"strconv"
"testing"

View File

@@ -6,14 +6,13 @@ import (
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
"github.com/iwind/TeaGo/types"
"io"
"os"
"strings"
"sync"
)
type FileWriter struct {
storage StorageInterface
rawWriter *os.File
rawWriter *fsutils.File
key string
metaHeaderSize int
@@ -26,9 +25,11 @@ type FileWriter struct {
maxSize int64
endFunc func()
once sync.Once
modifiedBytes int
}
func NewFileWriter(storage StorageInterface, rawWriter *os.File, key string, expiredAt int64, metaHeaderSize int, metaBodySize int64, maxSize int64, endFunc func()) *FileWriter {
func NewFileWriter(storage StorageInterface, rawWriter *fsutils.File, key string, expiredAt int64, metaHeaderSize int, metaBodySize int64, maxSize int64, endFunc func()) *FileWriter {
return &FileWriter{
storage: storage,
key: key,
@@ -43,9 +44,7 @@ func NewFileWriter(storage StorageInterface, rawWriter *os.File, key string, exp
// WriteHeader 写入数据
func (this *FileWriter) WriteHeader(data []byte) (n int, err error) {
fsutils.WriteBegin()
n, err = this.rawWriter.Write(data)
fsutils.WriteEnd()
this.headerSize += int64(n)
if err != nil {
_ = this.Discard()
@@ -79,7 +78,7 @@ func (this *FileWriter) Write(data []byte) (n int, err error) {
var l = len(data)
if l > (2 << 20) {
var offset = 0
const bufferSize = 256 << 10
const bufferSize = 64 << 10
for {
var end = offset + bufferSize
if end > l {
@@ -136,32 +135,33 @@ func (this *FileWriter) Close() error {
var path = this.rawWriter.Name()
// check content length
if this.metaBodySize > 0 && this.bodySize != this.metaBodySize {
_ = this.rawWriter.Close()
_ = fsutils.Remove(path)
return ErrUnexpectedContentLength
}
err := this.WriteHeaderLength(types.Int(this.headerSize))
if err != nil {
fsutils.WriteBegin()
_ = this.rawWriter.Close()
fsutils.WriteEnd()
_ = os.Remove(path)
_ = fsutils.Remove(path)
return err
}
err = this.WriteBodyLength(this.bodySize)
if err != nil {
fsutils.WriteBegin()
_ = this.rawWriter.Close()
fsutils.WriteEnd()
_ = os.Remove(path)
_ = fsutils.Remove(path)
return err
}
fsutils.WriteBegin()
err = this.rawWriter.Close()
fsutils.WriteEnd()
if err != nil {
_ = os.Remove(path)
_ = fsutils.Remove(path)
} else if strings.HasSuffix(path, FileTmpSuffix) {
err = os.Rename(path, strings.Replace(path, FileTmpSuffix, "", 1))
err = fsutils.Rename(path, strings.Replace(path, FileTmpSuffix, "", 1))
if err != nil {
_ = os.Remove(path)
_ = fsutils.Remove(path)
}
}
@@ -174,11 +174,9 @@ func (this *FileWriter) Discard() error {
this.endFunc()
})
fsutils.WriteBegin()
_ = this.rawWriter.Close()
fsutils.WriteEnd()
err := os.Remove(this.rawWriter.Name())
err := fsutils.Remove(this.rawWriter.Name())
return err
}
@@ -204,9 +202,7 @@ func (this *FileWriter) ItemType() ItemType {
}
func (this *FileWriter) write(data []byte) (n int, err error) {
fsutils.WriteBegin()
n, err = this.rawWriter.Write(data)
fsutils.WriteEnd()
this.bodySize += int64(n)
if this.maxSize > 0 && this.bodySize > this.maxSize {
@@ -220,5 +216,6 @@ func (this *FileWriter) write(data []byte) (n int, err error) {
if err != nil {
_ = this.Discard()
}
return
}

View File

@@ -3,8 +3,10 @@ package caches
import (
"errors"
"github.com/TeaOSLab/EdgeNode/internal/utils/fasttime"
"github.com/cespare/xxhash"
"github.com/cespare/xxhash/v2"
"github.com/iwind/TeaGo/types"
"sync"
"sync/atomic"
)
type MemoryWriter struct {
@@ -32,27 +34,11 @@ func NewMemoryWriter(memoryStorage *MemoryStorage, key string, expiredAt int64,
ModifiedAt: fasttime.Now().Unix(),
Status: status,
}
if enableFragmentPool &&
expectedBodySize > 0 &&
expectedBodySize <= maxMemoryFragmentPoolItemSize {
bodyBytes, ok := SharedFragmentMemoryPool.Get(expectedBodySize) // try to reuse memory
if ok {
valueItem.BodyValue = bodyBytes
valueItem.IsPrepared = true
} else {
if expectedBodySize <= (16 << 20) {
var allocSize = (expectedBodySize/16384 + 1) * 16384
valueItem.BodyValue = make([]byte, allocSize)[:expectedBodySize]
valueItem.IsPrepared = true
SharedFragmentMemoryPool.IncreaseNew()
}
}
} else {
if expectedBodySize > 0 {
valueItem.BodyValue = make([]byte, 0, expectedBodySize)
}
if expectedBodySize > 0 {
valueItem.BodyValue = make([]byte, 0, expectedBodySize)
}
var w = &MemoryWriter{
storage: memoryStorage,
key: key,
@@ -135,6 +121,14 @@ func (this *MemoryWriter) Close() error {
return nil
}
// check content length
if this.expectedBodySize > 0 && this.bodySize != this.expectedBodySize {
this.storage.locker.Lock()
delete(this.storage.valuesMap, this.hash)
this.storage.locker.Unlock()
return ErrUnexpectedContentLength
}
this.storage.locker.Lock()
this.item.IsDone = true
var err error
@@ -143,7 +137,8 @@ func (this *MemoryWriter) Close() error {
this.storage.valuesMap[this.hash] = this.item
select {
case this.storage.dirtyChan <- this.key:
case this.storage.dirtyChan <- types.String(this.bodySize) + "@" + this.key:
atomic.AddInt64(&this.storage.totalDirtySize, this.bodySize)
default:
// remove from values map
delete(this.storage.valuesMap, this.hash)
@@ -171,14 +166,6 @@ func (this *MemoryWriter) Discard() error {
this.storage.locker.Lock()
delete(this.storage.valuesMap, this.hash)
if enableFragmentPool &&
this.item != nil &&
!this.item.isReferring &&
cap(this.item.BodyValue) >= minMemoryFragmentPoolItemSize {
SharedFragmentMemoryPool.Put(this.item.BodyValue)
}
this.storage.locker.Unlock()
return nil
}

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package caches
@@ -7,12 +7,12 @@ import (
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
"github.com/iwind/TeaGo/types"
"io"
"os"
"strings"
"sync"
)
type PartialFileWriter struct {
rawWriter *os.File
rawWriter *fsutils.File
key string
metaHeaderSize int
@@ -31,9 +31,11 @@ type PartialFileWriter struct {
ranges *PartialRanges
rangePath string
writtenBytes int64
}
func NewPartialFileWriter(rawWriter *os.File, key string, expiredAt int64, metaHeaderSize int, metaBodySize int64, isNew bool, isPartial bool, bodyOffset int64, ranges *PartialRanges, endFunc func()) *PartialFileWriter {
func NewPartialFileWriter(rawWriter *fsutils.File, key string, expiredAt int64, metaHeaderSize int, metaBodySize int64, isNew bool, isPartial bool, bodyOffset int64, ranges *PartialRanges, endFunc func()) *PartialFileWriter {
return &PartialFileWriter{
key: key,
rawWriter: rawWriter,
@@ -54,9 +56,7 @@ func (this *PartialFileWriter) WriteHeader(data []byte) (n int, err error) {
if !this.isNew {
return
}
fsutils.WriteBegin()
n, err = this.rawWriter.Write(data)
fsutils.WriteEnd()
this.headerSize += int64(n)
if err != nil {
_ = this.Discard()
@@ -65,9 +65,7 @@ func (this *PartialFileWriter) WriteHeader(data []byte) (n int, err error) {
}
func (this *PartialFileWriter) AppendHeader(data []byte) error {
fsutils.WriteBegin()
_, err := this.rawWriter.Write(data)
fsutils.WriteEnd()
if err != nil {
_ = this.Discard()
} else {
@@ -104,9 +102,7 @@ func (this *PartialFileWriter) WriteHeaderLength(headerLength int) error {
// Write 写入数据
func (this *PartialFileWriter) Write(data []byte) (n int, err error) {
fsutils.WriteBegin()
n, err = this.rawWriter.Write(data)
fsutils.WriteEnd()
this.bodySize += int64(n)
if err != nil {
_ = this.Discard()
@@ -127,6 +123,32 @@ func (this *PartialFileWriter) WriteAt(offset int64, data []byte) error {
return nil
}
// prevent extending too much space in a single writing
var maxOffset = this.ranges.Max()
if offset-maxOffset > 16<<20 {
var extendSizePerStep int64 = 1 << 20
var maxExtendSize int64 = 32 << 20
if fsutils.DiskIsExtremelyFast() {
maxExtendSize = 128 << 20
extendSizePerStep = 4 << 20
} else if fsutils.DiskIsFast() {
maxExtendSize = 64 << 20
extendSizePerStep = 2 << 20
}
if offset-maxOffset > maxExtendSize {
stat, err := this.rawWriter.Stat()
if err != nil {
return nil
}
// extend min size to prepare for file tail
if stat.Size()+extendSizePerStep <= this.bodyOffset+offset+int64(len(data)) {
_ = this.rawWriter.Truncate(stat.Size() + extendSizePerStep)
return nil
}
}
}
if this.bodyOffset == 0 {
var keyLength = 0
if this.ranges.Version == 0 { // 以往的版本包含有Key
@@ -135,15 +157,25 @@ func (this *PartialFileWriter) WriteAt(offset int64, data []byte) error {
this.bodyOffset = SizeMeta + int64(keyLength) + this.headerSize
}
fsutils.WriteBegin()
_, err := this.rawWriter.WriteAt(data, this.bodyOffset+offset)
fsutils.WriteEnd()
n, err := this.rawWriter.WriteAt(data, this.bodyOffset+offset)
if err != nil {
return err
}
this.ranges.Add(offset, end)
// 保存ranges内容到文件当新增数据达到一定量时就更新是为了及时更新ranges文件以便于其他请求能够及时读取到已经缓存的部分内容
this.writtenBytes += int64(n)
if this.writtenBytes > (1 << 20) {
this.writtenBytes = 0
if len(this.rangePath) > 0 {
if this.bodySize > 0 {
this.ranges.BodySize = this.bodySize
}
_ = this.ranges.WriteToFile(this.rangePath)
}
}
return nil
}
@@ -152,6 +184,14 @@ func (this *PartialFileWriter) SetBodyLength(bodyLength int64) {
this.bodySize = bodyLength
}
// SetContentMD5 设置内容MD5
func (this *PartialFileWriter) SetContentMD5(contentMD5 string) {
if strings.Contains(contentMD5, "\n") || len(contentMD5) > 128 {
return
}
this.ranges.ContentMD5 = contentMD5
}
// WriteBodyLength 写入Body长度数据
func (this *PartialFileWriter) WriteBodyLength(bodyLength int64) error {
if this.metaBodySize > 0 && this.metaBodySize == bodyLength {
@@ -178,12 +218,12 @@ func (this *PartialFileWriter) Close() error {
this.endFunc()
})
this.ranges.BodySize = this.bodySize
if this.bodySize > 0 {
this.ranges.BodySize = this.bodySize
}
err := this.ranges.WriteToFile(this.rangePath)
if err != nil {
fsutils.WriteBegin()
_ = this.rawWriter.Close()
fsutils.WriteEnd()
this.remove()
return err
}
@@ -192,25 +232,19 @@ func (this *PartialFileWriter) Close() error {
if this.isNew {
err = this.WriteHeaderLength(types.Int(this.headerSize))
if err != nil {
fsutils.WriteBegin()
_ = this.rawWriter.Close()
fsutils.WriteEnd()
this.remove()
return err
}
err = this.WriteBodyLength(this.bodySize)
if err != nil {
fsutils.WriteBegin()
_ = this.rawWriter.Close()
fsutils.WriteEnd()
this.remove()
return err
}
}
fsutils.WriteBegin()
err = this.rawWriter.Close()
fsutils.WriteEnd()
if err != nil {
this.remove()
}
@@ -224,13 +258,14 @@ func (this *PartialFileWriter) Discard() error {
this.endFunc()
})
fsutils.WriteBegin()
_ = this.rawWriter.Close()
fsutils.WriteEnd()
_ = os.Remove(this.rangePath)
SharedPartialRangesQueue.Delete(this.rangePath)
_ = fsutils.Remove(this.rangePath)
err := fsutils.Remove(this.rawWriter.Name())
err := os.Remove(this.rawWriter.Name())
return err
}
@@ -259,7 +294,14 @@ func (this *PartialFileWriter) IsNew() bool {
return this.isNew && len(this.ranges.Ranges) == 0
}
func (this *PartialFileWriter) remove() {
_ = os.Remove(this.rawWriter.Name())
_ = os.Remove(this.rangePath)
func (this *PartialFileWriter) Ranges() *PartialRanges {
return this.ranges
}
func (this *PartialFileWriter) remove() {
_ = fsutils.Remove(this.rawWriter.Name())
SharedPartialRangesQueue.Delete(this.rangePath)
_ = fsutils.Remove(this.rangePath)
}

View File

@@ -1,9 +1,10 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package caches_test
import (
"github.com/TeaOSLab/EdgeNode/internal/caches"
fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
"github.com/iwind/TeaGo/types"
"os"
"testing"
@@ -15,7 +16,7 @@ func TestPartialFileWriter_Write(t *testing.T) {
_ = os.Remove(path)
var reader = func() {
data, err := os.ReadFile(path)
data, err := fsutils.ReadFile(path)
if err != nil {
t.Fatal(err)
}
@@ -27,7 +28,7 @@ func TestPartialFileWriter_Write(t *testing.T) {
t.Fatal(err)
}
var ranges = caches.NewPartialRanges(0)
var writer = caches.NewPartialFileWriter(fp, "test", time.Now().Unix()+86500, -1, -1, true, true, 0, ranges, func() {
var writer = caches.NewPartialFileWriter(fsutils.NewFile(fp, fsutils.FlagWrite), "test", time.Now().Unix()+86500, -1, -1, true, true, 0, ranges, func() {
t.Log("end")
})
_, err = writer.WriteHeader([]byte("header"))

View File

@@ -0,0 +1,14 @@
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package compressions
import "errors"
var ErrIsBusy = errors.New("the system is busy for compression")
func CanIgnore(err error) bool {
if err == nil {
return true
}
return errors.Is(err, ErrIsBusy)
}

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
@@ -9,6 +9,7 @@ type Reader interface {
Reset(reader io.Reader) error
RawClose() error
Close() error
IncreaseHit() uint32
SetPool(pool *ReaderPool)
ResetFinish()

View File

@@ -1,11 +1,14 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
import "sync/atomic"
type BaseReader struct {
pool *ReaderPool
isFinished bool
hits uint32
}
func (this *BaseReader) SetPool(pool *ReaderPool) {
@@ -13,8 +16,11 @@ func (this *BaseReader) SetPool(pool *ReaderPool) {
}
func (this *BaseReader) Finish(obj Reader) error {
if this.isFinished {
return nil
}
err := obj.RawClose()
if err == nil && this.pool != nil && !this.isFinished {
if err == nil && this.pool != nil {
this.pool.Put(obj)
}
this.isFinished = true
@@ -24,3 +30,7 @@ func (this *BaseReader) Finish(obj Reader) error {
func (this *BaseReader) ResetFinish() {
this.isFinished = false
}
func (this *BaseReader) IncreaseHit() uint32 {
return atomic.AddUint32(&this.hits, 1)
}

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
//go:build !plus || !linux
package compressions

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions_test

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions_test

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions_test

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
@@ -6,6 +6,8 @@ import (
"io"
)
const maxReadHits = 1 << 20
type ReaderPool struct {
c chan Reader
newFunc func(reader io.Reader) (Reader, error)
@@ -49,6 +51,11 @@ func (this *ReaderPool) Get(parentReader io.Reader) (Reader, error) {
}
func (this *ReaderPool) Put(reader Reader) {
if reader.IncreaseHit() > maxReadHits {
// do nothing to discard it
return
}
select {
case this.c <- reader:
default:

View File

@@ -1,10 +1,9 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
import (
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
"github.com/TeaOSLab/EdgeNode/internal/utils"
"io"
)
@@ -15,11 +14,8 @@ func init() {
return
}
var maxSize = utils.SystemMemoryGB() * 256
if maxSize == 0 {
maxSize = 256
}
sharedBrotliReaderPool = NewReaderPool(maxSize, func(reader io.Reader) (Reader, error) {
sharedBrotliReaderPool = NewReaderPool(CalculatePoolSize(), func(reader io.Reader) (Reader, error) {
return newBrotliReader(reader)
})
}

View File

@@ -1,10 +1,9 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
import (
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
"github.com/TeaOSLab/EdgeNode/internal/utils"
"io"
)
@@ -15,11 +14,7 @@ func init() {
return
}
var maxSize = utils.SystemMemoryGB() * 256
if maxSize == 0 {
maxSize = 256
}
sharedDeflateReaderPool = NewReaderPool(maxSize, func(reader io.Reader) (Reader, error) {
sharedDeflateReaderPool = NewReaderPool(CalculatePoolSize(), func(reader io.Reader) (Reader, error) {
return newDeflateReader(reader)
})
}

View File

@@ -1,10 +1,9 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
import (
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
"github.com/TeaOSLab/EdgeNode/internal/utils"
"io"
)
@@ -15,11 +14,7 @@ func init() {
return
}
var maxSize = utils.SystemMemoryGB() * 256
if maxSize == 0 {
maxSize = 256
}
sharedGzipReaderPool = NewReaderPool(maxSize, func(reader io.Reader) (Reader, error) {
sharedGzipReaderPool = NewReaderPool(CalculatePoolSize(), func(reader io.Reader) (Reader, error) {
return newGzipReader(reader)
})
}

View File

@@ -1,10 +1,9 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
import (
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
"github.com/TeaOSLab/EdgeNode/internal/utils"
"io"
)
@@ -15,11 +14,7 @@ func init() {
return
}
var maxSize = utils.SystemMemoryGB() * 256
if maxSize == 0 {
maxSize = 256
}
sharedZSTDReaderPool = NewReaderPool(maxSize, func(reader io.Reader) (Reader, error) {
sharedZSTDReaderPool = NewReaderPool(CalculatePoolSize(), func(reader io.Reader) (Reader, error) {
return newZSTDReader(reader)
})
}

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
@@ -18,7 +18,7 @@ func NewZSTDReader(reader io.Reader) (Reader, error) {
}
func newZSTDReader(reader io.Reader) (Reader, error) {
r, err := zstd.NewReader(reader)
r, err := zstd.NewReader(reader, zstd.WithDecoderMaxWindow(256<<20))
if err != nil {
return nil, err
}

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions_test

View File

@@ -1,12 +1,14 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
import (
"errors"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
memutils "github.com/TeaOSLab/EdgeNode/internal/utils/mem"
"io"
"net/http"
"runtime"
)
type ContentEncoding = string
@@ -88,3 +90,31 @@ func WrapHTTPResponse(resp *http.Response) {
resp.Header.Del("Content-Length")
resp.Body = reader
}
// 系统CPU线程数
var countCPU = runtime.NumCPU()
// GenerateCompressLevel 根据系统资源自动生成压缩级别
func GenerateCompressLevel(minLevel int, maxLevel int) (level int) {
if countCPU < 16 {
return minLevel
}
if countCPU < 32 {
return min(3, maxLevel)
}
return min(5, maxLevel)
}
// CalculatePoolSize 计算Pool尺寸
func CalculatePoolSize() int {
var maxSize = memutils.SystemMemoryGB() * 32
if maxSize == 0 {
maxSize = 128
}
if maxSize > 2048 {
maxSize = 2048
}
return maxSize
}

View File

@@ -0,0 +1,27 @@
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package compressions_test
import (
"github.com/TeaOSLab/EdgeNode/internal/compressions"
"github.com/iwind/TeaGo/assert"
"testing"
)
func TestGenerateCompressLevel(t *testing.T) {
var a = assert.NewAssertion(t)
t.Log(compressions.GenerateCompressLevel(0, 10))
t.Log(compressions.GenerateCompressLevel(1, 10))
t.Log(compressions.GenerateCompressLevel(1, 4))
{
var level = compressions.GenerateCompressLevel(1, 2)
t.Log(level)
a.IsTrue(level >= 1 && level <= 2)
}
}
func TestCalculatePoolSize(t *testing.T) {
t.Log(compressions.CalculatePoolSize())
}

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
@@ -11,6 +11,7 @@ type Writer interface {
RawClose() error
Close() error
Level() int
IncreaseHit() uint32
SetPool(pool *WriterPool)
ResetFinish()

View File

@@ -1,11 +1,17 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
import (
"sync/atomic"
)
type BaseWriter struct {
pool *WriterPool
isFinished bool
hits uint32
}
func (this *BaseWriter) SetPool(pool *WriterPool) {
@@ -13,8 +19,11 @@ func (this *BaseWriter) SetPool(pool *WriterPool) {
}
func (this *BaseWriter) Finish(obj Writer) error {
if this.isFinished {
return nil
}
err := obj.RawClose()
if err == nil && this.pool != nil && !this.isFinished {
if err == nil && this.pool != nil {
this.pool.Put(obj)
}
this.isFinished = true
@@ -24,3 +33,7 @@ func (this *BaseWriter) Finish(obj Writer) error {
func (this *BaseWriter) ResetFinish() {
this.isFinished = false
}
func (this *BaseWriter) IncreaseHit() uint32 {
return atomic.AddUint32(&this.hits, 1)
}

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
//go:build !plus || !linux
package compressions
@@ -19,12 +19,8 @@ func NewBrotliWriter(writer io.Writer, level int) (Writer, error) {
return sharedBrotliWriterPool.Get(writer, level)
}
func newBrotliWriter(writer io.Writer, level int) (*BrotliWriter, error) {
if level <= 0 {
level = brotli.BestSpeed
} else if level > brotli.BestCompression {
level = brotli.BestCompression
}
func newBrotliWriter(writer io.Writer) (*BrotliWriter, error) {
var level = GenerateCompressLevel(brotli.BestSpeed, brotli.BestCompression)
return &BrotliWriter{
writer: brotli.NewWriterOptions(writer, brotli.WriterOptions{
Quality: level,

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions_test

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
@@ -18,12 +18,8 @@ func NewDeflateWriter(writer io.Writer, level int) (Writer, error) {
return sharedDeflateWriterPool.Get(writer, level)
}
func newDeflateWriter(writer io.Writer, level int) (Writer, error) {
if level <= 0 {
level = flate.BestSpeed
} else if level > flate.BestCompression {
level = flate.BestCompression
}
func newDeflateWriter(writer io.Writer) (Writer, error) {
var level = GenerateCompressLevel(flate.BestSpeed, flate.BestCompression)
flateWriter, err := flate.NewWriter(writer, level)
if err != nil {

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions_test

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
@@ -18,12 +18,8 @@ func NewGzipWriter(writer io.Writer, level int) (Writer, error) {
return sharedGzipWriterPool.Get(writer, level)
}
func newGzipWriter(writer io.Writer, level int) (Writer, error) {
if level <= 0 {
level = gzip.BestSpeed
} else if level > gzip.BestCompression {
level = gzip.BestCompression
}
func newGzipWriter(writer io.Writer) (Writer, error) {
var level = GenerateCompressLevel(gzip.BestSpeed, gzip.BestCompression)
gzipWriter, err := gzip.NewWriterLevel(writer, level)
if err != nil {

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions_test

View File

@@ -1,40 +1,60 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
import (
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
"github.com/TeaOSLab/EdgeNode/internal/utils/goman"
"io"
"time"
)
const maxWriterHits = 1 << 20
var isBusy = false
func init() {
if !teaconst.IsMain {
return
}
goman.New(func() {
var ticker = time.NewTicker(100 * time.Millisecond)
for range ticker.C {
if isBusy {
isBusy = false
}
}
})
}
func IsBusy() bool {
return isBusy
}
type WriterPool struct {
m map[int]chan Writer // level => chan Writer
c chan Writer // level => chan Writer
newFunc func(writer io.Writer, level int) (Writer, error)
}
func NewWriterPool(maxSize int, maxLevel int, newFunc func(writer io.Writer, level int) (Writer, error)) *WriterPool {
func NewWriterPool(maxSize int, newFunc func(writer io.Writer, level int) (Writer, error)) *WriterPool {
if maxSize <= 0 {
maxSize = 1024
}
var m = map[int]chan Writer{}
for i := 0; i <= maxLevel; i++ {
m[i] = make(chan Writer, maxSize)
}
return &WriterPool{
m: m,
c: make(chan Writer, maxSize),
newFunc: newFunc,
}
}
func (this *WriterPool) Get(parentWriter io.Writer, level int) (Writer, error) {
c, ok := this.m[level]
if !ok {
c = this.m[0]
if isBusy {
return nil, ErrIsBusy
}
select {
case writer := <-c:
case writer := <-this.c:
writer.Reset(parentWriter)
writer.ResetFinish()
return writer, nil
@@ -49,13 +69,14 @@ func (this *WriterPool) Get(parentWriter io.Writer, level int) (Writer, error) {
}
func (this *WriterPool) Put(writer Writer) {
var level = writer.Level()
c, ok := this.m[level]
if !ok {
c = this.m[0]
if writer.IncreaseHit() > maxWriterHits {
// do nothing to discard it
return
}
select {
case c <- writer:
case this.c <- writer:
default:
isBusy = true
}
}

View File

@@ -1,11 +1,9 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
import (
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
"github.com/TeaOSLab/EdgeNode/internal/utils"
"github.com/andybalholm/brotli"
"io"
)
@@ -16,11 +14,7 @@ func init() {
return
}
var maxSize = utils.SystemMemoryGB() * 256
if maxSize == 0 {
maxSize = 256
}
sharedBrotliWriterPool = NewWriterPool(maxSize, brotli.BestCompression, func(writer io.Writer, level int) (Writer, error) {
return newBrotliWriter(writer, level)
sharedBrotliWriterPool = NewWriterPool(CalculatePoolSize(), func(writer io.Writer, level int) (Writer, error) {
return newBrotliWriter(writer)
})
}

View File

@@ -1,11 +1,9 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
import (
"compress/flate"
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
"github.com/TeaOSLab/EdgeNode/internal/utils"
"io"
)
@@ -16,11 +14,7 @@ func init() {
return
}
var maxSize = utils.SystemMemoryGB() * 256
if maxSize == 0 {
maxSize = 256
}
sharedDeflateWriterPool = NewWriterPool(maxSize, flate.BestCompression, func(writer io.Writer, level int) (Writer, error) {
return newDeflateWriter(writer, level)
sharedDeflateWriterPool = NewWriterPool(CalculatePoolSize(), func(writer io.Writer, level int) (Writer, error) {
return newDeflateWriter(writer)
})
}

View File

@@ -1,11 +1,9 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
import (
"compress/gzip"
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
"github.com/TeaOSLab/EdgeNode/internal/utils"
"io"
)
@@ -16,11 +14,7 @@ func init() {
return
}
var maxSize = utils.SystemMemoryGB() * 256
if maxSize == 0 {
maxSize = 256
}
sharedGzipWriterPool = NewWriterPool(maxSize, gzip.BestCompression, func(writer io.Writer, level int) (Writer, error) {
return newGzipWriter(writer, level)
sharedGzipWriterPool = NewWriterPool(CalculatePoolSize(), func(writer io.Writer, level int) (Writer, error) {
return newGzipWriter(writer)
})
}

View File

@@ -1,11 +1,9 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
import (
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
"github.com/TeaOSLab/EdgeNode/internal/utils"
"github.com/klauspost/compress/zstd"
"io"
)
@@ -16,11 +14,7 @@ func init() {
return
}
var maxSize = utils.SystemMemoryGB() * 256
if maxSize == 0 {
maxSize = 256
}
sharedZSTDWriterPool = NewWriterPool(maxSize, int(zstd.SpeedBestCompression), func(writer io.Writer, level int) (Writer, error) {
return newZSTDWriter(writer, level)
sharedZSTDWriterPool = NewWriterPool(CalculatePoolSize(), func(writer io.Writer, level int) (Writer, error) {
return newZSTDWriter(writer)
})
}

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions
@@ -18,21 +18,18 @@ func NewZSTDWriter(writer io.Writer, level int) (Writer, error) {
return sharedZSTDWriterPool.Get(writer, level)
}
func newZSTDWriter(writer io.Writer, level int) (Writer, error) {
if level < 0 {
level = 0
}
func newZSTDWriter(writer io.Writer) (Writer, error) {
var level = 1
var zstdLevel = zstd.SpeedFastest
var zstdLevel = zstd.EncoderLevelFromZstd(level)
zstdWriter, err := zstd.NewWriter(writer, zstd.WithEncoderLevel(zstdLevel))
zstdWriter, err := zstd.NewWriter(writer, zstd.WithEncoderLevel(zstdLevel), zstd.WithWindowSize(16<<10), zstd.WithLowerEncoderMem(true))
if err != nil {
return nil, err
}
return &ZSTDWriter{
writer: zstdWriter,
level: level,
writer: zstdWriter,
level: level,
}, nil
}

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
package compressions_test

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package conns

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package conns

View File

@@ -0,0 +1,67 @@
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package conns_test
import (
"github.com/TeaOSLab/EdgeNode/internal/conns"
"github.com/TeaOSLab/EdgeNode/internal/utils/testutils"
"net"
"runtime"
"testing"
"time"
)
type testConn struct {
net.Conn
addr net.Addr
}
func (this *testConn) Read(b []byte) (n int, err error) {
return
}
func (this *testConn) Write(b []byte) (n int, err error) {
return
}
func (this *testConn) Close() error {
return nil
}
func (this *testConn) LocalAddr() net.Addr {
return &net.TCPAddr{
IP: net.ParseIP(testutils.RandIP()),
Port: 1234,
}
}
func (this *testConn) RemoteAddr() net.Addr {
if this.addr != nil {
return this.addr
}
this.addr = &net.TCPAddr{
IP: net.ParseIP(testutils.RandIP()),
Port: 1234,
}
return this.addr
}
func (this *testConn) SetDeadline(t time.Time) error {
return nil
}
func (this *testConn) SetReadDeadline(t time.Time) error {
return nil
}
func (this *testConn) SetWriteDeadline(t time.Time) error {
return nil
}
func BenchmarkMap_Add(b *testing.B) {
runtime.GOMAXPROCS(512)
var m = conns.NewMap()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
var conn = &testConn{}
m.Add(conn)
m.Remove(conn)
}
})
}

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
//go:build !plus
// +build !plus

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
//go:build plus
// +build plus

View File

@@ -1,14 +1,13 @@
package teaconst
const (
Version = "1.3.4"
Version = "1.3.9"
ProductName = "Edge Node"
ProcessName = "edge-node"
Role = "node"
EncryptKey = "8f983f4d69b83aaa0d74b21a212f6967"
EncryptMethod = "aes-256-cfb"
// SystemdServiceName systemd
@@ -17,5 +16,5 @@ const (
AccessLogSockName = "edge-node.accesslog"
CacheGarbageSockName = "edge-node.cache.garbage"
EnableKVCacheStore = false // determine store cache keys in KVStore or sqlite
EnableKVCacheStore = true // determine store cache keys in KVStore or sqlite
)

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2021 GoEdge goedge.cdn@gmail.com. All rights reserved.
package teaconst

View File

@@ -1,11 +0,0 @@
package encrypt
import "testing"
func TestMagicKeyEncode(t *testing.T) {
dst := MagicKeyEncode([]byte("Hello,World"))
t.Log("dst:", string(dst))
src := MagicKeyDecode(dst)
t.Log("src:", string(src))
}

View File

@@ -1,8 +0,0 @@
package encrypt
import "testing"
func TestFindMethodInstance(t *testing.T) {
t.Log(NewMethodInstance("a", "b", ""))
t.Log(NewMethodInstance("aes-256-cfb", "123456", ""))
}

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
//go:build linux
package firewalls
@@ -16,7 +16,7 @@ import (
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
"github.com/TeaOSLab/EdgeNode/internal/utils"
executils "github.com/TeaOSLab/EdgeNode/internal/utils/exec"
"github.com/TeaOSLab/EdgeNode/internal/zero"
"github.com/TeaOSLab/EdgeNode/internal/utils/zero"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/types"
stringutil "github.com/iwind/TeaGo/utils/string"

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
// Copyright 2022 GoEdge goedge.cdn@gmail.com. All rights reserved.
//go:build !linux
// +build !linux

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