Skip to content
This repository has been archived by the owner on Jan 28, 2021. It is now read-only.

Commit

Permalink
sql: implement memory management system for caches
Browse files Browse the repository at this point in the history
This PR implements a memory management system, intended to have
control over the allocated memory for caches so that they can be
freed at any moment and we can avoid out of memory errors.

The main changes are the following:

- MemoryManager in the sql package, which is just the component that
  tracks all caches. Memory of all freeable caches can be freed
  using the Free method of this component. The only way to instantiate
  new caches is using the NewXXXCache methods.
- Rows, history and LRU cache implementations, accessed using the
  NewXXXCache methods of MemoryManager.
- Reporters, which is a component that reports the maximum amount
  of memory the program is allowed to use and the currently used memory.
  This interface is meant for making testing easier. There is a default
  ProcessMemory reporter that returns the memory used by the process and
  the maximum memory defined in the `MAX_MEMORY` environment variable.
- MemoryManager is passed down to every component through *sql.Context,
  which meant a little more boilerplate on the server SessionBuilder.
- GroupBy, Sort, Distinct and Join now use the provided APIs of memory
  and cache management for their in-memory computations.

Caveats:
- We need to think of a good default so that memory usage won't grow
  forever and crash eventually, which is the behaviour when MAX_MEMORY is 0.

Signed-off-by: Miguel Molina <miguel@erizocosmi.co>
  • Loading branch information
erizocosmico committed Aug 14, 2019
1 parent 875590d commit 4bc20fc
Show file tree
Hide file tree
Showing 71 changed files with 1,075 additions and 462 deletions.
24 changes: 0 additions & 24 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,11 @@ env:
addons:
apt:
packages:
- libonig-dev
- libmysqlclient-dev

matrix:
fast_finish: true

sudo: required

services:
- docker

install:
- go get ./...
- make dependencies

before_script:
- sudo service mysql stop

Expand All @@ -45,44 +35,34 @@ jobs:
python: '3.6'
before_install:
- eval "$(gimme 1.12.4)"
install:
- go get ./...
script:
- make TEST=python-pymysql integration

- language: php
php: '7.1'
before_install:
- eval "$(gimme 1.12.4)"
install:
- go get ./...
script:
- make TEST=php integration

- language: ruby
ruby: '2.3'
before_install:
- eval "$(gimme 1.12.4)"
install:
- go get ./...
script:
- make TEST=ruby integration

- language: java
jdk: openjdk8
before_install:
- eval "$(gimme 1.12.4)"
install:
- go get ./...
script:
- make TEST=jdbc-mariadb integration

- language: node_js
node_js: '7'
before_install:
- eval "$(gimme 1.12.4)"
install:
- go get ./...
script:
- make TEST=javascript integration

Expand All @@ -91,16 +71,12 @@ jobs:
dotnet: '2.1'
before_install:
- eval "$(gimme 1.12.4)"
install:
- go get ./...
script:
- make TEST=dotnet integration

- language: c
compiler: clang
before_install:
- eval "$(gimme 1.12.4)"
install:
- go get ./...
script:
- make TEST=c integration
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,7 @@ SET <variable name> = <value>
|:-----|:-----|:------------|
|`INMEMORY_JOINS`|environment|If set it will perform all joins in memory. Default is off.|
|`inmemory_joins`|session|If set it will perform all joins in memory. Default is off. This has precedence over `INMEMORY_JOINS`.|
|`MAX_MEMORY_JOIN`|environment|The maximum number of memory, in megabytes, that can be consumed by go-mysql-server before switching to multipass mode in joins. Default is the 20% of all available physical memory.|
|`max_memory_joins`|session|The maximum number of memory, in megabytes, that can be consumed by go-mysql-server before switching to multipass mode in joins. Default is the 20% of all available physical memory. This has precedence over `MAX_MEMORY_JOIN`.|
|`MAX_MEMORY`|environment|The maximum number of memory, in megabytes, that can be consumed by go-mysql-server. Any in-memory caches or computations will no longer try to use memory when the limit is reached. Note that this may cause certain queries to fail if there is not enough memory available, such as queries using DISTINCT, ORDER BY or GROUP BY with groupings.|
|`DEBUG_ANALYZER`|environment|If set, the analyzer will print debug messages. Default is off.|
|`PILOSA_INDEX_THREADS`|environment|Number of threads used in index creation. Default is the number of cores available in the machine.|
|`pilosa_index_threads`|environment|Number of threads used in index creation. Default is the number of cores available in the machine. This has precedence over `PILOSA_INDEX_THREADS`.|
Expand Down Expand Up @@ -176,14 +175,14 @@ func main() {
s.Start()
}

