Skip to content

Commit

Permalink
Merge pull request #34 from peng225/obj-existence-check-improve
Browse files Browse the repository at this point in the history
Obj existence check improve
  • Loading branch information
peng225 authored Feb 14, 2023
2 parents 4c39c80 + d93a167 commit e0c47fe
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 34 deletions.
53 changes: 32 additions & 21 deletions object/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ type Object struct {
}

type ObjectMeta struct {
ObjectList []Object `json:"objectList"`
ExistingObjectIDs []int64 `json:"existingObjectIDs"`
KeyIDOffset int64 `json:"keyIDOffset"`
KeyPrefix string
ObjectList []Object `json:"objectList"`
ExistingObjectIDs []int64 `json:"existingObjectIDs"`
existingObjectIDMap map[int64]struct{}
KeyIDOffset int64 `json:"keyIDOffset"`
KeyPrefix string
}

func (obj *Object) Clear() {
Expand All @@ -53,6 +54,7 @@ func NewObjectMeta(numObj int, keyIDOffset int64) *ObjectMeta {
om.ObjectList[objID] = *NewObject(keyIDOffset + int64(objID))
}
om.ExistingObjectIDs = make([]int64, 0, int(math.Sqrt(float64(numObj))))
om.existingObjectIDMap = make(map[int64]struct{})
om.KeyIDOffset = keyIDOffset
om.KeyPrefix = generateKey(keyIDOffset)[:KeyPrefixLength]

Expand All @@ -66,18 +68,16 @@ func (om *ObjectMeta) GetRandomObject() *Object {

// Caution: this function should be called while the object lock is acquired.
func (om *ObjectMeta) RegisterToExistingList(key string) {
objID, err := strconv.ParseInt(key[len(KeyShortPrefix):], 16, 64)
objID, err := strconv.ParseInt(key[KeyPrefixLength:], 16, 64)
if err != nil {
log.Fatal(err)
}
objID -= om.KeyIDOffset
for _, eoID := range om.ExistingObjectIDs {
if eoID == objID {
// The key is already registered.
return
}
if _, ok := om.existingObjectIDMap[objID]; ok {
// The key is already registered.
return
}
om.ExistingObjectIDs = append(om.ExistingObjectIDs, objID)
om.existingObjectIDMap[objID] = struct{}{}
if len(om.ObjectList) < len(om.ExistingObjectIDs) {
log.Fatal("Invalid contents of existing object ID list.")
}
Expand All @@ -87,34 +87,45 @@ func (om *ObjectMeta) PopExistingRandomObject() *Object {
if len(om.ExistingObjectIDs) == 0 {
return nil
}
existingObjID := rand.Intn(len(om.ExistingObjectIDs))
eoIDIndex := rand.Intn(len(om.ExistingObjectIDs))

objID := om.ExistingObjectIDs[existingObjID]
objID := om.ExistingObjectIDs[eoIDIndex]
// Delete the `existingObjID`-th entry from existing object ID list
om.ExistingObjectIDs[existingObjID] = om.ExistingObjectIDs[len(om.ExistingObjectIDs)-1]
om.ExistingObjectIDs[eoIDIndex] = om.ExistingObjectIDs[len(om.ExistingObjectIDs)-1]
om.ExistingObjectIDs = om.ExistingObjectIDs[:len(om.ExistingObjectIDs)-1]
if _, ok := om.existingObjectIDMap[objID]; !ok {
log.Fatalf("objID 0x%x found in ExistingObjectIDs, but not in existingObjectIDMap.", objID)
}
delete(om.existingObjectIDMap, objID)
return &om.ObjectList[objID]
}

func (om *ObjectMeta) GetExistingRandomObject() *Object {
if len(om.ExistingObjectIDs) == 0 {
return nil
}
existingObjID := rand.Intn(len(om.ExistingObjectIDs))
eoIDIndex := rand.Intn(len(om.ExistingObjectIDs))

objID := om.ExistingObjectIDs[existingObjID]
objID := om.ExistingObjectIDs[eoIDIndex]
return &om.ObjectList[objID]
}

func (om *ObjectMeta) Exist(key string) bool {
for _, id := range om.ExistingObjectIDs {
if key == om.ObjectList[id].Key {
return true
}
objID, err := strconv.ParseInt(key[KeyPrefixLength:], 16, 64)
if err != nil {
log.Fatal(err)
}
return false
_, ok := om.existingObjectIDMap[objID]
return ok
}

func (om *ObjectMeta) GetHeadAndTailKey() (string, string) {
return om.ObjectList[0].Key, om.ObjectList[len(om.ObjectList)-1].Key
}

func (om *ObjectMeta) TidyUp() {
om.existingObjectIDMap = make(map[int64]struct{})
for _, objID := range om.ExistingObjectIDs {
om.existingObjectIDMap[objID] = struct{}{}
}
}
5 changes: 4 additions & 1 deletion runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func (r *Runner) init() {
for j, bucketName := range r.execContext.BucketNames {
r.execContext.Workers[i].BucketsWithObject[j] = &BucketWithObject{
BucketName: bucketName,
ObjectMata: object.NewObjectMeta(
ObjectMeta: object.NewObjectMeta(
r.execContext.NumObj/r.execContext.NumWorker,
(int64(r.processID)<<32)+(int64(i)<<24)),
}
Expand All @@ -144,6 +144,9 @@ func (r *Runner) init() {
r.execContext.Workers[i].maxSize = r.execContext.MaxSize
r.execContext.Workers[i].client = r.client
r.execContext.Workers[i].st = &r.st
for j, _ := range r.execContext.Workers[i].BucketsWithObject {
r.execContext.Workers[i].BucketsWithObject[j].ObjectMeta.TidyUp()
}
r.execContext.Workers[i].ShowInfo()
}
}
Expand Down
24 changes: 12 additions & 12 deletions runner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,26 @@ type Worker struct {

type BucketWithObject struct {
BucketName string `json:"bucketName"`
ObjectMata *object.ObjectMeta `json:"objectMeta"`
ObjectMeta *object.ObjectMeta `json:"objectMeta"`
}

func (w *Worker) ShowInfo() {
// Only show the key range of the first bucket
// because key range is the same for all buckets.
head, tail := w.BucketsWithObject[0].ObjectMata.GetHeadAndTailKey()
head, tail := w.BucketsWithObject[0].ObjectMeta.GetHeadAndTailKey()
log.Printf("Worker ID = %#x, Key = [%s, %s]\n", w.id, head, tail)
}

func (w *Worker) Put() error {
bucketWithObj := w.selectBucketWithObject()
obj := bucketWithObj.ObjectMata.GetRandomObject()
obj := bucketWithObj.ObjectMeta.GetRandomObject()

// Validation before write
getBeforeBody, err := w.client.GetObject(bucketWithObj.BucketName, obj.Key)
if err != nil {
var nsk *s3_client.NoSuchKey
if errors.As(err, &nsk) {
if bucketWithObj.ObjectMata.Exist(obj.Key) {
if bucketWithObj.ObjectMeta.Exist(obj.Key) {
// expect: exists, actual: does not exist
err = fmt.Errorf("An object has been lost. (key = %s)", obj.Key)
log.Println(err.Error())
Expand All @@ -54,7 +54,7 @@ func (w *Worker) Put() error {
}
} else {
defer getBeforeBody.Close()
if !bucketWithObj.ObjectMata.Exist(obj.Key) {
if !bucketWithObj.ObjectMeta.Exist(obj.Key) {
// expect: does not exist, actual: exists
err = fmt.Errorf("An unexpected object was found. (key = %s)", obj.Key)
log.Println(err.Error())
Expand All @@ -69,7 +69,7 @@ func (w *Worker) Put() error {
w.st.AddGetForValidCount()
}

bucketWithObj.ObjectMata.RegisterToExistingList(obj.Key)
bucketWithObj.ObjectMeta.RegisterToExistingList(obj.Key)
obj.WriteCount++
body, size, err := pattern.Generate(w.minSize, w.maxSize, w.id, bucketWithObj.BucketName, obj)
obj.Size = size
Expand Down Expand Up @@ -107,7 +107,7 @@ func (w *Worker) Put() error {

func (w *Worker) Get() error {
bucketWithObj := w.selectBucketWithObject()
obj := bucketWithObj.ObjectMata.GetExistingRandomObject()
obj := bucketWithObj.ObjectMeta.GetExistingRandomObject()
if obj == nil {
return nil
}
Expand Down Expand Up @@ -136,21 +136,21 @@ func (w *Worker) Get() error {
func (w *Worker) List() error {
bucketWithObj := w.selectBucketWithObject()

objectNames, err := w.client.ListObjects(bucketWithObj.BucketName, bucketWithObj.ObjectMata.KeyPrefix)
objectNames, err := w.client.ListObjects(bucketWithObj.BucketName, bucketWithObj.ObjectMeta.KeyPrefix)
if err != nil {
log.Println(err.Error())
return err
}

if len(bucketWithObj.ObjectMata.ExistingObjectIDs) != len(objectNames) {
if len(bucketWithObj.ObjectMeta.ExistingObjectIDs) != len(objectNames) {
err = fmt.Errorf("Invalid number of objects found as a result of the LIST operation. expected = %d, actual = %d",
len(bucketWithObj.ObjectMata.ExistingObjectIDs), len(objectNames))
len(bucketWithObj.ObjectMeta.ExistingObjectIDs), len(objectNames))
log.Println(err.Error())
return err
}

for _, objName := range objectNames {
if !bucketWithObj.ObjectMata.Exist(objName) {
if !bucketWithObj.ObjectMeta.Exist(objName) {
err = fmt.Errorf("Invalid object key '%s' found in the result of the LIST operation. workerID = 0x%x",
objName, w.id)
log.Println(err.Error())
Expand All @@ -164,7 +164,7 @@ func (w *Worker) List() error {

func (w *Worker) Delete() error {
bucketWithObj := w.selectBucketWithObject()
obj := bucketWithObj.ObjectMata.PopExistingRandomObject()
obj := bucketWithObj.ObjectMeta.PopExistingRandomObject()
if obj == nil {
return nil
}
Expand Down

0 comments on commit e0c47fe

Please sign in to comment.