Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Go: Implement connection logic in lib.rs #119

Closed
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c0cb6fb
Add Rust connection logic and example
jonathanl-bq Feb 27, 2024
22bbf74
Add error handling logic for connections
jonathanl-bq Feb 27, 2024
79343ff
Add license headers
jonathanl-bq Feb 27, 2024
2a92415
Refactor cArgs
jonathanl-bq Feb 27, 2024
3278942
Update API for client creation
jonathanl-bq Feb 29, 2024
2b258e5
Remove non-connection logic
jonathanl-bq Mar 4, 2024
6ccc6c1
Update lib.h
jonathanl-bq Mar 4, 2024
bdf9c19
Add additional documentation to lib.rs functions
jonathanl-bq Mar 5, 2024
4bd25cc
Properly free connection response and error
jonathanl-bq Mar 6, 2024
dc4df76
Run go fmt
jonathanl-bq Mar 6, 2024
cd5c2da
Add error for when user closes client before creating it
jonathanl-bq Mar 6, 2024
055e74b
Add doc comments about avoiding memory leaks
jonathanl-bq Mar 6, 2024
f23b01a
Allow unused Client fields for now
jonathanl-bq Mar 6, 2024
aa1fb08
Add formatting directive to fmt.Errorf
jonathanl-bq Mar 6, 2024
2fe5bdd
Replace callback implementations with TODO implementations
jonathanl-bq Mar 6, 2024
6289bfb
Resolve merge conflicts
jonathanl-bq Mar 6, 2024
53c8d7d
Remove RedisErrorFFI struct and use glide-core RequetErrorType instead
jonathanl-bq Mar 7, 2024
926e050
Update go/glide/lib.h
jonathanl-bq Mar 7, 2024
b9e61c8
Update go/glide/lib.h
jonathanl-bq Mar 7, 2024
70fb74b
Update go/src/lib.rs
jonathanl-bq Mar 7, 2024
db8959b
Update go/src/lib.rs
jonathanl-bq Mar 7, 2024
b32408c
Update documentation for create_client
jonathanl-bq Mar 7, 2024
478acd6
Adjust documentation regarding memory leaks
jonathanl-bq Mar 7, 2024
0e52d91
Make free_connection_response also free its error
jonathanl-bq Mar 7, 2024
a02912f
Update doc comment for free_connection_response
jonathanl-bq Mar 8, 2024
7ea7bdd
Re-expose free_error for the error callback to use and update docs
jonathanl-bq Mar 8, 2024
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
3 changes: 3 additions & 0 deletions go/.gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# Go compilation files
*.pb.go

# Examples
examples/examples

