├── .gitignore ├── templates ├── nav.ego ├── index.ego ├── error.ego ├── head.ego ├── templates.go ├── page.ego ├── bolt.go └── ego.go ├── Makefile ├── README.md ├── cmd └── boltd │ └── main.go ├── LICENSE └── handler.go /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | -------------------------------------------------------------------------------- /templates/nav.ego: -------------------------------------------------------------------------------- 1 | <%! func nav(w io.Writer, tx *bolt.Tx) error %> 2 | 3 | <%% import "path/filepath" %%> 4 | <%% import "github.com/boltdb/bolt" %%> 5 | 6 |

<%= filepath.Base(tx.DB().Path()) %>

7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | default: build 2 | 3 | build: templates 4 | mkdir -p bin 5 | go build -o bin/boltd ./cmd/boltd 6 | 7 | # go get github.com/benbjohnson/ego/... 8 | templates: 9 | @ego . 10 | 11 | .PHONY: templates 12 | -------------------------------------------------------------------------------- /templates/index.ego: -------------------------------------------------------------------------------- 1 | <%! func Index(w io.Writer) error %> 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | redirecting... 10 | 11 | -------------------------------------------------------------------------------- /templates/error.ego: -------------------------------------------------------------------------------- 1 | <%! func Error(w io.Writer, err error) error %> 2 | 3 | 4 | 5 | 6 | 7 | boltd 8 | 9 | 10 | 11 |
12 |
13 |

Error

