OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package memory |
| 6 |
| 7 import ( |
| 8 "encoding/hex" |
| 9 "flag" |
| 10 "fmt" |
| 11 "io/ioutil" |
| 12 "os" |
| 13 "path/filepath" |
| 14 "runtime" |
| 15 "strings" |
| 16 "sync" |
| 17 "sync/atomic" |
| 18 |
| 19 "github.com/luci/gkvlite" |
| 20 ) |
| 21 |
| 22 var logMemCollectionFolder = flag.String( |
| 23 "luci.gae.gkvlite_trace_folder", "", |
| 24 "Set to a folder path to enable debugging traces to be dumped there. Set
to '-' to dump to stdout.") |
| 25 var logMemCollectionFolderTmp string |
| 26 var logMemCollectionOnce sync.Once |
| 27 var logMemCounter uint32 |
| 28 var logMemNameKey = "holds a string indicating the GKVLiteDebuggingTraceName" |
| 29 var stdoutLock sync.Mutex |
| 30 |
| 31 func wrapTracingMemStore(store memStore) memStore { |
| 32 var writer traceWriter |
| 33 logNum := atomic.AddUint32(&logMemCounter, 1) - 1 |
| 34 collName := fmt.Sprintf("coll%d", logNum) |
| 35 |
| 36 if *logMemCollectionFolder == "-" { |
| 37 writer = func(format string, a ...interface{}) { |
| 38 stdoutLock.Lock() |
| 39 defer stdoutLock.Unlock() |
| 40 fmt.Printf(format+"\n", a...) |
| 41 } |
| 42 } else { |
| 43 logMemCollectionOnce.Do(func() { |
| 44 var err error |
| 45 logMemCollectionFolderTmp, err = ioutil.TempDir(*logMemC
ollectionFolder, "luci-gae-gkvlite_trace") |
| 46 if err != nil { |
| 47 panic(err) |
| 48 } |
| 49 logMemCollectionFolderTmp, err = filepath.Abs(logMemColl
ectionFolderTmp) |
| 50 if err != nil { |
| 51 panic(err) |
| 52 } |
| 53 fmt.Fprintf(os.Stderr, "Saving GKVLite trace files to %q
\n", logMemCollectionFolderTmp) |
| 54 }) |
| 55 if logMemCollectionFolderTmp == "" { |
| 56 panic("unable to create folder for tracefiles") |
| 57 } |
| 58 |
| 59 lck := sync.Mutex{} |
| 60 fname := fmt.Sprintf(filepath.Join(logMemCollectionFolderTmp, fm
t.Sprintf("%d.trace", logNum))) |
| 61 fil, err := os.Create(fname) |
| 62 if err != nil { |
| 63 panic(err) |
| 64 } |
| 65 writer = func(format string, a ...interface{}) { |
| 66 lck.Lock() |
| 67 defer lck.Unlock() |
| 68 fmt.Fprintf(fil, format+"\n", a...) |
| 69 } |
| 70 runtime.SetFinalizer(&writer, func(_ *traceWriter) { fil.Close()
}) |
| 71 } |
| 72 writer("%s := newMemStore()", collName) |
| 73 return &tracingMemStoreImpl{store, writer, collName, 0, false} |
| 74 } |
| 75 |
| 76 type traceWriter func(format string, a ...interface{}) |
| 77 |
| 78 type tracingMemStoreImpl struct { |
| 79 i memStore |
| 80 w traceWriter |
| 81 |
| 82 collName string |
| 83 // for the mutable store, this is a counter that increments for every |
| 84 // Snapshot, and for snapshots, this is the number of the snapshot. |
| 85 snapNum uint |
| 86 isSnap bool |
| 87 } |
| 88 |
| 89 var _ memStore = (*tracingMemStoreImpl)(nil) |
| 90 |
| 91 func (t *tracingMemStoreImpl) ImATestingSnapshot() {} |
| 92 |
| 93 func (t *tracingMemStoreImpl) colWriter(action, name string) traceWriter { |
| 94 ident := t.ident() |
| 95 hexname := hex.EncodeToString([]byte(name)) |
| 96 writer := func(format string, a ...interface{}) { |
| 97 if strings.HasPrefix(format, "//") { // comment |
| 98 t.w(format, a...) |
| 99 } else { |
| 100 t.w(fmt.Sprintf("%s_%s%s", ident, hexname, format), a...
) |
| 101 } |
| 102 } |
| 103 writer(" := %s.%s(%q)", ident, action, name) |
| 104 return writer |
| 105 } |
| 106 |
| 107 func (t *tracingMemStoreImpl) ident() string { |
| 108 if t.isSnap { |
| 109 return fmt.Sprintf("%s_snap%d", t.collName, t.snapNum) |
| 110 } |
| 111 return t.collName |
| 112 } |
| 113 |
| 114 func (t *tracingMemStoreImpl) GetCollection(name string) memCollection { |
| 115 coll := t.i.GetCollection(name) |
| 116 if coll == nil { |
| 117 t.w("// %s.GetCollection(%q) -> nil", t.ident(), name) |
| 118 return nil |
| 119 } |
| 120 writer := t.colWriter("GetCollection", name) |
| 121 return &tracingMemCollectionImpl{coll, writer, 0} |
| 122 } |
| 123 |
| 124 func (t *tracingMemStoreImpl) GetCollectionNames() []string { |
| 125 t.w("%s.GetCollectionNames()", t.ident()) |
| 126 return t.i.GetCollectionNames() |
| 127 } |
| 128 |
| 129 func (t *tracingMemStoreImpl) GetOrCreateCollection(name string) memCollection { |
| 130 writer := t.colWriter("GetOrCreateCollection", name) |
| 131 return &tracingMemCollectionImpl{t.i.GetOrCreateCollection(name), writer
, 0} |
| 132 } |
| 133 |
| 134 func (t *tracingMemStoreImpl) Snapshot() memStore { |
| 135 snap := t.i.Snapshot() |
| 136 if snap == t.i { |
| 137 t.w("// %s.Snapshot() -> self", t.ident()) |
| 138 return t |
| 139 } |
| 140 ret := &tracingMemStoreImpl{snap, t.w, t.collName, t.snapNum, true} |
| 141 t.w("%s := %s.Snapshot()", ret.ident(), t.ident()) |
| 142 t.snapNum++ |
| 143 return ret |
| 144 } |
| 145 |
| 146 func (t *tracingMemStoreImpl) IsReadOnly() bool { |
| 147 return t.i.IsReadOnly() |
| 148 } |
| 149 |
| 150 type tracingMemCollectionImpl struct { |
| 151 i memCollection |
| 152 w traceWriter |
| 153 visitNumber uint |
| 154 } |
| 155 |
| 156 var _ memCollection = (*tracingMemCollectionImpl)(nil) |
| 157 |
| 158 func (t *tracingMemCollectionImpl) Name() string { |
| 159 return t.i.Name() |
| 160 } |
| 161 |
| 162 func (t *tracingMemCollectionImpl) Delete(k []byte) bool { |
| 163 t.w(".Delete(%#v)", k) |
| 164 return t.i.Delete(k) |
| 165 } |
| 166 |
| 167 func (t *tracingMemCollectionImpl) Get(k []byte) []byte { |
| 168 t.w(".Get(%#v)", k) |
| 169 return t.i.Get(k) |
| 170 } |
| 171 |
| 172 func (t *tracingMemCollectionImpl) GetTotals() (numItems, numBytes uint64) { |
| 173 t.w(".GetTotals()") |
| 174 return t.i.GetTotals() |
| 175 } |
| 176 |
| 177 func (t *tracingMemCollectionImpl) MinItem(withValue bool) *gkvlite.Item { |
| 178 t.w(".MinItem(%t)", withValue) |
| 179 return t.i.MinItem(withValue) |
| 180 } |
| 181 |
| 182 func (t *tracingMemCollectionImpl) Set(k, v []byte) { |
| 183 t.w(".Set(%#v, %#v)", k, v) |
| 184 t.i.Set(k, v) |
| 185 } |
| 186 |
| 187 func (t *tracingMemCollectionImpl) VisitItemsAscend(target []byte, withValue boo
l, visitor gkvlite.ItemVisitor) { |
| 188 vnum := t.visitNumber |
| 189 t.visitNumber++ |
| 190 |
| 191 t.w(".VisitItemsAscend(%#v, %t, func(i *gkvlite.Item) bool{ return true
}) // BEGIN VisitItemsAscend(%d)", target, withValue, vnum) |
| 192 defer t.w("// END VisitItemsAscend(%d)", vnum) |
| 193 t.i.VisitItemsAscend(target, withValue, visitor) |
| 194 } |
| 195 |
| 196 func (t *tracingMemCollectionImpl) IsReadOnly() bool { |
| 197 return t.i.IsReadOnly() |
| 198 } |
OLD | NEW |