The web version only has simple instructions since chapter 04, while the full book has detailed explanations and background info.

0603: Refactor Code

If SSTables are added to KV, queries must read both the in-memory structure (MemTable) and SSTables, then merge results. The current in-memory structure is just 2 arrays:

type KV struct {
    log  Log
    keys [][]byte
    vals [][]byte
}

This step adds no new features. It moves the in-memory structure into a separate type to prepare for the next step. It also makes it easier to replace the data structure later.

type KV struct {
    log Log
    mem SortedArray
}
type SortedArray struct {
    keys [][]byte
    vals [][]byte
}

The extracted SortedArray implements the SortedKV interface and can be used as input for SSTables:

func (arr *SortedArray) Size() int { return len(arr.keys) }
func (arr *SortedArray) Iter() (SortedKVIter, error) {
    return &SortedArrayIter{arr.keys, arr.vals, 0}, nil
}

Rename KVIterator to a more fitting name: SortedArrayIter. Change KV.Seek() to return an interface:

func (kv *KV) Seek(key []byte) (SortedKVIter, error)

Do not access struct fields directly. Use methods instead. Move the original get, set, del there as well:

func (arr *SortedArray) Key(i int) []byte { return arr.keys[i] }
func (arr *SortedArray) Clear()
func (arr *SortedArray) Push(key []byte, val []byte)
func (arr *SortedArray) Pop()
func (arr *SortedArray) Get(key []byte) (val []byte, ok bool, err error)
func (arr *SortedArray) Set(key []byte, val []byte) (updated bool, err error)
func (arr *SortedArray) Del(key []byte) (deleted bool, err error)

CodeCrafters.io has similar courses in many programming languages, including build your own Redis, SQLite, Docker, etc. It’s worth checking out.