Thanos源码专题【左扬精讲】——Thanos API 组件(release-0.26)源码阅读和分析(详解 pkg\api\blocks\v1.go)

Thanos API 组件(release-0.26)源码阅读和分析(详解 pkg\api\blocks\v1.go)

https://github.com/thanos-io/thanos/blob/v0.26.0/pkg/api/blocks/v1.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
// Copyright (c) The Thanos Authors.
// Licensed under the Apache License 2.0.
 
package v1
 
import (
    "net/http"
    "time"
 
    "github.com/go-kit/log"                                    // 日志库
    "github.com/oklog/ulid"                                    // ulid库
    "github.com/opentracing/opentracing-go"                    // opentracing库,用于分布式追踪
    "github.com/pkg/errors"                                    // 错误处理库
    "github.com/prometheus/client_golang/prometheus"           // prometheus库,用于监控和度量指标收集
    "github.com/prometheus/client_golang/prometheus/promauto"  // promauto库,用于自动注册度量指标
    "github.com/prometheus/common/route"                       // route库,用于路由管理
    "github.com/thanos-io/thanos/pkg/api"                      // api库,用于处理API请求和响应
    "github.com/thanos-io/thanos/pkg/block"                    // block库,用于处理块数据
    "github.com/thanos-io/thanos/pkg/block/metadata"           // metadata库,用于处理块元数据
    extpromhttp "github.com/thanos-io/thanos/pkg/extprom/http" // extpromhttp库,用于扩展Prometheus HTTP客户端功能
    "github.com/thanos-io/thanos/pkg/logging"                  // logging库,用于处理日志记录
    "github.com/thanos-io/thanos/pkg/objstore"                 // objstore库,用于处理对象存储
)
 
// BlocksAPI is a very simple API used by Thanos Block Viewer.
// BlocksAPI 是一个用于Thanos Block Viewer的非常简单的API。
type BlocksAPI struct {
    baseAPI          *api.BaseAPI    // 嵌入了api.BaseAPI,用于处理一些基础API操作
    logger           log.Logger      // 日志记录器,用于记录日志信息
    globalBlocksInfo *BlocksInfo     // 全局块信息
    loadedBlocksInfo *BlocksInfo     // 加载的块信息
    disableCORS      bool            // 是否禁用CORS
    bkt              objstore.Bucket // 对象存储桶,用于存储和检索块数据
}
 
// BlocksInfo 是块信息结构体,包含了标签、块元数据和刷新时间等信息。
type BlocksInfo struct {
    Label       string          `json:"label"`       // 标签,用于标识块信息
    Blocks      []metadata.Meta `json:"blocks"`      // 块元数据,包含了块的详细信息
    RefreshedAt time.Time       `json:"refreshedAt"` // 刷新时间,表示块信息最后一次刷新的时间
    Err         error           `json:"err"`         // 错误信息,如果获取块信息时发生错误,则包含具体的错误
}
 
// ActionType int32 枚举类型,表示不同的操作类型。
type ActionType int32
 
const (
    Deletion     ActionType = iota // 删除操作
    NoCompaction                   // 不压缩操作
    Unknown                        // 未知操作
)
 
// parse 函数根据传入的字符串 s 返回对应的 ActionType 类型
//
// 参数:
//
//  s string: 待解析的字符串
//
// 返回值:
//
//  ActionType: 返回对应的 ActionType 类型
func parse(s string) ActionType {
    // 根据传入的字符串s进行分支判断
    switch s {
    case "DELETION":
        // 当s为"DELETION"时,返回Deletion类型
        return Deletion
    case "NO_COMPACTION":
        // 当s为"NO_COMPACTION"时,返回NoCompaction类型
        return NoCompaction
    default:
        // 当s既不是"DELETION"也不是"NO_COMPACTION"时,返回Unknown类型
        return Unknown
    }
}
 
// NewBlocksAPI creates a simple API to be used by Thanos Block Viewer.
// NewBlocksAPI 创建一个新的 BlocksAPI 实例
//
// 参数:
// logger: 用于记录日志的 log.Logger 实例
// disableCORS: 是否禁用 CORS
// label: BlocksAPI 实例的标签
// flagsMap: 传递给 API 的标志映射
// bkt: 用于存储对象的 objstore.Bucket 实例
//
// 返回值:
// *BlocksAPI: 返回一个新的 BlocksAPI 实例
func NewBlocksAPI(logger log.Logger, disableCORS bool, label string, flagsMap map[string]string, bkt objstore.Bucket) *BlocksAPI {
    // 创建一个新的BlocksAPI实例
    return &BlocksAPI{
        // 创建baseAPI实例,传入logger, disableCORS, flagsMap参数
        baseAPI: api.NewBaseAPI(logger, disableCORS, flagsMap),
        // 传入logger参数
        logger: logger,
        // 创建globalBlocksInfo实例,并设置Blocks为空数组和Label为传入的label参数
        globalBlocksInfo: &BlocksInfo{
            Blocks: []metadata.Meta{},
            Label:  label,
        },
        // 创建loadedBlocksInfo实例,并设置Blocks为空数组和Label为传入的label参数
        loadedBlocksInfo: &BlocksInfo{
            Blocks: []metadata.Meta{},
            Label:  label,
        },
        // 传入disableCORS参数
        disableCORS: disableCORS,
        // 传入bkt参数
        bkt: bkt,
    }
}
 
