mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 10:54:59 +00:00
fixed crashing issue that was not handling container removal/recycling correctly
This commit is contained in:
parent
eb43707d19
commit
643e5e575a
6 changed files with 100 additions and 2 deletions
1
api.go
1
api.go
|
|
@ -658,7 +658,6 @@ func (api *API) ImportValue(ctx context.Context, req internal.ImportValueRequest
|
|||
if err != nil {
|
||||
return errors.Wrap(err, "getting field")
|
||||
}
|
||||
|
||||
// Import into fragment.
|
||||
err = field.ImportValue(req.ColumnIDs, req.Values)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -197,3 +197,55 @@ func GetIO(buf bytes.Buffer) (io.Reader, io.Writer, io.Writer) {
|
|||
stderr := bufio.NewWriter(&buf)
|
||||
return stdin, stdout, stderr
|
||||
}
|
||||
|
||||
func TestImportCommand_BugOverwriteValue(t *testing.T) {
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
stdin, stdout, stderr := GetIO(buf)
|
||||
cm := NewImportCommand(stdin, stdout, stderr)
|
||||
file, err := ioutil.TempFile("", "import-value.csv")
|
||||
file.Write([]byte("0,17\n"))
|
||||
ctx := context.Background()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hldr := test.MustOpenHolder()
|
||||
defer hldr.Close()
|
||||
s := test.NewServer()
|
||||
defer s.Close()
|
||||
|
||||
s.Handler.API.Cluster = test.NewCluster(1)
|
||||
s.Handler.API.Cluster.Nodes[0].URI = s.HostURI()
|
||||
s.Handler.API.Holder = hldr.Holder
|
||||
cm.Host = s.Host()
|
||||
|
||||
http.DefaultClient.Do(MustNewHTTPRequest("POST", s.URL+"/index/i", strings.NewReader("")))
|
||||
http.DefaultClient.Do(MustNewHTTPRequest("POST", s.URL+"/index/i/field/f", strings.NewReader(`{"options":{"type": "int", "min": 0, "max":2147483648 }}`)))
|
||||
|
||||
cm.Index = "i"
|
||||
cm.Field = "f"
|
||||
cm.Paths = []string{file.Name()}
|
||||
err = cm.Run(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Import Run with values doesn't work: %s", err)
|
||||
}
|
||||
|
||||
file.Close()
|
||||
file, err = ioutil.TempFile("", "import-value2.csv")
|
||||
file.Write([]byte("0,16\n"))
|
||||
cm.Paths = []string{file.Name()}
|
||||
err = cm.Run(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Import Run with values doesn't work: %s", err)
|
||||
}
|
||||
|
||||
file.Close()
|
||||
file, err = ioutil.TempFile("", "import-value3.csv")
|
||||
file.Write([]byte("0,19\n"))
|
||||
cm.Paths = []string{file.Name()}
|
||||
err = cm.Run(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Import Run with values doesn't work: %s", err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -160,6 +160,10 @@ func (btc *BTreeContainers) Size() int {
|
|||
return btc.tree.Len()
|
||||
}
|
||||
|
||||
func (btc *BTreeContainers) Reset() {
|
||||
btc.tree = TreeNew(cmp)
|
||||
}
|
||||
|
||||
func (btc *BTreeContainers) Iterator(key uint64) (citer roaring.ContainerIterator, found bool) {
|
||||
e, ok := btc.tree.Seek(key)
|
||||
if ok {
|
||||
|
|
|
|||
|
|
@ -213,6 +213,39 @@ func TestFragment_SetValue(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
t.Run("Crash", func(t *testing.T) {
|
||||
f := mustOpenFragment("i", "f", ViewStandard, 0, "")
|
||||
defer f.Close()
|
||||
|
||||
// Set value.
|
||||
if changed, err := f.setValue(0, 32, 17); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !changed {
|
||||
t.Fatal("expected change")
|
||||
}
|
||||
|
||||
if changed, err := f.setValue(0, 32, 16); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !changed {
|
||||
t.Fatal("expected change")
|
||||
}
|
||||
|
||||
if changed, err := f.setValue(0, 32, 19); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if !changed {
|
||||
t.Fatal("expected change")
|
||||
}
|
||||
|
||||
// Read value.
|
||||
if value, exists, err := f.value(0, 32); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if value != 19 {
|
||||
t.Fatalf("unexpected value: %d", value)
|
||||
} else if !exists {
|
||||
t.Fatal("expected to exist")
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// Ensure a fragment can sum values.
|
||||
|
|
|
|||
|
|
@ -132,6 +132,13 @@ func (sc *SliceContainers) Count() uint64 {
|
|||
return n
|
||||
}
|
||||
|
||||
func (sc *SliceContainers) Reset() {
|
||||
sc.keys = sc.keys[:0]
|
||||
sc.containers = sc.containers[:0]
|
||||
sc.lastContainer = nil
|
||||
sc.lastKey = 0
|
||||
}
|
||||
|
||||
func (sc *SliceContainers) seek(key uint64) (int, bool) {
|
||||
i := search64(sc.keys, key)
|
||||
found := true
|
||||
|
|
|
|||
|
|
@ -94,6 +94,8 @@ type Containers interface {
|
|||
// container is found at key.
|
||||
Iterator(key uint64) (citer ContainerIterator, found bool)
|
||||
Count() uint64
|
||||
//Reset will clear the containers collection to allow for recycling during snapshot
|
||||
Reset()
|
||||
}
|
||||
|
||||
type ContainerIterator interface {
|
||||
|
|
@ -631,7 +633,7 @@ func (b *Bitmap) UnmarshalBinary(data []byte) error {
|
|||
keyN := binary.LittleEndian.Uint32(data[4:8])
|
||||
|
||||
headerSize := headerBaseSize
|
||||
|
||||
b.Containers.Reset()
|
||||
// Descriptive header section: Read container keys and cardinalities.
|
||||
for i, buf := 0, data[headerSize:]; i < int(keyN); i, buf = i+1, buf[12:] {
|
||||
b.Containers.PutContainerValues(
|
||||
|
|
@ -688,6 +690,7 @@ func (b *Bitmap) UnmarshalBinary(data []byte) error {
|
|||
// FIXME(benbjohnson): return error with position so file can be trimmed.
|
||||
return err
|
||||
}
|
||||
|
||||
opr.apply(b)
|
||||
|
||||
// Increase the op count.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue