github.com/Cloud-Foundations/Dominator@v0.3.4/lib/objectserver/filesystem/garbageCollector.go (about)

     1  package filesystem
     2  
     3  import (
     4  	"syscall"
     5  	"time"
     6  
     7  	"github.com/Cloud-Foundations/Dominator/lib/format"
     8  )
     9  
    10  func sanitisePercentage(percent int) uint64 {
    11  	if percent < 1 {
    12  		return 1
    13  	}
    14  	if percent > 99 {
    15  		return 99
    16  	}
    17  	return uint64(percent)
    18  }
    19  
    20  func (objSrv *ObjectServer) garbageCollector() (uint64, error) {
    21  	objSrv.rwLock.Lock()
    22  	if time.Since(objSrv.lastGarbageCollection) < time.Second {
    23  		objSrv.rwLock.Unlock()
    24  		return 0, nil
    25  	}
    26  	objSrv.lastGarbageCollection = time.Now()
    27  	var bytesToDelete uint64
    28  	if objectServerCleanupStopSize < objectServerCleanupStartSize &&
    29  		objSrv.unreferencedBytes > uint64(objectServerCleanupStartSize) {
    30  		bytesToDelete = objSrv.unreferencedBytes -
    31  			uint64(objectServerCleanupStopSize)
    32  	}
    33  	objSrv.rwLock.Unlock()
    34  	if free, capacity, err := objSrv.getSpaceMetrics(); err != nil {
    35  		objSrv.Logger.Println(err)
    36  	} else {
    37  		cleanupStartPercent := sanitisePercentage(
    38  			*objectServerCleanupStartPercent)
    39  		cleanupStopPercent := sanitisePercentage(
    40  			*objectServerCleanupStopPercent)
    41  		if cleanupStopPercent >= cleanupStartPercent {
    42  			cleanupStopPercent = cleanupStartPercent - 1
    43  		}
    44  		utilisation := (capacity - free) * 100 / capacity
    45  		if utilisation >= cleanupStartPercent {
    46  			relativeBytesToDelete := (utilisation - cleanupStopPercent) *
    47  				capacity / 100
    48  			if relativeBytesToDelete > bytesToDelete {
    49  				bytesToDelete = relativeBytesToDelete
    50  			}
    51  		}
    52  	}
    53  	if bytesToDelete < 1 {
    54  		return 0, nil
    55  	}
    56  	var bytesDeleted uint64
    57  	var err error
    58  	if objSrv.gc == nil {
    59  		bytesDeleted, _, err = objSrv.deleteUnreferenced(0, bytesToDelete)
    60  	} else {
    61  		bytesDeleted, err = objSrv.gc(bytesToDelete)
    62  	}
    63  	if err != nil {
    64  		objSrv.Logger.Printf(
    65  			"Error collecting garbage, only deleted: %s of %s: %s\n",
    66  			format.FormatBytes(bytesDeleted), format.FormatBytes(bytesToDelete),
    67  			err)
    68  		return 0, err
    69  	}
    70  	return bytesDeleted, nil
    71  }
    72  
    73  // garbageCollectorLoop will periodically delete unreferenced objects if space
    74  // is running low. It returns if an external (deprecated) garbage collector is
    75  // set.
    76  func (objSrv *ObjectServer) garbageCollectorLoop() {
    77  	for time.Sleep(5 * time.Second); objSrv.gc == nil; time.Sleep(time.Second) {
    78  		objSrv.garbageCollector()
    79  	}
    80  }
    81  
    82  // getSpaceMetrics returns freeSpace, capacity.
    83  func (t *ObjectServer) getSpaceMetrics() (uint64, uint64, error) {
    84  	fd, err := syscall.Open(t.BaseDirectory, syscall.O_RDONLY, 0)
    85  	if err != nil {
    86  		t.Logger.Printf("error opening: %s: %s", t.BaseDirectory, err)
    87  		return 0, 0, err
    88  	} else {
    89  		defer syscall.Close(fd)
    90  		var statbuf syscall.Statfs_t
    91  		if err := syscall.Fstatfs(fd, &statbuf); err != nil {
    92  			t.Logger.Printf("error getting file-system stats: %s\n", err)
    93  			return 0, 0, err
    94  		}
    95  		rootReservation := statbuf.Bfree - statbuf.Bavail
    96  		return uint64(statbuf.Bavail) * uint64(statbuf.Bsize),
    97  			uint64(statbuf.Blocks-rootReservation) * uint64(statbuf.Bsize), nil
    98  	}
    99  }