Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delete op #6

Merged
merged 6 commits into from
Nov 1, 2023
Merged

Delete op #6

merged 6 commits into from
Nov 1, 2023

Conversation

PaulisMatrix
Copy link

No description provided.

Comment on lines 6 to 9
- 'final'
pull_request:
branches:
- 'final'
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel it is better if we keep the same build file across branches. We don't need to deal with merge conflicts etc

something like:

Suggested change
- 'final'
pull_request:
branches:
- 'final'
- 'master'
- 'final'
pull_request:
branches:
- 'master'
- 'final'

if err != nil {
panic("read error")
return "", ErrReadFailed
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for adding error handling. I had omitted them for simplicity.

err := r.EncodeKV(buf)
if err != nil {
log.Fatalf("error in encoding the value %v", err)
return ErrEncodingFailed
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need of log.Fatal when you are returning the error

disk_store.go Outdated
if err != nil {
log.Fatalf("error while reading the value: %v", err)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and at 237, no need to log.Fatal when it has break statement next

a better API would be to make initKeyDir return an error and log.fatal in the caller

format.go Outdated
// └───────────────┴──────────────┴────────────────┘
// ┌───────────────┬──────────────┬────────────────┬────────────────
// │ timestamp(4B) │ key_size(4B) | value_size(4B) │ tombstone(2B)
// └───────────────┴──────────────┴────────────────┴────────────────
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why 2 bytes for tombstone though, sounds like a lot to me

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because, bigger the size, bigger the storage space we would require.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest allocating one byte and call it Meta. The first bit would be set to 1 for tombstones

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

later we can introduce compression for values and use the second bit and so on.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, meta can be the first field:

Meta (2B) | timestamp(4B) │ key_size(4B) | value_size(4B)

disk_store.go Outdated
Comment on lines 148 to 149
buf := bytes.NewBuffer(make([]byte, headerSize))
err := r.EncodeKV(buf)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not make EncodeKV to take care of the buffer too? Here is the API I suggest:

buf, err := r.EncodeKV()

Internally, it will allocate the buffer and do whatever is necessary

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I followed the standard practice of preallocating buffer in the caller itself and letting the function fill it, much like Read works of the Reader interface. Also this avoids the sharing up construct.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also this avoids the sharing up construct.

can you elaborate?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I understand stack and heap allocations in golang, sharing pointers or references up(from the callee) escapes to heap right. So even though we are out of the callee, go has to keep tracking that value on the heap in case you work on it further.
https://youtu.be/ZMZpH4yT7M0?t=930

In this case, since we are pre allocating byte slice, if it's small enough to be allocated on stack, go will otherwise it will escape to heap anyways.

disk_store.go Outdated
return ErrEncodingFailed
}
d.write(buf.Bytes())
size := headerSize + h.KeySize + h.ValueSize
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about making size as property of Record, like Record.Size()? It has all the necessary information

disk_store.go Outdated
Comment on lines 230 to 231
h := &Header{}
h.DecodeHeader(header)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of this, I would prefer an API like:

h, err := NewHeader(headerBytes)

//check for deletion
for _, dkeys := range deletedKeys {
actualVal, err := store.Get(dkeys)
if actualVal != "" && errors.Is(err, ErrKeyNotFound) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ don't you want the condition to be or?

if actualVal != "" || errors.Is(err, ErrKeyNotFound)

Better would be splitting this into two conditions, so that we can log the actual error condition:

if actualVal != "" {}

if !errors.Is(err, ErrKeyNotFound) {}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added & cause Im checking only for the keys in deletedKeys list explicitly. But I get your point, making the change.

ErrSeekFailed = errors.New("see fail: failed to seek to the correct offset")
ErrReadFailed = errors.New("read fail: failed to read data from disk")
ErrEncodingFailed = errors.New("encoding fail: failed to encode kv record")
)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is nice, all the errors are at one place

@avinassh avinassh merged commit 3c525bd into avinassh:final Nov 1, 2023
3 checks passed
@avinassh
Copy link
Owner

avinassh commented Nov 1, 2023

Thank you 🎉

@PaulisMatrix PaulisMatrix deleted the delete-op branch November 1, 2023 15:27
@avinassh avinassh mentioned this pull request Nov 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants