From f8608a5228750076aa15b1e3a67acd7994492053 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= <peterke@gmail.com>
Date: Fri, 21 Oct 2016 18:34:17 +0300
Subject: [PATCH] trie: while fast syncing, don't keep trie nodes in memory
 (#3186)

---
 trie/sync.go | 32 +++++++++++++-------------------
 1 file changed, 13 insertions(+), 19 deletions(-)

diff --git a/trie/sync.go b/trie/sync.go
index 30caf6980..58b8a1fb6 100644
--- a/trie/sync.go
+++ b/trie/sync.go
@@ -31,9 +31,9 @@ var ErrNotRequested = errors.New("not requested")
 
 // request represents a scheduled or already in-flight state retrieval request.
 type request struct {
-	hash   common.Hash // Hash of the node data content to retrieve
-	data   []byte      // Data content of the node, cached until all subtrees complete
-	object *node       // Target node to populate with retrieved data (hashnode originally)
+	hash common.Hash // Hash of the node data content to retrieve
+	data []byte      // Data content of the node, cached until all subtrees complete
+	raw  bool        // Whether this is a raw entry (code) or a trie node
 
 	parents []*request // Parent state nodes referencing this entry (notify all upon completion)
 	depth   int        // Depth level within the trie the node is located to prioritise DFS
@@ -86,9 +86,7 @@ func (s *TrieSync) AddSubTrie(root common.Hash, depth int, parent common.Hash, c
 		return
 	}
 	// Assemble the new sub-trie sync request
-	node := node(hashNode(root.Bytes()))
 	req := &request{
-		object:   &node,
 		hash:     root,
 		depth:    depth,
 		callback: callback,
@@ -120,6 +118,7 @@ func (s *TrieSync) AddRawEntry(hash common.Hash, depth int, parent common.Hash)
 	// Assemble the new sub-trie sync request
 	req := &request{
 		hash:  hash,
+		raw:   true,
 		depth: depth,
 	}
 	// If this sub-trie has a designated parent, link them together
@@ -152,7 +151,7 @@ func (s *TrieSync) Process(results []SyncResult) (int, error) {
 			return i, ErrNotRequested
 		}
 		// If the item is a raw entry request, commit directly
-		if request.object == nil {
+		if request.raw {
 			request.data = item.Data
 			s.commit(request, nil)
 			continue
@@ -162,11 +161,10 @@ func (s *TrieSync) Process(results []SyncResult) (int, error) {
 		if err != nil {
 			return i, err
 		}
-		*request.object = node
 		request.data = item.Data
 
 		// Create and schedule a request for all the children nodes
-		requests, err := s.children(request)
+		requests, err := s.children(request, node)
 		if err != nil {
 			return i, err
 		}
@@ -203,27 +201,25 @@ func (s *TrieSync) schedule(req *request) {
 
 // children retrieves all the missing children of a state trie entry for future
 // retrieval scheduling.
-func (s *TrieSync) children(req *request) ([]*request, error) {
+func (s *TrieSync) children(req *request, object node) ([]*request, error) {
 	// Gather all the children of the node, irrelevant whether known or not
 	type child struct {
-		node  *node
+		node  node
 		depth int
 	}
 	children := []child{}
 
-	switch node := (*req.object).(type) {
+	switch node := (object).(type) {
 	case *shortNode:
-		node = node.copy() // Prevents linking all downloaded nodes together.
 		children = []child{{
-			node:  &node.Val,
+			node:  node.Val,
 			depth: req.depth + len(node.Key),
 		}}
 	case *fullNode:
-		node = node.copy()
 		for i := 0; i < 17; i++ {
 			if node.Children[i] != nil {
 				children = append(children, child{
-					node:  &node.Children[i],
+					node:  node.Children[i],
 					depth: req.depth + 1,
 				})
 			}
@@ -236,23 +232,21 @@ func (s *TrieSync) children(req *request) ([]*request, error) {
 	for _, child := range children {
 		// Notify any external watcher of a new key/value node
 		if req.callback != nil {
-			if node, ok := (*child.node).(valueNode); ok {
+			if node, ok := (child.node).(valueNode); ok {
 				if err := req.callback(node, req.hash); err != nil {
 					return nil, err
 				}
 			}
 		}
 		// If the child references another node, resolve or schedule
-		if node, ok := (*child.node).(hashNode); ok {
+		if node, ok := (child.node).(hashNode); ok {
 			// Try to resolve the node from the local database
 			blob, _ := s.database.Get(node)
 			if local, err := decodeNode(node[:], blob, 0); local != nil && err == nil {
-				*child.node = local
 				continue
 			}
 			// Locally unknown node, schedule for retrieval
 			requests = append(requests, &request{
-				object:   child.node,
 				hash:     common.BytesToHash(node),
 				parents:  []*request{req},
 				depth:    child.depth,
-- 
GitLab