github.com/stackdocker/rkt@v0.10.1-0.20151109095037-1aa827478248/rkt/image_gc.go (about)

     1  // Copyright 2015 The rkt Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package main
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"github.com/coreos/rkt/Godeps/_workspace/src/github.com/spf13/cobra"
    21  	"github.com/coreos/rkt/common"
    22  	"github.com/coreos/rkt/pkg/lock"
    23  	"github.com/coreos/rkt/store"
    24  )
    25  
    26  var (
    27  	cmdImageGc = &cobra.Command{
    28  		Use:   "gc",
    29  		Short: "Garbage collect local store",
    30  		Run:   runWrapper(runGcImage),
    31  	}
    32  )
    33  
    34  func init() {
    35  	cmdImage.AddCommand(cmdImageGc)
    36  }
    37  
    38  func runGcImage(cmd *cobra.Command, args []string) (exit int) {
    39  	s, err := store.NewStore(globalFlags.Dir)
    40  	if err != nil {
    41  		stderr("rkt: cannot open store: %v", err)
    42  		return 1
    43  	}
    44  
    45  	if err := gcTreeStore(s); err != nil {
    46  		stderr("rkt: failed to remove unreferenced treestores: %v", err)
    47  		return 1
    48  	}
    49  	return 0
    50  }
    51  
    52  // gcTreeStore removes all treeStoreIDs not referenced by any non garbage
    53  // collected pod from the store.
    54  func gcTreeStore(s *store.Store) error {
    55  	// Take an exclusive lock to block other pods being created.
    56  	// This is needed to avoid races between the below steps (getting the
    57  	// list of referenced treeStoreIDs, getting the list of treeStoreIDs
    58  	// from the store, removal of unreferenced treeStoreIDs) and new
    59  	// pods/treeStores being created/referenced
    60  	keyLock, err := lock.ExclusiveKeyLock(lockDir(), common.PrepareLock)
    61  	if err != nil {
    62  		return fmt.Errorf("cannot get exclusive prepare lock: %v", err)
    63  	}
    64  	defer keyLock.Close()
    65  	referencedTreeStoreIDs, err := getReferencedTreeStoreIDs()
    66  	if err != nil {
    67  		return fmt.Errorf("cannot get referenced treestoreIDs: %v", err)
    68  	}
    69  	treeStoreIDs, err := s.GetTreeStoreIDs()
    70  	if err != nil {
    71  		return fmt.Errorf("cannot get treestoreIDs from the store: %v", err)
    72  	}
    73  	for _, treeStoreID := range treeStoreIDs {
    74  		if _, ok := referencedTreeStoreIDs[treeStoreID]; !ok {
    75  			if err := s.RemoveTreeStore(treeStoreID); err != nil {
    76  				stderr("rkt: error removing treestore %q: %v", treeStoreID, err)
    77  			} else {
    78  				stderr("rkt: removed treestore %q", treeStoreID)
    79  			}
    80  		}
    81  	}
    82  	return nil
    83  }
    84  
    85  func getReferencedTreeStoreIDs() (map[string]struct{}, error) {
    86  	treeStoreIDs := map[string]struct{}{}
    87  	var walkErr error
    88  	// Consider pods in preparing, prepared, run, exitedgarbage state
    89  	if err := walkPods(includeMostDirs, func(p *pod) {
    90  		stage1TreeStoreID, err := p.getStage1TreeStoreID()
    91  		if err != nil {
    92  			walkErr = fmt.Errorf("cannot get stage1 treestoreID for pod %s: %v", p.uuid, err)
    93  			return
    94  		}
    95  		appsTreeStoreIDs, err := p.getAppsTreeStoreIDs()
    96  		if err != nil {
    97  			walkErr = fmt.Errorf("cannot get apps treestoreIDs for pod %s: %v", p.uuid, err)
    98  			return
    99  		}
   100  		allTreeStoreIDs := append(appsTreeStoreIDs, stage1TreeStoreID)
   101  
   102  		for _, treeStoreID := range allTreeStoreIDs {
   103  			treeStoreIDs[treeStoreID] = struct{}{}
   104  		}
   105  	}); err != nil {
   106  		return nil, fmt.Errorf("failed to get pod handles: %v", err)
   107  	}
   108  	if walkErr != nil {
   109  		return nil, walkErr
   110  	}
   111  	return treeStoreIDs, nil
   112  }