github.com/rohankumardubey/aresdb@v0.0.2-0.20190517170215-e54e3ca06b9c/diskstore/local_diskstore_test.go (about)

     1  //  Copyright (c) 2017-2018 Uber Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package diskstore
    16  
    17  import (
    18  	"io/ioutil"
    19  	"math/rand"
    20  	"os"
    21  	"sort"
    22  	"time"
    23  	"unsafe"
    24  
    25  	"github.com/onsi/ginkgo"
    26  	. "github.com/onsi/gomega"
    27  
    28  	"fmt"
    29  	"github.com/uber/aresdb/utils"
    30  	"path/filepath"
    31  )
    32  
    33  var _ = ginkgo.Describe("DiskStore", func() {
    34  	prefix := "/tmp/testDiskStoreSuite"
    35  	table := "myTable"
    36  	shard := 1
    37  	numFiles := 100
    38  	numNumbersToWrite := 10
    39  	createdUnixTs := make([]int64, numFiles)
    40  
    41  	ginkgo.BeforeEach(func() {
    42  		os.Remove(prefix)
    43  		os.MkdirAll(prefix, 0755)
    44  	})
    45  
    46  	ginkgo.AfterEach(func() {
    47  		os.RemoveAll(prefix)
    48  	})
    49  
    50  	ginkgo.It("Test Read/Write/Delete Redolog Files for LocalDiskstore", func() {
    51  		// Setup directory
    52  		redologDirPath := GetPathForTableRedologs(prefix, table, shard)
    53  		os.MkdirAll(redologDirPath, os.ModeDir|os.ModePerm)
    54  		for i := 0; i < numFiles; i++ {
    55  			randInt64 := int64(rand.Uint32())
    56  			filePath := GetPathForRedologFile(prefix, table, shard, randInt64)
    57  			createdUnixTs[i] = randInt64
    58  			ioutil.WriteFile(filePath, nil, os.ModePerm)
    59  		}
    60  		l := NewLocalDiskStore(prefix)
    61  		logsCreatedUnixTs, err := l.ListLogFiles(table, shard)
    62  		sort.Sort(utils.Int64Array(createdUnixTs))
    63  		Ω(err).Should(BeNil())
    64  		Ω(logsCreatedUnixTs).Should(Equal(createdUnixTs))
    65  		Ω(len(logsCreatedUnixTs)).Should(Equal(numFiles))
    66  		// Delete
    67  		for i := 0; i < numFiles; i++ {
    68  			err := l.DeleteLogFile(table, shard, createdUnixTs[i])
    69  			Ω(err).Should(BeNil())
    70  			logsCreatedUnixTs, err := l.ListLogFiles(table, shard)
    71  			Ω(err).Should(BeNil())
    72  			Ω(len(logsCreatedUnixTs)).Should(Equal(numFiles - i - 1))
    73  		}
    74  		// Write
    75  		for i := 0; i < numFiles; i++ {
    76  			writerCloser, err := l.OpenLogFileForAppend(table, shard, createdUnixTs[i])
    77  			Ω(writerCloser).ShouldNot(BeNil())
    78  			Ω(err).Should(BeNil())
    79  			ts := createdUnixTs[i]
    80  			for j := 0; j < numNumbersToWrite; j++ {
    81  				p := (*[8]byte)(unsafe.Pointer(&ts))[:]
    82  				Ω(len(p)).Should(Equal(8))
    83  				n, err := writerCloser.Write(p)
    84  				Ω(n).Should(Equal(8))
    85  				Ω(err).Should(BeNil())
    86  				err = writerCloser.Close()
    87  				Ω(err).Should(BeNil())
    88  				writerCloser, err = l.OpenLogFileForAppend(table, shard, createdUnixTs[i])
    89  				Ω(writerCloser).ShouldNot(BeNil())
    90  				Ω(err).Should(BeNil())
    91  				ts++
    92  			}
    93  			err = writerCloser.Close()
    94  			Ω(err).Should(BeNil())
    95  		}
    96  		// Read
    97  		for i := 0; i < numFiles; i++ {
    98  			readCloser, err := l.OpenLogFileForReplay(table, shard, createdUnixTs[i])
    99  			Ω(readCloser).ShouldNot(BeNil())
   100  			Ω(err).Should(BeNil())
   101  
   102  			for j := 0; j < numNumbersToWrite; j++ {
   103  				reader := utils.NewStreamDataReader(readCloser)
   104  				readCreatedUnixTs, err := reader.ReadUint64()
   105  				Ω(err).Should(BeNil())
   106  				Ω(int64(readCreatedUnixTs)).Should(Equal(createdUnixTs[i] + int64(j)))
   107  			}
   108  
   109  			err = readCloser.Close()
   110  			Ω(err).Should(BeNil())
   111  		}
   112  		// Delete
   113  		for i := 0; i < numFiles; i++ {
   114  			err := l.DeleteLogFile(table, shard, createdUnixTs[i])
   115  			Ω(err).Should(BeNil())
   116  			logsCreatedUnixTs, err := l.ListLogFiles(table, shard)
   117  			Ω(err).Should(BeNil())
   118  			Ω(len(logsCreatedUnixTs)).Should(Equal(numFiles - i - 1))
   119  		}
   120  	})
   121  
   122  	ginkgo.It("Test Truncating Redolog Files for LocalDiskstore", func() {
   123  		// Setup directory
   124  		redologDirPath := GetPathForTableRedologs(prefix, table, shard)
   125  		os.MkdirAll(redologDirPath, os.ModeDir|os.ModePerm)
   126  		for i := 0; i < numFiles; i++ {
   127  			randInt64 := int64(rand.Uint32())
   128  			filePath := GetPathForRedologFile(prefix, table, shard, randInt64)
   129  			createdUnixTs[i] = randInt64
   130  			ioutil.WriteFile(filePath, nil, os.ModePerm)
   131  		}
   132  		l := NewLocalDiskStore(prefix)
   133  		// Write
   134  		for i := 0; i < numFiles; i++ {
   135  			writerCloser, err := l.OpenLogFileForAppend(table, shard, createdUnixTs[i])
   136  			Ω(writerCloser).ShouldNot(BeNil())
   137  			Ω(err).Should(BeNil())
   138  			ts := createdUnixTs[i]
   139  			for j := 0; j < numNumbersToWrite; j++ {
   140  				p := (*[8]byte)(unsafe.Pointer(&ts))[:]
   141  				Ω(len(p)).Should(Equal(8))
   142  				n, err := writerCloser.Write(p)
   143  				Ω(n).Should(Equal(8))
   144  				Ω(err).Should(BeNil())
   145  				err = writerCloser.Close()
   146  				Ω(err).Should(BeNil())
   147  				writerCloser, err = l.OpenLogFileForAppend(table, shard, createdUnixTs[i])
   148  				Ω(writerCloser).ShouldNot(BeNil())
   149  				Ω(err).Should(BeNil())
   150  				ts++
   151  			}
   152  			err = writerCloser.Close()
   153  			Ω(err).Should(BeNil())
   154  		}
   155  		// Truncate
   156  		truncateSize := int64(numNumbersToWrite * 8 / 2)
   157  		for i := 0; i < numFiles; i++ {
   158  			filePath := GetPathForRedologFile(prefix, table, shard, createdUnixTs[i])
   159  			oldFileInfo, _ := os.Stat(filePath)
   160  			err := l.TruncateLogFile(table, shard, createdUnixTs[i], truncateSize)
   161  			Ω(err).Should(BeNil())
   162  			newFileInfo, _ := os.Stat(filePath)
   163  			Ω(oldFileInfo.Size()).Should(Equal(newFileInfo.Size() * 2))
   164  		}
   165  		// Read
   166  		for i := 0; i < numFiles; i++ {
   167  			readCloser, err := l.OpenLogFileForReplay(table, shard, createdUnixTs[i])
   168  			Ω(readCloser).ShouldNot(BeNil())
   169  			Ω(err).Should(BeNil())
   170  
   171  			for j := 0; j < numNumbersToWrite/2; j++ {
   172  				reader := utils.NewStreamDataReader(readCloser)
   173  				readCreatedUnixTs, err := reader.ReadUint64()
   174  				Ω(err).Should(BeNil())
   175  				Ω(int64(readCreatedUnixTs)).Should(Equal(createdUnixTs[i] + int64(j)))
   176  			}
   177  
   178  			err = readCloser.Close()
   179  			Ω(err).Should(BeNil())
   180  		}
   181  	})
   182  
   183  	ginkgo.It("works with non-existing redolog file directory", func() {
   184  		l := NewLocalDiskStore(prefix)
   185  		files, err := l.ListLogFiles(table, shard)
   186  		Ω(err).Should(BeNil())
   187  		Ω(files).Should(BeNil())
   188  	})
   189  
   190  	ginkgo.It("Test List Snapshot Dir for LocalDiskstore", func() {
   191  		// Setup directory
   192  		snapshotDirPath := GetPathForTableSnapshotDir(prefix, table, shard)
   193  		os.MkdirAll(snapshotDirPath, 0755)
   194  
   195  		var redoLogFile int64 = 1
   196  		var offset uint32 = 1
   197  		randomBatches := make([]int, numFiles)
   198  		for i := 0; i < numFiles; i++ {
   199  			randomBatch := int(rand.Int31())
   200  			filePath := GetPathForTableSnapshotColumnFilePath(prefix, table, shard, redoLogFile, offset,
   201  				randomBatch, 0)
   202  			os.MkdirAll(filepath.Dir(filePath), 0755)
   203  			randomBatches[i] = randomBatch
   204  			ioutil.WriteFile(filePath, []byte{}, os.ModePerm)
   205  		}
   206  
   207  		sort.Ints(randomBatches)
   208  		l := NewLocalDiskStore(prefix)
   209  
   210  		batches, err := l.ListSnapshotBatches(table, shard, redoLogFile, offset)
   211  		Ω(err).Should(BeNil())
   212  		Ω(batches).Should(Equal(randomBatches))
   213  
   214  		batches, err = l.ListSnapshotBatches(table, shard, redoLogFile, offset+1)
   215  		Ω(err).Should(BeNil())
   216  		Ω(batches).Should(BeEmpty())
   217  	})
   218  
   219  	ginkgo.It("Test List Snapshot VP Files", func() {
   220  		// Setup directory
   221  		var redoLogFile int64 = 1
   222  		var offset uint32 = 1
   223  		batchID := 1
   224  		batchDir := GetPathForTableSnapshotBatchDir(prefix, table, shard, redoLogFile, offset, batchID)
   225  		os.MkdirAll(batchDir, 0755)
   226  
   227  		randomColumns := make([]int, numFiles)
   228  		for i := 0; i < numFiles; i++ {
   229  			randomColumn := int(rand.Int31())
   230  			filePath := GetPathForTableSnapshotColumnFilePath(prefix, table, shard, redoLogFile, offset,
   231  				batchID, randomColumn)
   232  			randomColumns[i] = randomColumn
   233  			ioutil.WriteFile(filePath, []byte{}, os.ModePerm)
   234  		}
   235  
   236  		sort.Ints(randomColumns)
   237  		l := NewLocalDiskStore(prefix)
   238  
   239  		columns, err := l.ListSnapshotVectorPartyFiles(table, shard, redoLogFile, offset, batchID)
   240  		Ω(err).Should(BeNil())
   241  		Ω(columns).Should(Equal(randomColumns))
   242  
   243  		columns, err = l.ListSnapshotVectorPartyFiles(table, shard, redoLogFile, offset, batchID+1)
   244  		Ω(err).Should(BeNil())
   245  		Ω(columns).Should(BeEmpty())
   246  	})
   247  
   248  	ginkgo.It("Test Read Snapshot Files for LocalDiskstore", func() {
   249  		// Setup directory
   250  		var redoLogFile int64 = 1
   251  		var offset uint32 = 1
   252  		batchID := 1
   253  		batchDir := GetPathForTableSnapshotBatchDir(prefix, table, shard, redoLogFile, offset, batchID)
   254  		os.MkdirAll(batchDir, 0755)
   255  
   256  		randomThingToWrite := []byte("Test Read Snapshot Files for LocalDiskstore")
   257  		randomColumns := make([]int, numFiles)
   258  		for i := 0; i < numFiles; i++ {
   259  			randomColumn := int(rand.Int31())
   260  			filePath := GetPathForTableSnapshotColumnFilePath(prefix, table, shard, redoLogFile, offset, batchID, randomColumn)
   261  			randomColumns[i] = randomColumn
   262  			ioutil.WriteFile(filePath, randomThingToWrite, os.ModePerm)
   263  		}
   264  		l := NewLocalDiskStore(prefix)
   265  
   266  		// Read
   267  		for _, column := range randomColumns {
   268  			readCloser, err := l.OpenSnapshotVectorPartyFileForRead(table, shard, redoLogFile, offset, batchID, column)
   269  			Ω(readCloser).ShouldNot(BeNil())
   270  			Ω(err).Should(BeNil())
   271  			p := make([]byte, len(randomThingToWrite))
   272  			numBytesRead, err := readCloser.Read(p)
   273  			Ω(numBytesRead).Should(Equal(len(randomThingToWrite)))
   274  			Ω(p).Should(Equal(randomThingToWrite))
   275  			err = readCloser.Close()
   276  			Ω(err).Should(BeNil())
   277  		}
   278  	})
   279  
   280  	ginkgo.It("Test Write Snapshot Files for LocalDiskstore", func() {
   281  		// Setup directory
   282  		var redoLogFile int64 = 1
   283  		var offset uint32 = 1
   284  		batchID := 1
   285  		batchDir := GetPathForTableSnapshotBatchDir(prefix, table, shard, redoLogFile, offset, batchID)
   286  		os.MkdirAll(batchDir, 0755)
   287  
   288  		randomThingToWrite := []byte("Test Write Snapshot Files for LocalDiskstore")
   289  		randomColumns := make([]int, numFiles)
   290  		l := NewLocalDiskStore(prefix)
   291  		// Initial set and write something longer string.
   292  		for i := 0; i < numFiles; i++ {
   293  			randomColumn := int(rand.Int31())
   294  			randomColumns[i] = randomColumn
   295  			writeCloser, err := l.OpenSnapshotVectorPartyFileForWrite(table, shard, redoLogFile, offset, batchID, randomColumn)
   296  			Ω(writeCloser).ShouldNot(BeNil())
   297  			Ω(err).Should(BeNil())
   298  			numBytesWritten, err := writeCloser.Write(randomThingToWrite)
   299  			Ω(numBytesWritten).Should(Equal(len(randomThingToWrite)))
   300  			Ω(err).Should(BeNil())
   301  			err = writeCloser.Close()
   302  			Ω(err).Should(BeNil())
   303  		}
   304  		// Read
   305  		for _, column := range randomColumns {
   306  			readCloser, err := l.OpenSnapshotVectorPartyFileForRead(table, shard, redoLogFile, offset, batchID, column)
   307  			Ω(readCloser).ShouldNot(BeNil())
   308  			Ω(err).Should(BeNil())
   309  			p := make([]byte, len(randomThingToWrite))
   310  			numBytesRead, err := readCloser.Read(p)
   311  			Ω(numBytesRead).Should(Equal(len(randomThingToWrite)))
   312  			Ω(p).Should(Equal(randomThingToWrite))
   313  			err = readCloser.Close()
   314  			Ω(err).Should(BeNil())
   315  		}
   316  
   317  		anotherRandomThingToWrite := []byte("Write Snapshot Files for LocalDiskstore")
   318  		// Should overwrite exising files with shorter string.
   319  		for _, column := range randomColumns {
   320  			writeCloser, err := l.OpenSnapshotVectorPartyFileForWrite(table, shard, redoLogFile, offset, batchID, column)
   321  			Ω(writeCloser).ShouldNot(BeNil())
   322  			Ω(err).Should(BeNil())
   323  			numBytesWritten, err := writeCloser.Write(anotherRandomThingToWrite)
   324  			Ω(numBytesWritten).Should(Equal(len(anotherRandomThingToWrite)))
   325  			Ω(err).Should(BeNil())
   326  			err = writeCloser.Close()
   327  			Ω(err).Should(BeNil())
   328  		}
   329  
   330  		// Read
   331  		for _, column := range randomColumns {
   332  			readCloser, err := l.OpenSnapshotVectorPartyFileForRead(table, shard, redoLogFile, offset, batchID, column)
   333  			Ω(readCloser).ShouldNot(BeNil())
   334  			Ω(err).Should(BeNil())
   335  			p := make([]byte, len(anotherRandomThingToWrite))
   336  			numBytesRead, err := readCloser.Read(p)
   337  			Ω(numBytesRead).Should(Equal(len(anotherRandomThingToWrite)))
   338  			Ω(p).Should(Equal(anotherRandomThingToWrite))
   339  			err = readCloser.Close()
   340  			Ω(err).Should(BeNil())
   341  		}
   342  	})
   343  
   344  	ginkgo.It("Test Delete Snapshot Files for LocalDiskstore", func() {
   345  		// Setup directory
   346  		snapshotDirPath := GetPathForTableSnapshotDir(prefix, table, shard)
   347  		os.MkdirAll(snapshotDirPath, 0755)
   348  
   349  		randomThingToWrite := []byte("Another Test Write Snapshot Files for LocalDiskstore")
   350  		randomRedologFiles := make([]int64, numFiles)
   351  		randomOffsets := make([]uint32, numFiles)
   352  		l := NewLocalDiskStore(prefix)
   353  
   354  		var redoLogFileLimit int64 = 3
   355  		var offsetLimit uint32 = 10
   356  
   357  		keptFilesMap := make(map[string]string)
   358  
   359  		redoLogFile := redoLogFileLimit / 2
   360  		offset := offsetLimit / 2
   361  
   362  		// Initial set and write something longer string.
   363  		for i := 0; i < numFiles; i++ {
   364  			randomRedoLogFile := rand.Int63n(redoLogFileLimit)
   365  			randomOffset := uint32(rand.Int31n(int32(offsetLimit)))
   366  			randomRedologFiles[i] = randomRedoLogFile
   367  			randomOffsets[i] = randomOffset
   368  			if randomRedoLogFile > redoLogFile || (randomRedoLogFile == redoLogFile && randomOffset >= offset) {
   369  				fileName := fmt.Sprintf("%d_%d", randomRedoLogFile, randomOffset)
   370  				keptFilesMap[fileName] = fileName
   371  			}
   372  			writeCloser, err := l.OpenSnapshotVectorPartyFileForWrite(table, shard,
   373  				randomRedoLogFile, randomOffset, 0, 0)
   374  			Ω(writeCloser).ShouldNot(BeNil())
   375  			Ω(err).Should(BeNil())
   376  			numBytesWritten, err := writeCloser.Write(randomThingToWrite)
   377  			Ω(numBytesWritten).Should(Equal(len(randomThingToWrite)))
   378  			Ω(err).Should(BeNil())
   379  			err = writeCloser.Close()
   380  			Ω(err).Should(BeNil())
   381  		}
   382  
   383  		var keptFiles []string
   384  
   385  		for _, f := range keptFilesMap {
   386  			keptFiles = append(keptFiles, f)
   387  		}
   388  
   389  		sort.Strings(keptFiles)
   390  
   391  		err := l.DeleteSnapshot(table, shard, redoLogFile, offset)
   392  		Ω(err).Should(BeNil())
   393  		snapshotFileInfos, err := ioutil.ReadDir(snapshotDirPath)
   394  		Ω(err).Should(BeNil())
   395  		snapshotFiles := make([]string, len(snapshotFileInfos))
   396  
   397  		for i, fileInfo := range snapshotFileInfos {
   398  			snapshotFiles[i] = fileInfo.Name()
   399  		}
   400  
   401  		Ω(snapshotFiles).Should(Equal(keptFiles))
   402  	})
   403  
   404  	ginkgo.It("Test Read/Write Archiving Column and DeleteBatchVersions for LocalDiskstore", func() {
   405  		l := NewLocalDiskStore(prefix)
   406  		// Setup directory
   407  		batchID := "1988-06-17"
   408  		batchIDSinceEpoch := 6742
   409  		columnID := 617
   410  
   411  		randomThingToWrite := []byte("Test Read Snapshot Files for LocalDiskstore")
   412  		randBatchVersions := make([]uint32, numFiles*2)
   413  
   414  		// Write to columns
   415  		for i := 0; i < numFiles; i++ {
   416  			randBatchVersion := rand.Uint32()
   417  			randBatchVersions[i] = randBatchVersion
   418  			batchDirPath := GetPathForTableArchiveBatchDir(prefix, table, shard, batchID, randBatchVersion, 0)
   419  			os.MkdirAll(batchDirPath, 0755)
   420  			batchDirPath = GetPathForTableArchiveBatchDir(prefix, table, shard, batchID, randBatchVersion, 1)
   421  			os.MkdirAll(batchDirPath, 0755)
   422  			writeCloser, err := l.OpenVectorPartyFileForWrite(table, columnID, shard, batchIDSinceEpoch, randBatchVersion, 1)
   423  			numBytesWritten, err := writeCloser.Write(randomThingToWrite)
   424  			Ω(numBytesWritten).Should(Equal(len(randomThingToWrite)))
   425  			Ω(err).Should(BeNil())
   426  			err = writeCloser.Close()
   427  			Ω(err).Should(BeNil())
   428  		}
   429  
   430  		var maxVersion uint32
   431  		for _, version := range randBatchVersions {
   432  			if version > maxVersion {
   433  				maxVersion = version
   434  			}
   435  		}
   436  
   437  		// Read from columns
   438  		for i := 0; i < numFiles; i++ {
   439  			readCloser, err := l.OpenVectorPartyFileForRead(table, columnID, shard, batchIDSinceEpoch, randBatchVersions[i], 1)
   440  			Ω(readCloser).ShouldNot(BeNil())
   441  			Ω(err).Should(BeNil())
   442  			p := make([]byte, len(randomThingToWrite))
   443  			numBytesRead, err := readCloser.Read(p)
   444  			Ω(numBytesRead).Should(Equal(len(randomThingToWrite)))
   445  			Ω(p).Should(Equal(randomThingToWrite))
   446  			err = readCloser.Close()
   447  			Ω(err).Should(BeNil())
   448  		}
   449  
   450  		// DeleteBatchVersions using the max version will delete all batch versions.
   451  		batchRootDirPath := GetPathForTableArchiveBatchRootDir(prefix, table, shard)
   452  		dirs, err := ioutil.ReadDir(batchRootDirPath)
   453  		Ω(err).Should(BeNil())
   454  		Ω(len(dirs)).Should(Equal(numFiles * 2))
   455  		err = l.DeleteBatchVersions(table, shard, batchIDSinceEpoch, maxVersion, 1)
   456  		Ω(err).Should(BeNil())
   457  		dirs, err = ioutil.ReadDir(batchRootDirPath)
   458  		Ω(err).Should(BeNil())
   459  		Ω(len(dirs)).Should(Equal(0))
   460  	})
   461  
   462  	ginkgo.It("Test DeleteBatches with batchIDCutoff for LocalDiskstore", func() {
   463  		l := NewLocalDiskStore(prefix)
   464  		// Setup directory
   465  
   466  		startBatchID := "2017-06-17"
   467  		startBatchIDTime, err := time.Parse(timeFormatForBatchID, startBatchID)
   468  		Ω(err).Should(BeNil())
   469  		batchVersion := rand.Uint32()
   470  		archiveBatchRootDirPath := GetPathForTableArchiveBatchRootDir(prefix, table, shard)
   471  
   472  		// Create BatchID directories
   473  		for i := 0; i < numFiles; i++ {
   474  			batchIDTime := startBatchIDTime.Add(time.Duration(24*i) * time.Hour)
   475  			batchID := batchIDTime.Format(timeFormatForBatchID)
   476  			versionedBatchDirPath := GetPathForTableArchiveBatchDir(prefix, table, shard, batchID, batchVersion, 0)
   477  			os.MkdirAll(versionedBatchDirPath, 0755)
   478  		}
   479  
   480  		// DeleteBatch with batchIDCutoff
   481  		for i := 0; i < numFiles; i++ {
   482  			batchIDTime := startBatchIDTime.Add(time.Duration(24*i) * time.Hour)
   483  			_, err = l.DeleteBatches(table, shard, 0, int(batchIDTime.Unix()/86400))
   484  			Ω(err).Should(BeNil())
   485  			batchDirs, err := ioutil.ReadDir(archiveBatchRootDirPath)
   486  			Ω(err).Should(BeNil())
   487  			Ω(len(batchDirs)).Should(Equal(numFiles - i))
   488  		}
   489  		batchDirs, err := ioutil.ReadDir(archiveBatchRootDirPath)
   490  		Ω(err).Should(BeNil())
   491  		Ω(len(batchDirs)).Should(Equal(1))
   492  
   493  		// Create BatchID directories
   494  		for i := 0; i < numFiles; i++ {
   495  			batchIDTime := startBatchIDTime.Add(time.Duration(24*i) * time.Hour)
   496  			batchID := batchIDTime.Format(timeFormatForBatchID)
   497  			versionedBatchDirPath := GetPathForTableArchiveBatchDir(prefix, table, shard, batchID, batchVersion, 0)
   498  			os.MkdirAll(versionedBatchDirPath, 0755)
   499  		}
   500  
   501  		// DeleteBatch with batchIDCutoff
   502  		for i := 0; i < numFiles; i += 2 {
   503  			batchIDTime := startBatchIDTime.Add(time.Duration(24*i) * time.Hour)
   504  			_, err = l.DeleteBatches(table, shard, 0, int(batchIDTime.Unix()/86400))
   505  			Ω(err).Should(BeNil())
   506  			batchDirs, err := ioutil.ReadDir(archiveBatchRootDirPath)
   507  			Ω(err).Should(BeNil())
   508  			Ω(len(batchDirs)).Should(Equal(numFiles - i))
   509  		}
   510  		batchDirs, err = ioutil.ReadDir(archiveBatchRootDirPath)
   511  		Ω(err).Should(BeNil())
   512  		Ω(len(batchDirs)).Should(Equal(2))
   513  
   514  	})
   515  
   516  	ginkgo.It("Test DeleteColumn for LocalDiskstore", func() {
   517  		l := NewLocalDiskStore(prefix)
   518  		// Setup directory
   519  		numSubDir := 10
   520  		randomThingToWrite := []byte("Test Read Snapshot Files for LocalDiskstore")
   521  		startBatchID := "2017-06-17"
   522  		startBatchIDTime, err := time.Parse(timeFormatForBatchID, startBatchID)
   523  		Ω(err).Should(BeNil())
   524  		startBatchVersion := rand.Uint32()
   525  		archiveBatchRootDirPath := GetPathForTableArchiveBatchRootDir(prefix, table, shard)
   526  
   527  		// Create $numSubDir batches, each batch has $numSubDir versions, each version has $numSubDir columns.
   528  		for i := 0; i < numSubDir; i++ {
   529  			batchIDTime := startBatchIDTime.Add(time.Duration(24*i) * time.Hour)
   530  			batchID := batchIDTime.Format(timeFormatForBatchID)
   531  			for j := 0; j < numSubDir; j++ {
   532  				batchVersion := startBatchVersion + uint32(j)
   533  				versionedBatchDirPath := GetPathForTableArchiveBatchDir(prefix, table, shard, batchID, batchVersion, 0)
   534  				os.MkdirAll(versionedBatchDirPath, 0755)
   535  				for k := 0; k < numSubDir; k++ {
   536  					columnID := k
   537  					writeCloser, err := l.OpenVectorPartyFileForWrite(table, columnID, shard, int(batchIDTime.Unix()/86400), batchVersion, 0)
   538  					numBytesWritten, err := writeCloser.Write(randomThingToWrite)
   539  					Ω(numBytesWritten).Should(Equal(len(randomThingToWrite)))
   540  					Ω(err).Should(BeNil())
   541  					err = writeCloser.Close()
   542  					Ω(err).Should(BeNil())
   543  				}
   544  			}
   545  		}
   546  
   547  		// DeleteBatch with batchIDCutoff
   548  		for i := 0; i < numSubDir; i++ {
   549  			columnID := i
   550  			l.DeleteColumn(table, columnID, shard)
   551  			batchDirs, err := ioutil.ReadDir(archiveBatchRootDirPath)
   552  			Ω(err).Should(BeNil())
   553  			for _, f := range batchDirs {
   554  				batchID, versionID, seqNum, _ := ParseBatchIDAndVersionName(f.Name())
   555  				versionedBatchDir := GetPathForTableArchiveBatchDir(prefix, table, shard, batchID, versionID, seqNum)
   556  				columnFiles, err := ioutil.ReadDir(versionedBatchDir)
   557  				Ω(err).Should(BeNil())
   558  				Ω(len(columnFiles)).Should(Equal(10 - i - 1))
   559  				columnFilePath := GetPathForTableArchiveBatchColumnFile(prefix, table, shard, batchID, versionID, seqNum, columnID)
   560  				_, err = os.Stat(columnFilePath)
   561  				Ω(err).ShouldNot(BeNil())
   562  			}
   563  		}
   564  	})
   565  })