Skip to content

Commit d36cd90

Browse files
committed
👀 Readme and info
1 parent 84977d0 commit d36cd90

8 files changed

Lines changed: 181 additions & 58 deletions

File tree

Dockerfile

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
FROM golang:1.18-alpine as builder
2+
3+
# Install git, required for fetching Go dependencies.
4+
# Utilize the virtual package mechanism to keep the image small
5+
RUN apk add --no-cache git
6+
7+
WORKDIR /app
8+
9+
COPY go.mod go.sum ./
10+
11+
COPY . .
12+
13+
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .
14+
15+
FROM scratch
16+
17+
COPY --from=builder /app/main /main
18+
19+
EXPOSE 6379
20+
21+
CMD ["/main"]

README.md

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
<div align="center">
2+
<!-- logo -->
3+
<img src = "assets/icon.png" width="300">
4+
<h1 align="center">Go-Redis</h1>
5+
<img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-yellow.svg" /><br>
6+
Super fast drop-in replacement of the in memory key-value store redis in golang
7+
</div>
8+
9+
***
10+
[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](code_of_conduct.md)
11+
[Try it out instantly](#installation)
12+
13+
## 👀 What is this? Why?
14+
`go-redis` is a super fast drop-in replacement of the in memory key-value store redis, built with golang.
15+
16+
Why?
17+
Redis recently (Last week, as of Mar 25 2024) changed their license to a [dual 'source-available' license](https://news.ycombinator.com/item?id=39772562) - which means that it can't be used for commercial purposes without paying for a license. Everyone hated it. This is a problem for many companies and developers who use redis in their projects.
18+
19+
And, I was kinda bored and wanted to learn golang properly, so I built this.
20+
21+
Should you use this in production? Probably, probably not. It's not battle tested yet, but i (as a single person team) have tried to do my best to make it as reliable as possible.
22+
23+
I even made a cute mascot (Godis crushing Redis)
24+
25+
![Godis](assets/godis.png)
26+
27+
## 📜 Features
28+
29+
| Feature | Redis | Go-Redis |
30+
| ------------------------- | ----- | -------- |
31+
| In-memory key-value store |||
32+
| Strings |||
33+
| Lists |||
34+
| Sets |||
35+
| Sorted sets |||
36+
| Hashes |||
37+
| Streams |||
38+
| HyperLogLogs |||
39+
| Bitmaps |||
40+
| Persistence |||
41+
| Pub/Sub |||
42+
| Transactions |||
43+
| Lua scripting |||
44+
| LRU eviction |||
45+
| TTL || 😅 |
46+
| Clustering |||
47+
| Auth |||
48+
49+
### Available commands
50+
51+
For now, these commands are available (more to come)
52+
53+
#### MISC
54+
`INFO` `PING` `FLUSHALL` `SHUTDOWN` `SAVE` `BGSAVE`
55+
56+
#### Keys
57+
`DEL` `EXISTS` `KEYS` `EXPIRE` `TTL`
58+
59+
#### Strings
60+
`SET` `GET` `APPEND` `INCR` `INCRBY` `DECR` `DECRBY` `MSET` `MGET`
61+
62+
#### Lists
63+
`LPUSH` `LPOP` `RPUSH` `RPOP` `LRANGE` `LLEN`
64+
65+
#### Hashes
66+
`HSET` `HGET` `HMSET` `HMGET` `HGETALL` `HDEL`
67+
68+
#### Sets
69+
`SADD` `SMEMBERS` `SISMEMBER` `SREM`
70+
71+
#### Sorted Sets
72+
`ZADD` `ZRANGE` `ZREM`
73+
74+
#### Pub/Sub
75+
`SUBSCRIBE` `PUBLISH` `UNSUBSCRIBE`
76+
77+
#### Transactions
78+
`MULTI` `EXEC` `DISCARD`
79+
80+
## Installation
81+
82+
### Using `docker`
83+
To get it up and running instantly, you can use the docker image
84+
85+
```
86+
docker run -d -p 6379:6379 dhravyashah/go-redis
87+
```
88+
89+
### Using `go`
90+
91+
```
92+
go get github.com/dhrvyashah/go-redis
93+
```
94+
95+
and then just build and run the binary
96+
97+
98+
### Using the binary
99+
100+
Download the binary executables from `./bin/go-redis`.
101+
102+
Click here to get it [instantly](
103+
https://github.com/dhrvyashah/go-redis/releases/download/v0.1.0/go-redis-0.1.0-linux-amd64.tar.gz).
104+
105+
106+
## Having fun
107+
108+
This IS compatible with the existing redis tooling and client libraries! Try it out with some of them.
109+
110+
For eg.
111+
```
112+
npm i -g redis-cli
113+
```
114+
(make sure the server is running - docker is the easiest and fastest way)
115+
```
116+
❯ rdcli
117+
127.0.0.1:6379> incr mycounter
118+
(integer) 1
119+
127.0.0.1:6379> incr mycounter
120+
(integer) 2
121+
127.0.0.1:6379> set foo bar
122+
OK
123+
127.0.0.1:6379> get foo
124+
bar
125+
127.0.0.1:6379> get bar
126+
(nil)
127+
```
128+
129+
## Contributing
130+
Go-redis is *completely* open source. If you want to contribute, please create an issue on the repo and I will assign the task to someone (or you).
131+
132+
Steps to contribute:
133+
1. Clone the repo
134+
```
135+
git clone https://github.com/dhravya/go-redis
136+
```
137+
138+
2. Create a new branch
139+
140+
3. Make sure to build and test the code before creating a PR
141+
```
142+
go build -o ./bin
143+
```
144+
145+
4. Create a PR
146+
147+
## Help and the community
148+
If you need any help, or want to ask questions, or suggest features, please feel free to DM me on twitter - [https://dm.new/dhravya](https://dm.new/dhravya) or create an issue on the repo.
149+
150+
You can also join our [Discord server](https://discord.gg/z7MZYhmx6w) where we have a community of developers ready to help you out.
151+
152+
## License
153+
154+
Unlike redis, go-redis is licensed under the MIT license. You can use it for commercial purposes without any restrictions. Go wild!

assets/godis.png

256 KB
Loading

assets/icon.png

353 KB
Loading

assets/icon.svg

Lines changed: 0 additions & 21 deletions
This file was deleted.

assets/mascot.svg

Lines changed: 0 additions & 21 deletions
This file was deleted.

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module github.com/dhravya/go-redis
22

3-
go 1.21.6
3+
go 1.21

main.go

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,7 @@ func (kv *KeyValueStore) executeCommand(parts []string) string {
139139
for i := len(values) - 1; i >= 0; i-- {
140140
kv.Lists[key] = append([]string{values[i]}, kv.Lists[key]...)
141141
}
142-
return fmt.Sprintf("(integer) %d", len(kv.Lists[key]))
143-
142+
return fmt.Sprintf("(integer) %d", len(kv.Lists[key]))
144143
case "LPOP":
145144
if len(parts) != 2 {
146145
return "ERROR: LPOP requires 1 argument"
@@ -326,8 +325,7 @@ func (kv *KeyValueStore) executeCommand(parts []string) string {
326325
}
327326
key, value := parts[1], parts[2]
328327
kv.Strings[key] = value
329-
return "OK"
330-
328+
return "OK"
331329
case "GET":
332330
if len(parts) != 2 {
333331
return "ERROR: GET requires 1 argument"
@@ -339,7 +337,6 @@ func (kv *KeyValueStore) executeCommand(parts []string) string {
339337
return value
340338
}
341339
return "(nil)"
342-
343340
case "APPEND":
344341
if len(parts) != 3 {
345342
return "ERROR: APPEND requires 2 arguments"
@@ -352,8 +349,7 @@ func (kv *KeyValueStore) executeCommand(parts []string) string {
352349
} else {
353350
kv.Strings[key] = valueToAppend
354351
}
355-
return "OK"
356-
352+
return "OK"
357353
case "DEL":
358354
if len(parts) < 2 {
359355
return "ERROR: DEL requires at least 1 argument"
@@ -377,7 +373,6 @@ func (kv *KeyValueStore) executeCommand(parts []string) string {
377373
}
378374
}
379375
return fmt.Sprintf("(integer) %d", count)
380-
381376
case "EXISTS":
382377
if len(parts) != 2 {
383378
return "ERROR: EXISTS requires 1 argument"
@@ -393,7 +388,6 @@ func (kv *KeyValueStore) executeCommand(parts []string) string {
393388
return "(integer) 1"
394389
}
395390
return "(integer) 0"
396-
397391
case "KEYS":
398392
if len(parts) != 2 {
399393
return "ERROR: KEYS requires 1 argument"
@@ -408,8 +402,7 @@ func (kv *KeyValueStore) executeCommand(parts []string) string {
408402
}
409403
}
410404
// Optionally, search in other data structures
411-
return strings.TrimSpace(matchedKeys)
412-
405+
return strings.TrimSpace(matchedKeys)
413406
case "EXPIRE":
414407
if len(parts) != 3 {
415408
return "ERROR: EXPIRE requires 2 arguments"
@@ -424,7 +417,6 @@ func (kv *KeyValueStore) executeCommand(parts []string) string {
424417
expirationTime := time.Now().Add(time.Duration(seconds) * time.Second)
425418
kv.Expirations[key] = expirationTime
426419
return "OK"
427-
428420
case "TTL":
429421
if len(parts) != 2 {
430422
return "ERROR: TTL requires 1 argument"
@@ -576,7 +568,6 @@ func (kv *KeyValueStore) executeCommand(parts []string) string {
576568
return strings.Join(result, " ")
577569
}
578570
return "(empty sorted set)"
579-
580571
case "ZREM":
581572
if len(parts) < 3 {
582573
return "ERR ZREM requires at least 2 arguments"
@@ -601,8 +592,7 @@ func (kv *KeyValueStore) executeCommand(parts []string) string {
601592
kv.SortedSets[key] = sortedSet // Important to assign the modified slice back
602593
return fmt.Sprintf("(integer) %d", removed)
603594
}
604-
return "(integer) 0"
605-
595+
return "(integer) 0"
606596
case "MULTI":
607597
tx, err := kv.MultiCommand()
608598
if err != nil {

0 commit comments

Comments
 (0)