func (b *blockEtcd) GetINode() (torus.INodeRef, error) {
	resp, err := b.Etcd.Client.Get(b.getContext(), etcd.MkKey("volumemeta", etcd.Uint64ToHex(uint64(b.vid)), "blockinode"))
	if err != nil {
		return torus.NewINodeRef(0, 0), err
	}
	if len(resp.Kvs) != 1 {
		return torus.NewINodeRef(0, 0), errors.New("unexpected metadata for volume")
	}
	return torus.INodeRefFromBytes(resp.Kvs[0].Value), nil
}
func BenchmarkPutBlock(b *testing.B) {
	test := makeTestData(512 * 1024)
	m := &mockBlockRPC{
		data: test,
	}
	s, err := Serve("localhost:0", m, m.BlockSize())
	if err != nil {
		b.Fatal(err)
	}
	defer s.Close()
	c, err := Dial(s.ListenAddr().String(), time.Second, m.BlockSize())
	if err != nil {
		b.Fatal(err)
	}
	defer c.Close()
	total := 0
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		err = c.PutBlock(context.TODO(), torus.BlockRef{
			INodeRef: torus.NewINodeRef(1, 2),
			Index:    3,
		}, test)
		if err != nil {
			b.Fatal(err)
		}
		total += len(test)
	}
	b.SetBytes(int64(total / b.N))
}
func BenchmarkBlock(b *testing.B) {
	test := makeTestData(512 * 1024)
	m := &mockBlockRPC{
		data: test,
	}
	s, err := Serve("localhost:0", m, m.BlockSize())
	if err != nil {
		b.Fatal(err)
	}
	c, err := Dial(s.ListenAddr().String(), time.Second, m.BlockSize())
	if err != nil {
		b.Fatal(err)
	}
	total := 0
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		data, err := c.Block(context.TODO(), torus.BlockRef{
			INodeRef: torus.NewINodeRef(1, 2),
			Index:    3,
		})
		if err != nil {
			b.Fatal(err)
		}
		if !bytes.Equal(test, data) {
			b.Fatal("unequal response")
		}
		total += len(data)
		b.ReportAllocs()
	}
	b.SetBytes(int64(total / b.N))
}
func TestRebalanceCheck(t *testing.T) {
	test := make([]torus.BlockRef, nchecks)
	m := &mockBlockRPC{}
	for i, _ := range test {
		test[i].Index = 3
		test[i].INodeRef = torus.NewINodeRef(1, torus.INodeID(rand.Intn(40)))
	}
	s, err := Serve("localhost:0", m, m.BlockSize())
	if err != nil {
		t.Fatal(err)
	}
	defer s.Close()
	c, err := Dial(s.ListenAddr().String(), time.Second, m.BlockSize())
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()
	bs, err := c.RebalanceCheck(context.TODO(), test)
	if err != nil {
		t.Fatal(err)
	}
	for i, x := range bs {
		if x {
			if test[i].INode%2 == 0 {
				t.Fatal("unequal")
			}
		} else {
			if test[i].INode%2 == 1 {
				t.Fatal("unequal")
			}
		}
	}
}
func TestPutBlock(t *testing.T) {
	stest := makeTestData(512 * 1024)
	ctest := append([]byte(nil), stest...)

	m := &mockBlockRPC{
		data: stest,
	}
	s, err := Serve("localhost:0", m, m.BlockSize())
	if err != nil {
		t.Fatal(err)
	}
	defer s.Close()
	c, err := Dial(s.ListenAddr().String(), time.Second, m.BlockSize())
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()
	err = c.PutBlock(context.TODO(), torus.BlockRef{
		INodeRef: torus.NewINodeRef(1, 2),
		Index:    3,
	}, ctest)
	if err != nil {
		t.Fatal(err)
	}
}
func TestBlockGRPC(t *testing.T) {
	test := makeTestData(512 * 1024)
	m := &mockBlockGRPC{
		data: test,
	}
	lis, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		t.Fatal(err)
	}
	grpcSrv := grpc.NewServer()
	models.RegisterTorusStorageServer(grpcSrv, m)
	go grpcSrv.Serve(lis)
	defer grpcSrv.Stop()
	conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure(), grpc.WithTimeout(10*time.Second))
	if err != nil {
		t.Fatal(err)
	}
	defer conn.Close()
	client := models.NewTorusStorageClient(conn)
	resp, err := client.Block(context.TODO(), &models.BlockRequest{
		BlockRef: torus.BlockRef{
			INodeRef: torus.NewINodeRef(1, 2),
			Index:    3,
		}.ToProto(),
	})
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(test, resp.Data) {
		t.Fatal("unequal response")
	}
}
func TestBlock(t *testing.T) {
	test := makeTestData(512 * 1024)
	m := &mockBlockRPC{
		data: test,
	}
	s, err := Serve("localhost:0", m, m.BlockSize())
	if err != nil {
		t.Fatal(err)
	}
	defer s.Close()
	c, err := Dial(s.ListenAddr().String(), time.Second, m.BlockSize())
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()
	b, err := c.Block(context.TODO(), torus.BlockRef{
		INodeRef: torus.NewINodeRef(1, 2),
		Index:    3,
	})
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(test, b) {
		t.Fatal("unequal response")
	}
}
func marshalTest(t *testing.T, s torus.BlockStore, spec torus.BlockLayerSpec) {
	b, err := CreateBlocksetFromSpec(spec, s)
	if err != nil {
		t.Fatal(err)
	}
	inode := torus.NewINodeRef(1, 1)
	b.PutBlock(context.TODO(), inode, 0, []byte("Some data"))
	marshal, err := torus.MarshalBlocksetToProto(b)
	if err != nil {
		t.Fatal(err)
	}

	b = nil
	newb, err := UnmarshalFromProto(marshal, s)
	if err != nil {
		t.Fatal(err)
	}

	data, err := newb.GetBlock(context.TODO(), 0)
	if err != nil {
		t.Fatal(err)
	}
	if string(data) != "Some data" {
		t.Error("data not retrieved")
	}
}
func TestTinyPeer(t *testing.T) {
	pi := torus.PeerInfoList{
		&models.PeerInfo{
			UUID:        "a",
			TotalBlocks: 20 * 1024 * 1024 * 2,
		},
		&models.PeerInfo{
			UUID:        "b",
			TotalBlocks: 20 * 1024 * 1024 * 2,
		},
		&models.PeerInfo{
			UUID:        "c",
			TotalBlocks: 100 * 1024 * 2,
		},
	}
	k := &ketama{
		version: 1,
		peers:   pi,
		rep:     2,
		ring:    hashring.NewWithWeights(pi.GetWeights()),
	}
	l, err := k.GetPeers(torus.BlockRef{
		INodeRef: torus.NewINodeRef(3, 4),
		Index:    5,
	})
	if err != nil {
		t.Fatal(err)
	}
	t.Log(l.Peers)
}
func (b *blockEtcd) CreateBlockVolume(volume *models.Volume) error {
	new, err := b.AtomicModifyKey([]byte(etcd.MkKey("meta", "volumeminter")), etcd.BytesAddOne)
	volume.Id = new.(uint64)
	if err != nil {
		return err
	}
	vbytes, err := volume.Marshal()
	if err != nil {
		return err
	}
	inodeBytes := torus.NewINodeRef(torus.VolumeID(volume.Id), 1).ToBytes()

	do := b.Etcd.Client.Txn(b.getContext()).If(
		etcdv3.Compare(etcdv3.Version(etcd.MkKey("volumes", volume.Name)), "=", 0),
	).Then(
		etcdv3.OpPut(etcd.MkKey("volumes", volume.Name), string(etcd.Uint64ToBytes(volume.Id))),
		etcdv3.OpPut(etcd.MkKey("volumeid", etcd.Uint64ToHex(volume.Id)), string(vbytes)),
		etcdv3.OpPut(etcd.MkKey("volumemeta", etcd.Uint64ToHex(volume.Id), "inode"), string(etcd.Uint64ToBytes(1))),
		etcdv3.OpPut(etcd.MkKey("volumemeta", etcd.Uint64ToHex(volume.Id), "blockinode"), string(inodeBytes)),
	)
	resp, err := do.Commit()
	if err != nil {
		return err
	}
	if !resp.Succeeded {
		return torus.ErrExists
	}
	return nil
}
func generateLinearFile(vol torus.VolumeID, in torus.INodeID, size int) ([]torus.BlockRef, torus.INodeID) {
	var out []torus.BlockRef
	for x := 1; x <= size; x++ {
		out = append(out, torus.BlockRef{
			INodeRef: torus.NewINodeRef(vol, in),
			Index:    torus.IndexID(x),
		})
	}
	return out, in + 1
}
func readWriteTest(t *testing.T, b blockset) {
	inode := torus.NewINodeRef(1, 1)
	b.PutBlock(context.TODO(), inode, 0, []byte("Some data"))
	inode = torus.NewINodeRef(1, 2)
	b.PutBlock(context.TODO(), inode, 1, []byte("Some more data"))
	data, err := b.GetBlock(context.TODO(), 0)
	if err != nil {
		t.Fatal(err)
	}
	if string(data) != "Some data" {
		t.Error("data not retrieved")
	}
	b.PutBlock(context.TODO(), inode, 0, []byte("Some different data"))
	data, err = b.GetBlock(context.TODO(), 0)
	if err != nil {
		t.Fatal(err)
	}
	if string(data) != "Some different data" {
		t.Error("data not retrieved")
	}
}
func TestCRCCorruption(t *testing.T) {
	s, _ := torus.CreateBlockStore("temp", "test", torus.Config{StorageSize: 300 * 1024}, torus.GlobalMetadata{BlockSize: 1024})
	b := newBaseBlockset(s)
	crc := newCRCBlockset(b)
	inode := torus.NewINodeRef(1, 1)
	crc.PutBlock(context.TODO(), inode, 0, []byte("Some data"))
	s.WriteBlock(context.TODO(), b.blocks[0], []byte("Evil Corruption!!"))
	_, err := crc.GetBlock(context.TODO(), 0)
	if err != torus.ErrBlockUnavailable {
		t.Fatal("No corruption detection")
	}
}
func (b *blockTempMetadata) CreateBlockVolume(volume *models.Volume) error {
	b.LockData()
	defer b.UnlockData()
	_, ok := b.GetData(fmt.Sprint(volume.Id))
	if ok {
		return torus.ErrExists
	}
	b.CreateVolume(volume)
	b.SetData(fmt.Sprint(volume.Id), &blockTempVolumeData{
		locked: "",
		id:     torus.NewINodeRef(torus.VolumeID(volume.Id), 1),
	})
	return nil
}
func BenchmarkGRPCRebalanceCheck(b *testing.B) {
	test := make([]torus.BlockRef, nchecks)
	m := &mockBlockGRPC{}
	for i, _ := range test {
		test[i].Index = 3
		test[i].INodeRef = torus.NewINodeRef(1, torus.INodeID(rand.Intn(40)))
	}
	lis, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		b.Fatal(err)
	}
	grpcSrv := grpc.NewServer()
	models.RegisterTorusStorageServer(grpcSrv, m)
	go grpcSrv.Serve(lis)
	defer grpcSrv.Stop()
	conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure(), grpc.WithTimeout(10*time.Second))
	if err != nil {
		b.Fatal(err)
	}
	defer conn.Close()
	client := models.NewTorusStorageClient(conn)
	total := 0
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		refs := make([]*models.BlockRef, 0, len(test))
		for _, x := range test {
			refs = append(refs, x.ToProto())
		}
		resp, err := client.RebalanceCheck(context.TODO(), &models.RebalanceCheckRequest{
			BlockRefs: refs,
		})
		if err != nil {
			b.Fatal(err)
		}
		for i, x := range resp.Valid {
			if x {
				if test[i].INode%2 == 0 {
					b.Fatal("unequal")
				}
			} else {
				if test[i].INode%2 == 1 {
					b.Fatal("unequal")
				}
			}
		}
		total += len(resp.Valid)
	}
	b.SetBytes(int64(total / b.N))
}
func BenchmarkGRPCPutBlock(b *testing.B) {
	test := makeTestData(512 * 1024)
	m := &mockBlockGRPC{
		data: test,
	}
	lis, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		b.Fatal(err)
	}
	grpcSrv := grpc.NewServer()
	models.RegisterTorusStorageServer(grpcSrv, m)
	go grpcSrv.Serve(lis)
	defer grpcSrv.Stop()
	conn, err := grpc.Dial(lis.Addr().String(), grpc.WithInsecure(), grpc.WithTimeout(10*time.Second))
	if err != nil {
		b.Fatal(err)
	}
	defer conn.Close()
	client := models.NewTorusStorageClient(conn)
	total := 0
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		resp, err := client.PutBlock(context.TODO(), &models.PutBlockRequest{
			Refs: []*models.BlockRef{
				torus.BlockRef{
					INodeRef: torus.NewINodeRef(1, 2),
					Index:    3,
				}.ToProto(),
			},
			Blocks: [][]byte{
				test,
			},
		})
		if err != nil {
			b.Fatal(err)
		}
		if !resp.Ok {
			b.Fatal("unequal response")
		}
		total += len(test)
	}
	b.SetBytes(int64(total / b.N))
}
func BenchmarkRebalanceCheck(b *testing.B) {
	test := make([]torus.BlockRef, nchecks)
	m := &mockBlockRPC{}
	for i, _ := range test {
		test[i].Index = 3
		test[i].INodeRef = torus.NewINodeRef(1, torus.INodeID(rand.Intn(40)))
	}
	s, err := Serve("localhost:0", m, m.BlockSize())
	if err != nil {
		b.Fatal(err)
	}
	defer s.Close()
	c, err := Dial(s.ListenAddr().String(), time.Second, m.BlockSize())
	if err != nil {
		b.Fatal(err)
	}
	defer c.Close()
	total := 0
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		bs, err := c.RebalanceCheck(context.TODO(), test)
		if err != nil {
			b.Fatal(err)
		}
		for i, x := range bs {
			if x {
				if test[i].INode%2 == 0 {
					b.Fatal("unequal")
				}
			} else {
				if test[i].INode%2 == 1 {
					b.Fatal("unequal")
				}
			}
		}
		total += len(bs)
	}
	b.SetBytes(int64(total / b.N))
}