diff --git a/fs-v1.go b/fs-v1.go index eef7f1b54..6841cc6e3 100644 --- a/fs-v1.go +++ b/fs-v1.go @@ -49,6 +49,22 @@ func loadFormatFS(storageDisk StorageAPI) ([]byte, error) { return readAll(storageDisk, minioMetaBucket, fsFormatJSONFile) } +// Should be called when process shuts down. +func shutdownFS(storage StorageAPI) { + _, err := storage.ListDir(minioMetaBucket, mpartMetaPrefix) + if err != errFileNotFound { + // Multipart directory is not empty hence do not remove .minio volume. + os.Exit(0) + } + prefix := "" + if err := cleanupDir(storage, minioMetaBucket, prefix); err != nil { + os.Exit(0) + return + } + storage.DeleteVol(minioMetaBucket) + os.Exit(0) +} + // newFSObjects - initialize new fs object layer. func newFSObjects(disk string) (ObjectLayer, error) { storage, err := newStorageAPI(disk) @@ -72,6 +88,10 @@ func newFSObjects(disk string) (ObjectLayer, error) { return nil, err } } + // Register the callback that should be called when the process shuts down. + registerShutdown(func() { + shutdownFS(storage) + }) // Return successfully initialized object layer. return fsObjects{ storage: storage, diff --git a/object-common.go b/object-common.go index 83b6fa23b..d18e7bb9c 100644 --- a/object-common.go +++ b/object-common.go @@ -17,9 +17,11 @@ package main import ( + "os" "path/filepath" "strings" "sync" + "syscall" ) const ( @@ -27,6 +29,17 @@ const ( blockSizeV1 = 10 * 1024 * 1024 // 10MiB. ) +// Register callback functions that needs to be called when process shutsdown. +// For now, SIGINT triggers the callbacks, in future controller can trigger +// shutdown callbacks. +func registerShutdown(callback func()) { + go func() { + trapCh := signalTrap(os.Interrupt, syscall.SIGTERM) + <-trapCh + callback() + }() +} + // House keeping code needed for FS. func fsHouseKeeping(storageDisk StorageAPI) error { // Attempt to create `.minio`. diff --git a/signals.go b/signals.go new file mode 100644 index 000000000..e7e8b02bf --- /dev/null +++ b/signals.go @@ -0,0 +1,49 @@ +/* + * Minio Client, (C) 2015 Minio, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import ( + "os" + "os/signal" +) + +// signalTrap traps the registered signals and notifies the caller. +func signalTrap(sig ...os.Signal) <-chan bool { + // channel to notify the caller. + trapCh := make(chan bool, 1) + + go func(chan<- bool) { + // channel to receive signals. + sigCh := make(chan os.Signal, 1) + defer close(sigCh) + + // `signal.Notify` registers the given channel to + // receive notifications of the specified signals. + signal.Notify(sigCh, sig...) + + // Wait for the signal. + <-sigCh + + // Once signal has been received stop signal Notify handler. + signal.Stop(sigCh) + + // Notify the caller. + trapCh <- true + }(trapCh) + + return trapCh +}