Fix memory leak in secondary, cleanup code.
This commit is contained in:
		
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							| @@ -4,6 +4,7 @@ go 1.22 | |||||||
|  |  | ||||||
| require ( | require ( | ||||||
| 	github.com/google/btree v1.1.2 | 	github.com/google/btree v1.1.2 | ||||||
|  | 	go.uber.org/goleak v1.3.0 | ||||||
| 	golang.org/x/net v0.15.0 | 	golang.org/x/net v0.15.0 | ||||||
| 	golang.org/x/sys v0.12.0 | 	golang.org/x/sys v0.12.0 | ||||||
| ) | ) | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								go.sum
									
									
									
									
									
								
							| @@ -1,6 +1,16 @@ | |||||||
|  | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||||
|  | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||||
| github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= | github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= | ||||||
| github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= | github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= | ||||||
|  | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||||
|  | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||||
|  | github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= | ||||||
|  | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | ||||||
|  | go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= | ||||||
|  | go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= | ||||||
| golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= | golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= | ||||||
| golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= | golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= | ||||||
| golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= | golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= | ||||||
| golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
|  | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||||||
|  | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||||
|   | |||||||
| @@ -12,7 +12,6 @@ const ( | |||||||
| 	pathStreamWAL = "stream-wal" | 	pathStreamWAL = "stream-wal" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // TODO: Remove this! |  | ||||||
| func (rep *Replicator) Handle(w http.ResponseWriter, r *http.Request) { | func (rep *Replicator) Handle(w http.ResponseWriter, r *http.Request) { | ||||||
| 	// We'll handle two types of requests: HTTP GET requests for JSON, or | 	// We'll handle two types of requests: HTTP GET requests for JSON, or | ||||||
| 	// streaming requets for state or wall. | 	// streaming requets for state or wall. | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								lib/rep/main_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								lib/rep/main_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | package rep | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  |  | ||||||
|  | 	"go.uber.org/goleak" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func TestMain(m *testing.M) { | ||||||
|  | 	goleak.VerifyTestMain(m) | ||||||
|  | } | ||||||
| @@ -36,8 +36,8 @@ type App struct { | |||||||
| 	// SendState: The primary may need to send storage state to a secondary node. | 	// SendState: The primary may need to send storage state to a secondary node. | ||||||
| 	SendState func(conn net.Conn) error | 	SendState func(conn net.Conn) error | ||||||
|  |  | ||||||
| 	// (1) RecvState: Secondary nodes may need to load state from the primary if the | 	// (1) RecvState: Secondary nodes may need to load state from the primary if | ||||||
| 	// WAL is too far behind. | 	// the WAL is too far behind. | ||||||
| 	RecvState func(conn net.Conn) error | 	RecvState func(conn net.Conn) error | ||||||
|  |  | ||||||
| 	// (2) InitStorage: Prepare application storage for possible calls to | 	// (2) InitStorage: Prepare application storage for possible calls to | ||||||
|   | |||||||
| @@ -56,6 +56,7 @@ func (h TestAppHarness) Run(t *testing.T) { | |||||||
| 				WALSegMaxAgeSec: 1, | 				WALSegMaxAgeSec: 1, | ||||||
| 				WALSegGCAgeSec:  1, | 				WALSegGCAgeSec:  1, | ||||||
| 			}) | 			}) | ||||||
|  | 			defer app2.Close() | ||||||
|  |  | ||||||
| 			val.MethodByName(method.Name).Call([]reflect.Value{ | 			val.MethodByName(method.Name).Call([]reflect.Value{ | ||||||
| 				reflect.ValueOf(t), | 				reflect.ValueOf(t), | ||||||
|   | |||||||
| @@ -1,7 +1,6 @@ | |||||||
| package mdb | package mdb | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"bytes" |  | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"hash/crc64" | 	"hash/crc64" | ||||||
| @@ -25,8 +24,6 @@ type Collection[T any] struct { | |||||||
| 	uniqueIndices []*Index[T] | 	uniqueIndices []*Index[T] | ||||||
|  |  | ||||||
| 	ByID *Index[T] | 	ByID *Index[T] | ||||||
|  |  | ||||||
| 	buf *bytes.Buffer |  | ||||||
| } | } | ||||||
|  |  | ||||||
| type CollectionConfig[T any] struct { | type CollectionConfig[T any] struct { | ||||||
| @@ -67,7 +64,6 @@ func NewCollection[T any](db *Database, name string, conf *CollectionConfig[T]) | |||||||
| 		validate:      conf.Validate, | 		validate:      conf.Validate, | ||||||
| 		indices:       []*Index[T]{}, | 		indices:       []*Index[T]{}, | ||||||
| 		uniqueIndices: []*Index[T]{}, | 		uniqueIndices: []*Index[T]{}, | ||||||
| 		buf:           &bytes.Buffer{}, |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	db.addCollection(c.collectionID, c, &collectionState[T]{ | 	db.addCollection(c.collectionID, c, &collectionState[T]{ | ||||||
|   | |||||||
| @@ -99,6 +99,7 @@ func (db *Database) repApply(rec wal.Record) (err error) { | |||||||
| 	} | 	} | ||||||
| 	tx.seqNum = rec.SeqNum | 	tx.seqNum = rec.SeqNum | ||||||
| 	tx.timestampMS = rec.TimestampMS | 	tx.timestampMS = rec.TimestampMS | ||||||
|  | 	tx.setReadOnly() | ||||||
| 	db.snapshot.Store(tx) | 	db.snapshot.Store(tx) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|   | |||||||
| @@ -72,7 +72,7 @@ func testRunner_testCase(t *testing.T, testCase DBTestCase) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// TODO: Why is this necessary? | 	// TODO: Why is this necessary? | ||||||
| 	time.Sleep(time.Second) | 	//time.Sleep(time.Second) | ||||||
| 	finalStep := testCase.Steps[len(testCase.Steps)-1] | 	finalStep := testCase.Steps[len(testCase.Steps)-1] | ||||||
|  |  | ||||||
| 	secondarySnapshot := db2.Snapshot() | 	secondarySnapshot := db2.Snapshot() | ||||||
|   | |||||||
| @@ -1,92 +0,0 @@ | |||||||
| package mdb |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| type txAggregator struct { |  | ||||||
| 	Stop     chan struct{} |  | ||||||
| 	Done     *sync.WaitGroup |  | ||||||
| 	ModChan  chan txMod |  | ||||||
| 	W        *cswal.Writer |  | ||||||
| 	Index    *pagefile.Index |  | ||||||
| 	Snapshot *atomic.Pointer[Snapshot] |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p txAggregator) Run() { |  | ||||||
| 	defer p.Done.Done() |  | ||||||
| 	defer p.W.Close() |  | ||||||
|  |  | ||||||
| 	var ( |  | ||||||
| 		tx       *Snapshot |  | ||||||
| 		mod      txMod |  | ||||||
| 		rec      cswal.Record |  | ||||||
| 		err      error |  | ||||||
| 		toNotify = make([]chan error, 0, 1024) |  | ||||||
| 	) |  | ||||||
|  |  | ||||||
| READ_FIRST: |  | ||||||
|  |  | ||||||
| 	toNotify = toNotify[:0] |  | ||||||
|  |  | ||||||
| 	select { |  | ||||||
| 	case mod = <-p.ModChan: |  | ||||||
| 		goto BEGIN |  | ||||||
| 	case <-p.Stop: |  | ||||||
| 		goto END |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| BEGIN: |  | ||||||
|  |  | ||||||
| 	tx = p.Snapshot.Load().begin() |  | ||||||
| 	goto APPLY_MOD |  | ||||||
|  |  | ||||||
| CLONE: |  | ||||||
|  |  | ||||||
| 	tx = tx.clone() |  | ||||||
| 	goto APPLY_MOD |  | ||||||
|  |  | ||||||
| APPLY_MOD: |  | ||||||
|  |  | ||||||
| 	if err = mod.Update(tx); err != nil { |  | ||||||
| 		mod.Resp <- err |  | ||||||
| 		goto ROLLBACK |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	toNotify = append(toNotify, mod.Resp) |  | ||||||
| 	goto NEXT |  | ||||||
|  |  | ||||||
| ROLLBACK: |  | ||||||
|  |  | ||||||
| 	if len(toNotify) == 0 { |  | ||||||
| 		goto READ_FIRST |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	tx = tx.rollback() |  | ||||||
| 	goto NEXT |  | ||||||
|  |  | ||||||
| NEXT: |  | ||||||
|  |  | ||||||
| 	select { |  | ||||||
| 	case mod = <-p.ModChan: |  | ||||||
| 		goto CLONE |  | ||||||
| 	default: |  | ||||||
| 		goto WRITE |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| WRITE: |  | ||||||
|  |  | ||||||
| 	rec, err = writeChangesToWAL(tx.changes, p.Index, p.W) |  | ||||||
| 	if err == nil { |  | ||||||
| 		tx.seqNum = rec.SeqNum |  | ||||||
| 		tx.updatedAt = rec.CreatedAt |  | ||||||
| 		tx.setReadOnly() |  | ||||||
| 		p.Snapshot.Store(tx) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for i := range toNotify { |  | ||||||
| 		toNotify[i] <- err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	goto READ_FIRST |  | ||||||
|  |  | ||||||
| END: |  | ||||||
| } |  | ||||||
| */ |  | ||||||
		Reference in New Issue
	
	Block a user