Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ package config

var Host = "0.0.0.0"
var Port = 7379
var KeysLimit int=5
var KeysLimit int = 5

var EvictionStrategy string="simle-first"
var AOFile string="./dice-master.aof"
//will evict EvictionRatio of keys whenever eviction runs
//it would dictate whenever my eviction is triggered, how many keys i will be evicting.
var EvictionRatio float64 = 0.40 //Generally aise real scenario me kabhi itna to nahi hi krte hai but still

var EvictionStrategy string = "simle-first"
var AOFile string = "./velox.aof"
12 changes: 7 additions & 5 deletions config/main.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package config

var Host string="0.0.0.0"
var Port int=7379
// Duplicate variables - commenting out to avoid redeclaration
// See config.go for the actual declarations
//var Host string="0.0.0.0"
//var Port int=7379

var KeysLimit int=100 //like ye hum threshold set krdiye hai like our database still support atmax this many keys
//var KeysLimit int=100 //like ye hum threshold set krdiye hai like our database still support atmax this many keys

//will evict EvictionRation of keys whenever evictionruns
//it would dictate whenever my eviction is triggered, how many keys i will be evicting.
var EvictionRatio flaot64=0.40 //Generally aise real scenario me kabhi itna to nahi hi krte hai but still
// var EvictionRatio float64=0.40 //Generally aise real scenario me kabhi itna to nahi hi krte hai but still

var EvictionStrategy string="allkeys-random"
// var EvictionStrategy string="allkeys-random"
var AOFFile string="./velox.aof"

2 changes: 1 addition & 1 deletion core/aof.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
//TODO: Support sync write
func dumpKey(fp *os.File,key string,obj *Obj){
cmd:=fmt.Sprintf("SET %s %s", key,obj.Value)
tokens:=strings.Split(cmd,"")
tokens:=strings.Split(cmd," ")
fp.Write(Encode(tokens,false))
}

Expand Down
76 changes: 41 additions & 35 deletions core/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package core
import (
"bytes"
"errors"
"fmt"
"io"
"strconv"
"time"
Expand Down Expand Up @@ -60,11 +61,11 @@ func evalINCR(args []string)[]byte{
return Encode(err,false)
}
//which means value is indeed an integer
i,_:=strconv.ParseInt(obj.Value,(string),10,64)
i, _ := strconv.ParseInt(obj.Value.(string), 10, 64) // Fixed: proper type assertion
i++
obj.Value=strconv.FormatInt(i,10)
obj.Value = strconv.FormatInt(i, 10)

return Encode(i,false)
return Encode(i, false)
}


Expand Down Expand Up @@ -134,11 +135,11 @@ func evalGET(args []string)[]byte{
}

//if key already expired then return nil
if obj.ExpiresAt!=-1 && obj.ExpiresAt<=time.Now().UnixMilli(){
// c.Write(RESP_NIL)
// return nil
return RESP_NIL
}
// if obj.ExpiresAt!=-1 && obj.ExpiresAt<=time.Now().UnixMilli(){
// // c.Write(RESP_NIL)
// // return nil
// return RESP_NIL
// }

