Integer type policy

Integers are for numbers, enabling arithmetic like subtractions and for
loops without getting shot in the foot. Unsigneds are for bitfields.

- "int" for numbers that will always be laughably smaller than four
  billion, and where we don't care about the serialization format.

- "int32" for numbers that will always be laughably smaller than four
  billion, and will be serialized to four bytes.

- "int64" for numbers that may approach four billion or will be
  serialized to eight bytes.

- "uint32" and "uint64" for bitfields, depending on required number of
  bits and serialization format. Likewise "uint8" and "uint16", although
  rare in this project since they don't exist in XDR.

- "int8", "int16" and plain "uint" are almost never useful.
This commit is contained in:
Jakob Borg
2015-01-18 02:12:06 +01:00
parent 221e3eddd5
commit 2c8b627008
30 changed files with 181 additions and 151 deletions

View File

@@ -160,7 +160,7 @@ func (f *BlockFinder) Changed(cfg config.Configuration) error {
// the block) or false to continue iterating for whatever reason.
// The iterator finally returns the result, whether or not a satisfying block
// was eventually found.
func (f *BlockFinder) Iterate(hash []byte, iterFn func(string, string, uint32) bool) bool {
func (f *BlockFinder) Iterate(hash []byte, iterFn func(string, string, int32) bool) bool {
f.mut.RLock()
folders := f.folders
f.mut.RUnlock()
@@ -171,7 +171,7 @@ func (f *BlockFinder) Iterate(hash []byte, iterFn func(string, string, uint32) b
for iter.Next() && iter.Error() == nil {
folder, file := fromBlockKey(iter.Key())
index := binary.BigEndian.Uint32(iter.Value())
index := int32(binary.BigEndian.Uint32(iter.Value()))
if iterFn(folder, osutil.NativeFilename(file), index) {
return true
}
@@ -182,7 +182,7 @@ func (f *BlockFinder) Iterate(hash []byte, iterFn func(string, string, uint32) b
// A method for repairing incorrect blockmap entries, removes the old entry
// and replaces it with a new entry for the given block
func (f *BlockFinder) Fix(folder, file string, index uint32, oldHash, newHash []byte) error {
func (f *BlockFinder) Fix(folder, file string, index int32, oldHash, newHash []byte) error {
buf := make([]byte, 4)
binary.BigEndian.PutUint32(buf, uint32(index))

View File

@@ -32,7 +32,7 @@ func genBlocks(n int) []protocol.BlockInfo {
for j := range h {
h[j] = byte(i + j)
}
b[i].Size = uint32(i)
b[i].Size = int32(i)
b[i].Hash = h
}
return b
@@ -103,21 +103,21 @@ func TestBlockMapAddUpdateWipe(t *testing.T) {
t.Fatal(err)
}
f.Iterate(f1.Blocks[0].Hash, func(folder, file string, index uint32) bool {
f.Iterate(f1.Blocks[0].Hash, func(folder, file string, index int32) bool {
if folder != "folder1" || file != "f1" || index != 0 {
t.Fatal("Mismatch")
}
return true
})
f.Iterate(f2.Blocks[0].Hash, func(folder, file string, index uint32) bool {
f.Iterate(f2.Blocks[0].Hash, func(folder, file string, index int32) bool {
if folder != "folder1" || file != "f2" || index != 0 {
t.Fatal("Mismatch")
}
return true
})
f.Iterate(f3.Blocks[0].Hash, func(folder, file string, index uint32) bool {
f.Iterate(f3.Blocks[0].Hash, func(folder, file string, index int32) bool {
t.Fatal("Unexpected block")
return true
})
@@ -132,17 +132,17 @@ func TestBlockMapAddUpdateWipe(t *testing.T) {
t.Fatal(err)
}
f.Iterate(f1.Blocks[0].Hash, func(folder, file string, index uint32) bool {
f.Iterate(f1.Blocks[0].Hash, func(folder, file string, index int32) bool {
t.Fatal("Unexpected block")
return false
})
f.Iterate(f2.Blocks[0].Hash, func(folder, file string, index uint32) bool {
f.Iterate(f2.Blocks[0].Hash, func(folder, file string, index int32) bool {
t.Fatal("Unexpected block")
return false
})
f.Iterate(f3.Blocks[0].Hash, func(folder, file string, index uint32) bool {
f.Iterate(f3.Blocks[0].Hash, func(folder, file string, index int32) bool {
if folder != "folder1" || file != "f3" || index != 0 {
t.Fatal("Mismatch")
}
@@ -189,7 +189,7 @@ func TestBlockFinderLookup(t *testing.T) {
}
counter := 0
f.Iterate(f1.Blocks[0].Hash, func(folder, file string, index uint32) bool {
f.Iterate(f1.Blocks[0].Hash, func(folder, file string, index int32) bool {
counter++
switch counter {
case 1:
@@ -217,7 +217,7 @@ func TestBlockFinderLookup(t *testing.T) {
}
counter = 0
f.Iterate(f1.Blocks[0].Hash, func(folder, file string, index uint32) bool {
f.Iterate(f1.Blocks[0].Hash, func(folder, file string, index int32) bool {
counter++
switch counter {
case 1:
@@ -239,7 +239,7 @@ func TestBlockFinderLookup(t *testing.T) {
func TestBlockFinderFix(t *testing.T) {
db, f := setup()
iterFn := func(folder, file string, index uint32) bool {
iterFn := func(folder, file string, index int32) bool {
return true
}

View File

@@ -34,11 +34,11 @@ import (
)
var (
clockTick uint64
clockTick int64
clockMut sync.Mutex
)
func clock(v uint64) uint64 {
func clock(v int64) int64 {
clockMut.Lock()
defer clockMut.Unlock()
if v > clockTick {
@@ -56,7 +56,7 @@ const (
)
type fileVersion struct {
version uint64
version int64
device []byte
}
@@ -164,9 +164,9 @@ func globalKeyFolder(key []byte) []byte {
return folder[:izero]
}
type deletionHandler func(db dbReader, batch dbWriter, folder, device, name []byte, dbi iterator.Iterator) uint64
type deletionHandler func(db dbReader, batch dbWriter, folder, device, name []byte, dbi iterator.Iterator) int64
func ldbGenericReplace(db *leveldb.DB, folder, device []byte, fs []protocol.FileInfo, deleteFn deletionHandler) uint64 {
func ldbGenericReplace(db *leveldb.DB, folder, device []byte, fs []protocol.FileInfo, deleteFn deletionHandler) int64 {
runtime.GC()
sort.Sort(fileList(fs)) // sort list on name, same as in the database
@@ -197,7 +197,7 @@ func ldbGenericReplace(db *leveldb.DB, folder, device []byte, fs []protocol.File
moreDb := dbi.Next()
fsi := 0
var maxLocalVer uint64
var maxLocalVer int64
for {
var newName, oldName []byte
@@ -288,9 +288,9 @@ func ldbGenericReplace(db *leveldb.DB, folder, device []byte, fs []protocol.File
return maxLocalVer
}
func ldbReplace(db *leveldb.DB, folder, device []byte, fs []protocol.FileInfo) uint64 {
func ldbReplace(db *leveldb.DB, folder, device []byte, fs []protocol.FileInfo) int64 {
// TODO: Return the remaining maxLocalVer?
return ldbGenericReplace(db, folder, device, fs, func(db dbReader, batch dbWriter, folder, device, name []byte, dbi iterator.Iterator) uint64 {
return ldbGenericReplace(db, folder, device, fs, func(db dbReader, batch dbWriter, folder, device, name []byte, dbi iterator.Iterator) int64 {
// Database has a file that we are missing. Remove it.
if debugDB {
l.Debugf("delete; folder=%q device=%v name=%q", folder, protocol.DeviceIDFromBytes(device), name)
@@ -304,8 +304,8 @@ func ldbReplace(db *leveldb.DB, folder, device []byte, fs []protocol.FileInfo) u
})
}
func ldbReplaceWithDelete(db *leveldb.DB, folder, device []byte, fs []protocol.FileInfo) uint64 {
return ldbGenericReplace(db, folder, device, fs, func(db dbReader, batch dbWriter, folder, device, name []byte, dbi iterator.Iterator) uint64 {
func ldbReplaceWithDelete(db *leveldb.DB, folder, device []byte, fs []protocol.FileInfo) int64 {
return ldbGenericReplace(db, folder, device, fs, func(db dbReader, batch dbWriter, folder, device, name []byte, dbi iterator.Iterator) int64 {
var tf FileInfoTruncated
err := tf.UnmarshalXDR(dbi.Value())
if err != nil {
@@ -335,7 +335,7 @@ func ldbReplaceWithDelete(db *leveldb.DB, folder, device []byte, fs []protocol.F
})
}
func ldbUpdate(db *leveldb.DB, folder, device []byte, fs []protocol.FileInfo) uint64 {
func ldbUpdate(db *leveldb.DB, folder, device []byte, fs []protocol.FileInfo) int64 {
runtime.GC()
batch := new(leveldb.Batch)
@@ -356,7 +356,7 @@ func ldbUpdate(db *leveldb.DB, folder, device []byte, fs []protocol.FileInfo) ui
snap.Release()
}()
var maxLocalVer uint64
var maxLocalVer int64
for _, f := range fs {
name := []byte(f.Name)
fk := deviceKey(folder, device, name)
@@ -406,7 +406,7 @@ func ldbUpdate(db *leveldb.DB, folder, device []byte, fs []protocol.FileInfo) ui
return maxLocalVer
}
func ldbInsert(batch dbWriter, folder, device []byte, file protocol.FileInfo) uint64 {
func ldbInsert(batch dbWriter, folder, device []byte, file protocol.FileInfo) int64 {
if debugDB {
l.Debugf("insert; folder=%q device=%v %v", folder, protocol.DeviceIDFromBytes(device), file)
}
@@ -428,7 +428,7 @@ func ldbInsert(batch dbWriter, folder, device []byte, file protocol.FileInfo) ui
// ldbUpdateGlobal adds this device+version to the version list for the given
// file. If the device is already present in the list, the version is updated.
// If the file does not have an entry in the global list, it is created.
func ldbUpdateGlobal(db dbReader, batch dbWriter, folder, device, file []byte, version uint64) bool {
func ldbUpdateGlobal(db dbReader, batch dbWriter, folder, device, file []byte, version int64) bool {
if debugDB {
l.Debugf("update global; folder=%q device=%v file=%q version=%d", folder, protocol.DeviceIDFromBytes(device), file, version)
}
@@ -798,7 +798,7 @@ outer:
have := false // If we have the file, any version
need := false // If we have a lower version of the file
var haveVersion uint64
var haveVersion int64
for _, v := range vl.versions {
if bytes.Compare(v.device, device) == 0 {
have = true

View File

@@ -31,7 +31,7 @@ fileVersion Structure:
struct fileVersion {
unsigned hyper version;
hyper version;
opaque device<>;
}
@@ -62,7 +62,7 @@ func (o fileVersion) AppendXDR(bs []byte) ([]byte, error) {
}
func (o fileVersion) encodeXDR(xw *xdr.Writer) (int, error) {
xw.WriteUint64(o.version)
xw.WriteUint64(uint64(o.version))
xw.WriteBytes(o.device)
return xw.Tot(), xw.Error()
}
@@ -79,7 +79,7 @@ func (o *fileVersion) UnmarshalXDR(bs []byte) error {
}
func (o *fileVersion) decodeXDR(xr *xdr.Reader) error {
o.version = xr.ReadUint64()
o.version = int64(xr.ReadUint64())
o.device = xr.ReadBytes()
return xr.Error()
}

View File

@@ -31,7 +31,7 @@ import (
)
type FileSet struct {
localVersion map[protocol.DeviceID]uint64
localVersion map[protocol.DeviceID]int64
mutex sync.Mutex
folder string
db *leveldb.DB
@@ -56,7 +56,7 @@ type Iterator func(f FileIntf) bool
func NewFileSet(folder string, db *leveldb.DB) *FileSet {
var s = FileSet{
localVersion: make(map[protocol.DeviceID]uint64),
localVersion: make(map[protocol.DeviceID]int64),
folder: folder,
db: db,
blockmap: NewBlockMap(db, folder),
@@ -212,7 +212,7 @@ func (s *FileSet) Availability(file string) []protocol.DeviceID {
return ldbAvailability(s.db, []byte(s.folder), []byte(osutil.NormalizedFilename(file)))
}
func (s *FileSet) LocalVersion(device protocol.DeviceID) uint64 {
func (s *FileSet) LocalVersion(device protocol.DeviceID) int64 {
s.mutex.Lock()
defer s.mutex.Unlock()
return s.localVersion[device]

View File

@@ -43,7 +43,7 @@ func genBlocks(n int) []protocol.BlockInfo {
for j := range h {
h[j] = byte(i + j)
}
b[i].Size = uint32(i)
b[i].Size = int32(i)
b[i].Hash = h
}
return b

View File

@@ -29,9 +29,9 @@ type FileInfoTruncated struct {
Name string // max:8192
Flags uint32
Modified int64
Version uint64
LocalVersion uint64
NumBlocks uint32
Version int64
LocalVersion int64
NumBlocks int32
}
func (f FileInfoTruncated) String() string {
@@ -44,7 +44,7 @@ func (f FileInfoTruncated) Size() int64 {
if f.IsDeleted() || f.IsDirectory() {
return 128
}
return BlocksToSize(f.NumBlocks)
return BlocksToSize(int(f.NumBlocks))
}
func (f FileInfoTruncated) IsDeleted() bool {
@@ -67,7 +67,7 @@ func (f FileInfoTruncated) HasPermissionBits() bool {
return f.Flags&protocol.FlagNoPermBits == 0
}
func BlocksToSize(num uint32) int64 {
func BlocksToSize(num int) int64 {
if num < 2 {
return protocol.BlockSize / 2
}

View File

@@ -46,9 +46,9 @@ struct FileInfoTruncated {
string Name<8192>;
unsigned int Flags;
hyper Modified;
unsigned hyper Version;
unsigned hyper LocalVersion;
unsigned int NumBlocks;
hyper Version;
hyper LocalVersion;
int NumBlocks;
}
*/
@@ -84,9 +84,9 @@ func (o FileInfoTruncated) encodeXDR(xw *xdr.Writer) (int, error) {
xw.WriteString(o.Name)
xw.WriteUint32(o.Flags)
xw.WriteUint64(uint64(o.Modified))
xw.WriteUint64(o.Version)
xw.WriteUint64(o.LocalVersion)
xw.WriteUint32(o.NumBlocks)
xw.WriteUint64(uint64(o.Version))
xw.WriteUint64(uint64(o.LocalVersion))
xw.WriteUint32(uint32(o.NumBlocks))
return xw.Tot(), xw.Error()
}
@@ -105,8 +105,8 @@ func (o *FileInfoTruncated) decodeXDR(xr *xdr.Reader) error {
o.Name = xr.ReadStringMax(8192)
o.Flags = xr.ReadUint32()
o.Modified = int64(xr.ReadUint64())
o.Version = xr.ReadUint64()
o.LocalVersion = xr.ReadUint64()
o.NumBlocks = xr.ReadUint32()
o.Version = int64(xr.ReadUint64())
o.LocalVersion = int64(xr.ReadUint64())
o.NumBlocks = int32(xr.ReadUint32())
return xr.Error()
}

View File

@@ -22,7 +22,7 @@ import (
"time"
)
type EventType uint64
type EventType int
const (
Ping EventType = 1 << iota

View File

@@ -21,11 +21,11 @@ import "sync"
var Default = Clock{}
type Clock struct {
val uint64
val int64
mut sync.Mutex
}
func (c *Clock) Tick(v uint64) uint64 {
func (c *Clock) Tick(v int64) int64 {
c.mut.Lock()
if v > c.val {
c.val = v + 1

View File

@@ -17,12 +17,12 @@ package lamport
import "testing"
var inputs = []uint64{0, 42, 2, 3, 4, 8, 9, 33, 44, 112, 100}
var inputs = []int64{0, 42, 2, 3, 4, 8, 9, 33, 44, 112, 100}
func TestClock(t *testing.T) {
c := Clock{}
var prev uint64
var prev int64
for _, input := range inputs {
cur := c.Tick(input)
if cur <= prev || cur <= input {

View File

@@ -701,6 +701,10 @@ func (m *Model) Close(device protocol.DeviceID, err error) {
// Request returns the specified data segment by reading it from local disk.
// Implements the protocol.Model interface.
func (m *Model) Request(deviceID protocol.DeviceID, folder, name string, offset int64, size int) ([]byte, error) {
if offset < 0 || size < 0 {
return nil, ErrNoSuchFile
}
if !m.folderSharedWith(folder, deviceID) {
l.Warnf("Request from %s for file %s in unshared folder %q", deviceID, name, folder)
return nil, ErrNoSuchFile
@@ -970,12 +974,12 @@ func sendIndexes(conn protocol.Connection, folder string, fs *db.FileSet, ignore
}
}
func sendIndexTo(initial bool, minLocalVer uint64, conn protocol.Connection, folder string, fs *db.FileSet, ignores *ignore.Matcher) (uint64, error) {
func sendIndexTo(initial bool, minLocalVer int64, conn protocol.Connection, folder string, fs *db.FileSet, ignores *ignore.Matcher) (int64, error) {
deviceID := conn.ID()
name := conn.Name()
batch := make([]protocol.FileInfo, 0, indexBatchSize)
currentBatchSize := 0
maxLocalVer := uint64(0)
maxLocalVer := int64(0)
var err error
fs.WithHave(protocol.LocalDeviceID, func(fi db.FileIntf) bool {
@@ -1349,7 +1353,7 @@ func (m *Model) Override(folder string) {
// CurrentLocalVersion returns the change version for the given folder.
// This is guaranteed to increment if the contents of the local folder has
// changed.
func (m *Model) CurrentLocalVersion(folder string) uint64 {
func (m *Model) CurrentLocalVersion(folder string) int64 {
m.fmut.RLock()
fs, ok := m.folderFiles[folder]
m.fmut.RUnlock()
@@ -1365,7 +1369,7 @@ func (m *Model) CurrentLocalVersion(folder string) uint64 {
// RemoteLocalVersion returns the change version for the given folder, as
// sent by remote peers. This is guaranteed to increment if the contents of
// the remote or global folder has changed.
func (m *Model) RemoteLocalVersion(folder string) uint64 {
func (m *Model) RemoteLocalVersion(folder string) int64 {
m.fmut.RLock()
defer m.fmut.RUnlock()
@@ -1376,7 +1380,7 @@ func (m *Model) RemoteLocalVersion(folder string) uint64 {
return 0
}
var ver uint64
var ver int64
for _, n := range m.folderDevices[folder] {
ver += fs.LocalVersion(n)
}

View File

@@ -110,6 +110,33 @@ func TestRequest(t *testing.T) {
if bs != nil {
t.Errorf("Unexpected non nil data on insecure file read: %q", string(bs))
}
// Larger block than available
bs, err = m.Request(device1, "default", "foo", 0, 42)
if err == nil {
t.Error("Unexpected nil error on insecure file read")
}
if bs != nil {
t.Errorf("Unexpected non nil data on insecure file read: %q", string(bs))
}
// Negative offset
bs, err = m.Request(device1, "default", "foo", -4, 6)
if err == nil {
t.Error("Unexpected nil error on insecure file read")
}
if bs != nil {
t.Errorf("Unexpected non nil data on insecure file read: %q", string(bs))
}
// Negative size
bs, err = m.Request(device1, "default", "foo", 4, -4)
if err == nil {
t.Error("Unexpected nil error on insecure file read")
}
if bs != nil {
t.Errorf("Unexpected non nil data on insecure file read: %q", string(bs))
}
}
func genFiles(n int) []protocol.FileInfo {

View File

@@ -100,7 +100,7 @@ func (p *Puller) Serve() {
p.model.setState(p.folder, FolderIdle)
}()
var prevVer uint64
var prevVer int64
var prevIgnoreHash string
// We don't start pulling files until a scan has been completed.
@@ -623,9 +623,9 @@ func (p *Puller) handleFile(file protocol.FileInfo, copyChan chan<- copyBlocksSt
folder: p.folder,
tempName: tempName,
realName: realName,
copyTotal: uint32(len(blocks)),
copyNeeded: uint32(len(blocks)),
reused: uint32(reused),
copyTotal: len(blocks),
copyNeeded: len(blocks),
reused: reused,
}
if debug {
@@ -720,7 +720,7 @@ func (p *Puller) copierRoutine(in <-chan copyBlocksState, pullChan chan<- pullBl
for _, block := range state.blocks {
buf = buf[:int(block.Size)]
found := p.model.finder.Iterate(block.Hash, func(folder, file string, index uint32) bool {
found := p.model.finder.Iterate(block.Hash, func(folder, file string, index int32) bool {
path := filepath.Join(folderRoots[folder], file)
var fd *os.File

View File

@@ -199,7 +199,7 @@ func TestCopierFinder(t *testing.T) {
// Update index
m.updateLocal("default", existingFile)
iterFn := func(folder, file string, index uint32) bool {
iterFn := func(folder, file string, index int32) bool {
return true
}
@@ -264,7 +264,7 @@ func TestCopierFinder(t *testing.T) {
// Test that updating a file removes it's old blocks from the blockmap
func TestCopierCleanup(t *testing.T) {
iterFn := func(folder, file string, index uint32) bool {
iterFn := func(folder, file string, index int32) bool {
return true
}
@@ -341,7 +341,7 @@ func TestLastResortPulling(t *testing.T) {
// with a different name (causing to copy that particular block)
file.Name = "newfile"
iterFn := func(folder, file string, index uint32) bool {
iterFn := func(folder, file string, index int32) bool {
return true
}

View File

@@ -33,27 +33,27 @@ type sharedPullerState struct {
folder string
tempName string
realName string
reused uint32 // Number of blocks reused from temporary file
reused int // Number of blocks reused from temporary file
// Mutable, must be locked for access
err error // The first error we hit
fd *os.File // The fd of the temp file
copyTotal uint32 // Total number of copy actions for the whole job
pullTotal uint32 // Total number of pull actions for the whole job
copyOrigin uint32 // Number of blocks copied from the original file
copyNeeded uint32 // Number of copy actions still pending
pullNeeded uint32 // Number of block pulls still pending
copyTotal int // Total number of copy actions for the whole job
pullTotal int // Total number of pull actions for the whole job
copyOrigin int // Number of blocks copied from the original file
copyNeeded int // Number of copy actions still pending
pullNeeded int // Number of block pulls still pending
mut sync.Mutex // Protects the above
}
// A momentary state representing the progress of the puller
type pullerProgress struct {
Total uint32
Reused uint32
CopiedFromOrigin uint32
CopiedFromElsewhere uint32
Pulled uint32
Pulling uint32
Total int
Reused int
CopiedFromOrigin int
CopiedFromElsewhere int
Pulled int
Pulling int
BytesDone int64
BytesTotal int64
}

View File

@@ -46,7 +46,7 @@ func Blocks(r io.Reader, blocksize int, sizehint int64) ([]protocol.BlockInfo, e
}
b := protocol.BlockInfo{
Size: uint32(n),
Size: int32(n),
Offset: offset,
Hash: hf.Sum(nil),
}