reports
2 changes: 2 additions & 0 deletions go/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ redis = { path = "../submodules/redis-rs/redis", features = ["aio", "tokio-comp"
glide-core = { path = "../glide-core" }
tokio = { version = "^1", features = ["rt", "macros", "rt-multi-thread", "time"] }
protobuf = { version = "3.3.0", features = [] }
logger_core = {path = "../logger_core"}
tracing-subscriber = "0.3.16"

[profile.release]
lto = true
Expand Down
45 changes: 45 additions & 0 deletions go/examples/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0
*/
package main

import (
"fmt"
"github.com/aws/glide-for-redis/go/glide/glide"
"github.com/aws/glide-for-redis/go/glide/protobuf"
)

func main() {
fmt.Println("Starting go-glide client...")
client := glide.GlideRedisClient{}

request := &protobuf.ConnectionRequest{
TlsMode: protobuf.TlsMode_NoTls,
ClusterModeEnabled: false,
ReadFrom: protobuf.ReadFrom_Primary,
}
request.Addresses = append(
request.Addresses,
&protobuf.NodeAddress{Host: "localhost", Port: uint32(6379)},
)
err := client.ConnectToRedis(request)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens if a user calls client.set() before they call ConnectToRedis?

if err != nil {
return
}

err = client.Set("FOO", "BAR")
if err != nil {
panic(err)
}
fmt.Println("SET FOO : BAR")

val, err := client.Get("FOO")
if err != nil {
panic(err)
}
fmt.Println("GET FOO :", val)

client.CloseClient()

fmt.Println("Disconnected from Redis")
}
238 changes: 238 additions & 0 deletions go/glide/glide.go
Original file line number Diff line number Diff line change
@@ -1 +1,239 @@
/**
* Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0
*/
package glide

/*
#cgo LDFLAGS: -L../target/release -lglide_rs
#include "lib.h"

void successCallback(uintptr_t channelPtr, char *message);
void failureCallback(uintptr_t channelPtr, char *errMessage);
*/
import "C"

import (
"fmt"
"unsafe"
"github.com/aws/glide-for-redis/go/glide/protobuf"
"github.com/golang/protobuf/proto"
)

type GlideRedisClient struct {
coreClient unsafe.Pointer
}

type payload struct {
value string
errMessage error
}

type RequestType uint32

const (
_ = iota
CustomCommand RequestType = iota
GetString
SetString
Ping
Info
Del
Select
ConfigGet
ConfigSet
ConfigResetStat
ConfigRewrite
ClientGetName
ClientGetRedir
ClientId
ClientInfo
ClientKill
ClientList
ClientNoEvict
ClientNoTouch
ClientPause
ClientReply
ClientSetInfo
ClientSetName
ClientUnblock
ClientUnpause
Expire
HashSet
HashGet
HashDel
HashExists
MGet
MSet
Incr
IncrBy
Decr
IncrByFloat
DecrBy
HashGetAll
HashMSet
HashMGet
HashIncrBy
HashIncrByFloat
LPush
LPop
RPush
RPop
LLen
LRem
LRange
LTrim
SAdd
SRem
SMembers
SCard
PExpireAt
PExpire
ExpireAt
Exists
Unlink
TTL
Zadd
Zrem
Zrange
Zcard
Zcount
ZIncrBy
ZScore
Type
HLen
Echo
ZPopMin
Strlen
Lindex
ZPopMax
XRead
XAdd
XReadGroup
XAck
XTrim
XGroupCreate
XGroupDestroy
)

type ErrorType uint32

const (
ClosingError = iota
RequestError
TimeoutError
ExecAbortError
ConnectionError
)

//export successCallback
func successCallback(channelPtr C.uintptr_t, message *C.char) {
goMessage := C.GoString(message)
goChannelPointer := uintptr(channelPtr)
resultChannel := *(*chan payload)(unsafe.Pointer(goChannelPointer))
resultChannel <- payload{value: goMessage, errMessage: nil}
}

//export failureCallback
func failureCallback(channelPtr C.uintptr_t, errMessage *C.char) {
goMessage := C.GoString(errMessage)
goChannelPointer := uintptr(channelPtr)
resultChannel := *(*chan payload)(unsafe.Pointer(goChannelPointer))
resultChannel <- payload{value: "", errMessage: fmt.Errorf("error at redis operation: %s", goMessage)}
}

func stringsToCStrings(args []string) []*C.char {
cArgs := make([]*C.char, len(args))
for index, string := range args {
cString := C.CString(string)
cArgs[index] = cString
}
return cArgs
}

func freeCStrings(cArgs []*C.char) {
for _, arg := range cArgs {
C.free(unsafe.Pointer(arg))
}
}

func (glideRedisClient *GlideRedisClient) ConnectToRedis(request *protobuf.ConnectionRequest) error {
marshalledRequest, err := proto.Marshal(request)
if err != nil {
return fmt.Errorf("Failed to encode connection request:", err)
}
byteCount := len(marshalledRequest)
requestBytes := C.CBytes(marshalledRequest)
response := (*C.struct_ConnectionResponse)(C.create_client((*C.uchar)(requestBytes), C.uintptr_t(byteCount), (C.SuccessCallback)(unsafe.Pointer(C.successCallback)), (C.FailureCallback)(unsafe.Pointer(C.failureCallback))))
defer C.free(unsafe.Pointer(response))
if response.error != nil {
return fmt.Errorf(C.GoString(response.error.message))
}
glideRedisClient.coreClient = response.conn_ptr
return nil
}

func (glideRedisClient *GlideRedisClient) Set(key string, value interface{}) error {
strValue := fmt.Sprintf("%v", value)
ckey := C.CString(key)
cval := C.CString(strValue)
defer C.free(unsafe.Pointer(ckey))
defer C.free(unsafe.Pointer(cval))

resultChannel := make(chan payload)
resultChannelPtr := uintptr(unsafe.Pointer(&resultChannel))

args := []string{key, strValue}
cArgs := stringsToCStrings(args)
defer freeCStrings(cArgs)
requestType := C.uint32_t(SetString)
C.command(glideRedisClient.coreClient, C.uintptr_t(resultChannelPtr), requestType, C.uintptr_t(2), &cArgs[0])

resultPayload := <-resultChannel

return resultPayload.errMessage
}

func (glideRedisClient *GlideRedisClient) Get(key string) (string, error) {
ckey := C.CString(key)
defer C.free(unsafe.Pointer(ckey))

resultChannel := make(chan payload)
resultChannelPtr := uintptr(unsafe.Pointer(&resultChannel))

args := []string{key}
cArgs := stringsToCStrings(args)
defer freeCStrings(cArgs)
requestType := C.uint32_t(GetString)
C.command(glideRedisClient.coreClient, C.uintptr_t(resultChannelPtr), requestType, C.uintptr_t(1), &cArgs[0])
resultPayload := <-resultChannel

return resultPayload.value, nil

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return resultPayload.value, nil
return resultPayload.value, resultPayload.errMessage

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will deal with this later when we add command logic

}

func (glideRedisClient *GlideRedisClient) Ping() (string, error) {
resultChannel := make(chan payload)
resultChannelPtr := uintptr(unsafe.Pointer(&resultChannel))

cArgs := []*C.char{}
requestType := C.uint32_t(Ping)
C.command(glideRedisClient.coreClient, C.uintptr_t(resultChannelPtr), requestType, C.uintptr_t(0), &cArgs[0])
resultPayload := <-resultChannel

return resultPayload.value, resultPayload.errMessage
}

func (glideRedisClient *GlideRedisClient) Info() (string, error) {
resultChannel := make(chan payload)
resultChannelPtr := uintptr(unsafe.Pointer(&resultChannel))

cArgs := []*C.char{}
requestType := C.uint32_t(Info)
C.command(glideRedisClient.coreClient, C.uintptr_t(resultChannelPtr), requestType, C.uintptr_t(0), &cArgs[0])
resultPayload := <-resultChannel

return resultPayload.value, resultPayload.errMessage
}

func (glideRedisClient *GlideRedisClient) CloseClient() {
C.close_client(glideRedisClient.coreClient)
}
Loading
Loading