@@ -14,22 +14,54 @@ type txPending struct {
1414 lastReleaseBegin txid // beginning txid of last matching releaseRange
1515}
1616
17+ // pidSet holds the set of starting pgids which have the same span size
18+ type pidSet map [pgid ]struct {}
19+
1720// freelist represents a list of all pages that are available for allocation.
1821// It also tracks pages that have been freed but are still in use by open transactions.
1922type freelist struct {
20- ids []pgid // all free and available free page ids.
21- allocs map [pgid ]txid // mapping of txid that allocated a pgid.
22- pending map [txid ]* txPending // mapping of soon-to-be free page ids by tx.
23- cache map [pgid ]bool // fast lookup of all free and pending page ids.
23+ freelistType FreelistType // freelist type
24+ ids []pgid // all free and available free page ids.
25+ allocs map [pgid ]txid // mapping of txid that allocated a pgid.
26+ pending map [txid ]* txPending // mapping of soon-to-be free page ids by tx.
27+ cache map [pgid ]bool // fast lookup of all free and pending page ids.
28+ freemaps map [uint64 ]pidSet // key is the size of continuous pages(span), value is a set which contains the starting pgids of same size
29+ forwardMap map [pgid ]uint64 // key is start pgid, value is its span size
30+ backwardMap map [pgid ]uint64 // key is end pgid, value is its span size
31+ allocate func (txid txid , n int ) pgid // the freelist allocate func
32+ free_count func () int // the function which gives you free page number
33+ mergeSpans func (ids pgids ) // the mergeSpan func
34+ getFreePageIDs func () []pgid // get free pgids func
35+ readIDs func (pgids []pgid ) // readIDs func reads list of pages and init the freelist
2436}
2537
2638// newFreelist returns an empty, initialized freelist.
27- func newFreelist () * freelist {
28- return & freelist {
29- allocs : make (map [pgid ]txid ),
30- pending : make (map [txid ]* txPending ),
31- cache : make (map [pgid ]bool ),
39+ func newFreelist (freelistType FreelistType ) * freelist {
40+ f := & freelist {
41+ freelistType : freelistType ,
42+ allocs : make (map [pgid ]txid ),
43+ pending : make (map [txid ]* txPending ),
44+ cache : make (map [pgid ]bool ),
45+ freemaps : make (map [uint64 ]pidSet ),
46+ forwardMap : make (map [pgid ]uint64 ),
47+ backwardMap : make (map [pgid ]uint64 ),
48+ }
49+
50+ if freelistType == FreelistMapType {
51+ f .allocate = f .hashmapAllocate
52+ f .free_count = f .hashmapFreeCount
53+ f .mergeSpans = f .hashmapMergeSpans
54+ f .getFreePageIDs = f .hashmapGetFreePageIDs
55+ f .readIDs = f .hashmapReadIDs
56+ } else {
57+ f .allocate = f .arrayAllocate
58+ f .free_count = f .arrayFreeCount
59+ f .mergeSpans = f .arrayMergeSpans
60+ f .getFreePageIDs = f .arrayGetFreePageIDs
61+ f .readIDs = f .arrayReadIDs
3262 }
63+
64+ return f
3365}
3466
3567// size returns the size of the page after serialization.
@@ -47,8 +79,8 @@ func (f *freelist) count() int {
4779 return f .free_count () + f .pending_count ()
4880}
4981
50- // free_count returns count of free pages
51- func (f * freelist ) free_count () int {
82+ // arrayFreeCount returns count of free pages(array version)
83+ func (f * freelist ) arrayFreeCount () int {
5284 return len (f .ids )
5385}
5486
@@ -72,9 +104,9 @@ func (f *freelist) copyall(dst []pgid) {
72104 mergepgids (dst , f .getFreePageIDs (), m )
73105}
74106
75- // allocate returns the starting page id of a contiguous list of pages of a given size.
107+ // arrayAllocate returns the starting page id of a contiguous list of pages of a given size.
76108// If a contiguous block cannot be found then 0 is returned.
77- func (f * freelist ) allocate (txid txid , n int ) pgid {
109+ func (f * freelist ) arrayAllocate (txid txid , n int ) pgid {
78110 if len (f .ids ) == 0 {
79111 return 0
80112 }
@@ -160,8 +192,7 @@ func (f *freelist) release(txid txid) {
160192 delete (f .pending , tid )
161193 }
162194 }
163- sort .Sort (m )
164- f .ids = pgids (f .ids ).merge (m )
195+ f .mergeSpans (m )
165196}
166197
167198// releaseRange moves pending pages allocated within an extent [begin,end] to the free list.
@@ -194,8 +225,7 @@ func (f *freelist) releaseRange(begin, end txid) {
194225 delete (f .pending , tid )
195226 }
196227 }
197- sort .Sort (m )
198- f .ids = pgids (f .ids ).merge (m )
228+ f .mergeSpans (m )
199229}
200230
201231// rollback removes the pages from a given pending tx.
@@ -222,8 +252,7 @@ func (f *freelist) rollback(txid txid) {
222252 }
223253 // Remove pages from pending list and mark as free if allocated by txid.
224254 delete (f .pending , txid )
225- sort .Sort (m )
226- f .ids = pgids (f .ids ).merge (m )
255+ f .mergeSpans (m )
227256}
228257
229258// freed returns whether a given page is in the free list.
@@ -249,24 +278,24 @@ func (f *freelist) read(p *page) {
249278 f .ids = nil
250279 } else {
251280 ids := ((* [maxAllocSize ]pgid )(unsafe .Pointer (& p .ptr )))[idx : idx + count ]
252- f .ids = make ([]pgid , len (ids ))
253- copy (f .ids , ids )
254281
282+ // copy the ids, so we don't modify on the freelist page directly
283+ idsCopy := make ([]pgid , count )
284+ copy (idsCopy , ids )
255285 // Make sure they're sorted.
256- sort .Sort (pgids (f .ids ))
257- }
286+ sort .Sort (pgids (idsCopy ))
258287
259- // Rebuild the page cache.
260- f . reindex ()
288+ f . readIDs ( idsCopy )
289+ }
261290}
262291
263- // readIDs initializes the freelist from a given list of ids.
264- func (f * freelist ) readIDs (ids []pgid ) {
292+ // arrayReadIDs initializes the freelist from a given list of ids.
293+ func (f * freelist ) arrayReadIDs (ids []pgid ) {
265294 f .ids = ids
266295 f .reindex ()
267296}
268297
269- func (f * freelist ) getFreePageIDs () []pgid {
298+ func (f * freelist ) arrayGetFreePageIDs () []pgid {
270299 return f .ids
271300}
272301
@@ -322,8 +351,9 @@ func (f *freelist) reload(p *page) {
322351
323352// reindex rebuilds the free cache based on available and pending free lists.
324353func (f * freelist ) reindex () {
325- f .cache = make (map [pgid ]bool , len (f .getFreePageIDs ()))
326- for _ , id := range f .getFreePageIDs () {
354+ ids := f .getFreePageIDs ()
355+ f .cache = make (map [pgid ]bool , len (ids ))
356+ for _ , id := range ids {
327357 f .cache [id ] = true
328358 }
329359 for _ , txp := range f .pending {
@@ -332,3 +362,9 @@ func (f *freelist) reindex() {
332362 }
333363 }
334364}
365+
366+ // arrayMergeSpans try to merge list of pages(represented by pgids) with existing spans but using array
367+ func (f * freelist ) arrayMergeSpans (ids pgids ) {
368+ sort .Sort (ids )
369+ f .ids = pgids (f .ids ).merge (ids )
370+ }
0 commit comments