func createTestDatabase() *mem.Database {
func createTestDatabase() *memory.Database {
const (
dbName = "test"
tableName = "mytable"
)

db := mem.NewDatabase(dbName)
table := mem.NewTable(tableName, sql.Schema{
db := memory.NewDatabase(dbName)
table := memory.NewTable(tableName, sql.Schema{
{Name: "name", Type: sql.Text, Nullable: false, Source: tableName},
{Name: "email", Type: sql.Text, Nullable: false, Source: tableName},
{Name: "phone_numbers", Type: sql.JSON, Nullable: false, Source: tableName},
Expand Down
8 changes: 4 additions & 4 deletions _example/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (

sqle "github.com/src-d/go-mysql-server"
"github.com/src-d/go-mysql-server/auth"
"github.com/src-d/go-mysql-server/mem"
"github.com/src-d/go-mysql-server/memory"
"github.com/src-d/go-mysql-server/server"
"github.com/src-d/go-mysql-server/sql"
)
Expand Down Expand Up @@ -42,14 +42,14 @@ func main() {
s.Start()
}

func createTestDatabase() *mem.Database {
func createTestDatabase() *memory.Database {
const (
dbName = "mydb"
tableName = "mytable"
)

db := mem.NewDatabase(dbName)
table := mem.NewTable(tableName, sql.Schema{
db := memory.NewDatabase(dbName)
table := memory.NewTable(tableName, sql.Schema{
{Name: "name", Type: sql.Text, Nullable: false, Source: tableName},
{Name: "email", Type: sql.Text, Nullable: false, Source: tableName},
{Name: "phone_numbers", Type: sql.JSON, Nullable: false, Source: tableName},
Expand Down
3 changes: 2 additions & 1 deletion _integration/ruby/Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
vendor/bundle:
gem install bundler --version=1.16.5
bundler install --path vendor/bundle

dependencies: vendor/bundle

test: dependencies
bundler exec ruby mysql_test.rb

.PHONY: test
.PHONY: test
6 changes: 3 additions & 3 deletions auth/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/stretchr/testify/require"
sqle "github.com/src-d/go-mysql-server"
"github.com/src-d/go-mysql-server/auth"
"github.com/src-d/go-mysql-server/mem"
"github.com/src-d/go-mysql-server/memory"
"github.com/src-d/go-mysql-server/server"
"github.com/src-d/go-mysql-server/sql"
"github.com/src-d/go-mysql-server/sql/analyzer"
Expand All @@ -21,13 +21,13 @@ import (
const port = 3336

func authEngine(au auth.Auth) (string, *sqle.Engine, error) {
db := mem.NewDatabase("test")
db := memory.NewDatabase("test")
catalog := sql.NewCatalog()
catalog.AddDatabase(db)

tblName := "test"

table := mem.NewTable(tblName, sql.Schema{
table := memory.NewTable(tblName, sql.Schema{
{Name: "id", Type: sql.Text, Nullable: false, Source: tblName},
{Name: "name", Type: sql.Text, Nullable: false, Source: tblName},
})
Expand Down
10 changes: 5 additions & 5 deletions benchmark/tpc_h_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import (
"path/filepath"
"testing"

"github.com/src-d/go-mysql-server"
sqle "github.com/src-d/go-mysql-server"

"github.com/src-d/go-mysql-server/mem"
"github.com/src-d/go-mysql-server/memory"
"github.com/src-d/go-mysql-server/sql"
)

Expand Down Expand Up @@ -83,11 +83,11 @@ func executeQueries(b *testing.B, e *sqle.Engine) error {
}

func genDB(b *testing.B) (sql.Database, error) {
db := mem.NewDatabase("tpch")
db := memory.NewDatabase("tpch")

for _, m := range tpchTableMetadata {
b.Log("generating table", m.name)
t := mem.NewTable(m.name, m.schema)
t := memory.NewTable(m.name, m.schema)
if err := insertDataToTable(m.name, t, len(m.schema)); err != nil {
return nil, err
}
Expand All @@ -98,7 +98,7 @@ func genDB(b *testing.B) (sql.Database, error) {
return db, nil
}

func insertDataToTable(name string, t *mem.Table, columnCount int) error {
func insertDataToTable(name string, t *memory.Table, columnCount int) error {
f, err := os.Open(name + ".tbl")
if err != nil {
return err
Expand Down
Loading

0 comments on commit 4bc20fc

Please sign in to comment.