Postgres streaming replication protocol
I have know about the postgres wire protocol, but first I ran into streaming replication protocol.
I was looking at this code in stolon
replConnParams["replication"] = "1"
db, err := sql.Open("postgres", replConnParams.ConnString())
if err != nil {
return nil, err
}
defer db.Close()
rows, err := query(ctx, db, "IDENTIFY_SYSTEM")
if err != nil {
return nil, err
}
I was wondering what is this IDENTIFY_SYSTEM. A G-search pointed me to this
visi@viggy28-MacBook-Pro ~ % psql "dbname=postgres user=postgres replication=database password=replaceme" -c "IDENTIFY_SYSTEM;"
systemid | timeline | xlogpos | dbname
---------------------+----------+-----------+----------
6852440194718025990 | 1 | 0/1542DB8 | postgres
visi@visis-MacBook-Pro ~ % psql "dbname=postgres user=postgres replication=database password=replaceme" -c "TIMELINE_HISTORY 1;"
ERROR: could not open file "pg_xlog/00000001.history": No such file or directory
(1 row)
I learnt you can directly postgres using other than SQL by sending messages to the backend (server) through the wire protocol !!
Named break statement in Go
I came across this piece of code from The Go Programming Language book.
loop:
for {
select {
case size, ok := <-fileSizes:
if !ok {
break loop // fileSizes was closed
}
nfiles++
nbytes += size
case <-tick:
printDiskUsage(nfiles, nbytes)
}
}
The complete program is available in Github
Named break statement allows to break perhaps multiple control statements. In this example, break loop breaks the select and for statement.
capturing iteration variables in Go
I was going through The Go Programming Language and in chapter 5 there was a section Caveat: Capturing Iteration Variables.
The example is like this:
var rmdirs []func()
for _, dir := range tempDirs() { // 1
os.MkdirAll(dir, 0755) // 2
rmdirs = append(rmdirs, func() {
os.RemoveAll(dir) // NOTE: incorrect! // 3
})
}
diris the same variable. i.e. the address of the variable is samedir’s value evaluated at this point is different at each iteration- IMPORTANT
diris not evaluated here. Its just being used. It will be evaluated only when thefunc()is called
The following explanation from Ref[1]:
all goroutines are asleep - deadlock!
program1
package main
import (
"log"
)
func main() {
done := make(chan struct{})
go func() {
log.Println("done")
}()
<-done //wait for background goroutine to finish
}
program2
run nc -l 8000 on another terminal
package main
import (
"log"
"net"
)
func main() {
conn, err := net.Dial("tcp", "localhost:8000")
if err != nil {
log.Fatal(err)
}
conn.Close()
done := make(chan struct{})
go func() {
log.Println("done")
}()
<-done //wait for background goroutine to finish
}
Both of those examples have a receive statement from a channel that no one ever sends to. Such a statement must block forever, meaning the goroutine that contains it can never run. If there are no goroutines that can run, Go terminates the program with a deadlock message.
Embedded field in Go
- Initializing embedded field: The field name of an anonymous field during a struct instantiation is the name of the struct (Time)
type Event struct {
ID int
time.Time
}
event := Event{
ID: 1234,
Time: time.Now(),
}
- If an embedded field type implements an interface, the struct containing the embedded field will also implement this interface
Understanding shallow copy vs deep copy in Go
In Go, copying generally does a copy by value. So modifying the destination, doesn’t modify the source. However, that holds good only if you are copying value types not reference types (i.e. pointer, slice, map etc.)
package main
import (
"fmt"
)
func main() {
type Cat struct {
age int
name string
Friends []string //reference type
}
wilson := Cat{7, "Wilson", []string{"Tom", "Tabata", "Willie"}}
// shallow copy
nikita := wilson
// modifies both nikita and wilson
nikita.Friends[0] = "cruise"
fmt.Println("nikita:", wilson)
fmt.Println("wilson:", wilson)
// Here I am modifying the slice too, but whats stored in nikita.Friends is the address of new slice which append returns not wilson.Friends
nikita.Friends = append(wilson.Friends, "jerry")
fmt.Println("nikita:", nikita)
fmt.Println("wilson:", wilson)
// If the above doesn't makes sense this should. Created a new slice data
data := []string{"popeye"}
// shallow copy data to nikita Friends
nikita.Friends = data
// changing nikita Friends should change data too
nikita.Friends[0] = "pluto"
fmt.Println("nikita:", nikita)
fmt.Println("wilson:", wilson)
fmt.Println("data:", data)
}
This code explains one of the gotchas that I ran into.
nikita.Friends = append(wilson.Friends, "jerry") I was expecting wilson.Friends will also have jerry but since i did shallow copy nikita := wilson. However, that’s not the case.
I realized nikita.Friends = append(wilson.Friends, "jerry") actually creates a new slice and stores that’s reference. The data should clarify that further.