| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The LUCI Authors. All rights reserved. | |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 | |
| 3 // that can be 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 |