How golang garbage collection works
It is a Mark-and-Sweep GC. Phases Mark Stop-the-World: Set write barrier (to know how much was allocated during maark phase) Concurrent: Mark all memory which is still in use by the app Stop-the-World: Remove write barrier Concurrent: Sweep (it actually happens on new allocations) Details/Algorithm It’s a tri-color process: grey for objects to check, black …
Linux. History of system usage
There is a way to monitor your system usage and log to a file easily — with atop command. On my Ubuntu it can be installed with
1 |
sudo apt-get install atop |
It can be started as a top command — it’s output almost the same. But the most interesting feature is that it starts a daemon that logs …
Style guide for golang project file structure
Highly recommended. It has a couple of odds like not explaining about /test dir (I assume, they wanted to say to put there only e2e and other integrational tests, not unit-test as the latter should be kept together with the code itself in files like …_test.go). But it’s awesome in general. https://github.com/golang-standards/project-layout
Golang patterns. Worker pool
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
func worker(id int, jobs <-chan int, results chan<- int) { for j := range jobs { fmt.Println("worker", id, "started job", j) time.Sleep(time.Second) fmt.Println("worker", id, "finished job", j) results <- j * 2 } } func main() { // In order to use our pool of workers we need to send // them work and collect their results. We make 2 // channels for this. jobs := make(chan int, 100) results := make(chan int, 100) // This starts up 3 workers, initially blocked // because there are no jobs yet. for w := 1; w <= 3; w++ { go worker(w, jobs, results) } // Here we send 5 `jobs` and then `close` that // channel to indicate that's all the work we have. for j := 1; j <= 5; j++ { jobs <- j } close(jobs) for a := 1; a <= 5; a++ { <-results } } |
Further reading: https://gobyexample.com/worker-pools
PgBouncer and prepared statements
In our system, we use connection pooler called PgBouncer as a proxy to PostgreSQL server. PgBouncer has two main modes Session pooling mode This mode is less performant (it’s a default mode). When a client connects, a server connection will be assigned to it for the whole duration it stays connected. So it does not …
Golang: testing http and grpc servers
HTTP server is quite easy to test — here is a nice video about it:
Count lines in git repository
1 |
git ls-files | xargs wc -l |
https://stackoverflow.com/questions/4822471/count-number-of-lines-in-a-git-repository
Algorithms to find fastest route through network
This is a great article on that — https://www.redblobgames.com/pathfinding/a-star/introduction.html (in russain). It tells about Dijkstra, Breadth-first, Greedy and A* algorithms. It’s all about optimization of one travel. To optimize your entire network you should try to use Aint Colony algorithm — http://rain.ifmo.ru/cat/data/theory/unsorted/ant-algo-2006/article.pdf (it’s in russian). Another link to this PDF file — aca
How go code is being compiled to assembler code
https://go.godbolt.org/z/31FyJ3 I was interested in comparing line 15 vs line 17 of the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
package main import "fmt" type kv struct { key []byte value []byte } type sliceMap []kv func (sm *sliceMap) Add(k, v []byte) { kvs := *sm if cap(kvs) > len(kvs) { kvs = kvs[:len(kvs)+1] } else { kvs = append(kvs, kv{}) } kv := &kvs[len(kvs)-1] kv.key = append(kv.key[:0], k...) kv.value = append(kv.value[:0], v...) *sm = kvs } func main() { sm := sliceMap{} sm.Add([]byte("foo"), []byte("bar")) fmt.Println(sm) } |
E2E tests in go
I tried it via ginkgo and gomega. It has Agouti with WebDriver support out of the box, but I didn’t use it as we have grpc API. That’s the example (table tests):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
var _ = Describe("GetRoute", func() { var ( srClient sr.Client srErr error ) JustBeforeEach(func() { srClient, srErr = GetClient() }) DescribeTable("positive cases", func(fromGeoPointID, toGeoPointID int, expectedUID string, expectedCostGreaterThan float64) { Expect(srErr).NotTo(HaveOccurred()) Expect(srClient).NotTo(BeNil()) response, err := srClient.GetRoute(context.TODO(), &sr.GetRouteRequest{ FromGeoPointId: int64(fromGeoPointID), ToGeoPointId: int64(toGeoPointID), Quantity: 1, Volume: 1, Weight: 1, }) Expect(err).To(Succeed()) Expect(response).NotTo(BeNil()) Expect(response.RouteCost).NotTo(BeNil()) Expect(response.RouteCost.RouteUid).To(HaveSuffix(expectedUID)) Expect(response.RouteCost.GetCost()).To(BeNumerically(">", expectedCostGreaterThan)) }, Entry("from(geo=3)->to(geo=2)", 3, 2, "-3-2", float64(10)), ) |