diff --git a/config/config.go b/config/config.go index 77769ad..9f6a5e4 100644 --- a/config/config.go +++ b/config/config.go @@ -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" \ No newline at end of file +//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" \ No newline at end of file diff --git a/config/main.go b/config/main.go index b8182bf..b1c404a 100644 --- a/config/main.go +++ b/config/main.go @@ -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" diff --git a/core/aof.go b/core/aof.go index fb9ebcd..14ec9a6 100644 --- a/core/aof.go +++ b/core/aof.go @@ -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)) } diff --git a/core/eval.go b/core/eval.go index 8e23448..9dc3ba8 100644 --- a/core/eval.go +++ b/core/eval.go @@ -3,6 +3,7 @@ package core import ( "bytes" "errors" + "fmt" "io" "strconv" "time" @@ -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) } @@ -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){ @@ -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{ @@ -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{ @@ -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)) } diff --git a/core/eviction.go b/core/eviction.go index 60c4094..3f2ae6a 100644 --- a/core/eviction.go +++ b/core/eviction.go @@ -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 @@ -37,11 +41,11 @@ 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 } } @@ -49,10 +53,10 @@ func populateEvictionPool(){ //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:=;i0 ;i++{ + evictCount:=int16(config.EvictionRatio*float64(config.KeysLimit)) + for i:=0;i0 ;i++{ item:=ePool.Pop() if item==nil{ return @@ -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() } } diff --git a/core/evictionpool.go b/core/evictionpool.go index 9a2d721..f3d4154 100644 --- a/core/evictionpool.go +++ b/core/evictionpool.go @@ -1,8 +1,8 @@ package core -import{ +import( "sort" -} +) type PoolItem struct{ @@ -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)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) } } @@ -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), } } diff --git a/core/expire.go b/core/expire.go index 3390c28..5e06ac8 100644 --- a/core/expire.go +++ b/core/expire.go @@ -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 diff --git a/core/object.go b/core/object.go index b2095d7..67c3511 100644 --- a/core/object.go +++ b/core/object.go @@ -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 diff --git a/core/stats.go b/core/stats.go index e9e4233..d159bbd 100644 --- a/core/stats.go +++ b/core/stats.go @@ -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 + } } diff --git a/core/store.go b/core/store.go index 8054364..86837d0 100644 --- a/core/store.go +++ b/core/store.go @@ -2,9 +2,10 @@ package core import ( "time" - "store.go" + "github.com/sharpsalt/Velox-In-Memory-Database/config" ) +// "store.go" import removed - not a valid package var store map[string]*Obj //the best datastrcuture to hold key value is hash table so we are using it @@ -27,7 +28,7 @@ func setExpiry(obj *Obj,expDurationMs int64){ func NewObj(value interface{},expDurationMs int64,oType uint8,oEnc uint8) *Obj{ //creating a new object, setting things up and returning another object //since we want to store abolution expires instead of doing it multiple time that's why we have created this fucntion - var expiresAt int64=-1 + // var expiresAt int64=-1 if expDurationMs>0{ /* when we say setExpiry? @@ -71,7 +72,7 @@ func Get(k string) *Obj{ /*we check for the expiration and if it is already not deleted then we have to delete it */ if v != nil{ - if v.ExpiresAt <= time.Now().UnixMilli(){ + // if v.ExpiresAt <= time.Now().UnixMilli(){ //this is like a lazy deletion /* If a key is accessed and fund to be expired , then it deleted else it is not deleted @@ -82,9 +83,11 @@ func Get(k string) *Obj{ Del(k) return nil } - } + // } + } + if v!=nil{ + v.LastAccessedAt=getCurrentClock() } - v.LastAccessedAt=getCurrentClock() return v } diff --git a/core/type_string.go b/core/type_string.go index 3a907cc..f263e8c 100644 --- a/core/type_string.go +++ b/core/type_string.go @@ -7,7 +7,7 @@ import "strconv" //tryObjectEncoding Function in redis func deduceTypeEncoding(v string)(uint8,uint8){ oType:=OBJ_TYPE_STRING - if _,rr:=strconv.ParseInt(v,10,64);err==nil{ + if _,err:=strconv.ParseInt(v,10,64);err==nil{ return oType,OBJ_ENCODING_INT //we are converting ans stroing int as a string inside my redis object } if len(v)<=44{