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 }