// getInternal implements the actual logic of get function. // The values of multiple versions for the given key should // be organized as follows: // ... // keyA : keyMetatata of keyA // keyA_Timestamp_n : value of version_n // keyA_Timestamp_n-1 : value of version_n-1 // ... // keyA_Timestamp_0 : value of version_0 // keyB : keyMetadata of keyB // ... func (mvcc *MVCC) getInternal(key Key, timestamp hlc.HLTimestamp, txnID string) ([]byte, hlc.HLTimestamp, string, error) { keyMetadata := &keyMetadata{} ok, err := GetI(mvcc.engine, key, keyMetadata) if err != nil || !ok { return nil, hlc.HLTimestamp{}, "", err } // If the read timestamp is greater than the latest one, we can just // fetch the value without a scan. if !timestamp.Less(keyMetadata.Timestamp) { if len(keyMetadata.TxnID) > 0 && (len(txnID) == 0 || keyMetadata.TxnID != txnID) { return nil, hlc.HLTimestamp{}, "", &writeIntentError{TxnID: keyMetadata.TxnID} } latestKey := mvccEncodeKey(key, keyMetadata.Timestamp) val, err := mvcc.engine.Get(latestKey) return val, keyMetadata.Timestamp, keyMetadata.TxnID, err } nextKey := mvccEncodeKey(key, timestamp) // We use the PrefixEndKey(key) as the upper bound for scan. // If there is no other version after nextKey, it won't return // the value of the next key. kvs, err := mvcc.engine.Scan(nextKey, PrefixEndKey(key), 1) if len(kvs) > 0 { _, ts := mvccDecodeKey(kvs[0].Key) return kvs[0].Value, ts, "", err } return nil, hlc.HLTimestamp{}, "", err }
func (mvcc *MVCC) putInternal(key Key, timestamp hlc.HLTimestamp, value []byte, txnID string) error { keyMeta := &keyMetadata{} ok, err := GetI(mvcc.engine, key, keyMeta) if err != nil { return err } // In case the key metadata exists. if ok { // There is an uncommitted write intent and the current Put // operation does not come from the same transaction. // This should not happen since range should check the existing // write intent before executing any Put action at MVCC level. if len(keyMeta.TxnID) > 0 && (len(txnID) == 0 || keyMeta.TxnID != txnID) { return &writeIntentError{TxnID: keyMeta.TxnID} } if keyMeta.Timestamp.Less(timestamp) || (timestamp.Equal(keyMeta.Timestamp) && txnID == keyMeta.TxnID) { // Update key metadata. PutI(mvcc.engine, key, &keyMetadata{TxnID: txnID, Timestamp: timestamp}) } else { // In case we receive a Put request to update an old version, // it must be an error since raft should handle any client // retry from timeout. return &writeTimestampTooOldError{Timestamp: keyMeta.Timestamp} } } else { // In case the key metadata does not exist yet. // Create key metadata. PutI(mvcc.engine, key, &keyMetadata{TxnID: txnID, Timestamp: timestamp}) } // Save the value with the given version (Key + Timestamp). return mvcc.engine.Put(mvccEncodeKey(key, timestamp), value) }