diff --git a/go.mod b/go.mod index 3605589c287..3067d774136 100644 --- a/go.mod +++ b/go.mod @@ -32,6 +32,7 @@ require ( github.com/influxdata/flux v0.169.0 github.com/influxdata/httprouter v1.3.1-0.20191122104820-ee83e2772f69 github.com/influxdata/influx-cli/v2 v2.2.1-0.20220318222112-88ba3464cd07 + github.com/influxdata/influxdb v1.9.7 github.com/influxdata/influxql v1.1.1-0.20211004132434-7e7d61973256 github.com/influxdata/line-protocol v0.0.0-20200327222509-2487e7298839 github.com/influxdata/pkg-config v0.2.11 @@ -49,7 +50,7 @@ require ( github.com/prometheus/client_golang v1.5.1 github.com/prometheus/client_model v0.2.0 github.com/prometheus/common v0.9.1 - github.com/retailnext/hllpp v1.0.0 + github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52 github.com/spf13/cast v1.3.0 github.com/spf13/cobra v1.0.0 github.com/spf13/pflag v1.0.5 @@ -64,7 +65,7 @@ require ( go.uber.org/multierr v1.6.0 go.uber.org/zap v1.16.0 golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 - golang.org/x/sync v0.0.0-20210220032951-036812b2e83c + golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 golang.org/x/text v0.3.7 golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba @@ -97,7 +98,7 @@ require ( github.com/SAP/go-hdb v0.14.1 // indirect github.com/aokoli/goutils v1.0.1 // indirect github.com/apache/arrow/go/arrow v0.0.0-20211112161151-bc219186db40 // indirect - github.com/aws/aws-sdk-go v1.29.16 // indirect + github.com/aws/aws-sdk-go v1.30.12 // indirect github.com/aws/aws-sdk-go-v2 v1.11.0 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.0.0 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.6.1 // indirect @@ -176,10 +177,10 @@ require ( github.com/pierrec/lz4/v4 v4.1.11 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/procfs v0.0.8 // indirect + github.com/prometheus/procfs v0.0.11 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect - github.com/segmentio/kafka-go v0.1.0 // indirect + github.com/segmentio/kafka-go v0.2.0 // indirect github.com/sergi/go-diff v1.1.0 // indirect github.com/sirupsen/logrus v1.8.1 // indirect github.com/spf13/afero v1.1.2 // indirect diff --git a/go.sum b/go.sum index adf2f3636cb..1a1b1433dca 100644 --- a/go.sum +++ b/go.sum @@ -128,8 +128,9 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.29.16 h1:Gbtod7Y4W/Ai7wPtesdvgGVTkFN8JxAaGouRLlcQfQs= github.com/aws/aws-sdk-go v1.29.16/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg= +github.com/aws/aws-sdk-go v1.30.12 h1:KrjyosZvkpJjcwMk0RNxMZewQ47v7+ZkbQDXjWsJMs8= +github.com/aws/aws-sdk-go v1.30.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aws/aws-sdk-go-v2 v1.11.0 h1:HxyD62DyNhCfiFGUHqJ/xITD6rAjJ7Dm/2nLxLmO4Ag= github.com/aws/aws-sdk-go-v2 v1.11.0/go.mod h1:SQfA+m2ltnu1cA0soUkj4dRSsmITiVQUJvBIZjzfPyQ= @@ -504,6 +505,8 @@ github.com/influxdata/httprouter v1.3.1-0.20191122104820-ee83e2772f69 h1:WQsmW0f github.com/influxdata/httprouter v1.3.1-0.20191122104820-ee83e2772f69/go.mod h1:pwymjR6SrP3gD3pRj9RJwdl1j5s3doEEV8gS4X9qSzA= github.com/influxdata/influx-cli/v2 v2.2.1-0.20220318222112-88ba3464cd07 h1:qfj5kTFYg5KhePA0A5BzFV6zxW0yLYF5K0O7t3drqn8= github.com/influxdata/influx-cli/v2 v2.2.1-0.20220318222112-88ba3464cd07/go.mod h1:p1X8Ga67SzLC35qmwvTCmWXdpZOTHSWWMXJ0zwRTW50= +github.com/influxdata/influxdb v1.9.7 h1:asjvZJ8NFFmxkSw+kOJj1ItGLQdU1nvRQE3jvdQXeRU= +github.com/influxdata/influxdb v1.9.7/go.mod h1:YZMcI9MYeMGLcg7Td7z5YRk52tL85r5bF4qX6WCnSt4= github.com/influxdata/influxdb-client-go/v2 v2.3.1-0.20210518120617-5d1fff431040 h1:MBLCfcSsUyFPDJp6T7EoHp/Ph3Jkrm4EuUKLD2rUWHg= github.com/influxdata/influxdb-client-go/v2 v2.3.1-0.20210518120617-5d1fff431040/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= @@ -516,6 +519,7 @@ github.com/influxdata/pkg-config v0.2.11/go.mod h1:EMS7Ll0S4qkzDk53XS3Z72/egBsPI github.com/influxdata/tdigest v0.0.2-0.20210216194612-fc98d27c9e8b h1:i44CesU68ZBRvtCjBi3QSosCIKrjmMbYlQMFAwVLds4= github.com/influxdata/tdigest v0.0.2-0.20210216194612-fc98d27c9e8b/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= @@ -720,12 +724,13 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI= +github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/retailnext/hllpp v1.0.0 h1:7+NffI2mo7lZG78NruEsf3jEnjJ6Z0n1otEyFqdK8zA= -github.com/retailnext/hllpp v1.0.0/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= +github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52 h1:RnWNS9Hlm8BIkjr6wx8li5abe0fr73jljLycdfemTp0= +github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -742,8 +747,8 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b h1:gQZ0qzfKHQIybLANtM3mBXNUtOfsCFXeTsnBqCsx1KM= github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/segmentio/kafka-go v0.1.0 h1:IXCHG+sXPNiIR5pC/vTEItZduPKu4cnpr85YgxpxlW0= -github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= +github.com/segmentio/kafka-go v0.2.0 h1:HtCSf6B4gN/87yc5qTl7WsxPKQIIGXLPPM1bMCPOsoY= +github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= @@ -1024,8 +1029,9 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4= +golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1056,6 +1062,7 @@ golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/pkg/mmap/mmap_unix.go b/pkg/mmap/mmap_unix.go index e4e4cffb501..6dac341481f 100644 --- a/pkg/mmap/mmap_unix.go +++ b/pkg/mmap/mmap_unix.go @@ -10,15 +10,17 @@ package mmap import ( "os" "syscall" + + errors2 "github.com/influxdata/influxdb/pkg/errors" ) // Map memory-maps a file. -func Map(path string, sz int64) ([]byte, error) { +func Map(path string, sz int64) (data []byte, err error) { f, err := os.Open(path) if err != nil { return nil, err } - defer f.Close() + defer errors2.Capture(&err, f.Close)() fi, err := f.Stat() if err != nil { @@ -32,7 +34,7 @@ func Map(path string, sz int64) ([]byte, error) { sz = fi.Size() } - data, err := syscall.Mmap(int(f.Fd()), 0, int(sz), syscall.PROT_READ, syscall.MAP_SHARED) + data, err = syscall.Mmap(int(f.Fd()), 0, int(sz), syscall.PROT_READ, syscall.MAP_SHARED) if err != nil { return nil, err } diff --git a/tsdb/index/tsi1/file_set.go b/tsdb/index/tsi1/file_set.go index 1e58269cb30..b42e482ce61 100644 --- a/tsdb/index/tsi1/file_set.go +++ b/tsdb/index/tsi1/file_set.go @@ -38,13 +38,7 @@ func (fs *FileSet) bytes() int { // Close closes all the files in the file set. func (fs FileSet) Close() error { - var err error - for _, f := range fs.files { - if e := f.Close(); e != nil && err == nil { - err = e - } - } - return err + return Files(fs.files).Close() } // Retain adds a reference count to all files. @@ -456,6 +450,16 @@ func (a Files) IDs() []int { return ids } +func (a Files) Close() error { + var err error + for _, f := range a { + if e := f.Close(); e != nil && err == nil { + err = e + } + } + return err +} + // fileSetSeriesIDIterator attaches a fileset to an iterator that is released on close. type fileSetSeriesIDIterator struct { once sync.Once diff --git a/tsdb/index/tsi1/index.go b/tsdb/index/tsi1/index.go index f5fc2407d6c..373cac71833 100644 --- a/tsdb/index/tsi1/index.go +++ b/tsdb/index/tsi1/index.go @@ -21,6 +21,7 @@ import ( "github.com/influxdata/influxdb/v2/tsdb" "github.com/influxdata/influxql" "go.uber.org/zap" + "golang.org/x/sync/errgroup" ) // IndexName is the name of the index. @@ -252,7 +253,7 @@ func (i *Index) SeriesIDSet() *tsdb.SeriesIDSet { } // Open opens the index. -func (i *Index) Open() error { +func (i *Index) Open() (rErr error) { i.mu.Lock() defer i.mu.Unlock() @@ -281,29 +282,16 @@ func (i *Index) Open() error { partitionN := len(i.partitions) n := i.availableThreads() - // Store results. - errC := make(chan error, partitionN) - // Run fn on each partition using a fixed number of goroutines. - var pidx uint32 // Index of maximum Partition being worked on. - for k := 0; k < n; k++ { - go func(k int) { - for { - idx := int(atomic.AddUint32(&pidx, 1) - 1) // Get next partition to work on. - if idx >= partitionN { - return // No more work. - } - err := i.partitions[idx].Open() - errC <- err - } - }(k) + g := new(errgroup.Group) + g.SetLimit(n) + for idx := 0; idx < partitionN; idx++ { + g.Go(i.partitions[idx].Open) } - - // Check for error - for i := 0; i < partitionN; i++ { - if err := <-errC; err != nil { - return err - } + err := g.Wait() + defer i.cleanUpFail(&rErr) + if err != nil { + return err } // Refresh cached sketches. @@ -319,6 +307,18 @@ func (i *Index) Open() error { return nil } +func (i *Index) cleanUpFail(err *error) { + if nil != *err { + for _, p := range i.partitions { + if (p != nil) && p.IsOpen() { + if e := p.Close(); e != nil { + i.logger.Warn("Failed to clean up partition") + } + } + } + } +} + // Compact requests a compaction of partitions. func (i *Index) Compact() { i.mu.Lock() diff --git a/tsdb/index/tsi1/index_test.go b/tsdb/index/tsi1/index_test.go index d4895099dbd..078f5495164 100644 --- a/tsdb/index/tsi1/index_test.go +++ b/tsdb/index/tsi1/index_test.go @@ -5,6 +5,7 @@ import ( "fmt" "io" "os" + "path" "path/filepath" "reflect" "regexp" @@ -16,6 +17,8 @@ import ( "github.com/influxdata/influxdb/v2/models" "github.com/influxdata/influxdb/v2/tsdb" "github.com/influxdata/influxdb/v2/tsdb/index/tsi1" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) // Bloom filter settings used in tests. @@ -208,6 +211,28 @@ func TestIndex_DropMeasurement(t *testing.T) { }) } +func TestIndex_OpenFail(t *testing.T) { + idx := NewDefaultIndex() + require.NoError(t, idx.Open()) + idx.Index.Close() + // mess up the index: + tslPath := path.Join(idx.Index.Path(), "3", "L0-00000001.tsl") + tslFile, err := os.OpenFile(tslPath, os.O_RDWR, 0666) + require.NoError(t, err) + require.NoError(t, tslFile.Truncate(0)) + // write poisonous TSL file - first byte doesn't matter, remaining bytes are an invalid uvarint + _, err = tslFile.Write([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}) + require.NoError(t, err) + require.NoError(t, tslFile.Close()) + idx.Index = tsi1.NewIndex(idx.SeriesFile.SeriesFile, "db0", tsi1.WithPath(idx.Index.Path())) + require.EqualError(t, idx.Index.Open(), "parsing binary-encoded uint64 value failed; binary.Uvarint() returned -11") + // ensure each partition is closed: + for i := 0; i < int(idx.Index.PartitionN); i++ { + assert.Equal(t, idx.Index.PartitionAt(i).FileN(), 0) + } + require.NoError(t, idx.Close()) +} + func TestIndex_Open(t *testing.T) { // Opening a fresh index should set the MANIFEST version to current version. idx := NewDefaultIndex() diff --git a/tsdb/index/tsi1/partition.go b/tsdb/index/tsi1/partition.go index 3ecaac126c0..daa5450cb2c 100644 --- a/tsdb/index/tsi1/partition.go +++ b/tsdb/index/tsi1/partition.go @@ -90,11 +90,11 @@ type Partition struct { // NewPartition returns a new instance of Partition. func NewPartition(sfile *tsdb.SeriesFile, path string) *Partition { return &Partition{ - closing: make(chan struct{}), - path: path, - sfile: sfile, - seriesIDSet: tsdb.NewSeriesIDSet(), - + closing: make(chan struct{}), + path: path, + sfile: sfile, + seriesIDSet: tsdb.NewSeriesIDSet(), + fileSet: &FileSet{}, MaxLogFileSize: tsdb.DefaultMaxIndexLogFileSize, // compactionEnabled: true, @@ -144,7 +144,7 @@ func (p *Partition) bytes() int { var ErrIncompatibleVersion = errors.New("incompatible tsi1 index MANIFEST") // Open opens the partition. -func (p *Partition) Open() error { +func (p *Partition) Open() (rErr error) { p.mu.Lock() defer p.mu.Unlock() @@ -190,6 +190,12 @@ func (p *Partition) Open() error { // Open each file in the manifest. var files []File + defer func() { + if rErr != nil { + Files(files).Close() + } + }() + for _, filename := range m.Files { switch filepath.Ext(filename) { case LogFileExt: @@ -230,7 +236,7 @@ func (p *Partition) Open() error { } } - // Build series existance set. + // Build series existence set. if err := p.buildSeriesSet(); err != nil { return err } @@ -244,6 +250,10 @@ func (p *Partition) Open() error { return nil } +func (p *Partition) IsOpen() bool { + return p.opened +} + // openLogFile opens a log file and appends it to the index. func (p *Partition) openLogFile(path string) (*LogFile, error) { f := NewLogFile(p.sfile, path)