@ -24,9 +24,7 @@ import (
"path"
"strings"
"sync"
"time"
"github.com/minio/minio-go/pkg/set"
"github.com/minio/minio/cmd/logger"
"github.com/minio/minio/pkg/lifecycle"
)
@ -45,6 +43,11 @@ type LifecycleSys struct {
// Set - sets lifecycle config to given bucket name.
func ( sys * LifecycleSys ) Set ( bucketName string , lifecycle lifecycle . Lifecycle ) {
if globalIsGateway {
// no-op
return
}
sys . Lock ( )
defer sys . Unlock ( )
@ -53,6 +56,16 @@ func (sys *LifecycleSys) Set(bucketName string, lifecycle lifecycle.Lifecycle) {
// Get - gets lifecycle config associated to a given bucket name.
func ( sys * LifecycleSys ) Get ( bucketName string ) ( lifecycle lifecycle . Lifecycle , ok bool ) {
if globalIsGateway {
// When gateway is enabled, no cached value
// is used to validate life cycle policies.
objAPI := newObjectLayerFn ( )
if objAPI == nil {
return
}
l , err := objAPI . GetBucketLifecycle ( context . Background ( ) , bucketName )
return * l , err == nil
}
sys . Lock ( )
defer sys . Unlock ( )
@ -107,26 +120,16 @@ func NewLifecycleSys() *LifecycleSys {
}
// Init - initializes lifecycle system from lifecycle.xml of all buckets.
func ( sys * LifecycleSys ) Init ( objAPI ObjectLayer ) error {
func ( sys * LifecycleSys ) Init ( buckets [ ] BucketInfo , objAPI ObjectLayer ) error {
if objAPI == nil {
return errServerNotInitialized
}
defer func ( ) {
// Refresh LifecycleSys in background.
go func ( ) {
ticker := time . NewTicker ( globalRefreshBucketLifecycleInterval )
defer ticker . Stop ( )
for {
select {
case <- GlobalServiceDoneCh :
return
case <- ticker . C :
sys . refresh ( objAPI )
}
}
} ( )
} ( )
// In gateway mode, we always fetch the bucket lifecycle configuration from the gateway backend.
// So, this is a no-op for gateway servers.
if globalIsGateway {
return nil
}
doneCh := make ( chan struct { } )
defer close ( doneCh )
@ -140,7 +143,7 @@ func (sys *LifecycleSys) Init(objAPI ObjectLayer) error {
select {
case <- retryTimerCh :
// Load LifecycleSys once during boot.
if err := sys . refresh ( objAPI ) ; err != nil {
if err := sys . load ( buckets , objAPI ) ; err != nil {
if err == errDiskNotFound ||
strings . Contains ( err . Error ( ) , InsufficientReadQuorum { } . Error ( ) ) ||
strings . Contains ( err . Error ( ) , InsufficientWriteQuorum { } . Error ( ) ) {
@ -156,14 +159,8 @@ func (sys *LifecycleSys) Init(objAPI ObjectLayer) error {
}
}
// Refresh LifecycleSys.
func ( sys * LifecycleSys ) refresh ( objAPI ObjectLayer ) error {
buckets , err := objAPI . ListBuckets ( context . Background ( ) )
if err != nil {
logger . LogIf ( context . Background ( ) , err )
return err
}
sys . removeDeletedBuckets ( buckets )
// Loads lifecycle policies for all buckets into LifecycleSys.
func ( sys * LifecycleSys ) load ( buckets [ ] BucketInfo , objAPI ObjectLayer ) error {
for _ , bucket := range buckets {
config , err := objAPI . GetBucketLifecycle ( context . Background ( ) , bucket . Name )
if err != nil {
@ -179,24 +176,6 @@ func (sys *LifecycleSys) refresh(objAPI ObjectLayer) error {
return nil
}
// removeDeletedBuckets - to handle a corner case where we have cached the lifecycle for a deleted
// bucket. i.e if we miss a delete-bucket notification we should delete the corresponding
// bucket policy during sys.refresh()
func ( sys * LifecycleSys ) removeDeletedBuckets ( bucketInfos [ ] BucketInfo ) {
buckets := set . NewStringSet ( )
for _ , info := range bucketInfos {
buckets . Add ( info . Name )
}
sys . Lock ( )
defer sys . Unlock ( )
for bucket := range sys . bucketLifecycleMap {
if ! buckets . Contains ( bucket ) {
delete ( sys . bucketLifecycleMap , bucket )
}
}
}
// Remove - removes policy for given bucket name.
func ( sys * LifecycleSys ) Remove ( bucketName string ) {
sys . Lock ( )