// Register 注册BlocksAPI路由到路由器
//
// 参数:
//
//  r *route.Router: 路由器对象
//  tracer opentracing.Tracer: OpenTracing追踪器对象
//  logger log.Logger: 日志记录器对象
//  ins extpromhttp.InstrumentationMiddleware: 监控中间件对象
//  logMiddleware *logging.HTTPServerMiddleware: HTTP服务器中间件对象
func (bapi *BlocksAPI) Register(r *route.Router, tracer opentracing.Tracer, logger log.Logger, ins extpromhttp.InstrumentationMiddleware, logMiddleware *logging.HTTPServerMiddleware) {
    // 调用基类API的注册方法
    bapi.baseAPI.Register(r, tracer, logger, ins, logMiddleware)
 
    // 获取API的Instrumentation实例
    instr := api.GetInstr(tracer, logger, ins, logMiddleware, bapi.disableCORS)
 
    // 注册GET请求处理函数
    // 路径为"/blocks",处理函数为bapi.blocks
    r.Get("/blocks", instr("blocks", bapi.blocks))
 
    // 注册POST请求处理函数
    // 路径为"/blocks/mark",处理函数为bapi.markBlock
    r.Post("/blocks/mark", instr("blocks_mark", bapi.markBlock))
}
 
// markBlock 函数用于标记一个块(Block)执行特定的操作。
//
// 参数:
// r: *http.Request 类型,包含请求信息的HTTP请求对象。
//
// 返回值:
// interface{}: 无返回值,故为nil。
// []error: 错误列表,这里不返回错误,故为nil。
// *api.ApiError: API错误对象,当发生错误时返回。
func (bapi *BlocksAPI) markBlock(r *http.Request) (interface{}, []error, *api.ApiError) {
    // 获取请求参数
    idParam := r.FormValue("id")         // 获取请求参数中的"id",表示要操作的块的ID
    actionParam := r.FormValue("action") // 获取请求参数中的"action",表示要执行的操作类型
    detailParam := r.FormValue("detail") // 获取请求参数中的"detail",表示操作的详细信息,例如原因或备注
 
    // 检查ID是否为空
    if idParam == "" {
        return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.New("ID cannot be empty")}
    }
 
    // 检查Action是否为空
    if actionParam == "" {
        return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.New("Action cannot be empty")}
    }
 
    // 解析ULID
    id, err := ulid.Parse(idParam)
    if err != nil {
        return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf("ULID %q is not valid: %v", idParam, err)}
    }
 
    // 解析Action类型
    actionType := parse(actionParam)
    switch actionType {
    case Deletion:
        // 执行删除操作
        err := block.MarkForDeletion(r.Context(), bapi.logger, bapi.bkt, id, detailParam, promauto.With(nil).NewCounter(prometheus.CounterOpts{}))
        if err != nil {
            return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
        }
    case NoCompaction:
        // 执行不压缩操作
        err := block.MarkForNoCompact(r.Context(), bapi.logger, bapi.bkt, id, metadata.ManualNoCompactReason, detailParam, promauto.With(nil).NewCounter(prometheus.CounterOpts{}))
        if err != nil {
            return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: err}
        }
    default:
        // 返回不支持的操作错误
        return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf("not supported marker %v", actionParam)}
    }
    return nil, nil, nil
}
 
// blocks 函数用于处理BlocksAPI的blocks请求。
//
// 参数:
//
//  r *http.Request: HTTP请求对象
//
// 返回值:
//
//  interface{}: 返回的响应数据
//  []error: 返回的错误列表
//  *api.ApiError: API错误对象
func (bapi *BlocksAPI) blocks(r *http.Request) (interface{}, []error, *api.ApiError) {
    // 获取URL查询参数中的"view"参数
    viewParam := r.URL.Query().Get("view")
 
    // 如果"view"参数值为"loaded"
    if viewParam == "loaded" {
        // 返回已加载的区块信息
        return bapi.loadedBlocksInfo, nil, nil
    }
 
    // 返回全局区块信息
    return bapi.globalBlocksInfo, nil, nil
}
 
// set 方法用于更新 BlocksInfo 结构体中的数据
//
// 参数:
// - blocks:[]metadata.Meta 类型的切片,包含要更新的区块数据
// - err:error 类型,包含错误信息,如果更新成功则为 nil
func (b *BlocksInfo) set(blocks []metadata.Meta, err error) {
    // 判断是否存在错误
    if err != nil {
        // 如果存在错误,则保持上次视图不变
        // Last view is maintained.
        b.RefreshedAt = time.Now()
        b.Err = err
        return
    }
 
    // 更新视图时间
    b.RefreshedAt = time.Now()
    // 更新区块数据
    b.Blocks = blocks
    // 设置错误信息
    b.Err = err
}
 
// SetGlobal updates the global blocks' metadata in the API.
// SetGlobal 设置全局块信息
//
// 参数:
//
//  blocks - []metadata.Meta:块信息的切片
//  err - error:错误信息
//
// 说明:
//
//  将blocks和err参数传递给bapi.globalBlocksInfo的set方法,用于设置全局块信息
func (bapi *BlocksAPI) SetGlobal(blocks []metadata.Meta, err error) {
    // 设置全局块信息
    // 将blocks和err参数传递给bapi.globalBlocksInfo的set方法
    bapi.globalBlocksInfo.set(blocks, err)
}
 
// SetLoaded 设置 BlocksAPI 实例的已加载区块信息
//
// 参数:
// - blocks []metadata.Meta:已加载的区块元数据列表
// - err error:加载区块过程中出现的错误
func (bapi *BlocksAPI) SetLoaded(blocks []metadata.Meta, err error) {
    // 调用 loadedBlocksInfo 的 set 方法,将 blocks 和 err 传入
    bapi.loadedBlocksInfo.set(blocks, err)
}
posted @   左扬  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
levels of contents
点击右上角即可分享
微信分享提示