Skip to content

Instantly share code, notes, and snippets.

@lambrospetrou
Last active November 11, 2023 18:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lambrospetrou/0a1e62abec4a6a76852d40bed336d223 to your computer and use it in GitHub Desktop.
Save lambrospetrou/0a1e62abec4a6a76852d40bed336d223 to your computer and use it in GitHub Desktop.
package main
import (
"database/sql"
"context"
"fmt"
"log"
"time"
"os"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/redis/go-redis/v9"
// "github.com/libsql/go-libsql"
_ "github.com/libsql/libsql-client-go/libsql"
_ "modernc.org/sqlite"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)
type Person struct {
Name string
Age int
Foods []string
}
func main() {
runMongo()
runRedis()
runDynamoDB()
runSQLite(true)
// runSQLite(false)
// runLibsql() // not supporting arm64 yet
}
func runSQLite(local bool) {
var dbUrl string
if local {
dbUrl = "file:test.sqlite"
} else {
// Frankfurt
dbUrl = "libsql://<redacted>.turso.io/?authToken=<redacted>"
}
db, err := sql.Open("libsql", dbUrl)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to open db %s: %s", dbUrl, err)
os.Exit(1)
}
defer db.Close()
createTableQuery := `
CREATE TABLE IF NOT EXISTS users (
name TEXT NOT NULL PRIMARY KEY,
age INTEGER
);
`
_, err = db.Exec(createTableQuery)
if err != nil {
log.Fatal(err)
}
// fmt.Println("Table created successfully.")
// Insert a record
// insertQuery := "INSERT INTO users (name, age) VALUES (?, ?);"
// _, err = db.Exec(insertQuery, "lambros", 33)
// if err != nil {
// log.Fatal(err)
// }
// fmt.Println("Record inserted successfully.")
SumNs := int64(0)
N := 100
for i:=0; i<N; i++ {
startTime := time.Now()
doSqliteWrite(db)
doSqliteRead(db)
elapsedTime := time.Since(startTime).Nanoseconds()
SumNs += elapsedTime
}
fmt.Println("SQLite local:", local, "N:", N, "Total time (ms):", SumNs/int64(1000000), "per iteration (us):", SumNs/int64(N)/1000)
}
func doSqliteRead(db *sql.DB) {
selectQuery := "SELECT * FROM users WHERE users.name = 'lambros' LIMIT 1;"
rows, err := db.Query(selectQuery)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var age int
var name string
err = rows.Scan(&name, &age)
if err != nil {
log.Fatal(err)
}
// fmt.Printf("Name: %s, Age: %d\n", name, age)
}
}
func doSqliteWrite(db *sql.DB) {
insertQuery := "REPLACE INTO users (name, age) VALUES (?, ?);"
_, err := db.Exec(insertQuery, "lambros", 33)
if err != nil {
panic(err)
}
// fmt.Println("Record inserted successfully.")
}
func runMongo() {
// MongoDB is in Belgium GCP!
// Use the SetServerAPIOptions() method to set the Stable API version to 1
serverAPI := options.ServerAPI(options.ServerAPIVersion1)
opts := options.Client().ApplyURI("mongodb+srv://<redacted>:<redacted>.mongodb.net/?retryWrites=true&w=majority").SetServerAPIOptions(serverAPI)
// Create a new client and connect to the server
client, err := mongo.Connect(context.TODO(), opts)
if err != nil {
panic(err)
}
defer func() {
if err = client.Disconnect(context.TODO()); err != nil {
panic(err)
}
}()
// Send a ping to confirm a successful connection
if err := client.Database("admin").RunCommand(context.TODO(), bson.D{{"ping", 1}}).Err(); err != nil {
panic(err)
}
// fmt.Println("Pinged your deployment. You successfully connected to MongoDB!")
// Accessing a collection
collection := client.Database("monosource").Collection("test")
// fmt.Printf("Found person: %+v\n", doMongoRead(collection, "lambros"))
SumNs := int64(0)
N := 100
for i:=0; i<N; i++ {
startTime := time.Now()
doMongoWrite(collection, &Person{Name: "lambros", Age: 33, Foods: []string{"pizza", "burger"}})
doMongoRead(collection, "lambros")
elapsedTime := time.Since(startTime).Nanoseconds()
SumNs += elapsedTime
}
fmt.Println("Mongo N:", N, "Total time (ms):", SumNs/int64(1000000), "per iteration (us):", SumNs/int64(N)/1000)
}
func doMongoRead(collection *mongo.Collection, name string) *Person {
// Define a filter
filter := bson.D{{"name", name}}
// Find one document
var result Person
err := collection.FindOne(context.TODO(), filter).Decode(&result)
if err != nil {
panic(err)
}
return &result
}
func doMongoWrite(collection *mongo.Collection, person *Person) {
filter := bson.D{{"name", person.Name}}
update := bson.D{{"$set", bson.D{{"name", person.Name}, {"age", person.Age}, {"foods", person.Foods}}}}
_, err := collection.UpdateOne(context.TODO(), filter, update, options.Update().SetUpsert(true))
if err != nil {
panic(err)
}
}
func runRedis() {
opt, err := redis.ParseURL("rediss://default:<redacted>-31505.upstash.io:31505")
if err != nil {
panic(err)
}
rdb := redis.NewClient(opt)
// fmt.Println(doRedisRead(rdb, "lambros"))
SumNs := int64(0)
N := 100
for i:=0; i<N; i++ {
startTime := time.Now()
doRedisWrite(rdb, "lambros", "some-long-value-like-age-food-jdnajskdasdadsadasdasdasidajsndan")
doRedisRead(rdb, "lambros")
elapsedTime := time.Since(startTime).Nanoseconds()
SumNs += elapsedTime
}
fmt.Println("Redis N:", N, "Total time (ms):", SumNs/int64(1000000), "per iteration (us):", SumNs/int64(N)/1000)
}
func doRedisRead(rdb *redis.Client, name string) string {
// rdb.HGet(context.Background(), "people", name).String()
rcmd := rdb.HGet(context.Background(), "people", name)
if err := rcmd.Err(); err != nil {
panic(err)
}
return rcmd.String()
}
func doRedisWrite(rdb *redis.Client, name string, val string) {
_, err := rdb.HSet(context.Background(), "people", name, val).Result()
if err != nil {
panic(err)
}
}
func runDynamoDB() {
sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
}))
// Create DynamoDB client
svc := dynamodb.New(sess, aws.NewConfig().WithRegion("eu-central-1"))
SumNs := int64(0)
N := 100
for i:=0; i<N; i++ {
startTime := time.Now()
doDynamoDbWrite(svc, "person#1234", "lambros")
doDynamoDbRead(svc, "person#1234", "lambros")
elapsedTime := time.Since(startTime).Nanoseconds()
SumNs += elapsedTime
}
fmt.Println("DynamoDB N:", N, "Total time (ms):", SumNs/int64(1000000), "per iteration (us):", SumNs/int64(N)/1000)
}
func doDynamoDbRead(svc *dynamodb.DynamoDB, pk string, sk string) map[string]string {
result, err := svc.GetItem(&dynamodb.GetItemInput{
TableName: aws.String("test-latency"),
ConsistentRead: aws.Bool(true),
Key: map[string]*dynamodb.AttributeValue{
"pk": {
S: aws.String(pk),
},
"sk": {
S: aws.String(sk),
},
},
})
if err != nil {
log.Fatalf("Got error calling GetItem: %s", err)
}
if result.Item == nil {
fmt.Println("Could not find '" + pk + "'")
return nil
}
item := make(map[string]string)
err = dynamodbattribute.UnmarshalMap(result.Item, &item)
if err != nil {
panic(fmt.Sprintf("Failed to unmarshal Record, %v", err))
}
// fmt.Println(item)
return item
}
func doDynamoDbWrite(svc *dynamodb.DynamoDB, pk, sk string) {
input := &dynamodb.PutItemInput{
TableName: aws.String("test-latency"),
Item: map[string]*dynamodb.AttributeValue{
"pk": {
S: aws.String(pk),
},
"sk": {
S: aws.String(sk),
},
},
ReturnConsumedCapacity: aws.String("TOTAL"),
}
_, err := svc.PutItem(input)
if err != nil {
panic(err)
}
// fmt.Println(result)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment