diff --git a/api/object-handlers.go b/api/object-handlers.go index 00442a9f1..8bae017f9 100644 --- a/api/object-handlers.go +++ b/api/object-handlers.go @@ -963,7 +963,7 @@ func (api ObjectAPIHandlers) AppendObjectHandler(w http.ResponseWriter, r *http. return } - if objInfo != nil && objInfo.Type != meta.ObjectTypeAppendable { + if objInfo != nil && (objInfo.Type != meta.ObjectTypeAppendable || objInfo.DeleteMarker) { WriteErrorResponse(w, r, ErrObjectNotAppendable) return } diff --git a/meta/client/client.go b/meta/client/client.go index 2ca46a525..2f0c931c3 100644 --- a/meta/client/client.go +++ b/meta/client/client.go @@ -2,6 +2,7 @@ package client import ( "database/sql" + "github.com/journeymidnight/yig/api/datatype" . "github.com/journeymidnight/yig/meta/types" ) @@ -16,7 +17,7 @@ type Client interface { GetObject(bucketName, objectName, version string) (object *Object, err error) GetAllObject(bucketName, objectName, version string) (object []*Object, err error) PutObject(object *Object, tx DB) error - UpdateAppendObject(object *Object, tx DB) error + UpdateAppendObject(object *Object, tx DB, versionId string) error RenameObjectPart(object *Object, sourceObject string, tx DB) (err error) RenameObject(object *Object, sourceObject string, tx DB) (err error) ReplaceObjectMetas(object *Object, tx DB) (err error) @@ -29,7 +30,7 @@ type Client interface { PutBucket(bucket Bucket) error CheckAndPutBucket(bucket Bucket) (bool, error) DeleteBucket(bucket Bucket) error - ListObjects(bucketName, marker, verIdMarker, prefix, delimiter string, versioned bool, maxKeys int) (retObjects []*Object, prefixes []string, truncated bool, nextMarker, nextVerIdMarker string, err error) + ListObjects(bucketName, marker, verIdMarker, prefix, delimiter string, versioned bool, maxKeys int, withDeleteMarker bool) (retObjects []*Object, prefixes []string, truncated bool, nextMarker, nextVerIdMarker string, err error) UpdateUsage(bucketName string, size int64, tx DB) error //multipart @@ -38,10 +39,6 @@ type Client interface { PutObjectPart(multipart *Multipart, part *Part, tx DB) (err error) DeleteMultipart(multipart *Multipart, tx DB) (err error) ListMultipartUploads(bucketName, keyMarker, uploadIdMarker, prefix, delimiter, encodingType string, maxUploads int) (uploads []datatype.Upload, prefixs []string, isTruncated bool, nextKeyMarker, nextUploadIdMarker string, err error) - //objmap - GetObjectMap(bucketName, objectName string) (objMap *ObjMap, err error) - PutObjectMap(objMap *ObjMap, tx DB) error - DeleteObjectMap(objMap *ObjMap, tx DB) error //cluster GetClusters() (cluster []Cluster, err error) //lc diff --git a/meta/client/tidbclient/bucket.go b/meta/client/tidbclient/bucket.go index bf4f28b79..666eef7fe 100644 --- a/meta/client/tidbclient/bucket.go +++ b/meta/client/tidbclient/bucket.go @@ -3,7 +3,6 @@ package tidbclient import ( "database/sql" "encoding/json" - "strconv" "strings" "time" @@ -146,10 +145,7 @@ func (t *TidbClient) CheckAndPutBucket(bucket Bucket) (bool, error) { return processed, err } -func (t *TidbClient) ListObjects(bucketName, marker, verIdMarker, prefix, delimiter string, versioned bool, maxKeys int) (retObjects []*Object, prefixes []string, truncated bool, nextMarker, nextVerIdMarker string, err error) { - if versioned { - return - } +func (t *TidbClient) ListObjects(bucketName, marker, verIdMarker, prefix, delimiter string, versioned bool, maxKeys int, withDeleteMarker bool) (retObjects []*Object, prefixes []string, truncated bool, nextMarker, nextVerIdMarker string, err error) { var count int var exit bool objectMap := make(map[string]struct{}) @@ -175,7 +171,7 @@ func (t *TidbClient) ListObjects(bucketName, marker, verIdMarker, prefix, delimi loopcount += 1 //fetch related date var bucketname, name string - var version uint64 + var version uint64 // Internal version, the same as in DB. var nullversion, deletemarker bool err = rows.Scan( &bucketname, @@ -201,13 +197,15 @@ func (t *TidbClient) ListObjects(bucketName, marker, verIdMarker, prefix, delimi continue } //filte by objectname - if _, ok := objectMap[name]; !ok { - objectMap[name] = struct{}{} - } else { - continue + if !versioned { + if _, ok := objectMap[name]; !ok { + objectMap[name] = struct{}{} + } else { + continue + } } //filte by deletemarker - if deletemarker { + if deletemarker && !withDeleteMarker { continue } if name == omarker { @@ -236,8 +234,7 @@ func (t *TidbClient) ListObjects(bucketName, marker, verIdMarker, prefix, delimi } } var o *Object - Strver := strconv.FormatUint(version, 10) - o, err = t.GetObject(bucketname, name, Strver) + o, err = t.GetObject(bucketname, name, ConvertRawVersionToS3Version(version)) if err != nil { return } diff --git a/meta/client/tidbclient/object.go b/meta/client/tidbclient/object.go index 03fdbc845..0f743a3eb 100644 --- a/meta/client/tidbclient/object.go +++ b/meta/client/tidbclient/object.go @@ -9,6 +9,7 @@ import ( "time" . "github.com/journeymidnight/yig/error" + "github.com/journeymidnight/yig/helper" . "github.com/journeymidnight/yig/meta/types" "github.com/xxtea/xxtea-go/xxtea" ) @@ -23,9 +24,16 @@ func (t *TidbClient) GetObject(bucketName, objectName, version string) (object * if version == "" { sqltext += "order by bucketname,name,version limit 1;" row = t.Client.QueryRow(sqltext, bucketName, objectName) + } else if version == ObjectNullVersion { + sqltext += "and nullversion=1 limit 1;" // There should be only one NullVersion object. + row = t.Client.QueryRow(sqltext, bucketName, objectName) } else { sqltext += "and version=?;" - row = t.Client.QueryRow(sqltext, bucketName, objectName, version) + internalVersion, err := ConvertS3VersionToRawVersion(version) + if err != nil { + return nil, ErrInternalError + } + row = t.Client.QueryRow(sqltext, bucketName, objectName, internalVersion) } object = &Object{} err = row.Scan( @@ -79,32 +87,44 @@ func (t *TidbClient) GetObject(bucketName, objectName, version string) (object * } object.PartsIndex = &SimpleIndex{Index: sortedPartNum} } - var reversedTime uint64 - timestamp := math.MaxUint64 - reversedTime - timeData := []byte(strconv.FormatUint(timestamp, 10)) - object.VersionId = hex.EncodeToString(xxtea.Encrypt(timeData, XXTEA_KEY)) + object.VersionId = ConvertRawVersionToS3Version(iversion) + return } +func ConvertRawVersionToS3Version(rawVersion uint64) string { + return hex.EncodeToString(xxtea.Encrypt([]byte(strconv.FormatUint(rawVersion, 10)), XXTEA_KEY)) +} + +func ConvertS3VersionToRawVersion(s3Version string) (string, error) { + versionEncryped, err := hex.DecodeString(s3Version) + if err != nil { + helper.Logger.Error("Err in DecodeString()", s3Version) + return "", ErrInternalError + } + + return string(xxtea.Decrypt(versionEncryped, XXTEA_KEY)), nil +} + func (t *TidbClient) GetAllObject(bucketName, objectName, version string) (object []*Object, err error) { sqltext := "select version from objects where bucketname=? and name=?;" - var versions []string + var versions []uint64 rows, err := t.Client.Query(sqltext, bucketName, objectName) if err != nil { return } defer rows.Close() for rows.Next() { - var sversion string - err = rows.Scan(&sversion) + var iversion uint64 + err = rows.Scan(&iversion) if err != nil { return } - versions = append(versions, sversion) + versions = append(versions, iversion) } for _, v := range versions { var obj *Object - obj, err = t.GetObject(bucketName, objectName, v) + obj, err = t.GetObject(bucketName, objectName, ConvertRawVersionToS3Version(v)) if err != nil { return } @@ -143,11 +163,15 @@ func (t *TidbClient) ReplaceObjectMetas(object *Object, tx DB) (err error) { return } -func (t *TidbClient) UpdateAppendObject(object *Object, tx DB) (err error) { +func (t *TidbClient) UpdateAppendObject(object *Object, tx DB, versionId string) (err error) { if tx == nil { tx = t.Client } - sql, args := object.GetAppendSql() + rawVersionId, err := ConvertS3VersionToRawVersion(versionId) + if err != nil { + return err + } + sql, args := object.GetAppendSql(rawVersionId) _, err = tx.Exec(sql, args...) return err } @@ -167,7 +191,8 @@ func (t *TidbClient) PutObject(object *Object, tx DB) (err error) { } }() } - sql, args := object.GetCreateSql() + sql, args, iversion := object.GetCreateSql() + object.VersionId = ConvertRawVersionToS3Version(iversion) _, err = tx.Exec(sql, args...) if object.Parts != nil { v := math.MaxUint64 - uint64(object.LastModifiedTime.UnixNano()) @@ -204,11 +229,13 @@ func (t *TidbClient) DeleteObject(object *Object, tx DB) (err error) { sqltext := "delete from objects where name=? and bucketname=? and version=?;" _, err = tx.Exec(sqltext, object.Name, object.BucketName, version) if err != nil { + helper.Logger.Error(object.Name, object.BucketName, version) return err } sqltext = "delete from objectpart where objectname=? and bucketname=? and version=?;" _, err = tx.Exec(sqltext, object.Name, object.BucketName, version) if err != nil { + helper.Logger.Error(object.Name, object.BucketName, version) return err } return nil diff --git a/meta/client/tidbclient/objmap.go b/meta/client/tidbclient/objmap.go deleted file mode 100644 index 4f0642b35..000000000 --- a/meta/client/tidbclient/objmap.go +++ /dev/null @@ -1,40 +0,0 @@ -package tidbclient - -import ( - . "github.com/journeymidnight/yig/meta/types" - "strconv" -) - -//objmap -func (t *TidbClient) GetObjectMap(bucketName, objectName string) (objMap *ObjMap, err error) { - objMap = &ObjMap{} - sqltext := "select bucketname,objectname,nullvernum from objmap where bucketname=? and objectName=?;" - err = t.Client.QueryRow(sqltext, bucketName, objectName).Scan( - &objMap.BucketName, - &objMap.Name, - &objMap.NullVerNum, - ) - if err != nil { - return - } - objMap.NullVerId = strconv.FormatUint(objMap.NullVerNum, 10) - return -} - -func (t *TidbClient) PutObjectMap(objMap *ObjMap, tx DB) (err error) { - if tx == nil { - tx = t.Client - } - sqltext := "insert into objmap(bucketname,objectname,nullvernum) values(?,?,?);" - _, err = tx.Exec(sqltext, objMap.BucketName, objMap.Name, objMap.NullVerNum) - return err -} - -func (t *TidbClient) DeleteObjectMap(objMap *ObjMap, tx DB) (err error) { - if tx == nil { - tx = t.Client - } - sqltext := "delete from objmap where bucketname=? and objectname=?;" - _, err = tx.Exec(sqltext, objMap.BucketName, objMap.Name) - return err -} diff --git a/meta/object.go b/meta/object.go index 717b35f7a..38653085a 100644 --- a/meta/object.go +++ b/meta/object.go @@ -2,6 +2,7 @@ package meta import ( "database/sql" + . "github.com/journeymidnight/yig/error" "github.com/journeymidnight/yig/helper" . "github.com/journeymidnight/yig/meta/types" @@ -46,11 +47,6 @@ func (m *Meta) GetAllObject(bucketName string, objectName string) (object []*Obj return m.Client.GetAllObject(bucketName, objectName, "") } -func (m *Meta) GetObjectMap(bucketName, objectName string) (objMap *ObjMap, err error) { - m.Client.GetObjectMap(bucketName, objectName) - return -} - func (m *Meta) GetObjectVersion(bucketName, objectName, version string, willNeed bool) (object *Object, err error) { getObjectVersion := func() (o interface{}, err error) { object, err := m.Client.GetObject(bucketName, objectName, version) @@ -81,7 +77,7 @@ func (m *Meta) GetObjectVersion(bucketName, objectName, version string, willNeed return object, nil } -func (m *Meta) PutObject(object *Object, multipart *Multipart, objMap *ObjMap, updateUsage bool) error { +func (m *Meta) PutObject(object *Object, multipart *Multipart, updateUsage bool) error { tx, err := m.Client.NewTrans() if err != nil { return err @@ -97,13 +93,6 @@ func (m *Meta) PutObject(object *Object, multipart *Multipart, objMap *ObjMap, u return err } - if objMap != nil { - err = m.Client.PutObjectMap(objMap, tx) - if err != nil { - return err - } - } - if multipart != nil { err = m.Client.DeleteMultipart(multipart, tx) if err != nil { @@ -145,12 +134,7 @@ func (m *Meta) ReplaceObjectMetas(object *Object) error { return err } -func (m *Meta) PutObjMapEntry(objMap *ObjMap) error { - err := m.Client.PutObjectMap(objMap, nil) - return err -} - -func (m *Meta) DeleteObject(object *Object, DeleteMarker bool, objMap *ObjMap) (err error) { +func (m *Meta) DeleteObject(object *Object, DeleteMarker bool) (err error) { var tx *sql.Tx tx, err = m.Client.NewTrans() if err != nil { @@ -167,20 +151,16 @@ func (m *Meta) DeleteObject(object *Object, DeleteMarker bool, objMap *ObjMap) ( err = m.Client.DeleteObject(object, tx) if err != nil { + helper.Logger.Error(err) return err } - if objMap != nil { - err = m.Client.DeleteObjectMap(objMap, tx) - if err != nil { - return err - } - } - if DeleteMarker { return nil } + helper.Logger.Info("DeleteObject meta: gc") + err = m.Client.PutObjectToGarbageCollection(object, tx) if err != nil { return err @@ -189,7 +169,7 @@ func (m *Meta) DeleteObject(object *Object, DeleteMarker bool, objMap *ObjMap) ( return m.Client.UpdateUsage(object.BucketName, -object.Size, tx) } -func (m *Meta) AppendObject(object *Object, isExist bool) error { +func (m *Meta) AppendObject(object *Object, isExist bool, versionId string) error { tx, err := m.Client.NewTrans() if err != nil { return err @@ -202,7 +182,7 @@ func (m *Meta) AppendObject(object *Object, isExist bool) error { if !isExist { err = m.Client.PutObject(object, tx) } else { - err = m.Client.UpdateAppendObject(object, tx) + err = m.Client.UpdateAppendObject(object, tx, versionId) } if err != nil { return err diff --git a/meta/types/object.go b/meta/types/object.go index dda5fe73a..c518e8db2 100644 --- a/meta/types/object.go +++ b/meta/types/object.go @@ -48,6 +48,8 @@ type Object struct { StorageClass StorageClass } +const ObjectNullVersion = "null" + type ObjectType int const ( @@ -127,20 +129,20 @@ func (o *Object) encryptSseKey() (err error) { } func (o *Object) GetVersionId() string { - if o.NullVersion { + if o.NullVersion || o.VersionId == "" { return "null" } if o.VersionId != "" { return o.VersionId } - timeData := []byte(strconv.FormatUint(uint64(o.LastModifiedTime.UnixNano()), 10)) + timeData := []byte(strconv.FormatUint(math.MaxUint64-uint64(o.LastModifiedTime.UnixNano()), 10)) o.VersionId = hex.EncodeToString(xxtea.Encrypt(timeData, XXTEA_KEY)) return o.VersionId } //Tidb related function -func (o *Object) GetCreateSql() (string, []interface{}) { +func (o *Object) GetCreateSql() (string, []interface{}, uint64) { version := math.MaxUint64 - uint64(o.LastModifiedTime.UnixNano()) customAttributes, _ := json.Marshal(o.CustomAttributes) acl, _ := json.Marshal(o.ACL) @@ -151,14 +153,14 @@ func (o *Object) GetCreateSql() (string, []interface{}) { args := []interface{}{o.BucketName, o.Name, version, o.Location, o.Pool, o.OwnerId, o.Size, o.ObjectId, lastModifiedTime, o.Etag, o.ContentType, customAttributes, acl, o.NullVersion, o.DeleteMarker, o.SseType, o.EncryptionKey, o.InitializationVector, o.Type, o.StorageClass} - return sql, args + return sql, args, version } -func (o *Object) GetAppendSql() (string, []interface{}) { +func (o *Object) GetAppendSql(oldRawVersion string) (string, []interface{}) { version := math.MaxUint64 - uint64(o.LastModifiedTime.UnixNano()) lastModifiedTime := o.LastModifiedTime.Format(TIME_LAYOUT_TIDB) - sql := "update objects set lastmodifiedtime=?, size=?, version=? where bucketname=? and name=?" - args := []interface{}{lastModifiedTime, o.Size, version, o.BucketName, o.Name} + sql := "update objects set lastmodifiedtime=?, size=?, version=? where bucketname=? and name=? and version=?" + args := []interface{}{lastModifiedTime, o.Size, version, o.BucketName, o.Name, oldRawVersion} return sql, args } diff --git a/meta/types/objectmap.go b/meta/types/objectmap.go deleted file mode 100644 index 8487717e4..000000000 --- a/meta/types/objectmap.go +++ /dev/null @@ -1,10 +0,0 @@ -package types - -type ObjMap struct { - Rowkey []byte // Rowkey cache - Name string - BucketName string - NullVerNum uint64 - NullVerId string -} - diff --git a/storage/backend_ceph.go b/storage/backend_ceph.go index 163ea7a0c..201cba19d 100644 --- a/storage/backend_ceph.go +++ b/storage/backend_ceph.go @@ -68,6 +68,7 @@ func (yig *YigStorage) AppendObject(bucketName string, objectName string, creden var poolName, oid string var initializationVector []byte var objSize int64 + var oldVersionId string if objInfo != nil { cephCluster = yig.DataStorage[objInfo.Location] // Every appendable file must be treated as a big file @@ -76,6 +77,7 @@ func (yig *YigStorage) AppendObject(bucketName string, objectName string, creden initializationVector = objInfo.InitializationVector objSize = objInfo.Size storageClass = objInfo.StorageClass + oldVersionId = objInfo.VersionId helper.Logger.Println(20, "request append oid:", oid, "iv:", initializationVector, "size:", objSize) } else { // New appendable object @@ -152,7 +154,7 @@ func (yig *YigStorage) AppendObject(bucketName string, objectName string, creden result.NextPosition = object.Size helper.Logger.Println(20, "Append info.", "bucket:", bucketName, "objName:", objectName, "oid:", oid, "objSize:", object.Size, "bytesWritten:", bytesWritten, "storageClass:", storageClass) - err = yig.MetaStorage.AppendObject(object, objInfo != nil) + err = yig.MetaStorage.AppendObject(object, objInfo != nil, oldVersionId) if err != nil { return } diff --git a/storage/bucket.go b/storage/bucket.go index be7958f6b..b1e3a49fa 100644 --- a/storage/bucket.go +++ b/storage/bucket.go @@ -448,7 +448,7 @@ func (yig *YigStorage) DeleteBucket(bucketName string, credential common.Credent } // Check if bucket is empty - objs, _, _, _, _, err := yig.MetaStorage.Client.ListObjects(bucketName, "", "", "", "", false, 1) + objs, _, _, _, _, err := yig.MetaStorage.Client.ListObjects(bucketName, "", "", "", "", false, 1, true) if err != nil { return err } @@ -491,10 +491,22 @@ func (yig *YigStorage) DeleteBucket(bucketName string, credential common.Credent return nil } +// Without delete-marker. func (yig *YigStorage) ListObjectsInternal(bucketName string, request datatype.ListObjectsRequest) (retObjects []*meta.Object, prefixes []string, truncated bool, nextMarker, nextVerIdMarker string, err error) { + return yig.ListObjectsInternalCore(bucketName, request, false) +} + +func (yig *YigStorage) ListObjectsInternalWithDeleteMarker(bucketName string, + request datatype.ListObjectsRequest) (retObjects []*meta.Object, prefixes []string, truncated bool, + nextMarker, nextVerIdMarker string, err error) { + return yig.ListObjectsInternalCore(bucketName, request, true) +} +func (yig *YigStorage) ListObjectsInternalCore(bucketName string, + request datatype.ListObjectsRequest, withDeleteMarker bool) (retObjects []*meta.Object, prefixes []string, truncated bool, + nextMarker, nextVerIdMarker string, err error) { var marker string var verIdMarker string if request.Versioned { @@ -515,8 +527,9 @@ func (yig *YigStorage) ListObjectsInternal(bucketName string, } helper.Logger.Info("Prefix:", request.Prefix, "Marker:", request.Marker, "MaxKeys:", request.MaxKeys, "Delimiter:", request.Delimiter, "Version:", request.Version, - "keyMarker:", request.KeyMarker, "versionIdMarker:", request.VersionIdMarker) - return yig.MetaStorage.Client.ListObjects(bucketName, marker, verIdMarker, request.Prefix, request.Delimiter, request.Versioned, request.MaxKeys) + "keyMarker:", request.KeyMarker, "versionIdMarker:", request.VersionIdMarker, + "withDeleteMarker", withDeleteMarker) + return yig.MetaStorage.Client.ListObjects(bucketName, marker, verIdMarker, request.Prefix, request.Delimiter, request.Versioned, request.MaxKeys, withDeleteMarker) } func (yig *YigStorage) ListObjects(credential common.Credential, bucketName string, @@ -617,7 +630,7 @@ func (yig *YigStorage) ListVersionedObjects(credential common.Credential, bucket } } - retObjects, prefixes, truncated, nextMarker, nextVerIdMarker, err := yig.ListObjectsInternal(bucketName, request) + retObjects, prefixes, truncated, nextMarker, nextVerIdMarker, err := yig.ListObjectsInternalWithDeleteMarker(bucketName, request) if truncated && len(nextMarker) != 0 { result.NextKeyMarker = nextMarker result.NextVersionIdMarker = nextVerIdMarker diff --git a/storage/multipart.go b/storage/multipart.go index 7571c705b..97c5e16eb 100644 --- a/storage/multipart.go +++ b/storage/multipart.go @@ -610,28 +610,15 @@ func (yig *YigStorage) CompleteMultipartUpload(credential common.Credential, buc StorageClass: multipart.Metadata.StorageClass, } - var nullVerNum uint64 - nullVerNum, err = yig.checkOldObject(bucketName, objectName, bucket.Versioning) + err = yig.checkOldObject(bucketName, objectName, bucket.Versioning) if err != nil { return } - if bucket.Versioning == "Enabled" { - result.VersionId = object.GetVersionId() - } - // update null version number - if bucket.Versioning == "Suspended" { - nullVerNum = uint64(object.LastModifiedTime.UnixNano()) - } - objMap := &meta.ObjMap{ - Name: objectName, - BucketName: bucketName, - } + err = yig.MetaStorage.PutObject(object, &multipart, false) - if nullVerNum != 0 { - err = yig.MetaStorage.PutObject(object, &multipart, objMap, false) - } else { - err = yig.MetaStorage.PutObject(object, &multipart, nil, false) + if bucket.Versioning == "Enabled" { + result.VersionId = object.GetVersionId() } sseRequest := multipart.Metadata.SseRequest diff --git a/storage/object.go b/storage/object.go index 83083c293..99dea934d 100644 --- a/storage/object.go +++ b/storage/object.go @@ -615,39 +615,26 @@ func (yig *YigStorage) PutObject(bucketName string, objectName string, credentia } result.LastModified = object.LastModifiedTime - var nullVerNum uint64 - nullVerNum, err = yig.checkOldObject(bucketName, objectName, bucket.Versioning) - if err != nil { + + // Delete old object if necessary. + if err = yig.checkOldObject(bucketName, objectName, bucket.Versioning); err != nil { RecycleQueue <- maybeObjectToRecycle return } - if bucket.Versioning == meta.VersionEnabled { - result.VersionId = object.GetVersionId() - } - // update null version number - if bucket.Versioning == meta.VersionSuspended { - nullVerNum = uint64(object.LastModifiedTime.UnixNano()) - } - - if nullVerNum != 0 { - objMap := &meta.ObjMap{ - Name: objectName, - BucketName: bucketName, - } - err = yig.MetaStorage.PutObject(object, nil, objMap, true) - } else { - err = yig.MetaStorage.PutObject(object, nil, nil, true) - } - if err != nil { + if err = yig.MetaStorage.PutObject(object, nil, true); err != nil { RecycleQueue <- maybeObjectToRecycle return } - if err == nil { - yig.MetaStorage.Cache.Remove(redis.ObjectTable, bucketName+":"+objectName+":") - yig.DataCache.Remove(bucketName + ":" + objectName + ":" + object.GetVersionId()) + // object.VersionId is filled in meta.PutObject + if bucket.Versioning == meta.VersionEnabled { + result.VersionId = object.VersionId } + + yig.MetaStorage.Cache.Remove(redis.ObjectTable, bucketName+":"+objectName+":") + yig.DataCache.Remove(bucketName + ":" + objectName + ":" + object.GetVersionId()) + return result, nil } @@ -878,47 +865,32 @@ func (yig *YigStorage) CopyObject(targetObject *meta.Object, source io.Reader, c result.LastModified = targetObject.LastModifiedTime - var nullVerNum uint64 - nullVerNum, err = yig.checkOldObject(targetObject.BucketName, targetObject.Name, bucket.Versioning) + err = yig.checkOldObject(targetObject.BucketName, targetObject.Name, bucket.Versioning) if err != nil { RecycleQueue <- maybeObjectToRecycle return } - if bucket.Versioning == "Enabled" { - result.VersionId = targetObject.GetVersionId() - } - // update null version number - if bucket.Versioning == "Suspended" { - nullVerNum = uint64(targetObject.LastModifiedTime.UnixNano()) - } - - objMap := &meta.ObjMap{ - Name: targetObject.Name, - BucketName: targetObject.BucketName, - } - - if nullVerNum != 0 { - objMap.NullVerNum = nullVerNum - err = yig.MetaStorage.PutObject(targetObject, nil, objMap, true) - } else { - err = yig.MetaStorage.PutObject(targetObject, nil, nil, true) - } + err = yig.MetaStorage.PutObject(targetObject, nil, true) if err != nil { RecycleQueue <- maybeObjectToRecycle return } + if bucket.Versioning == "Enabled" { + result.VersionId = targetObject.GetVersionId() + } + yig.MetaStorage.Cache.Remove(redis.ObjectTable, targetObject.BucketName+":"+targetObject.Name+":") yig.DataCache.Remove(targetObject.BucketName + ":" + targetObject.Name + ":" + targetObject.GetVersionId()) return result, nil } -func (yig *YigStorage) removeByObject(object *meta.Object, objMap *meta.ObjMap) (err error) { - - err = yig.MetaStorage.DeleteObject(object, object.DeleteMarker, objMap) +func (yig *YigStorage) removeByObject(object *meta.Object) (err error) { + err = yig.MetaStorage.DeleteObject(object, object.DeleteMarker) if err != nil { + helper.Logger.Error("removeByObject", err) return } return nil @@ -926,14 +898,9 @@ func (yig *YigStorage) removeByObject(object *meta.Object, objMap *meta.ObjMap) func (yig *YigStorage) getObjWithVersion(bucketName, objectName, version string) (object *meta.Object, err error) { if version == "null" { - objMap, err := yig.MetaStorage.GetObjectMap(bucketName, objectName) - if err != nil { - return nil, err - } - version = objMap.NullVerId + version = meta.ObjectNullVersion } - return yig.MetaStorage.GetObjectVersion(bucketName, objectName, version, true) - + return yig.MetaStorage.GetObjectVersion(bucketName, objectName, version, false) } func (yig *YigStorage) removeAllObjectsEntryByName(bucketName, objectName string) (err error) { @@ -943,78 +910,45 @@ func (yig *YigStorage) removeAllObjectsEntryByName(bucketName, objectName string return nil } if err != nil { + helper.Logger.Error(bucketName, objectName, err) return err } for _, obj := range objs { - err = yig.removeByObject(obj, nil) + err = yig.removeByObject(obj) if err != nil { + helper.Logger.Error(err, obj) return err } } return } -func (yig *YigStorage) checkOldObject(bucketName, objectName, versioning string) (version uint64, err error) { - - if versioning == meta.VersionDisabled { - err = yig.removeAllObjectsEntryByName(bucketName, objectName) - return - } +func (yig *YigStorage) checkOldObject(bucketName, objectName, versioning string) (err error) { + switch versioning { + case meta.VersionDisabled: + // Delete all the bucketName + objectName. + return yig.removeAllObjectsEntryByName(bucketName, objectName) // TODO: not deleted. - if versioning == meta.VersionEnabled || versioning == meta.VersionSuspended { - objMapExist := true - objectExist := true + case meta.VersionEnabled: + // Do nothing. - var objMap *meta.ObjMap - objMap, err = yig.MetaStorage.GetObjectMap(bucketName, objectName) - if err == ErrNoSuchKey { - err = nil - objMapExist = false - } else if err != nil { - return 0, err - } + case meta.VersionSuspended: + // Delete null version object. var object *meta.Object - if objMapExist { - object, err = yig.MetaStorage.GetObjectVersion(bucketName, objectName, objMap.NullVerId, false) + if object, err = yig.MetaStorage.GetObjectVersion(bucketName, objectName, meta.ObjectNullVersion, false); err != nil { if err == ErrNoSuchKey { - err = nil - objectExist = false - } else if err != nil { - return 0, err - } - } else { - object, err = yig.MetaStorage.GetObject(bucketName, objectName, false) - if err == ErrNoSuchKey { - err = nil - objectExist = false - } else if err != nil { - return 0, err + return nil } + return err } - if versioning == "Enabled" { - if !objMapExist && objectExist && object.NullVersion { - version, err = object.GetVersionNumber() - if err != nil { - helper.Logger.Error("GetVersionNumber error:", err) - return 0, err - } - helper.Logger.Info("Old object version:", version) - return - } - } else { - helper.Logger.Info("object.NullVersion:", object.NullVersion) - if objectExist && object.NullVersion { - err = yig.MetaStorage.DeleteObject(object, object.DeleteMarker, nil) - if err != nil { - return - } - } - } - return + return yig.MetaStorage.DeleteObject(object, object.DeleteMarker) + + default: + return errors.New("No Such versioning status!") } - return 0, errors.New("No Such versioning status!") + return nil } func (yig *YigStorage) removeObjectVersion(bucketName, objectName, version string) error { @@ -1023,19 +957,16 @@ func (yig *YigStorage) removeObjectVersion(bucketName, objectName, version strin return nil } if err != nil { + helper.Logger.Info("Delete err", err) return err } - if version == "null" { - objMap := &meta.ObjMap{ - Name: objectName, - BucketName: bucketName, - } - err = yig.removeByObject(object, objMap) - if err != nil { - return err - } + err = yig.removeByObject(object) + if err != nil { + helper.Logger.Info("removeObjectVersion: ", err) + return err } + return nil } @@ -1051,17 +982,9 @@ func (yig *YigStorage) addDeleteMarker(bucket meta.Bucket, objectName string, DeleteMarker: true, } - versionId = deleteMarker.GetVersionId() - objMap := &meta.ObjMap{ - Name: objectName, - BucketName: bucket.Name, - } + err = yig.MetaStorage.PutObject(deleteMarker, nil, false) - if nullVersion { - err = yig.MetaStorage.PutObject(deleteMarker, nil, objMap, false) - } else { - err = yig.MetaStorage.PutObject(deleteMarker, nil, nil, false) - } + versionId = deleteMarker.GetVersionId() return } @@ -1102,6 +1025,7 @@ func (yig *YigStorage) DeleteObject(bucketName string, objectName string, versio return } case meta.VersionEnabled: + // https://docs.aws.amazon.com/AmazonS3/latest/dev/DeletingObjectVersions.html if version == "" { result.VersionId, err = yig.addDeleteMarker(*bucket, objectName, false) if err != nil { @@ -1116,9 +1040,11 @@ func (yig *YigStorage) DeleteObject(bucketName string, objectName string, versio result.VersionId = version } case meta.VersionSuspended: + // https://docs.aws.amazon.com/AmazonS3/latest/dev/DeletingObjectsfromVersioningSuspendedBuckets.html if version == "" { err = yig.removeObjectVersion(bucketName, objectName, "null") if err != nil { + helper.Logger.Error("DeleteObject", err) return } result.VersionId, err = yig.addDeleteMarker(*bucket, objectName, true) @@ -1129,6 +1055,7 @@ func (yig *YigStorage) DeleteObject(bucketName string, objectName string, versio } else { err = yig.removeObjectVersion(bucketName, objectName, version) if err != nil { + helper.Logger.Info("DeleteObject", err) return } result.VersionId = version