convert.go 3.51 KB
Newer Older
1 2 3 4 5 6
// Package flatfs is a Datastore implementation that stores all
// objects in a two-level directory structure in the local file
// system, regardless of the hierarchy of the keys.
package flatfs

import (
7
	"errors"
8 9 10 11
	"fmt"
	"io"
	"os"
	"path/filepath"
12
	"strings"
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

	"github.com/ipfs/go-datastore"
	"github.com/ipfs/go-datastore/query"
)

func UpgradeV0toV1(path string, prefixLen int) error {
	fun := Prefix(prefixLen)
	err := WriteShardFunc(path, fun)
	if err != nil {
		return err
	}
	err = WriteReadme(path, fun)
	if err != nil {
		return err
	}
	return nil
}

func DowngradeV1toV0(path string) error {
32 33 34 35 36 37 38 39
	fun, err := ReadShardFunc(path)
	if err != nil {
		return err
	} else if fun.funName != "prefix" {
		return fmt.Errorf("%s: can only downgrade datastore that use the 'prefix' sharding function", path)
	}

	err = os.Remove(filepath.Join(path, SHARDING_FN))
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
	if err != nil {
		return err
	}
	err = os.Remove(filepath.Join(path, README_FN))
	if err != nil && !os.IsNotExist(err) {
		return err
	}
	return nil
}

func Move(oldPath string, newPath string, out io.Writer) error {
	oldDS, err := Open(oldPath, false)
	if err != nil {
		return fmt.Errorf("%s: %v", oldPath, err)
	}
	newDS, err := Open(newPath, false)
	if err != nil {
		return fmt.Errorf("%s: %v", newPath, err)
	}

	res, err := oldDS.Query(query.Query{KeysOnly: true})
	if err != nil {
		return err
	}

	if out != nil {
		fmt.Fprintf(out, "Moving Keys...\n")
	}

	// first move the keys
70 71 72 73 74 75 76 77 78 79
	count := 0
	for {
		e, ok := res.NextSync()
		if !ok {
			break
		}
		if e.Error != nil {
			return e.Error
		}

80 81 82 83
		err := moveKey(oldDS, newDS, datastore.RawKey(e.Key))
		if err != nil {
			return err
		}
84 85 86 87 88

		count++
		if out != nil && count%10 == 0 {
			fmt.Fprintf(out, "\r%d keys so far", count)
		}
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
	}

	if out != nil {
		fmt.Fprintf(out, "\nCleaning Up...\n")
	}

	// now walk the old top-level directory
	dir, err := os.Open(oldDS.path)
	if err != nil {
		return err
	}
	defer dir.Close()
	names, err := dir.Readdirnames(-1)
	if err != nil {
		return err
	}
	for _, fn := range names {
		if fn == "." || fn == ".." {
			continue
		}
		oldPath := filepath.Join(oldDS.path, fn)
		inf, err := os.Stat(oldPath)
		if err != nil {
			return err
		}
114 115 116 117 118 119 120
		if inf.IsDir() {
			indir, err := os.Open(oldPath)
			if err != nil {
				return err
			}

			names, err := indir.Readdirnames(-1)
121
			indir.Close()
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
			if err != nil {
				return err
			}

			for _, n := range names {
				p := filepath.Join(oldPath, n)
				// part of unfinished write transaction
				// remove it
				if strings.HasPrefix(n, "put-") {
					err := os.Remove(p)
					if err != nil {
						return err
					}
				} else {
					return errors.New("unknown file in flatfs: " + p)
				}
			}

			err = os.Remove(oldPath)
			if err != nil {
				return err
			}
		} else if fn == SHARDING_FN || fn == README_FN {
			// generated file so just remove it
146 147 148 149 150
			err := os.Remove(oldPath)
			if err != nil {
				return err
			}
		} else {
151
			// else we found something unexpected, so to be safe just move it
Jakub Sztandera's avatar
Jakub Sztandera committed
152
			log.Warningf("found unexpected file in datastore directory: \"%s\", moving anyway\n", fn)
153
			newPath := filepath.Join(newDS.path, fn)
154
			err := os.Rename(oldPath, newPath)
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
			if err != nil {
				return err
			}
		}
	}

	if out != nil {
		fmt.Fprintf(out, "All Done.\n")
	}

	return nil
}

func moveKey(oldDS *Datastore, newDS *Datastore, key datastore.Key) error {
	_, oldPath := oldDS.encode(key)
	dir, newPath := newDS.encode(key)
	err := newDS.makeDirNoSync(dir)
	if err != nil {
		return err
	}
175
	err = os.Rename(oldPath, newPath)
176 177 178 179 180
	if err != nil {
		return err
	}
	return nil
}