github.com/bhojpur/cache@v0.0.4/templates/dashboard.go (about) 1 package templates 2 3 // Copyright (c) 2018 Bhojpur Consulting Private Limited, India. All rights reserved. 4 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 12 // The above copyright notice and this permission notice shall be included in 13 // all copies or substantial portions of the Software. 14 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 // THE SOFTWARE. 22 23 // This file contains low-level Bhojpur Cache in-memory database storage engine 24 // structs that are used for reading from the database files. 25 26 import ( 27 "fmt" 28 "unsafe" 29 30 memcache "github.com/bhojpur/cache/pkg/memory" 31 ) 32 33 const pageHeaderSize = int(unsafe.Offsetof(((*page)(nil)).ptr)) 34 const branchPageElementSize = int(unsafe.Sizeof(branchPageElement{})) 35 const leafPageElementSize = int(unsafe.Sizeof(leafPageElement{})) 36 37 const maxAllocSize = 0xFFFFFFF 38 const maxNodesPerPage = 65535 39 40 const ( 41 branchPageFlag = 0x01 42 leafPageFlag = 0x02 43 metaPageFlag = 0x04 44 freelistPageFlag = 0x10 45 ) 46 47 const ( 48 bucketLeafFlag = 0x01 49 ) 50 51 type pgid uint64 52 type txid uint64 53 54 type page struct { 55 id pgid 56 flags uint16 57 count uint16 58 overflow uint32 59 ptr uintptr 60 } 61 62 type stats struct { 63 inuse int 64 alloc int 65 utilization float64 66 histogram map[int]int 67 } 68 69 // typ returns a human readable page type string used for debugging. 70 func (p *page) typ() string { 71 if (p.flags & branchPageFlag) != 0 { 72 return "branch" 73 } else if (p.flags & leafPageFlag) != 0 { 74 return "leaf" 75 } else if (p.flags & metaPageFlag) != 0 { 76 return "meta" 77 } else if (p.flags & freelistPageFlag) != 0 { 78 return "freelist" 79 } 80 return fmt.Sprintf("unknown<%02x>", p.flags) 81 } 82 83 func (p *page) meta() *meta { 84 return (*meta)(unsafe.Pointer(&p.ptr)) 85 } 86 87 func (p *page) leafPageElement(index uint16) *leafPageElement { 88 n := &((*[maxNodesPerPage]leafPageElement)(unsafe.Pointer(&p.ptr)))[index] 89 return n 90 } 91 92 func (p *page) branchPageElement(index uint16) *branchPageElement { 93 return &((*[maxNodesPerPage]branchPageElement)(unsafe.Pointer(&p.ptr)))[index] 94 } 95 96 // stats calcuates statistics for a page. 97 func (p *page) stats(pageSize int) stats { 98 var s stats 99 s.alloc = (int(p.overflow) + 1) * pageSize 100 s.inuse = p.inuse() 101 102 // Calculate space utilitization 103 if s.alloc > 0 { 104 s.utilization = float64(s.inuse) / float64(s.alloc) 105 } 106 107 return s 108 } 109 110 // inuse returns the number of bytes used in a given page. 111 func (p *page) inuse() int { 112 var n int 113 if (p.flags & leafPageFlag) != 0 { 114 n = pageHeaderSize 115 if p.count > 0 { 116 n += leafPageElementSize * int(p.count-1) 117 e := p.leafPageElement(p.count - 1) 118 n += int(e.pos + e.ksize + e.vsize) 119 } 120 121 } else if (p.flags & branchPageFlag) != 0 { 122 n = pageHeaderSize 123 if p.count > 0 { 124 n += branchPageElementSize * int(p.count-1) 125 e := p.branchPageElement(p.count - 1) 126 n += int(e.pos + e.ksize) 127 } 128 } 129 return n 130 } 131 132 // usage calculates a histogram of page sizes within nested pages. 133 func usage(tx *memcache.Tx, pgid pgid) map[int]int { 134 m := make(map[int]int) 135 forEachPage(tx, pgid, func(p *page) { 136 m[p.inuse()]++ 137 }) 138 return m 139 } 140 141 // branchPageElement represents a node on a branch page. 142 type branchPageElement struct { 143 pos uint32 144 ksize uint32 145 pgid pgid 146 } 147 148 // key returns a byte slice of the node key. 149 func (n *branchPageElement) key() []byte { 150 buf := (*[maxAllocSize]byte)(unsafe.Pointer(n)) 151 return buf[n.pos : n.pos+n.ksize] 152 } 153 154 // leafPageElement represents a node on a leaf page. 155 type leafPageElement struct { 156 flags uint32 157 pos uint32 158 ksize uint32 159 vsize uint32 160 } 161 162 // key returns a byte slice of the node key. 163 func (n *leafPageElement) key() []byte { 164 buf := (*[maxAllocSize]byte)(unsafe.Pointer(n)) 165 return buf[n.pos : n.pos+n.ksize] 166 } 167 168 // value returns a byte slice of the node value. 169 func (n *leafPageElement) value() []byte { 170 buf := (*[maxAllocSize]byte)(unsafe.Pointer(n)) 171 return buf[n.pos+n.ksize : n.pos+n.ksize+n.vsize] 172 } 173 174 type meta struct { 175 magic uint32 176 version uint32 177 pageSize uint32 178 flags uint32 179 root bucket 180 freelist pgid 181 pgid pgid 182 txid txid 183 checksum uint64 184 } 185 186 // bucket_ represents the memcache.Bucket type. 187 type bucket_ struct { 188 *bucket 189 } 190 191 type bucket struct { 192 root pgid 193 sequence uint64 194 } 195 196 type tx struct { 197 writable bool 198 managed bool 199 db uintptr 200 meta *meta 201 root bucket 202 // remaining fields not used. 203 } 204 205 // find locates a page using either a set of page indices or a direct page id. 206 // It returns a list of parent page numbers if the indices are used. 207 // It also returns the page reference. 208 func find(tx *memcache.Tx, directID int, indexes []int) (*page, []pgid, error) { 209 // If a direct ID is provided then just use it. 210 if directID != 0 { 211 return pageAt(tx, pgid(directID)), nil, nil 212 } 213 214 // Otherwise traverse the pages index. 215 ids, err := pgids(tx, indexes) 216 if err != nil { 217 return nil, nil, err 218 } 219 220 return pageAt(tx, ids[len(ids)-1]), ids, nil 221 } 222 223 // retrieves the page from a given transaction. 224 func pageAt(tx *memcache.Tx, id pgid) *page { 225 info := tx.DB().Info() 226 return (*page)(unsafe.Pointer(info.Data + uintptr(info.PageSize*int(id)))) 227 } 228 229 // forEachPage recursively iterates over all pages starting at a given page. 230 func forEachPage(tx *memcache.Tx, pgid pgid, fn func(*page)) { 231 p := pageAt(tx, pgid) 232 fn(p) 233 234 if (p.flags & leafPageFlag) != 0 { 235 for i := 0; i < int(p.count); i++ { 236 if e := p.leafPageElement(uint16(i)); (e.flags & bucketLeafFlag) != 0 { 237 if b := (*bucket)(unsafe.Pointer(&e.value()[0])); b.root != 0 { 238 forEachPage(tx, b.root, fn) 239 } 240 } 241 } 242 } else if (p.flags & branchPageFlag) != 0 { 243 for i := 0; i < int(p.count); i++ { 244 forEachPage(tx, p.branchPageElement(uint16(i)).pgid, fn) 245 } 246 } 247 }