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 }