2023-03-31 10:30:33 +00:00
|
|
|
package s3local
|
|
|
|
|
|
|
|
import (
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/data"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
|
2024-01-11 18:46:57 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/xk6-frostfs/internal/datagen"
|
2023-12-14 13:22:07 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/xk6-frostfs/internal/local"
|
2023-03-31 10:30:33 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/xk6-frostfs/internal/stats"
|
|
|
|
"go.k6.io/k6/js/modules"
|
|
|
|
"go.k6.io/k6/metrics"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Client struct {
|
|
|
|
vu modules.VU
|
|
|
|
l layer.Client
|
|
|
|
ownerID *user.ID
|
|
|
|
resolver layer.BucketResolver
|
2023-12-14 13:22:07 +00:00
|
|
|
limiter local.Limiter
|
2023-03-31 10:30:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type (
|
|
|
|
SuccessOrErrorResponse struct {
|
|
|
|
Success bool
|
2023-12-14 13:22:07 +00:00
|
|
|
Abort bool
|
2023-03-31 10:30:33 +00:00
|
|
|
Error string
|
|
|
|
}
|
|
|
|
|
|
|
|
CreateBucketResponse SuccessOrErrorResponse
|
|
|
|
PutResponse SuccessOrErrorResponse
|
|
|
|
DeleteResponse SuccessOrErrorResponse
|
|
|
|
GetResponse SuccessOrErrorResponse
|
|
|
|
)
|
|
|
|
|
2024-01-11 18:46:57 +00:00
|
|
|
func (c *Client) Put(bucket, key string, payload datagen.Payload) PutResponse {
|
2023-12-14 13:22:07 +00:00
|
|
|
if c.limiter.IsFull() {
|
|
|
|
return PutResponse{
|
|
|
|
Success: false,
|
|
|
|
Abort: true,
|
|
|
|
Error: "engine size limit reached",
|
|
|
|
}
|
|
|
|
}
|
2023-03-31 10:30:33 +00:00
|
|
|
cid, err := c.resolver.Resolve(c.vu.Context(), bucket)
|
|
|
|
if err != nil {
|
|
|
|
stats.Report(c.vu, objPutFails, 1)
|
|
|
|
return PutResponse{Error: err.Error()}
|
|
|
|
}
|
|
|
|
|
|
|
|
prm := &layer.PutObjectParams{
|
|
|
|
BktInfo: &data.BucketInfo{
|
|
|
|
Name: bucket,
|
|
|
|
CID: cid,
|
|
|
|
Owner: *c.ownerID,
|
|
|
|
Created: time.Now(),
|
|
|
|
},
|
|
|
|
Header: map[string]string{},
|
|
|
|
Object: key,
|
2024-05-05 18:28:29 +00:00
|
|
|
Size: uint64(payload.Size()),
|
2024-01-11 18:46:57 +00:00
|
|
|
Reader: payload.Reader(),
|
2023-03-31 10:30:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
start := time.Now()
|
|
|
|
if _, err := c.l.PutObject(c.vu.Context(), prm); err != nil {
|
|
|
|
stats.Report(c.vu, objPutFails, 1)
|
|
|
|
return PutResponse{Error: err.Error()}
|
|
|
|
}
|
|
|
|
|
|
|
|
stats.Report(c.vu, objPutDuration, metrics.D(time.Since(start)))
|
2024-01-24 09:44:16 +00:00
|
|
|
stats.Report(c.vu, objPutSuccess, 1)
|
2023-03-31 10:30:33 +00:00
|
|
|
stats.ReportDataSent(c.vu, float64(prm.Size))
|
2024-01-24 09:44:16 +00:00
|
|
|
stats.Report(c.vu, objPutData, float64(prm.Size))
|
2023-03-31 10:30:33 +00:00
|
|
|
|
|
|
|
return PutResponse{Success: true}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) Get(bucket, key string) GetResponse {
|
|
|
|
cid, err := c.resolver.Resolve(c.vu.Context(), bucket)
|
|
|
|
if err != nil {
|
|
|
|
stats.Report(c.vu, objGetFails, 1)
|
|
|
|
return GetResponse{Error: err.Error()}
|
|
|
|
}
|
|
|
|
|
|
|
|
start := time.Now()
|
|
|
|
|
|
|
|
bktInfo := &data.BucketInfo{
|
|
|
|
Name: bucket,
|
|
|
|
CID: cid,
|
|
|
|
Owner: *c.ownerID,
|
|
|
|
}
|
|
|
|
|
|
|
|
headPrm := &layer.HeadObjectParams{
|
|
|
|
BktInfo: bktInfo,
|
|
|
|
Object: key,
|
|
|
|
}
|
|
|
|
extInfo, err := c.l.GetExtendedObjectInfo(c.vu.Context(), headPrm)
|
|
|
|
if err != nil {
|
|
|
|
stats.Report(c.vu, objGetFails, 1)
|
|
|
|
return GetResponse{Error: err.Error()}
|
|
|
|
}
|
|
|
|
|
|
|
|
wr := &recvDataReporter{}
|
|
|
|
getPrm := &layer.GetObjectParams{
|
|
|
|
BucketInfo: bktInfo,
|
|
|
|
ObjectInfo: extInfo.ObjectInfo,
|
|
|
|
Range: &layer.RangeParams{
|
|
|
|
Start: 0,
|
|
|
|
End: uint64(extInfo.ObjectInfo.Size),
|
|
|
|
},
|
|
|
|
}
|
2024-05-05 18:28:29 +00:00
|
|
|
objPayload, err := c.l.GetObject(c.vu.Context(), getPrm)
|
|
|
|
if err != nil {
|
|
|
|
stats.Report(c.vu, objGetFails, 1)
|
|
|
|
return GetResponse{Error: err.Error()}
|
|
|
|
}
|
|
|
|
err = objPayload.StreamTo(wr)
|
|
|
|
if err != nil {
|
2023-03-31 10:30:33 +00:00
|
|
|
stats.Report(c.vu, objGetFails, 1)
|
|
|
|
return GetResponse{Error: err.Error()}
|
|
|
|
}
|
|
|
|
|
|
|
|
stats.Report(c.vu, objGetDuration, metrics.D(time.Since(start)))
|
2024-01-24 09:44:16 +00:00
|
|
|
stats.Report(c.vu, objGetSuccess, 1)
|
2023-03-31 10:30:33 +00:00
|
|
|
stats.ReportDataReceived(c.vu, wr.total)
|
2024-01-24 09:44:16 +00:00
|
|
|
stats.Report(c.vu, objGetData, wr.total)
|
2023-03-31 10:30:33 +00:00
|
|
|
|
|
|
|
return GetResponse{Success: true}
|
|
|
|
}
|
|
|
|
|
|
|
|
type recvDataReporter struct{ total float64 }
|
|
|
|
|
|
|
|
func (r *recvDataReporter) Write(p []byte) (int, error) {
|
|
|
|
r.total += float64(len(p))
|
|
|
|
return len(p), nil
|
|
|
|
}
|