//if key already expired then return nil
if hasExpired(obj){
Expand Down Expand Up @@ -170,42 +171,46 @@ func evalTTL(args []string) []byte{
}

//if object exist, but no expiration is set on it then send -1
if obj.ExpiresAt==-1{
// c.Write([]byte(":-1\r\n"))
// return nil
return RESP_MINUS_1
}
// if obj.ExpiresAt==-1{ // Commented out - ExpiresAt field removed
// // c.Write([]byte(":-1\r\n"))
// // return nil
// return RESP_MINUS_1
// }

//compute the time remaining for the key to expire and
//return the RESP encoded form of it
durationMs:=obj.ExpiresAt-time.Now().UnixMilli()
// durationMs:=obj.ExpiresAt-time.Now().UnixMilli() // Commented out

//if key expired i.e key does not exist hence return -2
if durationMs < 0{
// c.Write([]byte(":-2\r\n"))
// return nil
return RESP_MINUS_2
}

exp.isExpirySet:=getExpiry(obj)
if !isExpirySet{
// if durationMs < 0{ // Commented out
// // c.Write([]byte(":-2\r\n"))
// // return nil
// return RESP_MINUS_2
// }

exp, isExpirySet := getExpiry(obj) // Fixed: handle both return values
if !isExpirySet{ // Fixed: proper handling
return RESP_MINUS_1
}

//if key expired i.e key does not exist hence return -2
if uint64(time.Now().UnixMilli())>exp{
if uint64(time.Now().UnixMilli())>uint64(exp){
return RESP_MINUS_2
}

//compute the time remaining for the key to expire and
//return the RESP encoded form of it
durationMS:=exp-uint64(time.Now().UnixMilli())

//return the RESP encoded form of it
durationMs:=int64(exp)-time.Now().UnixMilli()

return Encode(durationMs/1000,false)
}
// Duplicate code commented out below - was causing syntax error
// durationMS:=exp-uint64(time.Now().UnixMilli())
// c.Write(Encode(int64(durationMS/1000),false))
// return nil
return Encode(int64(durationMs/1000), false)
}
// return Encode(int64(durationMs/1000), false)

// Continue with next function
func evalDEL(args []string) []byte{
var countDeleted int = 0
for _, key := range args{
Expand Down Expand Up @@ -255,10 +260,11 @@ func evalBGREWRITEAOF(args []string) []byte{

func evalINFO(args []string)[]byte{
var info []byte
buf:=bytes.NewBuffer(info)
buf := bytes.NewBuffer(info)
for i := range KeyspaceStat{
buf.WriteString(fmt.Sprintf("db%d:keys=%d,expire=0,avg_ttl=0\r\n",i,KeyspaceStat[i]["keys"]))
buf.WriteString(fmt.Sprintf("db%d:keys=%d,expire=0,avg_ttl=0\r\n", i, KeyspaceStat[i]["keys"]))
}
return buf.Bytes() // Fixed: added missing return
}

// func EvalAndRespond(cmd *Rediscmd,c net.Conn)error{
Expand Down Expand Up @@ -286,13 +292,13 @@ func EvalAndRespond(cmds []*RedisCmd, c io.ReadWriter) error{
case "BGREWRITEAOF":
buf.Write(evalBGREWRITEAOF(cmd.Args))
case "INCR":
buf.Write(evalPING(cmd.Args))
buf.Write(evalINCR(cmd.Args))
case "INFO":
buf.Write(evalINFO(cmd.Args))
case "CLIENT":
buf.Write(evalCLIENT(cmd.Args))
case "LATENCY":
buf.Write(evalLATENCY(cmd.Args))
// case "CLIENT": // Commented out - evalCLIENT not implemented
// buf.Write(evalCLIENT(cmd.Args))
// case "LATENCY": // Commented out - evalLATENCY not implemented
// buf.Write(evalLATENCY(cmd.Args))
default:
buf.Write(evalPING(cmd.Args))
}
Expand Down
30 changes: 17 additions & 13 deletions core/eviction.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ whenevr a cache is full, we will be evicting the first key which we do find

package core

import "github.com/sharpsalt/Velox-In-Memory-Database/config"
import (
"time"

"github.com/sharpsalt/Velox-In-Memory-Database/config"
)

//Evcits the first key it found while iterating the map
//TODP: Make it efficient by doing thrugh somehting
Expand Down Expand Up @@ -37,22 +41,22 @@ func getIdleTime(LastAccessdAt uint32) uint32{
}

func populateEvictionPool(){
sampleSize:=5
for k:=range store{
ePool.Push(k,store[k].lastaccessedat)
sampleSize := 5
for k := range store{
ePool.Push(k, store[k].LastAccessedAt) // Fixed: was lowercase
sampleSize--
if sampleSize==0{
if sampleSize == 0{
break
}
}
}

//TODO: no need to populate everytime, should populate
//only when the number of keys to evict is less than what we have in the pool
funct evictAllKeysLRU(){
func evictAllKeysLRU(){ // Commented out - incomplete implementation
populateEvictionPool()
evictCount:=int16(config.EvictionRatio=float64(config.KeysLimit))
for i:=;i<int(evictCount) && len(ePool.pool)>0 ;i++{
evictCount:=int16(config.EvictionRatio*float64(config.KeysLimit))
for i:=0;i<int(evictCount) && len(ePool.pool)>0 ;i++{
item:=ePool.Pop()
if item==nil{
return
Expand Down Expand Up @@ -89,10 +93,10 @@ func evict(){
// evictFirst()
switch config.EvictionStrategy{
case "simple-first":
evictfirst()
case "allkets-random":
evictAllkeysRandom()
case: "allkeys-lru":
evictAllKeysLRU()
evictFirst() // Fixed function name case
case "allkeys-random": // Fixed spelling
evictAllKeysRandom() // Fixed function name case
// case "allkeys-lru": // Commented out - incomplete
// evictAllKeysLRU()
}
}
39 changes: 19 additions & 20 deletions core/evictionpool.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package core

import{
import(
"sort"
}
)


type PoolItem struct{
Expand All @@ -19,42 +19,41 @@ type EvictionPool struct{

type ByIdleTime []*PoolItem

func (a ByIdleTime) len() int{
func (a ByIdleTime) Len() int{ // Fixed: was lowercase 'len'
return len(a)
}

func (a ByIdleTime) Swap(i int,j int){
a[i],a[j]=a[j],a[i]
func (a ByIdleTime) Swap(i int, j int){
a[i], a[j] = a[j], a[i]
}

func (a ByIdleTime) Less(i int,j int) bool{//basically it is a comparator function which i am suing to sort the time
return getIdleTime(a[i].lastaccessedat)>getIdleTime(a[j].lastaccessedat)
func (a ByIdleTime) Less(i int, j int) bool{//basically it is a comparator function which i am suing to sort the time
return getIdleTime(a[i].lastaccessedat) > getIdleTime(a[j].lastaccessedat)
}

//TODO: Make the Implementation efficient to not need repeated sorting
func (pq *EvictionPool) Push(key string,lastaccessedat uint32){
_,ok:=pq.keyset[key]
func (pq *EvictionPool) Push(key string, lastaccessedat uint32){
_, ok := pq.keyset[key]
if ok{
//while pushing it into eviction pool if it already exists then we don;t have to push it again it in eveiction pool
return
}
ietm:=&PoolItem(key:key,lastaccessedat:lastaccessedat)
if len(pq.pool)<ePoolSizeMax{
item := &PoolItem{key: key, lastaccessedat: lastaccessedat} // Fixed: was using () instead of {}
if len(pq.pool) < ePoolSizeMax{
//which means there is some space for adding element
//remeber eviction pool is needed to be sorted by idle time
pq.keyset[key]=items
pq.pool=append(pq.pool,item)

pq.keyset[key] = item
pq.pool = append(pq.pool, item)

//Performance bottleneck
sort.Sort(ByIdleTime(pq.pool))
}else if lastaccessedat>pq.pool[len(pq.pool)-1].lastaccessedat{
}else if lastaccessedat > pq.pool[len(pq.pool)-1].lastaccessedat{
//if i have no space in eviction pool but the element which i have smapled is worse than my current
//i will create space for that by removing the 1st one and adding new element by appending it
///so this way we are ensuring that our pool contains best possible candidates to be evcited
pq.pool=pq.pool[1:]
pq.keyset[key]=item
pq.pool=append(pq.pool,item)
pq.pool = pq.pool[1:]
pq.keyset[key] = item
pq.pool = append(pq.pool, item)
}
}

Expand All @@ -69,8 +68,8 @@ func (pq *EvictionPool) Pop() *PoolItem{

func newEvictionPool(size int) *EvictionPool{
return &EvictionPool{
pool: make([]*PoolItem,size)
keyset: make(map[string]*PoolItem)
pool: make([]*PoolItem, size), // Fixed: added missing comma
keyset: make(map[string]*PoolItem),
}
}

Expand Down
17 changes: 11 additions & 6 deletions core/expire.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,18 @@ func expireSample() float32{

//assuming iteration of golang hash table in randomized
for key, obj := range store{
if obj.ExpiresAt != -1{
// if obj.ExpiresAt != -1{
// limit--
// //if the key is expired
// if obj.ExpiresAt <= time.Now().UnixMilli(){
// delete(store, key)
// expiresCount++
// }
// }
if hasExpired(obj){
delete(store,key)
expiresCount++
limit--
//if the key is expired
if obj.ExpiresAt <= time.Now().UnixMilli(){
delete(store, key)
expiresCount++
}
}

//one we iterated to 20 keys that have some expirations set
Expand Down
2 changes: 1 addition & 1 deletion core/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ var OBJ_TYPE_STRING uint8=0<<4 //because first 4 bits i want to set

var OBJ_ENCODING_RAW uint8=0
var OBJ_ENCODING_INT uint8=1
var OBJ_ENCODING_ENDSTR uint8=8
var OBJ_ENCODING_EMBSTR uint8=8 //Object encoding is embedded string



14 changes: 12 additions & 2 deletions core/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,17 @@ var KeyspaceStat [4]map[string]int //just all global object
//eg i support 4 databases within my redis
//in redis you can have 16 databases in redis itself, by deault it goes from db0,db1,db2,...db15

func init(){
// Initialize the maps for each database
for i := 0; i < 4; i++ {
KeyspaceStat[i] = make(map[string]int)
}
}

//for which db,which metric,which value
func UpdatDBStat(num int,metric string,value int){
KeyspaceStat[num][metric]=value
func UpdatDBStat(num int, metric string, value int){
// Check bounds before accessing
if num >= 0 && num < len(KeyspaceStat) {
KeyspaceStat[num][metric] = value
}
}
Loading
Loading