Make WriteValue return a "skinny" copy of input value

Fixes #141
This commit is contained in:
Aaron Boodman
2015-07-29 16:03:32 -07:00
parent 45a3a27f15
commit a84893c0d8
22 changed files with 85 additions and 41 deletions

View File

@@ -72,11 +72,7 @@ func main() {
return nil
}
ref, err := types.WriteValue(nomsObj, ds)
Chk.NoError(err)
// BUG 141
nomsObj, err = types.ReadValue(ref, ds)
_, nomsObj, err = types.WriteValue(nomsObj, ds)
Chk.NoError(err)
list = list.Append(nomsObj)

View File

@@ -22,13 +22,17 @@ func NewDataStore(cs chunks.ChunkStore, rt chunks.RootTracker) DataStore {
}
func newDataStoreInternal(cs chunks.ChunkStore, rt chunks.RootTracker, cc *commitCache) DataStore {
var commitSet SetOfCommit
if (rt.Root() == ref.Ref{}) {
r, err := types.WriteValue(NewSetOfCommit().NomsValue(), cs)
commitSet = NewSetOfCommit()
r, _, err := types.WriteValue(commitSet.NomsValue(), cs)
Chk.NoError(err)
Chk.True(rt.UpdateRoot(r, ref.Ref{}))
} else {
commitSet = commitSetFromRef(rt.Root(), cs)
}
return DataStore{
cs, rt, cc, commitSetFromRef(rt.Root(), cs),
cs, rt, cc, commitSet,
}
}
@@ -44,7 +48,7 @@ func (ds *DataStore) Heads() SetOfCommit {
// Commit returns a new DataStore with newCommits as the heads, but backed by the same ChunkStore and RootTracker instances as the current one.
func (ds *DataStore) Commit(newCommits SetOfCommit) DataStore {
Chk.True(newCommits.Len() > 0)
// TODO: We probably shouldn't let this go *forever*. Consider putting a limit and... I know don't...panicing?
// TODO: We probably shouldn't let this go *forever*. Consider putting a limit and... I don't know...panicing?
for !ds.doCommit(newCommits) {
}
return newDataStoreInternal(ds.ChunkStore, ds.rt, ds.cc)
@@ -80,7 +84,8 @@ func (ds *DataStore) doCommit(commits SetOfCommit) bool {
}
// TODO: This set will be orphaned if this UpdateRoot below fails
newRootRef, err := types.WriteValue(newHeads.NomsValue(), ds)
// TODO: Instead of dropping the output value on the floor here (and probably re-reading it in newDataStoreInternal, is it correct to just use it?
newRootRef, _, err := types.WriteValue(newHeads.NomsValue(), ds)
Chk.NoError(err)
return ds.rt.UpdateRoot(newRootRef, currentRootRef)

View File

@@ -18,7 +18,7 @@ func createTestDataset(name string) dataset.Dataset {
func TestValidateRef(t *testing.T) {
cs := &chunks.TestStore{}
r, err := types.WriteValue(types.Bool(true), cs)
r, _, err := types.WriteValue(types.Bool(true), cs)
assert.NoError(t, err)
_, err = validateRefAsSetOfCommit(r, cs)

View File

@@ -36,6 +36,9 @@ func (fb Blob) Chunks() []Future {
return nil
}
func (fb Blob) Release() {
}
func NewBlob(data []byte) Blob {
return Blob{data, &ref.Ref{}}
}

View File

@@ -22,7 +22,7 @@ func TestUnresolvedFuture(t *testing.T) {
cs := &chunks.TestStore{}
v := NewString("hello")
r, _ := WriteValue(v, cs)
r, _, _ := WriteValue(v, cs)
f := futureFromRef(r)
v2, err := f.Deref(cs)
@@ -41,7 +41,7 @@ func TestEqualsFastPath(t *testing.T) {
cs := &chunks.MemoryStore{}
v := Int32(1)
r, err := WriteValue(v, cs)
r, _, err := WriteValue(v, cs)
assert.NoError(err)
fv := futureFromValue(v)

View File

@@ -16,7 +16,9 @@ func (v {{.NomsType}}) Chunks() []Future {
return nil
}
func (v {{.NomsType}}) Release() {
}
func {{.NomsType}}FromVal(v Value) {{.NomsType}} {
return v.({{.NomsType}})
}

View File

@@ -16,7 +16,7 @@ func getRef(v Value) ref.Ref {
}
func getRefNoOverride(v Value) ref.Ref {
r, err := WriteValue(v, chunks.NopStore{})
r, _, err := WriteValue(v, chunks.NopStore{})
// This can never fail because NopStore doesn't write anywhere.
Chk.Nil(err)
return r

View File

@@ -39,7 +39,7 @@ func TestIncrementalLoadList(t *testing.T) {
cs := &chunks.TestStore{}
expected := NewList(testVals...)
ref, err := WriteValue(expected, cs)
ref, _, err := WriteValue(expected, cs)
assert.NoError(err)
actualVar, err := ReadValue(ref, cs)
@@ -66,7 +66,7 @@ func TestIncrementalLoadSet(t *testing.T) {
cs := &chunks.TestStore{}
expected := NewSet(testVals...)
ref, err := WriteValue(expected, cs)
ref, _, err := WriteValue(expected, cs)
assert.NoError(err)
actualVar, err := ReadValue(ref, cs)
@@ -87,7 +87,7 @@ func TestIncrementalLoadMap(t *testing.T) {
cs := &chunks.TestStore{}
expected := NewMap(testVals...)
ref, err := WriteValue(expected, cs)
ref, _, err := WriteValue(expected, cs)
assert.NoError(err)
actualVar, err := ReadValue(ref, cs)

View File

@@ -161,13 +161,13 @@ func getChildJSON(f Future, s chunks.ChunkSink) (interface{}, error) {
switch v := v.(type) {
// Blobs, lists, maps, and sets are always out-of-line
case Blob:
r, err = WriteValue(v, s)
r, _, err = WriteValue(v, s)
case List:
r, err = WriteValue(v, s)
r, _, err = WriteValue(v, s)
case Map:
r, err = WriteValue(v, s)
r, _, err = WriteValue(v, s)
case Set:
r, err = WriteValue(v, s)
r, _, err = WriteValue(v, s)
default:
// Other types are always inline.
return getJSON(v, s)

View File

@@ -165,7 +165,7 @@ func TestListFutures(t *testing.T) {
cs := &chunks.TestStore{}
v := NewString("hello")
r, _ := WriteValue(v, cs)
r, _, _ := WriteValue(v, cs)
f := futureFromRef(r)
l := listFromFutures([]Future{f, futureFromValue(Int64(0xbeefcafe))}, cs)

View File

@@ -109,6 +109,13 @@ func (fm Map) Chunks() (futures []Future) {
return
}
func (fn Map) Release() {
for _, f := range fn.m {
f.key.Release()
f.value.Release()
}
}
type mapEntry struct {
key Future
value Future

View File

@@ -173,7 +173,7 @@ func TestMapFutures(t *testing.T) {
cs := &chunks.TestStore{}
k := NewString("hello")
kRef, _ := WriteValue(k, cs)
kRef, _, _ := WriteValue(k, cs)
f := futureFromRef(kRef)
m := mapFromFutures([]Future{f, futureFromValue(Int64(0xbeefcafe))}, cs)

View File

@@ -25,10 +25,12 @@ func (v Bool) Chunks() []Future {
return nil
}
func (v Bool) Release() {
}
func BoolFromVal(v Value) Bool {
return v.(Bool)
}
type Int16 int16
func (self Int16) Equals(other Value) bool {
@@ -47,10 +49,12 @@ func (v Int16) Chunks() []Future {
return nil
}
func (v Int16) Release() {
}
func Int16FromVal(v Value) Int16 {
return v.(Int16)
}
type Int32 int32
func (self Int32) Equals(other Value) bool {
@@ -69,10 +73,12 @@ func (v Int32) Chunks() []Future {
return nil
}
func (v Int32) Release() {
}
func Int32FromVal(v Value) Int32 {
return v.(Int32)
}
type Int64 int64
func (self Int64) Equals(other Value) bool {
@@ -91,10 +97,12 @@ func (v Int64) Chunks() []Future {
return nil
}
func (v Int64) Release() {
}
func Int64FromVal(v Value) Int64 {
return v.(Int64)
}
type UInt16 uint16
func (self UInt16) Equals(other Value) bool {
@@ -113,10 +121,12 @@ func (v UInt16) Chunks() []Future {
return nil
}
func (v UInt16) Release() {
}
func UInt16FromVal(v Value) UInt16 {
return v.(UInt16)
}
type UInt32 uint32
func (self UInt32) Equals(other Value) bool {
@@ -135,10 +145,12 @@ func (v UInt32) Chunks() []Future {
return nil
}
func (v UInt32) Release() {
}
func UInt32FromVal(v Value) UInt32 {
return v.(UInt32)
}
type UInt64 uint64
func (self UInt64) Equals(other Value) bool {
@@ -157,10 +169,12 @@ func (v UInt64) Chunks() []Future {
return nil
}
func (v UInt64) Release() {
}
func UInt64FromVal(v Value) UInt64 {
return v.(UInt64)
}
type Float32 float32
func (self Float32) Equals(other Value) bool {
@@ -179,10 +193,12 @@ func (v Float32) Chunks() []Future {
return nil
}
func (v Float32) Release() {
}
func Float32FromVal(v Value) Float32 {
return v.(Float32)
}
type Float64 float64
func (self Float64) Equals(other Value) bool {
@@ -201,7 +217,9 @@ func (v Float64) Chunks() []Future {
return nil
}
func (v Float64) Release() {
}
func Float64FromVal(v Value) Float64 {
return v.(Float64)
}

View File

@@ -26,4 +26,5 @@ func (rf resolvedFuture) Deref(cs chunks.ChunkSource) (Value, error) {
}
func (rf resolvedFuture) Release() {
rf.val.Release()
}

View File

@@ -119,6 +119,12 @@ func (fs Set) Chunks() (futures []Future) {
return
}
func (fs Set) Release() {
for _, f := range fs.m {
f.Release()
}
}
func newSetFromData(m setData, cs chunks.ChunkSource) Set {
return Set{m, cs, &ref.Ref{}}
}

View File

@@ -130,7 +130,7 @@ func TestSetFutures(t *testing.T) {
cs := &chunks.TestStore{}
v := NewString("hello")
r, _ := WriteValue(v, cs)
r, _, _ := WriteValue(v, cs)
f := futureFromRef(r)
s := listFromFutures([]Future{f, futureFromValue(Int64(0xbeefcafe))}, cs)

View File

@@ -37,6 +37,9 @@ func (fs String) Chunks() []Future {
return nil
}
func (fs String) Release() {
}
func StringFromVal(v Value) String {
return v.(String)
}

View File

@@ -9,4 +9,5 @@ type Value interface {
Equals(other Value) bool
Ref() ref.Ref
Chunks() []Future
Release()
}

View File

@@ -5,12 +5,14 @@ import (
"github.com/attic-labs/noms/ref"
)
// TODO: This ends up loading the entire value recursively. We need to change the encoder to look at the futures directly and not expand them.
func WriteValue(v Value, cs chunks.ChunkSink) (ref.Ref, error) {
switch v := v.(type) {
func WriteValue(in Value, cs chunks.ChunkSink) (r ref.Ref, out Value, err error) {
switch in := in.(type) {
case Blob:
return blobEncode(v, cs)
r, err = blobEncode(in, cs)
default:
return jsonEncode(v, cs)
r, err = jsonEncode(in, cs)
}
out = in
out.Release()
return
}

View File

@@ -16,7 +16,7 @@ func TestWriteValue(t *testing.T) {
testEncode := func(expected string, v Value) ref.Ref {
s = &chunks.MemoryStore{}
r, err := WriteValue(v, s)
r, _, err := WriteValue(v, s)
assert.NoError(err)
// Assuming that MemoryStore works correctly, we don't need to check the actual serialization, only the hash. Neat.

View File

@@ -14,7 +14,7 @@ func TestDifference(t *testing.T) {
cs := &chunks.TestStore{}
storeAndRef := func(v types.Value) (r ref.Ref) {
r, err := types.WriteValue(v, cs)
r, _, err := types.WriteValue(v, cs)
assert.NoError(err)
return
}

View File

@@ -33,7 +33,7 @@ func (suite *WalkAllTestSuite) walkWorker(r ref.Ref, expected int) {
}
func (suite *WalkAllTestSuite) storeAndRef(v types.Value) (r ref.Ref) {
r, err := types.WriteValue(v, suite.cs)
r, _, err := types.WriteValue(v, suite.cs)
dbg.Chk.NoError(err)
return
}