shard.go 2.81 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
package flatfs

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

12
type ShardIdV1 struct {
13
	funName string
14 15
	param   int
	fun     ShardFunc
16 17
}

18
const PREFIX = "/repo/flatfs/shard/"
19 20
const SHARDING_FN = "SHARDING"
const README_FN = "README"
21 22

func (f *ShardIdV1) String() string {
23
	return fmt.Sprintf("%sv1/%s/%d", PREFIX, f.funName, f.param)
24 25 26 27
}

func (f *ShardIdV1) Func() ShardFunc {
	return f.fun
28 29
}

30
func ParseShardFunc(str string) (*ShardIdV1, error) {
31 32
	str = strings.TrimSpace(str)
	// ignore prefix for now
33 34 35 36
	if len(str) == 0 {
		return nil, fmt.Errorf("empty shard identifier")
	}
	if str[0] == '/' {
Kevin Atkinson's avatar
Kevin Atkinson committed
37 38
		trimmed := strings.TrimPrefix(str, PREFIX)
		if str == trimmed { // nothing trimmed
39 40
			return nil, fmt.Errorf("invalid prefix in shard identifier: %s", str)
		}
Kevin Atkinson's avatar
Kevin Atkinson committed
41
		str = trimmed
42
	}
43

44
	parts := strings.Split(str, "/")
45
	if len(parts) != 3 {
46
		return nil, fmt.Errorf("invalid shard identifier: %s", str)
47
	}
48

49 50 51 52 53 54
	version := parts[0]
	if version != "v1" {
		return nil, fmt.Errorf("expected 'v1' for version string got: %s\n", version)
	}

	id := &ShardIdV1{funName: parts[1]}
55

56
	param, err := strconv.Atoi(parts[2])
57
	if err != nil {
58
		return nil, fmt.Errorf("invalid parameter: %v", err)
59
	}
60 61 62
	id.param = param

	switch id.funName {
63
	case "prefix":
64
		id.fun = Prefix(param)
65
	case "suffix":
66
		id.fun = Suffix(param)
67
	case "next-to-last":
68
		id.fun = NextToLast(param)
69
	default:
70
		return nil, fmt.Errorf("expected 'prefix', 'suffix' or 'next-to-last' got: %s", id.funName)
71 72
	}

73
	return id, nil
74 75
}

76
func ReadShardFunc(dir string) (*ShardIdV1, error) {
77
	buf, err := ioutil.ReadFile(filepath.Join(dir, SHARDING_FN))
78
	if os.IsNotExist(err) {
Kevin Atkinson's avatar
Kevin Atkinson committed
79
		return nil, ErrShardingFileMissing
80
	} else if err != nil {
81
		return nil, err
82
	}
83
	return ParseShardFunc(string(buf))
84 85
}

86
func WriteShardFunc(dir string, id *ShardIdV1) error {
87
	file, err := os.Create(filepath.Join(dir, SHARDING_FN))
88 89 90 91
	if err != nil {
		return err
	}
	defer file.Close()
92
	_, err = file.WriteString(id.String())
93 94 95 96
	if err != nil {
		return err
	}
	_, err = file.WriteString("\n")
97 98 99 100 101
	return err
}

func WriteReadme(dir string, id *ShardIdV1) error {
	if id.String() == IPFS_DEF_SHARD {
102
		err := ioutil.WriteFile(filepath.Join(dir, README_FN), []byte(README_IPFS_DEF_SHARD), 0444)
103 104 105 106
		if err != nil {
			return err
		}
	}
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
	return nil
}

func Prefix(prefixLen int) ShardFunc {
	padding := strings.Repeat("_", prefixLen)
	return func(noslash string) string {
		return (noslash + padding)[:prefixLen]
	}
}

func Suffix(suffixLen int) ShardFunc {
	padding := strings.Repeat("_", suffixLen)
	return func(noslash string) string {
		str := padding + noslash
		return str[len(str)-suffixLen:]
	}
}

func NextToLast(suffixLen int) ShardFunc {
	padding := strings.Repeat("_", suffixLen+1)
	return func(noslash string) string {
		str := padding + noslash
		offset := len(str) - suffixLen - 1
		return str[offset : offset+suffixLen]
	}
}