@@ -21,6 +21,7 @@ type Manager interface {
2121 IterateNames (predicate func (name []byte ) bool )
2222 Hash (name []byte ) (* chainhash.Hash , int32 )
2323 Flush () error
24+ ClearCache ()
2425}
2526
2627type BaseManager struct {
@@ -30,31 +31,62 @@ type BaseManager struct {
3031 changes []change.Change
3132
3233 tempChanges map [string ][]change.Change
34+
35+ cache * Cache
3336}
3437
3538func NewBaseManager (repo Repo ) (* BaseManager , error ) {
3639
3740 nm := & BaseManager {
38- repo : repo ,
41+ repo : repo ,
42+ cache : NewCache (10000 ), // TODO: how many should we cache?
3943 }
4044
4145 return nm , nil
4246}
4347
48+ func (nm * BaseManager ) ClearCache () {
49+ nm .cache .clear ()
50+ }
51+
4452func (nm * BaseManager ) NodeAt (height int32 , name []byte ) (* Node , error ) {
4553
46- changes , err := nm .repo .LoadChanges (name )
47- if err != nil {
48- return nil , errors .Wrap (err , "in load changes" )
49- }
54+ n , changes , oldHeight := nm .cache .fetch (name , height )
55+ if n == nil {
56+ changes , err := nm .repo .LoadChanges (name )
57+ if err != nil {
58+ return nil , errors .Wrap (err , "in load changes" )
59+ }
5060
51- if nm .tempChanges != nil { // making an assumption that we only ever have tempChanges for a single block
52- changes = append (changes , nm .tempChanges [string (name )]... )
53- }
61+ if nm .tempChanges != nil { // making an assumption that we only ever have tempChanges for a single block
62+ changes = append (changes , nm .tempChanges [string (name )]... )
63+ }
5464
55- n , err := nm .newNodeFromChanges (changes , height )
56- if err != nil {
57- return nil , errors .Wrap (err , "in new node" )
65+ n , err = nm .newNodeFromChanges (changes , height )
66+ if err != nil {
67+ return nil , errors .Wrap (err , "in new node" )
68+ }
69+ // TODO: how can we tell what needs to be cached?
70+ if nm .tempChanges == nil && height == nm .height && n != nil && (len (changes ) > 4 || len (name ) < 12 ) {
71+ nm .cache .insert (name , n , height )
72+ }
73+ } else {
74+ if nm .tempChanges != nil { // making an assumption that we only ever have tempChanges for a single block
75+ changes = append (changes , nm .tempChanges [string (name )]... )
76+ n = n .Clone ()
77+ } else if height != nm .height {
78+ n = n .Clone ()
79+ }
80+ updated , err := nm .updateFromChanges (n , changes , height )
81+ if err != nil {
82+ return nil , errors .Wrap (err , "in update from changes" )
83+ }
84+ if ! updated {
85+ n .AdjustTo (oldHeight , height , name )
86+ }
87+ if nm .tempChanges == nil && height == nm .height {
88+ nm .cache .insert (name , n , height )
89+ }
5890 }
5991
6092 return n , nil
@@ -66,17 +98,13 @@ func (nm *BaseManager) node(name []byte) (*Node, error) {
6698 return nm .NodeAt (nm .height , name )
6799}
68100
69- // newNodeFromChanges returns a new Node constructed from the changes.
70- // The changes must preserve their order received.
71- func (nm * BaseManager ) newNodeFromChanges (changes []change.Change , height int32 ) (* Node , error ) {
101+ func (nm * BaseManager ) updateFromChanges (n * Node , changes []change.Change , height int32 ) (bool , error ) {
72102
73- if len (changes ) == 0 {
74- return nil , nil
103+ count := len (changes )
104+ if count == 0 {
105+ return false , nil
75106 }
76-
77- n := New ()
78107 previous := changes [0 ].Height
79- count := len (changes )
80108
81109 for i , chg := range changes {
82110 if chg .Height < previous {
@@ -95,15 +123,37 @@ func (nm *BaseManager) newNodeFromChanges(changes []change.Change, height int32)
95123 delay := nm .getDelayForName (n , chg )
96124 err := n .ApplyChange (chg , delay )
97125 if err != nil {
98- return nil , errors .Wrap (err , "in apply change" )
126+ return false , errors .Wrap (err , "in apply change" )
99127 }
100128 }
101129
102130 if count <= 0 {
103- return nil , nil
131+ // we applied no changes, which means we shouldn't exist if we had all the changes
132+ // or might mean nothing significant if we are applying a partial changeset
133+ return false , nil
104134 }
105135 lastChange := changes [count - 1 ]
106- return n .AdjustTo (lastChange .Height , height , lastChange .Name ), nil
136+ n .AdjustTo (lastChange .Height , height , lastChange .Name )
137+ return true , nil
138+ }
139+
140+ // newNodeFromChanges returns a new Node constructed from the changes.
141+ // The changes must preserve their order received.
142+ func (nm * BaseManager ) newNodeFromChanges (changes []change.Change , height int32 ) (* Node , error ) {
143+
144+ if len (changes ) == 0 {
145+ return nil , nil
146+ }
147+
148+ n := New ()
149+ updated , err := nm .updateFromChanges (n , changes , height )
150+ if err != nil {
151+ return nil , errors .Wrap (err , "in update from changes" )
152+ }
153+ if updated {
154+ return n , nil
155+ }
156+ return nil , nil
107157}
108158
109159func (nm * BaseManager ) AppendChange (chg change.Change ) {
@@ -220,6 +270,7 @@ func (nm *BaseManager) IncrementHeightTo(height int32, temporary bool) ([][]byte
220270 }
221271
222272 if ! temporary {
273+ nm .cache .addChanges (nm .changes , height )
223274 if err := nm .repo .AppendChanges (nm .changes ); err != nil { // destroys names
224275 return nil , errors .Wrap (err , "in append changes" )
225276 }
@@ -255,6 +306,8 @@ func (nm *BaseManager) DecrementHeightTo(affectedNames [][]byte, height int32) (
255306 return affectedNames , errors .Wrap (err , "in drop changes" )
256307 }
257308 }
309+
310+ nm .cache .drop (affectedNames )
258311 }
259312 nm .height = height
260313
0 commit comments