github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/pkg/blobserver/localdisk/upgrade32.go (about)

     1  /*
     2  Copyright 2013 The Camlistore Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8       http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // This file deals with the migration of stuff from the old xxx/yyy/sha1-xxxyyyzzz.dat
    18  // files to the xx/yy format.
    19  
    20  package localdisk
    21  
    22  import (
    23  	"fmt"
    24  	"log"
    25  	"os"
    26  	"path/filepath"
    27  	"sort"
    28  	"strings"
    29  	"time"
    30  
    31  	"camlistore.org/pkg/blob"
    32  )
    33  
    34  func (ds *DiskStorage) migrate3to2() error {
    35  	sha1root := filepath.Join(ds.root, "sha1")
    36  	f, err := os.Open(sha1root)
    37  	if os.IsNotExist(err) {
    38  		return nil
    39  	} else if err != nil {
    40  		return err
    41  	}
    42  	names, err := f.Readdirnames(-1)
    43  	if err != nil {
    44  		return err
    45  	}
    46  	f.Close()
    47  	var three []string
    48  	for _, name := range names {
    49  		if len(name) == 3 {
    50  			three = append(three, name)
    51  		}
    52  	}
    53  	if len(three) == 0 {
    54  		return nil
    55  	}
    56  	sort.Strings(three)
    57  	made := make(map[string]bool) // dirs made
    58  	for i, dir := range three {
    59  		log.Printf("Migrating structure of %d/%d directories in %s; doing %q", i+1, len(three), sha1root, dir)
    60  		fullDir := filepath.Join(sha1root, dir)
    61  		err := filepath.Walk(fullDir, func(path string, fi os.FileInfo, err error) error {
    62  			if err != nil {
    63  				return err
    64  			}
    65  			baseName := filepath.Base(path)
    66  
    67  			// Cases like "sha1-7ea231f1bd008e04c0629666ba695c399db76b8a.dat.tmp546786166"
    68  			if strings.Contains(baseName, ".dat.tmp") && fi.Mode().IsRegular() &&
    69  				fi.ModTime().Before(time.Now().Add(-24*time.Hour)) {
    70  				return ds.cleanupTempFile(path)
    71  			}
    72  
    73  			if !(fi.Mode().IsRegular() && strings.HasSuffix(baseName, ".dat")) {
    74  				return nil
    75  			}
    76  			br, ok := blob.Parse(strings.TrimSuffix(baseName, ".dat"))
    77  			if !ok {
    78  				return nil
    79  			}
    80  			dir := ds.blobDirectory(br)
    81  			if !made[dir] {
    82  				if err := os.MkdirAll(dir, 0700); err != nil {
    83  					return err
    84  				}
    85  				made[dir] = true
    86  			}
    87  			dst := ds.blobPath(br)
    88  			if fi, err := os.Stat(dst); !os.IsNotExist(err) {
    89  				return fmt.Errorf("Expected %s to not exist; got stat %v, %v", fi, err)
    90  			}
    91  			if err := os.Rename(path, dst); err != nil {
    92  				return err
    93  			}
    94  			return nil
    95  		})
    96  		if err != nil {
    97  			return err
    98  		}
    99  		if err := removeEmptyDirOrDirs(fullDir); err != nil {
   100  			log.Printf("Failed to remove old dir %s: %v", fullDir, err)
   101  		}
   102  	}
   103  	return nil
   104  }
   105  
   106  func removeEmptyDirOrDirs(dir string) error {
   107  	err := filepath.Walk(dir, func(subdir string, fi os.FileInfo, err error) error {
   108  		if subdir == dir {
   109  			// root.
   110  			return nil
   111  		}
   112  		if err != nil {
   113  			return err
   114  		}
   115  		if fi.Mode().IsDir() {
   116  			removeEmptyDirOrDirs(subdir)
   117  			return filepath.SkipDir
   118  		}
   119  		return nil
   120  	})
   121  	if err != nil {
   122  		return err
   123  	}
   124  	return os.Remove(dir)
   125  }
   126  
   127  func (ds *DiskStorage) cleanupTempFile(path string) error {
   128  	base := filepath.Base(path)
   129  	i := strings.Index(base, ".dat.tmp")
   130  	if i < 0 {
   131  		return nil
   132  	}
   133  	br, ok := blob.Parse(base[:i])
   134  	if !ok {
   135  		return nil
   136  	}
   137  
   138  	// If it already exists at the good path, delete it.
   139  	goodPath := ds.blobPath(br)
   140  	if _, err := os.Stat(goodPath); err == nil {
   141  		return os.Remove(path)
   142  	}
   143  
   144  	// TODO(bradfitz): care whether it's correct digest or not?
   145  	return nil
   146  }