Skip to content

Commit

Permalink
COMPLETE project4A & PASS
Browse files Browse the repository at this point in the history
  • Loading branch information
Metafora072 committed Jul 22, 2024
1 parent 1c88ea4 commit 916978e
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 3 deletions.
152 changes: 150 additions & 2 deletions kv/transaction/mvcc/transaction.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package mvcc

import (
"bytes"
"encoding/binary"
"github.com/pingcap-incubator/tinykv/kv/util/engine_util"

"github.com/pingcap-incubator/tinykv/kv/storage"
"github.com/pingcap-incubator/tinykv/kv/util/codec"
Expand All @@ -20,9 +22,13 @@ func (ke *KeyError) Error() string {

// MvccTxn groups together writes as part of a single transaction. It also provides an abstraction over low-level
// storage, lowering the concepts of timestamps, writes, and locks into plain keys and values.
// MvccTxn 结构体用于将多个写操作组合成一个事务。它还提供了对低级存储的抽象,将时间戳、写操作和锁的概念简化为普通的键和值。
type MvccTxn struct {
// 事务的开始时间戳。
StartTS uint64
// 用于读取存储的接口.
Reader storage.StorageReader
// 存储修改操作的切片。
writes []storage.Modify
}

Expand All @@ -39,61 +45,201 @@ func (txn *MvccTxn) Writes() []storage.Modify {
}

// PutWrite records a write at key and ts.
// PutWrite 函数的作用是记录一个写操作到指定的键和时间戳。
func (txn *MvccTxn) PutWrite(key []byte, ts uint64, write *Write) {
// Your Code Here (4A).
txn.writes = append(txn.writes, storage.Modify{
Data: storage.Put {
Key: EncodeKey(key,ts),
Cf: engine_util.CfWrite,
Value: write.ToBytes(),
},
})
}

// GetLock returns a lock if key is locked. It will return (nil, nil) if there is no lock on key, and (nil, err)
// if an error occurs during lookup.
// GetLock 函数的作用是检查指定的键是否被锁定,并返回相应的锁信息。
func (txn *MvccTxn) GetLock(key []byte) (*Lock, error) {
// Your Code Here (4A).
return nil, nil
value, err := txn.Reader.GetCF(engine_util.CfLock,key)
if err != nil {
return nil, err
}

// It will return (nil, nil) if there is no lock on key
if value == nil {
return nil, nil
}

lock, err := ParseLock(value)
if err != nil {
return nil, err
}
return lock, nil
}

// PutLock adds a key/lock to this transaction.
// PutLock 函数的作用是将一个键和锁添加到当前事务中。
func (txn *MvccTxn) PutLock(key []byte, lock *Lock) {
// Your Code Here (4A).
txn.writes = append(txn.writes, storage.Modify{
Data: storage.Put {
Key: key,
Cf: engine_util.CfLock,
Value: lock.ToBytes(),
},
})
}

// DeleteLock adds a delete lock to this transaction.
// DeleteLock 函数的作用是将一个删除锁操作添加到当前事务中。
func (txn *MvccTxn) DeleteLock(key []byte) {
// Your Code Here (4A).
txn.writes = append(txn.writes, storage.Modify{
Data: storage.Delete {
Key: key,
Cf: engine_util.CfLock,
},
})
}

// GetValue finds the value for key, valid at the start timestamp of this transaction.
// I.e., the most recent value committed before the start of this transaction.
// GetValue 查询当前事务下,传入 key 对应的 Value。
func (txn *MvccTxn) GetValue(key []byte) ([]byte, error) {
// Your Code Here (4A).
it := txn.Reader.IterCF(engine_util.CfWrite)
defer it.Close()

encodeKey := EncodeKey(key,txn.StartTS)
// Seek 函数的作用是将迭代器定位到提供的键。如果该键存在,迭代器将指向该键;如果不存在,迭代器将指向大于提供键的下一个最小键。
it.Seek(encodeKey)
if it.Valid() == false {
return nil, nil
}

// 判断找到的 key 是不是预期的 key
// KeyCopy(dst []byte) []byte: 返回键的副本。如果传入的切片为 nil 或容量不足,将分配一个新的切片并返回。
resultKey := DecodeUserKey(it.Item().KeyCopy(nil))

if bytes.Equal(resultKey,key) == false { // key 不相等
return nil, nil
}

// ValueCopy(dst []byte) ([]byte, error): 返回值的副本。如果传入的切片为 nil 或容量不足,将分配一个新的切片并返回。
value, err := it.Item().ValueCopy(nil)
if err != nil {
return nil, err
}

// 根据 value 获取其对应的 write 结构体
write, err := ParseWrite(value)
if err != nil {
return nil, err
}

if write.Kind == WriteKindPut {
goatKey := EncodeKey(key, write.StartTS)
return txn.Reader.GetCF(engine_util.CfDefault,goatKey)
}
return nil, nil
}

// PutValue adds a key/value write to this transaction.
// PutValue 函数将一个键/值写入操作添加到事务中
func (txn *MvccTxn) PutValue(key []byte, value []byte) {
// Your Code Here (4A).
txn.writes = append(txn.writes, storage.Modify{
Data: storage.Put {
Key: EncodeKey(key,txn.StartTS),
Cf: engine_util.CfDefault,
Value: value,
},
})
}

// DeleteValue removes a key/value pair in this transaction.
// DeleteValue 函数将一个键/值删除操作添加到事务中
func (txn *MvccTxn) DeleteValue(key []byte) {
// Your Code Here (4A).
txn.writes = append(txn.writes, storage.Modify{
Data: storage.Delete {
Key: EncodeKey(key,txn.StartTS),
Cf: engine_util.CfDefault,
},
})
}

// CurrentWrite searches for a write with this transaction's start timestamp. It returns a Write from the DB and that
// write's commit timestamp, or an error.
// CurrentWrite 查询当前事务(根据 start timestamp)下,传入 key 的最新 Write。
func (txn *MvccTxn) CurrentWrite(key []byte) (*Write, uint64, error) {
// Your Code Here (4A).
it := txn.Reader.IterCF(engine_util.CfWrite)
defer it.Close()

for it.Seek(EncodeKey(key,0xFFFFFFFFFFFFFFFF)); it.Valid(); it.Next() {
item := it.Item()
curKey := item.KeyCopy(nil)
userKey := DecodeUserKey(curKey)
if bytes.Equal(userKey,key) == false {
return nil, 0, nil
}

value, err := item.ValueCopy(nil)
if err != nil {
return nil, 0, err
}
write, err := ParseWrite(value)
if err != nil {
return nil, 0, err
}

if write.StartTS == txn.StartTS {
return write, decodeTimestamp(curKey), nil
}
}
return nil, 0, nil
}

// MostRecentWrite finds the most recent write with the given key. It returns a Write from the DB and that
// write's commit timestamp, or an error.
// MostRecentWrite 查询传入 key 的最新 Write
func (txn *MvccTxn) MostRecentWrite(key []byte) (*Write, uint64, error) {
// Your Code Here (4A).
return nil, 0, nil
it := txn.Reader.IterCF(engine_util.CfWrite)
defer it.Close()

it.Seek(EncodeKey(key,0xFFFFFFFFFFFFFFFF))
if it.Valid() == false {
return nil, 0, nil
}

curKey := it.Item().KeyCopy(nil)
userKey := DecodeUserKey(curKey)

if bytes.Equal(userKey,key) == false {
return nil, 0, nil
}

value, err := it.Item().ValueCopy(nil)
if err != nil {
return nil, 0, err
}

write, err := ParseWrite(value)
if err != nil {
return nil, 0, err
}

return write, decodeTimestamp(curKey), nil
}

// EncodeKey encodes a user key and appends an encoded timestamp to a key. Keys and timestamps are encoded so that
// timestamped keys are sorted first by key (ascending), then by timestamp (descending). The encoding is based on
// https://github.com/facebook/mysql-5.6/wiki/MyRocks-record-format#memcomparable-format.
// EncodeKey 的作用是对用户的键进行编码,并附加一个编码的时间戳。这样做的目的是使带有时间戳的键首先按键(升序)排序,然后按时间戳(降序)排序。
func EncodeKey(key []byte, ts uint64) []byte {
encodedKey := codec.EncodeBytes(key)
newKey := append(encodedKey, make([]byte, 8)...)
Expand All @@ -102,6 +248,7 @@ func EncodeKey(key []byte, ts uint64) []byte {
}

// DecodeUserKey takes a key + timestamp and returns the key part.
// DecodeUserKey 函数从包含键和时间戳的编码键中提取并返回用户键部分。
func DecodeUserKey(key []byte) []byte {
_, userKey, err := codec.DecodeBytes(key)
if err != nil {
Expand All @@ -111,6 +258,7 @@ func DecodeUserKey(key []byte) []byte {
}

// decodeTimestamp takes a key + timestamp and returns the timestamp part.
// decodeTimestamp 函数从包含键和时间戳的编码键中提取并返回时间戳部分。
func decodeTimestamp(key []byte) uint64 {
left, _, err := codec.DecodeBytes(key)
if err != nil {
Expand Down
8 changes: 8 additions & 0 deletions kv/transaction/mvcc/write.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,22 @@ import (
// Write is a representation of a committed write to backing storage.
// A serialized version is stored in the "write" CF of our engine when a write is committed. That allows MvccTxn to find
// the status of a key at a given timestamp.
// Write 结构体表示提交到后端存储的写操作。序列化版本存储在引擎的 “write” 列族(CF)中,当写操作提交时,这允许 MvccTxn 在给定时间戳找到键的状态。
type Write struct {
// 写操作的开始时间戳。
StartTS uint64
// 写操作的类型,使用 WriteKind 枚举表示。
Kind WriteKind
}

// ToBytes 方法将 Write 结构体序列化为字节切片。
func (wr *Write) ToBytes() []byte {
buf := append([]byte{byte(wr.Kind)}, 0, 0, 0, 0, 0, 0, 0, 0)
binary.BigEndian.PutUint64(buf[1:], wr.StartTS)
return buf
}

// ParseWrite 函数将字节切片反序列化为 Write 结构体。
func ParseWrite(value []byte) (*Write, error) {
if value == nil {
return nil, nil
Expand All @@ -37,8 +42,11 @@ func ParseWrite(value []byte) (*Write, error) {
type WriteKind int

const (
// WriteKindPut 表示写入操作。
WriteKindPut WriteKind = 1
// WriteKindDelete 表示删除操作。
WriteKindDelete WriteKind = 2
// WriteKindRollback 表示回滚操作。
WriteKindRollback WriteKind = 3
)

Expand Down
Binary file added note/project2A.assets/QQ截图20240719160418.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion note/project2A.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,4 +288,6 @@ const (
EntryType_EntryNormal EntryType = 0 // 普通条目
EntryType_EntryConfChange EntryType = 1 // 配置变更条目
)
```
```

![](project2A.assets/QQ截图20240719160418.png)
Binary file added note/project4.assets/QQ截图20240722220046.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file added note/project4.md
Empty file.

0 comments on commit 916978e

Please sign in to comment.