14 |
15 | 16 | An error has occurred: <%= err %> 17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /templates/head.ego: -------------------------------------------------------------------------------- 1 | <%! func head(w io.Writer, tx *bolt.Tx) error %> 2 | 3 | <%% import "path/filepath" %%> 4 | <%% import "github.com/boltdb/bolt" %%> 5 | 6 | 7 | 8 | <%= filepath.Base(tx.DB().Path()) %> 9 | 10 | 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | boltd ![Project status](http://img.shields.io/status/alpha.png?color=yellow) 2 | ===== 3 | 4 | This server allows you introspect Bolt database in a web browser. The boltd tool 5 | gives you access to low-level page information and b-tree structures so you can 6 | better understand how Bolt is laying out your data. 7 | 8 | 9 | ## Getting Started 10 | 11 | To install boltd, use the `go get` command: 12 | 13 | ```sh 14 | $ go get github.com/boltdb/boltd/... 15 | ``` 16 | 17 | And then run the `boltd` binary by passing in the path to your database: 18 | 19 | ```sh 20 | $ boltd path/to/my.db 21 | ``` 22 | 23 | 24 | ## HTTP Integration 25 | 26 | You can also use boltd as an `http.Handler` in your own application. To use it, 27 | simply add the handler to your muxer: 28 | 29 | ```go 30 | http.Handle("/introspect", http.StripPrefix("/introspect", boltd.NewHandler(mydb))) 31 | ``` 32 | -------------------------------------------------------------------------------- /cmd/boltd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | 9 | "github.com/boltdb/bolt" 10 | "github.com/boltdb/boltd" 11 | ) 12 | 13 | func main() { 14 | log.SetFlags(0) 15 | var ( 16 | addr = flag.String("addr", ":9000", "bind address") 17 | ) 18 | flag.Parse() 19 | 20 | // Validate parameters. 21 | var path = flag.Arg(0) 22 | if path == "" { 23 | log.Fatal("path required") 24 | } 25 | 26 | // Open the database. 27 | db, err := bolt.Open(path, 0600, nil) 28 | if err != nil { 29 | log.Fatal(err) 30 | } 31 | 32 | // Enable logging. 33 | log.SetFlags(log.LstdFlags) 34 | 35 | // Setup the HTTP handlers. 36 | http.Handle("/", boltd.NewHandler(db)) 37 | 38 | // Start the HTTP server. 39 | go func() { log.Fatal(http.ListenAndServe(*addr, nil)) }() 40 | 41 | fmt.Printf("Listening on http://localhost%s\n", *addr) 42 | select {} 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Ben Johnson 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 all 13 | 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 THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /handler.go: -------------------------------------------------------------------------------- 1 | package boltd 2 | 3 | import ( 4 | "net/http" 5 | "strconv" 6 | "strings" 7 | 8 | "github.com/boltdb/bolt" 9 | "github.com/boltdb/boltd/templates" 10 | ) 11 | 12 | // NewHandler returns a new root HTTP handler. 13 | func NewHandler(db *bolt.DB) http.Handler { 14 | h := &handler{db} 15 | mux := http.NewServeMux() 16 | mux.HandleFunc("/", h.index) 17 | mux.HandleFunc("/page", h.page) 18 | return mux 19 | } 20 | 21 | type handler struct { 22 | db *bolt.DB 23 | } 24 | 25 | func (h *handler) index(w http.ResponseWriter, r *http.Request) { 26 | templates.Index(w) 27 | } 28 | 29 | func (h *handler) page(w http.ResponseWriter, r *http.Request) { 30 | err := h.db.View(func(tx *bolt.Tx) error { 31 | showUsage := (r.FormValue("usage") == "true") 32 | 33 | // Use the direct page id, if available. 34 | if r.FormValue("id") != "" { 35 | id, _ := strconv.Atoi(r.FormValue("id")) 36 | return templates.Page(w, r, tx, nil, id, showUsage) 37 | } 38 | 39 | // Otherwise extract the indexes and traverse. 40 | indexes, err := indexes(r) 41 | if err != nil { 42 | return err 43 | } 44 | 45 | return templates.Page(w, r, tx, indexes, 0, showUsage) 46 | }) 47 | if err != nil { 48 | templates.Error(w, err) 49 | } 50 | } 51 | 52 | // parses and returns all indexes from a request. 53 | func indexes(r *http.Request) ([]int, error) { 54 | var a = []int{0} 55 | if len(r.FormValue("index")) > 0 { 56 | for _, s := range strings.Split(r.FormValue("index"), ":") { 57 | i, err := strconv.Atoi(s) 58 | if err != nil { 59 | return nil, err 60 | } 61 | a = append(a, i) 62 | } 63 | } 64 | return a, nil 65 | } 66 | -------------------------------------------------------------------------------- /templates/templates.go: -------------------------------------------------------------------------------- 1 | package templates 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "sort" 7 | "strconv" 8 | "strings" 9 | "unicode" 10 | "unicode/utf8" 11 | "unsafe" 12 | 13 | "github.com/boltdb/bolt" 14 | ) 15 | 16 | // tostr converts a byte slice to a string if all characters are printable. 17 | // otherwise prints the hex representation. 18 | func tostr(b []byte) string { 19 | // Check if byte slice is utf-8 encoded. 20 | if !utf8.Valid(b) { 21 | return fmt.Sprintf("%x", b) 22 | } 23 | 24 | // Check every rune to see if it's printable. 25 | var s = string(b) 26 | for _, ch := range s { 27 | if !unicode.IsPrint(ch) { 28 | return fmt.Sprintf("%x", b) 29 | } 30 | } 31 | 32 | return s 33 | } 34 | 35 | func trunc(s string, n int) string { 36 | if len(s) > n { 37 | return s[:n] + "..." 38 | } 39 | return s 40 | } 41 | 42 | // traverses the page hierarchy by index and returns associated page ids. 43 | // returns an error if an index is out of range. 44 | func pgids(t *bolt.Tx, indexes []int) ([]pgid, error) { 45 | tx := (*tx)(unsafe.Pointer(t)) 46 | 47 | p := pageAt(t, tx.meta.root.root) 48 | ids := []pgid{tx.meta.root.root} 49 | for _, index := range indexes[1:] { 50 | if uint16(index) >= p.count { 51 | return nil, fmt.Errorf("out of range") 52 | } 53 | 54 | if (p.flags & branchPageFlag) != 0 { 55 | e := p.branchPageElement(uint16(index)) 56 | ids = append(ids, e.pgid) 57 | p = pageAt(t, e.pgid) 58 | 59 | } else if (p.flags & leafPageFlag) != 0 { 60 | // Only non-inline buckets on leaf pages can be traversed. 61 | e := p.leafPageElement(uint16(index)) 62 | if (e.flags & bucketLeafFlag) == 0 { 63 | return nil, fmt.Errorf("index not a bucket") 64 | } 65 | 66 | b := (*bucket)(unsafe.Pointer(&e.value()[0])) 67 | if (e.flags & bucketLeafFlag) == 0 { 68 | return nil, fmt.Errorf("index is an inline bucket") 69 | } 70 | 71 | ids = append(ids, b.root) 72 | p = pageAt(t, b.root) 73 | } else { 74 | return nil, fmt.Errorf("invalid page type: %s" + p.typ()) 75 | } 76 | } 77 | return ids, nil 78 | } 79 | 80 | func pagelink(indexes []int) string { 81 | var a []string 82 | for _, index := range indexes[1:] { 83 | a = append(a, strconv.Itoa(index)) 84 | } 85 | return "page?index=" + strings.Join(a, ":") 86 | } 87 | 88 | func subpagelink(indexes []int, index int) string { 89 | var tmp = make([]int, len(indexes)) 90 | copy(tmp, indexes) 91 | tmp = append(tmp, index) 92 | return pagelink(tmp) 93 | } 94 | 95 | // borrowed from: https://github.com/dustin/go-humanize 96 | func comma(v int) string { 97 | sign := "" 98 | if v < 0 { 99 | sign = "-" 100 | v = 0 - v 101 | } 102 | 103 | parts := []string{"", "", "", "", "", "", "", ""} 104 | j := len(parts) - 1 105 | 106 | for v > 999 { 107 | parts[j] = strconv.FormatInt(int64(v)%1000, 10) 108 | switch len(parts[j]) { 109 | case 2: 110 | parts[j] = "0" + parts[j] 111 | case 1: 112 | parts[j] = "00" + parts[j] 113 | } 114 | v = v / 1000 115 | j-- 116 | } 117 | parts[j] = strconv.Itoa(int(v)) 118 | return sign + strings.Join(parts[j:len(parts)], ",") 119 | } 120 | 121 | // maxHistogramN is the maximum number of buckets that can be used for the histogram. 122 | const maxHistogramN = 100 123 | 124 | // bucketize converts a map of observations into a histogram with a 125 | // smaller set of buckets using the square root choice method. 126 | func bucketize(m map[int]int) (mins, maxs, values []int) { 127 | if len(m) == 0 { 128 | return nil, nil, nil 129 | } else if len(m) == 1 { 130 | for k, v := range m { 131 | return []int{k}, []int{k}, []int{v} 132 | } 133 | } 134 | 135 | // Retrieve sorted set of keys. 136 | var keys []int 137 | var vsum int 138 | for k, v := range m { 139 | keys = append(keys, k) 140 | vsum += v 141 | } 142 | sort.Ints(keys) 143 | 144 | // Determine min/max for 5-95 percentile. 145 | var pmin, pmax, x int 146 | for _, k := range keys { 147 | v := m[k] 148 | 149 | // Grab the min when we cross the 5% threshold and 95% threshold. 150 | if (x*100)/vsum < 5 && ((x+v)*100)/vsum >= 5 { 151 | pmin = k 152 | } 153 | if (x*100)/vsum < 95 && ((x+v)*100)/vsum >= 95 { 154 | pmax = k 155 | } 156 | 157 | x += m[k] 158 | } 159 | min, max := keys[0], keys[len(keys)-1] 160 | 161 | // Calculate number of buckets and step size. 162 | n := int(math.Ceil(math.Sqrt(float64(vsum)))) 163 | if n > maxHistogramN { 164 | n = maxHistogramN 165 | } 166 | step := float64(pmax-pmin) / float64(n) 167 | 168 | // Bucket everything. 169 | for i := 0; i < n; i++ { 170 | var kmin, kmax int 171 | if i == 0 { 172 | kmin = min 173 | } else { 174 | kmin = int(math.Floor(float64(pmin) + step*float64(i))) 175 | } 176 | if i == n-1 { 177 | kmax = max 178 | } else { 179 | kmax = int(math.Floor(float64(pmin)+step*float64(i+1))) - 1 180 | } 181 | value := 0 182 | 183 | for k, v := range m { 184 | if (i == 0 || k >= kmin) && (i == (n-1) || k <= kmax) { 185 | value += v 186 | } 187 | } 188 | 189 | mins = append(mins, kmin) 190 | maxs = append(maxs, kmax) 191 | values = append(values, value) 192 | } 193 | 194 | return 195 | } 196 | -------------------------------------------------------------------------------- /templates/page.ego: -------------------------------------------------------------------------------- 1 | <%! func Page(w io.Writer, r *http.Request, tx *bolt.Tx, indexes []int, directID int, showUsage bool) error %> 2 | 3 | <%% import "net/http" %%> 4 | <%% import "strings" %%> 5 | <%% import "unsafe" %%> 6 | <%% import "github.com/boltdb/bolt" %%> 7 | 8 | <% 9 | p, ids, err := find(tx, directID, indexes) 10 | if err != nil { 11 | return err 12 | } 13 | 14 | // Generate page stats. 15 | pageSize := tx.DB().Info().PageSize 16 | stats := p.stats(pageSize) 17 | 18 | // Generate histogram of all nested page usage. 19 | var histogram map[int]int 20 | if showUsage { 21 | histogram = usage(tx, p.id) 22 | } 23 | %> 24 | 25 | 26 | 27 | <% head(w, tx) %> 28 | 29 | 30 | <% nav(w, tx) %> 31 | 32 |

33 | <% for i, id := range ids { %> 34 | <% if i > 0 { %>»<% } %> 35 | #<%= id %> 36 | <% } %> 37 |

38 | 39 |

Page Information

40 |

41 | ID: <%= comma(int(p.id)) %>
42 | Type: <%= fmt.Sprintf("%s (%x)", p.typ(), p.flags) %>
43 | Overflow: <%= p.overflow %>

44 | 45 | Alloc: <%= comma(stats.alloc) %>
46 | In Use: <%= comma(stats.inuse) %>
47 | Utilization: <%= fmt.Sprintf("%.2f%%", stats.utilization*100) %>
48 |

49 | 50 | <% if (p.flags & branchPageFlag) != 0 { %> 51 |

Branch Elements (<%= p.count %>)

52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | <% for i := uint16(0); i < p.count; i++ { %> 63 | <% e := p.branchPageElement(i) %> 64 | <% subpage := pageAt(tx, e.pgid) %> 65 | <% substats := subpage.stats(pageSize) %> 66 | 67 | 68 | 69 | 70 | 71 | 72 | <% } %> 73 | 74 |
KeyPage IDSize (k)%%Util
<%= trunc(tostr(e.key()), 40) %><%= e.pgid %><%= len(e.key()) %><%= fmt.Sprintf("%.2f%%", substats.utilization*100) %>
75 | 76 | <% } else if (p.flags & leafPageFlag) != 0 { %> 77 |

Leaf Elements (<%= p.count %>)

78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | <% for i := uint16(0); i < p.count; i++ { %> 89 | <% e := p.leafPageElement(i) %> 90 | <% if (e.flags & bucketLeafFlag) != 0 { %> 91 | <% b := ((*bucket)(unsafe.Pointer(&e.value()[0]))) %> 92 | <% 93 | util := "-" 94 | if b.root != 0 { 95 | substats := pageAt(tx, b.root).stats(pageSize) 96 | util = fmt.Sprintf("%.2f%%", substats.utilization*100) 97 | } 98 | %> 99 | 100 | 101 | 104 | 105 | 106 | 107 | <% } else { %> 108 | 109 | 110 | 111 | 112 | 113 | 114 | <% } %> 115 | <% } %> 116 | 117 |
KeyValueSize (k/v)%%Util
<%= trunc(tostr(e.key()), 40) %> 102 | <bucket(root=<% if b.root != 0 { %><% } %><%= b.root %><% if b.root != 0 { %><% } %>; seq=<%= b.sequence %>)> 103 | <%= len(e.key()) %> / <%= len(e.value()) %><%= util %>
<%= trunc(tostr(e.key()), 40) %><%= trunc(tostr(e.value()), 40) %><%= len(e.key()) %> / <%= len(e.value()) %> 
118 | <% } %> 119 | 120 | <% if showUsage { %> 121 | <% 122 | mins, maxs, values := bucketize(histogram) 123 | vmax, maxlen := 0, 20 124 | for _, v := range values { 125 | if v > vmax { 126 | vmax = v 127 | } 128 | } 129 | %> 130 | 131 |

Page Usage Histogram

132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | <% for i := 0; i < len(values); i++ { %> 142 | 143 | 146 | 147 | <% } %> 148 | 149 |
Usage (bytes)Count 
<%= mins[i] %> - <%= maxs[i] %> 144 | <%= values[i] %> 145 | <%= strings.Repeat("█", int((float64(values[i])/float64(vmax))*float64(maxlen))) %>
150 | <% } else { %> 151 | <% 152 | u, q := r.URL, r.URL.Query() 153 | q.Set("usage", "true") 154 | u.RawQuery = q.Encode() 155 | %> 156 | 157 |

Show Page Usage

158 | <% } %> 159 | 160 |

161 |
162 | Go to page: 163 | 164 |
165 | 166 | 167 | -------------------------------------------------------------------------------- /templates/bolt.go: -------------------------------------------------------------------------------- 1 | package templates 2 | 3 | // This file contains low-level bolt structs that are used for reading from 4 | // bolt database files. 5 | 6 | import ( 7 | "fmt" 8 | "unsafe" 9 | 10 | "github.com/boltdb/bolt" 11 | ) 12 | 13 | const pageHeaderSize = int(unsafe.Offsetof(((*page)(nil)).ptr)) 14 | const branchPageElementSize = int(unsafe.Sizeof(branchPageElement{})) 15 | const leafPageElementSize = int(unsafe.Sizeof(leafPageElement{})) 16 | 17 | const maxAllocSize = 0xFFFFFFF 18 | const maxNodesPerPage = 65535 19 | 20 | const ( 21 | branchPageFlag = 0x01 22 | leafPageFlag = 0x02 23 | metaPageFlag = 0x04 24 | freelistPageFlag = 0x10 25 | ) 26 | 27 | const ( 28 | bucketLeafFlag = 0x01 29 | ) 30 | 31 | type pgid uint64 32 | type txid uint64 33 | 34 | type page struct { 35 | id pgid 36 | flags uint16 37 | count uint16 38 | overflow uint32 39 | ptr uintptr 40 | } 41 | 42 | type stats struct { 43 | inuse int 44 | alloc int 45 | utilization float64 46 | histogram map[int]int 47 | } 48 | 49 | // typ returns a human readable page type string used for debugging. 50 | func (p *page) typ() string { 51 | if (p.flags & branchPageFlag) != 0 { 52 | return "branch" 53 | } else if (p.flags & leafPageFlag) != 0 { 54 | return "leaf" 55 | } else if (p.flags & metaPageFlag) != 0 { 56 | return "meta" 57 | } else if (p.flags & freelistPageFlag) != 0 { 58 | return "freelist" 59 | } 60 | return fmt.Sprintf("unknown<%02x>", p.flags) 61 | } 62 | 63 | func (p *page) meta() *meta { 64 | return (*meta)(unsafe.Pointer(&p.ptr)) 65 | } 66 | 67 | func (p *page) leafPageElement(index uint16) *leafPageElement { 68 | n := &((*[maxNodesPerPage]leafPageElement)(unsafe.Pointer(&p.ptr)))[index] 69 | return n 70 | } 71 | 72 | func (p *page) branchPageElement(index uint16) *branchPageElement { 73 | return &((*[maxNodesPerPage]branchPageElement)(unsafe.Pointer(&p.ptr)))[index] 74 | } 75 | 76 | // stats calcuates statistics for a page. 77 | func (p *page) stats(pageSize int) stats { 78 | var s stats 79 | s.alloc = (int(p.overflow) + 1) * pageSize 80 | s.inuse = p.inuse() 81 | 82 | // Calculate space utilitization 83 | if s.alloc > 0 { 84 | s.utilization = float64(s.inuse) / float64(s.alloc) 85 | } 86 | 87 | return s 88 | } 89 | 90 | // inuse returns the number of bytes used in a given page. 91 | func (p *page) inuse() int { 92 | var n int 93 | if (p.flags & leafPageFlag) != 0 { 94 | n = pageHeaderSize 95 | if p.count > 0 { 96 | n += leafPageElementSize * int(p.count-1) 97 | e := p.leafPageElement(p.count - 1) 98 | n += int(e.pos + e.ksize + e.vsize) 99 | } 100 | 101 | } else if (p.flags & branchPageFlag) != 0 { 102 | n = pageHeaderSize 103 | if p.count > 0 { 104 | n += branchPageElementSize * int(p.count-1) 105 | e := p.branchPageElement(p.count - 1) 106 | n += int(e.pos + e.ksize) 107 | } 108 | } 109 | return n 110 | } 111 | 112 | // usage calculates a histogram of page sizes within nested pages. 113 | func usage(tx *bolt.Tx, pgid pgid) map[int]int { 114 | m := make(map[int]int) 115 | forEachPage(tx, pgid, func(p *page) { 116 | m[p.inuse()]++ 117 | }) 118 | return m 119 | } 120 | 121 | // branchPageElement represents a node on a branch page. 122 | type branchPageElement struct { 123 | pos uint32 124 | ksize uint32 125 | pgid pgid 126 | } 127 | 128 | // key returns a byte slice of the node key. 129 | func (n *branchPageElement) key() []byte { 130 | buf := (*[maxAllocSize]byte)(unsafe.Pointer(n)) 131 | return buf[n.pos : n.pos+n.ksize] 132 | } 133 | 134 | // leafPageElement represents a node on a leaf page. 135 | type leafPageElement struct { 136 | flags uint32 137 | pos uint32 138 | ksize uint32 139 | vsize uint32 140 | } 141 | 142 | // key returns a byte slice of the node key. 143 | func (n *leafPageElement) key() []byte { 144 | buf := (*[maxAllocSize]byte)(unsafe.Pointer(n)) 145 | return buf[n.pos : n.pos+n.ksize] 146 | } 147 | 148 | // value returns a byte slice of the node value. 149 | func (n *leafPageElement) value() []byte { 150 | buf := (*[maxAllocSize]byte)(unsafe.Pointer(n)) 151 | return buf[n.pos+n.ksize : n.pos+n.ksize+n.vsize] 152 | } 153 | 154 | type meta struct { 155 | magic uint32 156 | version uint32 157 | pageSize uint32 158 | flags uint32 159 | root bucket 160 | freelist pgid 161 | pgid pgid 162 | txid txid 163 | checksum uint64 164 | } 165 | 166 | // bucket_ represents the bolt.Bucket type. 167 | type bucket_ struct { 168 | *bucket 169 | } 170 | 171 | type bucket struct { 172 | root pgid 173 | sequence uint64 174 | } 175 | 176 | type tx struct { 177 | writable bool 178 | managed bool 179 | db uintptr 180 | meta *meta 181 | root bucket 182 | // remaining fields not used. 183 | } 184 | 185 | // find locates a page using either a set of page indices or a direct page id. 186 | // It returns a list of parent page numbers if the indices are used. 187 | // It also returns the page reference. 188 | func find(tx *bolt.Tx, directID int, indexes []int) (*page, []pgid, error) { 189 | // If a direct ID is provided then just use it. 190 | if directID != 0 { 191 | return pageAt(tx, pgid(directID)), nil, nil 192 | } 193 | 194 | // Otherwise traverse the pages index. 195 | ids, err := pgids(tx, indexes) 196 | if err != nil { 197 | return nil, nil, err 198 | } 199 | 200 | return pageAt(tx, ids[len(ids)-1]), ids, nil 201 | } 202 | 203 | // retrieves the page from a given transaction. 204 | func pageAt(tx *bolt.Tx, id pgid) *page { 205 | info := tx.DB().Info() 206 | return (*page)(unsafe.Pointer(info.Data + uintptr(info.PageSize*int(id)))) 207 | } 208 | 209 | // forEachPage recursively iterates over all pages starting at a given page. 210 | func forEachPage(tx *bolt.Tx, pgid pgid, fn func(*page)) { 211 | p := pageAt(tx, pgid) 212 | fn(p) 213 | 214 | if (p.flags & leafPageFlag) != 0 { 215 | for i := 0; i < int(p.count); i++ { 216 | if e := p.leafPageElement(uint16(i)); (e.flags & bucketLeafFlag) != 0 { 217 | if b := (*bucket)(unsafe.Pointer(&e.value()[0])); b.root != 0 { 218 | forEachPage(tx, b.root, fn) 219 | } 220 | } 221 | } 222 | } else if (p.flags & branchPageFlag) != 0 { 223 | for i := 0; i < int(p.count); i++ { 224 | forEachPage(tx, p.branchPageElement(uint16(i)).pgid, fn) 225 | } 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /templates/ego.go: -------------------------------------------------------------------------------- 1 | package templates 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net/http" 7 | "path/filepath" 8 | "strings" 9 | "unsafe" 10 | 11 | "github.com/boltdb/bolt" 12 | ) 13 | 14 | //line error.ego:1 15 | func Error(w io.Writer, err error) error { 16 | //line error.ego:2 17 | if _, err := fmt.Fprintf(w, "\n\n"); err != nil { 18 | return err 19 | } 20 | //line error.ego:3 21 | if _, err := fmt.Fprintf(w, "\n"); err != nil { 22 | return err 23 | } 24 | //line error.ego:4 25 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 26 | return err 27 | } 28 | //line error.ego:5 29 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 30 | return err 31 | } 32 | //line error.ego:6 33 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 34 | return err 35 | } 36 | //line error.ego:7 37 | if _, err := fmt.Fprintf(w, "boltd"); err != nil { 38 | return err 39 | } 40 | //line error.ego:7 41 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 42 | return err 43 | } 44 | //line error.ego:8 45 | if _, err := fmt.Fprintf(w, "\n\n "); err != nil { 46 | return err 47 | } 48 | //line error.ego:10 49 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 50 | return err 51 | } 52 | //line error.ego:11 53 | if _, err := fmt.Fprintf(w, "
\n "); err != nil { 54 | return err 55 | } 56 | //line error.ego:12 57 | if _, err := fmt.Fprintf(w, "
\n "); err != nil { 58 | return err 59 | } 60 | //line error.ego:13 61 | if _, err := fmt.Fprintf(w, "

Error"); err != nil { 62 | return err 63 | } 64 | //line error.ego:13 65 | if _, err := fmt.Fprintf(w, "

\n "); err != nil { 66 | return err 67 | } 68 | //line error.ego:14 69 | if _, err := fmt.Fprintf(w, "
\n\n An error has occurred: "); err != nil { 70 | return err 71 | } 72 | //line error.ego:16 73 | if _, err := fmt.Fprintf(w, "%v", err); err != nil { 74 | return err 75 | } 76 | //line error.ego:17 77 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 78 | return err 79 | } 80 | //line error.ego:17 81 | if _, err := fmt.Fprintf(w, "
"); err != nil { 82 | return err 83 | } 84 | //line error.ego:17 85 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 86 | return err 87 | } 88 | //line error.ego:18 89 | if _, err := fmt.Fprintf(w, "\n"); err != nil { 90 | return err 91 | } 92 | //line error.ego:19 93 | if _, err := fmt.Fprintf(w, "\n"); err != nil { 94 | return err 95 | } 96 | return nil 97 | } 98 | 99 | //line head.ego:1 100 | func head(w io.Writer, tx *bolt.Tx) error { 101 | //line head.ego:2 102 | if _, err := fmt.Fprintf(w, "\n\n"); err != nil { 103 | return err 104 | } 105 | //line head.ego:4 106 | if _, err := fmt.Fprintf(w, "\n"); err != nil { 107 | return err 108 | } 109 | //line head.ego:5 110 | if _, err := fmt.Fprintf(w, "\n\n"); err != nil { 111 | return err 112 | } 113 | //line head.ego:6 114 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 115 | return err 116 | } 117 | //line head.ego:7 118 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 119 | return err 120 | } 121 | //line head.ego:8 122 | if _, err := fmt.Fprintf(w, ""); err != nil { 123 | return err 124 | } 125 | //line head.ego:8 126 | if _, err := fmt.Fprintf(w, "%v", filepath.Base(tx.DB().Path())); err != nil { 127 | return err 128 | } 129 | //line head.ego:8 130 | if _, err := fmt.Fprintf(w, "\n\n "); err != nil { 131 | return err 132 | } 133 | //line head.ego:10 134 | if _, err := fmt.Fprintf(w, "\n"); err != nil { 139 | return err 140 | } 141 | //line head.ego:24 142 | if _, err := fmt.Fprintf(w, "\n"); err != nil { 143 | return err 144 | } 145 | return nil 146 | } 147 | 148 | //line index.ego:1 149 | func Index(w io.Writer) error { 150 | //line index.ego:2 151 | if _, err := fmt.Fprintf(w, "\n\n"); err != nil { 152 | return err 153 | } 154 | //line index.ego:3 155 | if _, err := fmt.Fprintf(w, "\n"); err != nil { 156 | return err 157 | } 158 | //line index.ego:4 159 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 160 | return err 161 | } 162 | //line index.ego:5 163 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 164 | return err 165 | } 166 | //line index.ego:6 167 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 168 | return err 169 | } 170 | //line index.ego:7 171 | if _, err := fmt.Fprintf(w, "\n\n "); err != nil { 172 | return err 173 | } 174 | //line index.ego:9 175 | if _, err := fmt.Fprintf(w, "redirecting..."); err != nil { 176 | return err 177 | } 178 | //line index.ego:9 179 | if _, err := fmt.Fprintf(w, "\n"); err != nil { 180 | return err 181 | } 182 | //line index.ego:10 183 | if _, err := fmt.Fprintf(w, "\n"); err != nil { 184 | return err 185 | } 186 | return nil 187 | } 188 | 189 | //line nav.ego:1 190 | func nav(w io.Writer, tx *bolt.Tx) error { 191 | //line nav.ego:2 192 | if _, err := fmt.Fprintf(w, "\n\n"); err != nil { 193 | return err 194 | } 195 | //line nav.ego:4 196 | if _, err := fmt.Fprintf(w, "\n"); err != nil { 197 | return err 198 | } 199 | //line nav.ego:5 200 | if _, err := fmt.Fprintf(w, "\n\n"); err != nil { 201 | return err 202 | } 203 | //line nav.ego:6 204 | if _, err := fmt.Fprintf(w, "

"); err != nil { 205 | return err 206 | } 207 | //line nav.ego:6 208 | if _, err := fmt.Fprintf(w, "%v", filepath.Base(tx.DB().Path())); err != nil { 209 | return err 210 | } 211 | //line nav.ego:6 212 | if _, err := fmt.Fprintf(w, "

\n"); err != nil { 213 | return err 214 | } 215 | return nil 216 | } 217 | 218 | //line page.ego:1 219 | func Page(w io.Writer, r *http.Request, tx *bolt.Tx, indexes []int, directID int, showUsage bool) error { 220 | //line page.ego:2 221 | if _, err := fmt.Fprintf(w, "\n\n"); err != nil { 222 | return err 223 | } 224 | //line page.ego:4 225 | if _, err := fmt.Fprintf(w, "\n"); err != nil { 226 | return err 227 | } 228 | //line page.ego:5 229 | if _, err := fmt.Fprintf(w, "\n"); err != nil { 230 | return err 231 | } 232 | //line page.ego:6 233 | if _, err := fmt.Fprintf(w, "\n"); err != nil { 234 | return err 235 | } 236 | //line page.ego:7 237 | if _, err := fmt.Fprintf(w, "\n\n"); err != nil { 238 | return err 239 | } 240 | //line page.ego:9 241 | p, ids, err := find(tx, directID, indexes) 242 | if err != nil { 243 | return err 244 | } 245 | 246 | // Generate page stats. 247 | pageSize := tx.DB().Info().PageSize 248 | stats := p.stats(pageSize) 249 | 250 | // Generate histogram of all nested page usage. 251 | var histogram map[int]int 252 | if showUsage { 253 | histogram = usage(tx, p.id) 254 | } 255 | 256 | //line page.ego:25 257 | if _, err := fmt.Fprintf(w, "\n\n"); err != nil { 258 | return err 259 | } 260 | //line page.ego:26 261 | if _, err := fmt.Fprintf(w, "\n"); err != nil { 262 | return err 263 | } 264 | //line page.ego:27 265 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 266 | return err 267 | } 268 | //line page.ego:28 269 | head(w, tx) 270 | //line page.ego:29 271 | if _, err := fmt.Fprintf(w, "\n\n "); err != nil { 272 | return err 273 | } 274 | //line page.ego:30 275 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 276 | return err 277 | } 278 | //line page.ego:31 279 | nav(w, tx) 280 | //line page.ego:32 281 | if _, err := fmt.Fprintf(w, "\n\n "); err != nil { 282 | return err 283 | } 284 | //line page.ego:33 285 | if _, err := fmt.Fprintf(w, "

\n "); err != nil { 286 | return err 287 | } 288 | //line page.ego:34 289 | for i, id := range ids { 290 | //line page.ego:35 291 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 292 | return err 293 | } 294 | //line page.ego:35 295 | if i > 0 { 296 | //line page.ego:35 297 | if _, err := fmt.Fprintf(w, "»"); err != nil { 298 | return err 299 | } 300 | //line page.ego:35 301 | } 302 | //line page.ego:36 303 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 304 | return err 305 | } 306 | //line page.ego:36 307 | if _, err := fmt.Fprintf(w, "#"); err != nil { 316 | return err 317 | } 318 | //line page.ego:36 319 | if _, err := fmt.Fprintf(w, "%v", id); err != nil { 320 | return err 321 | } 322 | //line page.ego:36 323 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 324 | return err 325 | } 326 | //line page.ego:37 327 | } 328 | //line page.ego:38 329 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 330 | return err 331 | } 332 | //line page.ego:38 333 | if _, err := fmt.Fprintf(w, "

\n\n "); err != nil { 334 | return err 335 | } 336 | //line page.ego:40 337 | if _, err := fmt.Fprintf(w, "

Page Information"); err != nil { 338 | return err 339 | } 340 | //line page.ego:40 341 | if _, err := fmt.Fprintf(w, "

\n "); err != nil { 342 | return err 343 | } 344 | //line page.ego:41 345 | if _, err := fmt.Fprintf(w, "

\n "); err != nil { 346 | return err 347 | } 348 | //line page.ego:42 349 | if _, err := fmt.Fprintf(w, "ID:"); err != nil { 350 | return err 351 | } 352 | //line page.ego:42 353 | if _, err := fmt.Fprintf(w, " "); err != nil { 354 | return err 355 | } 356 | //line page.ego:42 357 | if _, err := fmt.Fprintf(w, "%v", comma(int(p.id))); err != nil { 358 | return err 359 | } 360 | //line page.ego:42 361 | if _, err := fmt.Fprintf(w, "
\n "); err != nil { 362 | return err 363 | } 364 | //line page.ego:43 365 | if _, err := fmt.Fprintf(w, "Type:"); err != nil { 366 | return err 367 | } 368 | //line page.ego:43 369 | if _, err := fmt.Fprintf(w, " "); err != nil { 370 | return err 371 | } 372 | //line page.ego:43 373 | if _, err := fmt.Fprintf(w, "%v", fmt.Sprintf("%s (%x)", p.typ(), p.flags)); err != nil { 374 | return err 375 | } 376 | //line page.ego:43 377 | if _, err := fmt.Fprintf(w, "
\n "); err != nil { 378 | return err 379 | } 380 | //line page.ego:44 381 | if _, err := fmt.Fprintf(w, "Overflow:"); err != nil { 382 | return err 383 | } 384 | //line page.ego:44 385 | if _, err := fmt.Fprintf(w, " "); err != nil { 386 | return err 387 | } 388 | //line page.ego:44 389 | if _, err := fmt.Fprintf(w, "%v", p.overflow); err != nil { 390 | return err 391 | } 392 | //line page.ego:44 393 | if _, err := fmt.Fprintf(w, "
"); err != nil { 394 | return err 395 | } 396 | //line page.ego:44 397 | if _, err := fmt.Fprintf(w, "
\n\n "); err != nil { 398 | return err 399 | } 400 | //line page.ego:46 401 | if _, err := fmt.Fprintf(w, "Alloc:"); err != nil { 402 | return err 403 | } 404 | //line page.ego:46 405 | if _, err := fmt.Fprintf(w, " "); err != nil { 406 | return err 407 | } 408 | //line page.ego:46 409 | if _, err := fmt.Fprintf(w, "%v", comma(stats.alloc)); err != nil { 410 | return err 411 | } 412 | //line page.ego:46 413 | if _, err := fmt.Fprintf(w, "
\n "); err != nil { 414 | return err 415 | } 416 | //line page.ego:47 417 | if _, err := fmt.Fprintf(w, "In Use:"); err != nil { 418 | return err 419 | } 420 | //line page.ego:47 421 | if _, err := fmt.Fprintf(w, " "); err != nil { 422 | return err 423 | } 424 | //line page.ego:47 425 | if _, err := fmt.Fprintf(w, "%v", comma(stats.inuse)); err != nil { 426 | return err 427 | } 428 | //line page.ego:47 429 | if _, err := fmt.Fprintf(w, "
\n "); err != nil { 430 | return err 431 | } 432 | //line page.ego:48 433 | if _, err := fmt.Fprintf(w, "Utilization:"); err != nil { 434 | return err 435 | } 436 | //line page.ego:48 437 | if _, err := fmt.Fprintf(w, " "); err != nil { 438 | return err 439 | } 440 | //line page.ego:48 441 | if _, err := fmt.Fprintf(w, "%v", fmt.Sprintf("%.2f%%", stats.utilization*100)); err != nil { 442 | return err 443 | } 444 | //line page.ego:48 445 | if _, err := fmt.Fprintf(w, "
\n "); err != nil { 446 | return err 447 | } 448 | //line page.ego:49 449 | if _, err := fmt.Fprintf(w, "

\n\n "); err != nil { 450 | return err 451 | } 452 | //line page.ego:51 453 | if (p.flags & branchPageFlag) != 0 { 454 | //line page.ego:52 455 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 456 | return err 457 | } 458 | //line page.ego:52 459 | if _, err := fmt.Fprintf(w, "

Branch Elements ("); err != nil { 460 | return err 461 | } 462 | //line page.ego:52 463 | if _, err := fmt.Fprintf(w, "%v", p.count); err != nil { 464 | return err 465 | } 466 | //line page.ego:52 467 | if _, err := fmt.Fprintf(w, ")"); err != nil { 468 | return err 469 | } 470 | //line page.ego:52 471 | if _, err := fmt.Fprintf(w, "

\n "); err != nil { 472 | return err 473 | } 474 | //line page.ego:53 475 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 476 | return err 477 | } 478 | //line page.ego:54 479 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 480 | return err 481 | } 482 | //line page.ego:55 483 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 484 | return err 485 | } 486 | //line page.ego:56 487 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 492 | return err 493 | } 494 | //line page.ego:57 495 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 500 | return err 501 | } 502 | //line page.ego:58 503 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 508 | return err 509 | } 510 | //line page.ego:59 511 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 516 | return err 517 | } 518 | //line page.ego:60 519 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 520 | return err 521 | } 522 | //line page.ego:61 523 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 524 | return err 525 | } 526 | //line page.ego:62 527 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 528 | return err 529 | } 530 | //line page.ego:63 531 | for i := uint16(0); i < p.count; i++ { 532 | //line page.ego:64 533 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 534 | return err 535 | } 536 | //line page.ego:64 537 | e := p.branchPageElement(i) 538 | //line page.ego:65 539 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 540 | return err 541 | } 542 | //line page.ego:65 543 | subpage := pageAt(tx, e.pgid) 544 | //line page.ego:66 545 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 546 | return err 547 | } 548 | //line page.ego:66 549 | substats := subpage.stats(pageSize) 550 | //line page.ego:67 551 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 552 | return err 553 | } 554 | //line page.ego:67 555 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 556 | return err 557 | } 558 | //line page.ego:68 559 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 568 | return err 569 | } 570 | //line page.ego:69 571 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 596 | return err 597 | } 598 | //line page.ego:70 599 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 608 | return err 609 | } 610 | //line page.ego:71 611 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 620 | return err 621 | } 622 | //line page.ego:72 623 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 624 | return err 625 | } 626 | //line page.ego:73 627 | } 628 | //line page.ego:74 629 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 630 | return err 631 | } 632 | //line page.ego:74 633 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 634 | return err 635 | } 636 | //line page.ego:75 637 | if _, err := fmt.Fprintf(w, "
Key"); err != nil { 488 | return err 489 | } 490 | //line page.ego:56 491 | if _, err := fmt.Fprintf(w, "Page ID"); err != nil { 496 | return err 497 | } 498 | //line page.ego:57 499 | if _, err := fmt.Fprintf(w, "Size (k)"); err != nil { 504 | return err 505 | } 506 | //line page.ego:58 507 | if _, err := fmt.Fprintf(w, "%%Util"); err != nil { 512 | return err 513 | } 514 | //line page.ego:59 515 | if _, err := fmt.Fprintf(w, "
"); err != nil { 560 | return err 561 | } 562 | //line page.ego:68 563 | if _, err := fmt.Fprintf(w, "%v", trunc(tostr(e.key()), 40)); err != nil { 564 | return err 565 | } 566 | //line page.ego:68 567 | if _, err := fmt.Fprintf(w, ""); err != nil { 572 | return err 573 | } 574 | //line page.ego:69 575 | if _, err := fmt.Fprintf(w, ""); err != nil { 584 | return err 585 | } 586 | //line page.ego:69 587 | if _, err := fmt.Fprintf(w, "%v", e.pgid); err != nil { 588 | return err 589 | } 590 | //line page.ego:69 591 | if _, err := fmt.Fprintf(w, ""); err != nil { 592 | return err 593 | } 594 | //line page.ego:69 595 | if _, err := fmt.Fprintf(w, ""); err != nil { 600 | return err 601 | } 602 | //line page.ego:70 603 | if _, err := fmt.Fprintf(w, "%v", len(e.key())); err != nil { 604 | return err 605 | } 606 | //line page.ego:70 607 | if _, err := fmt.Fprintf(w, ""); err != nil { 612 | return err 613 | } 614 | //line page.ego:71 615 | if _, err := fmt.Fprintf(w, "%v", fmt.Sprintf("%.2f%%", substats.utilization*100)); err != nil { 616 | return err 617 | } 618 | //line page.ego:71 619 | if _, err := fmt.Fprintf(w, "
\n \n "); err != nil { 638 | return err 639 | } 640 | //line page.ego:77 641 | } else if (p.flags & leafPageFlag) != 0 { 642 | //line page.ego:78 643 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 644 | return err 645 | } 646 | //line page.ego:78 647 | if _, err := fmt.Fprintf(w, "

Leaf Elements ("); err != nil { 648 | return err 649 | } 650 | //line page.ego:78 651 | if _, err := fmt.Fprintf(w, "%v", p.count); err != nil { 652 | return err 653 | } 654 | //line page.ego:78 655 | if _, err := fmt.Fprintf(w, ")"); err != nil { 656 | return err 657 | } 658 | //line page.ego:78 659 | if _, err := fmt.Fprintf(w, "

\n "); err != nil { 660 | return err 661 | } 662 | //line page.ego:79 663 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 664 | return err 665 | } 666 | //line page.ego:80 667 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 668 | return err 669 | } 670 | //line page.ego:81 671 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 672 | return err 673 | } 674 | //line page.ego:82 675 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 680 | return err 681 | } 682 | //line page.ego:83 683 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 688 | return err 689 | } 690 | //line page.ego:84 691 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 696 | return err 697 | } 698 | //line page.ego:85 699 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 704 | return err 705 | } 706 | //line page.ego:86 707 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 708 | return err 709 | } 710 | //line page.ego:87 711 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 712 | return err 713 | } 714 | //line page.ego:88 715 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 716 | return err 717 | } 718 | //line page.ego:89 719 | for i := uint16(0); i < p.count; i++ { 720 | //line page.ego:90 721 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 722 | return err 723 | } 724 | //line page.ego:90 725 | e := p.leafPageElement(i) 726 | //line page.ego:91 727 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 728 | return err 729 | } 730 | //line page.ego:91 731 | if (e.flags & bucketLeafFlag) != 0 { 732 | //line page.ego:92 733 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 734 | return err 735 | } 736 | //line page.ego:92 737 | b := ((*bucket)(unsafe.Pointer(&e.value()[0]))) 738 | //line page.ego:93 739 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 740 | return err 741 | } 742 | //line page.ego:94 743 | util := "-" 744 | if b.root != 0 { 745 | substats := pageAt(tx, b.root).stats(pageSize) 746 | util = fmt.Sprintf("%.2f%%", substats.utilization*100) 747 | } 748 | 749 | //line page.ego:101 750 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 751 | return err 752 | } 753 | //line page.ego:101 754 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 755 | return err 756 | } 757 | //line page.ego:102 758 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 775 | return err 776 | } 777 | //line page.ego:103 778 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 823 | return err 824 | } 825 | //line page.ego:106 826 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 843 | return err 844 | } 845 | //line page.ego:107 846 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 855 | return err 856 | } 857 | //line page.ego:108 858 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 859 | return err 860 | } 861 | //line page.ego:109 862 | } else { 863 | //line page.ego:110 864 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 865 | return err 866 | } 867 | //line page.ego:110 868 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 869 | return err 870 | } 871 | //line page.ego:111 872 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 881 | return err 882 | } 883 | //line page.ego:112 884 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 893 | return err 894 | } 895 | //line page.ego:113 896 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 913 | return err 914 | } 915 | //line page.ego:114 916 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 921 | return err 922 | } 923 | //line page.ego:115 924 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 925 | return err 926 | } 927 | //line page.ego:116 928 | } 929 | //line page.ego:117 930 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 931 | return err 932 | } 933 | //line page.ego:117 934 | } 935 | //line page.ego:118 936 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 937 | return err 938 | } 939 | //line page.ego:118 940 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 941 | return err 942 | } 943 | //line page.ego:119 944 | if _, err := fmt.Fprintf(w, "
Key"); err != nil { 676 | return err 677 | } 678 | //line page.ego:82 679 | if _, err := fmt.Fprintf(w, "Value"); err != nil { 684 | return err 685 | } 686 | //line page.ego:83 687 | if _, err := fmt.Fprintf(w, "Size (k/v)"); err != nil { 692 | return err 693 | } 694 | //line page.ego:84 695 | if _, err := fmt.Fprintf(w, "%%Util"); err != nil { 700 | return err 701 | } 702 | //line page.ego:85 703 | if _, err := fmt.Fprintf(w, "
"); err != nil { 759 | return err 760 | } 761 | //line page.ego:102 762 | if _, err := fmt.Fprintf(w, ""); err != nil { 763 | return err 764 | } 765 | //line page.ego:102 766 | if _, err := fmt.Fprintf(w, "%v", trunc(tostr(e.key()), 40)); err != nil { 767 | return err 768 | } 769 | //line page.ego:102 770 | if _, err := fmt.Fprintf(w, ""); err != nil { 771 | return err 772 | } 773 | //line page.ego:102 774 | if _, err := fmt.Fprintf(w, "\n <bucket(root="); err != nil { 779 | return err 780 | } 781 | //line page.ego:104 782 | if b.root != 0 { 783 | //line page.ego:104 784 | if _, err := fmt.Fprintf(w, ""); err != nil { 793 | return err 794 | } 795 | //line page.ego:104 796 | } 797 | //line page.ego:104 798 | if _, err := fmt.Fprintf(w, "%v", b.root); err != nil { 799 | return err 800 | } 801 | //line page.ego:104 802 | if b.root != 0 { 803 | //line page.ego:104 804 | if _, err := fmt.Fprintf(w, ""); err != nil { 805 | return err 806 | } 807 | //line page.ego:104 808 | } 809 | //line page.ego:104 810 | if _, err := fmt.Fprintf(w, "; seq="); err != nil { 811 | return err 812 | } 813 | //line page.ego:104 814 | if _, err := fmt.Fprintf(w, "%v", b.sequence); err != nil { 815 | return err 816 | } 817 | //line page.ego:104 818 | if _, err := fmt.Fprintf(w, ">\n "); err != nil { 819 | return err 820 | } 821 | //line page.ego:105 822 | if _, err := fmt.Fprintf(w, ""); err != nil { 827 | return err 828 | } 829 | //line page.ego:106 830 | if _, err := fmt.Fprintf(w, "%v", len(e.key())); err != nil { 831 | return err 832 | } 833 | //line page.ego:106 834 | if _, err := fmt.Fprintf(w, " / "); err != nil { 835 | return err 836 | } 837 | //line page.ego:106 838 | if _, err := fmt.Fprintf(w, "%v", len(e.value())); err != nil { 839 | return err 840 | } 841 | //line page.ego:106 842 | if _, err := fmt.Fprintf(w, ""); err != nil { 847 | return err 848 | } 849 | //line page.ego:107 850 | if _, err := fmt.Fprintf(w, "%v", util); err != nil { 851 | return err 852 | } 853 | //line page.ego:107 854 | if _, err := fmt.Fprintf(w, "
"); err != nil { 873 | return err 874 | } 875 | //line page.ego:111 876 | if _, err := fmt.Fprintf(w, "%v", trunc(tostr(e.key()), 40)); err != nil { 877 | return err 878 | } 879 | //line page.ego:111 880 | if _, err := fmt.Fprintf(w, ""); err != nil { 885 | return err 886 | } 887 | //line page.ego:112 888 | if _, err := fmt.Fprintf(w, "%v", trunc(tostr(e.value()), 40)); err != nil { 889 | return err 890 | } 891 | //line page.ego:112 892 | if _, err := fmt.Fprintf(w, ""); err != nil { 897 | return err 898 | } 899 | //line page.ego:113 900 | if _, err := fmt.Fprintf(w, "%v", len(e.key())); err != nil { 901 | return err 902 | } 903 | //line page.ego:113 904 | if _, err := fmt.Fprintf(w, " / "); err != nil { 905 | return err 906 | } 907 | //line page.ego:113 908 | if _, err := fmt.Fprintf(w, "%v", len(e.value())); err != nil { 909 | return err 910 | } 911 | //line page.ego:113 912 | if _, err := fmt.Fprintf(w, " "); err != nil { 917 | return err 918 | } 919 | //line page.ego:114 920 | if _, err := fmt.Fprintf(w, "
\n "); err != nil { 945 | return err 946 | } 947 | //line page.ego:120 948 | } 949 | //line page.ego:121 950 | if _, err := fmt.Fprintf(w, "\n\n "); err != nil { 951 | return err 952 | } 953 | //line page.ego:122 954 | if showUsage { 955 | //line page.ego:123 956 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 957 | return err 958 | } 959 | //line page.ego:124 960 | mins, maxs, values := bucketize(histogram) 961 | vmax, maxlen := 0, 20 962 | for _, v := range values { 963 | if v > vmax { 964 | vmax = v 965 | } 966 | } 967 | 968 | //line page.ego:133 969 | if _, err := fmt.Fprintf(w, "\n\n "); err != nil { 970 | return err 971 | } 972 | //line page.ego:134 973 | if _, err := fmt.Fprintf(w, "

Page Usage Histogram"); err != nil { 974 | return err 975 | } 976 | //line page.ego:134 977 | if _, err := fmt.Fprintf(w, "

\n "); err != nil { 978 | return err 979 | } 980 | //line page.ego:135 981 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 982 | return err 983 | } 984 | //line page.ego:136 985 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 986 | return err 987 | } 988 | //line page.ego:137 989 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 990 | return err 991 | } 992 | //line page.ego:138 993 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 998 | return err 999 | } 1000 | //line page.ego:139 1001 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 1006 | return err 1007 | } 1008 | //line page.ego:140 1009 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 1014 | return err 1015 | } 1016 | //line page.ego:141 1017 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 1018 | return err 1019 | } 1020 | //line page.ego:142 1021 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 1022 | return err 1023 | } 1024 | //line page.ego:143 1025 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 1026 | return err 1027 | } 1028 | //line page.ego:144 1029 | for i := 0; i < len(values); i++ { 1030 | //line page.ego:145 1031 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 1032 | return err 1033 | } 1034 | //line page.ego:145 1035 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 1036 | return err 1037 | } 1038 | //line page.ego:146 1039 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 1080 | return err 1081 | } 1082 | //line page.ego:149 1083 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 1084 | return err 1085 | } 1086 | //line page.ego:150 1087 | } 1088 | //line page.ego:151 1089 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 1090 | return err 1091 | } 1092 | //line page.ego:151 1093 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 1094 | return err 1095 | } 1096 | //line page.ego:152 1097 | if _, err := fmt.Fprintf(w, "
Usage (bytes)"); err != nil { 994 | return err 995 | } 996 | //line page.ego:138 997 | if _, err := fmt.Fprintf(w, "Count"); err != nil { 1002 | return err 1003 | } 1004 | //line page.ego:139 1005 | if _, err := fmt.Fprintf(w, " "); err != nil { 1010 | return err 1011 | } 1012 | //line page.ego:140 1013 | if _, err := fmt.Fprintf(w, "
"); err != nil { 1040 | return err 1041 | } 1042 | //line page.ego:146 1043 | if _, err := fmt.Fprintf(w, "%v", mins[i]); err != nil { 1044 | return err 1045 | } 1046 | //line page.ego:146 1047 | if _, err := fmt.Fprintf(w, " - "); err != nil { 1048 | return err 1049 | } 1050 | //line page.ego:146 1051 | if _, err := fmt.Fprintf(w, "%v", maxs[i]); err != nil { 1052 | return err 1053 | } 1054 | //line page.ego:146 1055 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 1056 | return err 1057 | } 1058 | //line page.ego:147 1059 | if _, err := fmt.Fprintf(w, ""); err != nil { 1060 | return err 1061 | } 1062 | //line page.ego:147 1063 | if _, err := fmt.Fprintf(w, "%v", values[i]); err != nil { 1064 | return err 1065 | } 1066 | //line page.ego:147 1067 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 1068 | return err 1069 | } 1070 | //line page.ego:148 1071 | if _, err := fmt.Fprintf(w, ""); err != nil { 1072 | return err 1073 | } 1074 | //line page.ego:148 1075 | if _, err := fmt.Fprintf(w, "%v", strings.Repeat("█", int((float64(values[i])/float64(vmax))*float64(maxlen)))); err != nil { 1076 | return err 1077 | } 1078 | //line page.ego:148 1079 | if _, err := fmt.Fprintf(w, "
\n "); err != nil { 1098 | return err 1099 | } 1100 | //line page.ego:153 1101 | } else { 1102 | //line page.ego:154 1103 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 1104 | return err 1105 | } 1106 | //line page.ego:155 1107 | u, q := r.URL, r.URL.Query() 1108 | q.Set("usage", "true") 1109 | u.RawQuery = q.Encode() 1110 | 1111 | //line page.ego:160 1112 | if _, err := fmt.Fprintf(w, "\n\n "); err != nil { 1113 | return err 1114 | } 1115 | //line page.ego:161 1116 | if _, err := fmt.Fprintf(w, "

"); err != nil { 1117 | return err 1118 | } 1119 | //line page.ego:161 1120 | if _, err := fmt.Fprintf(w, "Show Page Usage"); err != nil { 1129 | return err 1130 | } 1131 | //line page.ego:161 1132 | if _, err := fmt.Fprintf(w, ""); err != nil { 1133 | return err 1134 | } 1135 | //line page.ego:161 1136 | if _, err := fmt.Fprintf(w, "

\n "); err != nil { 1137 | return err 1138 | } 1139 | //line page.ego:162 1140 | } 1141 | //line page.ego:163 1142 | if _, err := fmt.Fprintf(w, "\n\n "); err != nil { 1143 | return err 1144 | } 1145 | //line page.ego:164 1146 | if _, err := fmt.Fprintf(w, "
"); err != nil { 1147 | return err 1148 | } 1149 | //line page.ego:164 1150 | if _, err := fmt.Fprintf(w, "
\n "); err != nil { 1151 | return err 1152 | } 1153 | //line page.ego:165 1154 | if _, err := fmt.Fprintf(w, "
\n Go to page: "); err != nil { 1155 | return err 1156 | } 1157 | //line page.ego:166 1158 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 1159 | return err 1160 | } 1161 | //line page.ego:167 1162 | if _, err := fmt.Fprintf(w, "\n "); err != nil { 1167 | return err 1168 | } 1169 | //line page.ego:168 1170 | if _, err := fmt.Fprintf(w, "
\n "); err != nil { 1171 | return err 1172 | } 1173 | //line page.ego:169 1174 | if _, err := fmt.Fprintf(w, "\n"); err != nil { 1175 | return err 1176 | } 1177 | //line page.ego:170 1178 | if _, err := fmt.Fprintf(w, "\n"); err != nil { 1179 | return err 1180 | } 1181 | return nil 1182 | } 1183 | --------------------------------------------------------------------------------