Commit 83328dd7 authored by Sushant Mahajan's avatar Sushant Mahajan

handled expired keys and made key deletion on expiry more efficient

parent b6eb9e07
...@@ -23,7 +23,7 @@ const ( ...@@ -23,7 +23,7 @@ const (
CAS = "cas" CAS = "cas"
DELETE = "delete" DELETE = "delete"
NOREPLY = "noreply" NOREPLY = "noreply"
//
// //response // //response
OK = "OK" OK = "OK"
CRLF = "\r\n" CRLF = "\r\n"
...@@ -39,10 +39,11 @@ const ( ...@@ -39,10 +39,11 @@ const (
//represents the value in the main hashtable (key, value) pair //represents the value in the main hashtable (key, value) pair
type Data struct { type Data struct {
numBytes uint64 //number of bytes of the value bytes numBytes uint64 //number of bytes of the value bytes
version uint64 //current version of the key version uint64 //current version of the key
expTime uint64 //time offset in seconds after which the key should expire expTime uint64 //time offset in seconds after which the key should expire
value []byte //bytes representing the actual content of the value value []byte //bytes representing the actual content of the value
isPerpetual bool //specifies that the key does not expire
} }
//represents the main hashtable where the dance actually happens //represents the main hashtable where the dance actually happens
...@@ -289,7 +290,11 @@ func parseInput(conn net.Conn, msg string, table *KeyValueStore, ch chan string) ...@@ -289,7 +290,11 @@ func parseInput(conn net.Conn, msg string, table *KeyValueStore, ch chan string)
buffer.WriteString(" ") buffer.WriteString(" ")
buffer.WriteString(strconv.FormatUint(data.version, 10)) buffer.WriteString(strconv.FormatUint(data.version, 10))
buffer.WriteString(" ") buffer.WriteString(" ")
buffer.WriteString(strconv.FormatUint(data.expTime-uint64(time.Now().Unix()), 10)) if data.isPerpetual {
buffer.WriteString("0")
} else {
buffer.WriteString(strconv.FormatUint(data.expTime-uint64(time.Now().Unix()), 10))
}
buffer.WriteString(" ") buffer.WriteString(" ")
buffer.WriteString(strconv.FormatUint(data.numBytes, 10)) buffer.WriteString(strconv.FormatUint(data.numBytes, 10))
write(conn, buffer.String()) write(conn, buffer.String())
...@@ -430,8 +435,10 @@ func performSet(conn net.Conn, tokens []string, table *KeyValueStore, ch chan st ...@@ -430,8 +435,10 @@ func performSet(conn net.Conn, tokens []string, table *KeyValueStore, ch chan st
val.numBytes = n val.numBytes = n
val.version = ver val.version = ver
if e == 0 { if e == 0 {
val.expTime = e val.isPerpetual = true
val.expTime = 0
} else { } else {
val.isPerpetual = false
val.expTime = e + uint64(time.Now().Unix()) val.expTime = e + uint64(time.Now().Unix())
} }
val.value = v val.value = v
...@@ -449,8 +456,7 @@ func performGet(conn net.Conn, tokens []string, table *KeyValueStore) (*Data, bo ...@@ -449,8 +456,7 @@ func performGet(conn net.Conn, tokens []string, table *KeyValueStore) (*Data, bo
table.RLock() table.RLock()
//critical section begin //critical section begin
if v, ok := table.dictionary[k]; ok { if v, ok := table.dictionary[k]; ok {
if v.expTime != 0 && v.expTime < uint64(time.Now().Unix()) { if !v.isPerpetual && v.expTime < uint64(time.Now().Unix()) {
table.RUnlock()
return nil, false return nil, false
} }
data := new(Data) data := new(Data)
...@@ -472,7 +478,7 @@ func performGetm(conn net.Conn, tokens []string, table *KeyValueStore) (*Data, b ...@@ -472,7 +478,7 @@ func performGetm(conn net.Conn, tokens []string, table *KeyValueStore) (*Data, b
table.RLock() table.RLock()
//critical section begin //critical section begin
if v, ok := table.dictionary[k]; ok { if v, ok := table.dictionary[k]; ok {
if v.expTime != 0 && v.expTime < uint64(time.Now().Unix()) { if !v.isPerpetual && v.expTime < uint64(time.Now().Unix()) {
return nil, false return nil, false
} }
data := new(Data) data := new(Data)
...@@ -512,16 +518,25 @@ func performCas(conn net.Conn, tokens []string, table *KeyValueStore, ch chan st ...@@ -512,16 +518,25 @@ func performCas(conn net.Conn, tokens []string, table *KeyValueStore, ch chan st
table.Lock() table.Lock()
if val, ok := table.dictionary[k]; ok { if val, ok := table.dictionary[k]; ok {
if val.version == ve { if val.version == ve {
if e == 0 { //if expiry time is zero, key should not be deleted if val.isPerpetual || val.expTime >= uint64(time.Now().Unix()) {
val.expTime = e if e == 0 { //if expiry time is zero, key should not be deleted
val.isPerpetual = true
val.expTime = 0
} else {
val.isPerpetual = false
val.expTime = e + uint64(time.Now().Unix())
}
val.numBytes = n
ver++
val.version = ver
val.value = v
return val.version, 0, r //key found and changed
} else { } else {
val.expTime = e + uint64(time.Now().Unix()) logger.Println("expired key found!")
//version found but key expired, can delete key safely and tell client that it does not exist
delete(table.dictionary, k)
return 0, 3, r
} }
val.numBytes = n
ver++
val.version = ver
val.value = v
return val.version, 0, r //key found and changed
} }
return 0, 2, r //version mismatch return 0, 2, r //version mismatch
} }
...@@ -541,9 +556,7 @@ func performDelete(conn net.Conn, tokens []string, table *KeyValueStore) int { ...@@ -541,9 +556,7 @@ func performDelete(conn net.Conn, tokens []string, table *KeyValueStore) int {
table.Lock() table.Lock()
//begin critical section //begin critical section
if v, ok := table.dictionary[k]; ok { if v, ok := table.dictionary[k]; ok {
if v.expTime < uint64(time.Now().Unix()) { if v.isPerpetual || v.expTime >= uint64(time.Now().Unix()) {
flag = 1 //found but expired
} else {
flag = 0 //found not expired flag = 0 //found not expired
} }
delete(table.dictionary, k) //delete anyway as expired or needs to be deleted delete(table.dictionary, k) //delete anyway as expired or needs to be deleted
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment