| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package memory | 5 package memory |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "bytes" | 8 "bytes" |
| 9 "fmt" | 9 "fmt" |
| 10 "sort" | 10 "sort" |
| 11 | 11 |
| 12 ds "github.com/luci/gae/service/datastore" | 12 ds "github.com/luci/gae/service/datastore" |
| 13 "github.com/luci/gae/service/datastore/serialize" |
| 13 "github.com/luci/gkvlite" | 14 "github.com/luci/gkvlite" |
| 14 ) | 15 ) |
| 15 | 16 |
| 16 var indexCreationDeterministic = false | 17 var indexCreationDeterministic = false |
| 17 | 18 |
| 18 type qIndexSlice []*ds.IndexDefinition | 19 type qIndexSlice []*ds.IndexDefinition |
| 19 | 20 |
| 20 func (s qIndexSlice) Len() int { return len(s) } | 21 func (s qIndexSlice) Len() int { return len(s) } |
| 21 func (s qIndexSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } | 22 func (s qIndexSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } |
| 22 func (s qIndexSlice) Less(i, j int) bool { return s[i].Less(s[j]) } | 23 func (s qIndexSlice) Less(i, j int) bool { return s[i].Less(s[j]) } |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 66 | 67 |
| 67 buf := &bytes.Buffer{} | 68 buf := &bytes.Buffer{} |
| 68 ret = make(serializedIndexablePmap, len(pm)) | 69 ret = make(serializedIndexablePmap, len(pm)) |
| 69 for k, vals := range pm { | 70 for k, vals := range pm { |
| 70 newVals := make(serializedPvals, 0, len(vals)) | 71 newVals := make(serializedPvals, 0, len(vals)) |
| 71 for _, v := range vals { | 72 for _, v := range vals { |
| 72 if v.IndexSetting() == ds.NoIndex { | 73 if v.IndexSetting() == ds.NoIndex { |
| 73 continue | 74 continue |
| 74 } | 75 } |
| 75 buf.Reset() | 76 buf.Reset() |
| 76 » » » v.Write(buf, ds.WithoutContext) | 77 » » » serialize.WriteProperty(buf, serialize.WithoutContext, v
) |
| 77 newVal := make([]byte, buf.Len()) | 78 newVal := make([]byte, buf.Len()) |
| 78 copy(newVal, buf.Bytes()) | 79 copy(newVal, buf.Bytes()) |
| 79 newVals = append(newVals, newVal) | 80 newVals = append(newVals, newVal) |
| 80 } | 81 } |
| 81 if len(newVals) > 0 { | 82 if len(newVals) > 0 { |
| 82 sort.Sort(newVals) | 83 sort.Sort(newVals) |
| 83 ret[k] = newVals | 84 ret[k] = newVals |
| 84 } | 85 } |
| 85 } | 86 } |
| 86 return | 87 return |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 176 } | 177 } |
| 177 } | 178 } |
| 178 return m.buf, true | 179 return m.buf, true |
| 179 } | 180 } |
| 180 | 181 |
| 181 func (sip serializedIndexablePmap) indexEntries(k ds.Key, idxs []*ds.IndexDefini
tion) *memStore { | 182 func (sip serializedIndexablePmap) indexEntries(k ds.Key, idxs []*ds.IndexDefini
tion) *memStore { |
| 182 ret := newMemStore() | 183 ret := newMemStore() |
| 183 idxColl := ret.SetCollection("idx", nil) | 184 idxColl := ret.SetCollection("idx", nil) |
| 184 // getIdxEnts retrieves an index collection or adds it if it's not there
. | 185 // getIdxEnts retrieves an index collection or adds it if it's not there
. |
| 185 getIdxEnts := func(qi *ds.IndexDefinition) *memCollection { | 186 getIdxEnts := func(qi *ds.IndexDefinition) *memCollection { |
| 186 » » buf := &bytes.Buffer{} | 187 » » b := serialize.ToBytes(*qi) |
| 187 » » qi.Write(buf) | |
| 188 » » b := buf.Bytes() | |
| 189 idxColl.Set(b, []byte{}) | 188 idxColl.Set(b, []byte{}) |
| 190 return ret.SetCollection(fmt.Sprintf("idx:%s:%s", k.Namespace(),
b), nil) | 189 return ret.SetCollection(fmt.Sprintf("idx:%s:%s", k.Namespace(),
b), nil) |
| 191 } | 190 } |
| 192 | 191 |
| 193 » buf := &bytes.Buffer{} | 192 » keyData := serialize.ToBytes(k) |
| 194 » ds.WriteKey(buf, ds.WithoutContext, k) | |
| 195 » keyData := buf.Bytes() | |
| 196 | 193 |
| 197 walkPermutations := func(prefix []byte, irg indexRowGen, ents *memCollec
tion) { | 194 walkPermutations := func(prefix []byte, irg indexRowGen, ents *memCollec
tion) { |
| 198 prev := []byte{} // intentionally make a non-nil slice, gkvlite
hates nil. | 195 prev := []byte{} // intentionally make a non-nil slice, gkvlite
hates nil. |
| 199 irg.permute(func(data []byte) { | 196 irg.permute(func(data []byte) { |
| 200 buf := bytes.NewBuffer(make([]byte, 0, len(prefix)+len(d
ata)+len(keyData))) | 197 buf := bytes.NewBuffer(make([]byte, 0, len(prefix)+len(d
ata)+len(keyData))) |
| 201 buf.Write(prefix) | 198 buf.Write(prefix) |
| 202 buf.Write(data) | 199 buf.Write(data) |
| 203 buf.Write(keyData) | 200 buf.Write(keyData) |
| 204 ents.Set(buf.Bytes(), prev) | 201 ents.Set(buf.Bytes(), prev) |
| 205 prev = data | 202 prev = data |
| 206 }) | 203 }) |
| 207 } | 204 } |
| 208 | 205 |
| 209 mtch := matcher{} | 206 mtch := matcher{} |
| 210 for _, idx := range idxs { | 207 for _, idx := range idxs { |
| 211 if irg, ok := mtch.match(idx, sip); ok { | 208 if irg, ok := mtch.match(idx, sip); ok { |
| 212 idxEnts := getIdxEnts(idx) | 209 idxEnts := getIdxEnts(idx) |
| 213 if len(irg.propVec) == 0 { | 210 if len(irg.propVec) == 0 { |
| 214 idxEnts.Set(keyData, []byte{}) // propless index
, e.g. kind -> key = nil | 211 idxEnts.Set(keyData, []byte{}) // propless index
, e.g. kind -> key = nil |
| 215 } else if idx.Ancestor { | 212 } else if idx.Ancestor { |
| 216 for ancKey := k; ancKey != nil; ancKey = ancKey.
Parent() { | 213 for ancKey := k; ancKey != nil; ancKey = ancKey.
Parent() { |
| 217 » » » » » buf := &bytes.Buffer{} | 214 » » » » » walkPermutations(serialize.ToBytes(ancKe
y), irg, idxEnts) |
| 218 » » » » » ds.WriteKey(buf, ds.WithoutContext, ancK
ey) | |
| 219 » » » » » walkPermutations(buf.Bytes(), irg, idxEn
ts) | |
| 220 } | 215 } |
| 221 } else { | 216 } else { |
| 222 walkPermutations(nil, irg, idxEnts) | 217 walkPermutations(nil, irg, idxEnts) |
| 223 } | 218 } |
| 224 } | 219 } |
| 225 } | 220 } |
| 226 | 221 |
| 227 return ret | 222 return ret |
| 228 } | 223 } |
| 229 | 224 |
| 230 func getCompIdxs(idxColl *memCollection) []*ds.IndexDefinition { | 225 func getCompIdxs(idxColl *memCollection) []*ds.IndexDefinition { |
| 231 // load all current complex query index definitions. | 226 // load all current complex query index definitions. |
| 232 compIdx := []*ds.IndexDefinition{} | 227 compIdx := []*ds.IndexDefinition{} |
| 233 complexQueryPrefix := ds.IndexComplexQueryPrefix() | 228 complexQueryPrefix := ds.IndexComplexQueryPrefix() |
| 234 idxColl.VisitItemsAscend(complexQueryPrefix, false, func(i *gkvlite.Item
) bool { | 229 idxColl.VisitItemsAscend(complexQueryPrefix, false, func(i *gkvlite.Item
) bool { |
| 235 if !bytes.HasPrefix(i.Key, complexQueryPrefix) { | 230 if !bytes.HasPrefix(i.Key, complexQueryPrefix) { |
| 236 return false | 231 return false |
| 237 } | 232 } |
| 238 » » qi := &ds.IndexDefinition{} | 233 » » qi, err := serialize.ReadIndexDefinition(bytes.NewBuffer(i.Key)) |
| 239 » » if err := qi.Read(bytes.NewBuffer(i.Key)); err != nil { | 234 » » if err != nil { |
| 240 panic(err) // memory corruption | 235 panic(err) // memory corruption |
| 241 } | 236 } |
| 242 » » compIdx = append(compIdx, qi) | 237 » » compIdx = append(compIdx, &qi) |
| 243 return true | 238 return true |
| 244 }) | 239 }) |
| 245 return compIdx | 240 return compIdx |
| 246 } | 241 } |
| 247 | 242 |
| 248 func getIdxColl(store *memStore) *memCollection { | 243 func getIdxColl(store *memStore) *memCollection { |
| 249 idxColl := store.GetCollection("idx") | 244 idxColl := store.GetCollection("idx") |
| 250 if idxColl == nil { | 245 if idxColl == nil { |
| 251 idxColl = store.SetCollection("idx", nil) | 246 idxColl = store.SetCollection("idx", nil) |
| 252 } | 247 } |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 // when there are no index entries for that index any more. | 292 // when there are no index entries for that index any more. |
| 298 }) | 293 }) |
| 299 } | 294 } |
| 300 | 295 |
| 301 func addIndex(store *memStore, ns string, compIdx []*ds.IndexDefinition) { | 296 func addIndex(store *memStore, ns string, compIdx []*ds.IndexDefinition) { |
| 302 store.GetCollection("ents:"+ns).VisitItemsAscend(nil, true, func(i *gkvl
ite.Item) bool { | 297 store.GetCollection("ents:"+ns).VisitItemsAscend(nil, true, func(i *gkvl
ite.Item) bool { |
| 303 pm, err := rpmWoCtx(i.Val, ns) | 298 pm, err := rpmWoCtx(i.Val, ns) |
| 304 if err != nil { | 299 if err != nil { |
| 305 panic(err) // memory corruption | 300 panic(err) // memory corruption |
| 306 } | 301 } |
| 307 » » k, err := ds.ReadKey(bytes.NewBuffer(i.Key), ds.WithoutContext,
globalAppID, ns) | 302 » » k, err := serialize.ReadKey(bytes.NewBuffer(i.Key), serialize.Wi
thoutContext, globalAppID, ns) |
| 308 if err != nil { | 303 if err != nil { |
| 309 panic(err) | 304 panic(err) |
| 310 } | 305 } |
| 311 sip := partiallySerialize(pm) | 306 sip := partiallySerialize(pm) |
| 312 mergeIndexes(ns, store, newMemStore(), sip.indexEntries(k, compI
dx)) | 307 mergeIndexes(ns, store, newMemStore(), sip.indexEntries(k, compI
dx)) |
| 313 return true | 308 return true |
| 314 }) | 309 }) |
| 315 } | 310 } |
| 316 | 311 |
| 317 func updateIndicies(store *memStore, key ds.Key, oldEnt, newEnt ds.PropertyMap)
{ | 312 func updateIndicies(store *memStore, key ds.Key, oldEnt, newEnt ds.PropertyMap)
{ |
| 318 // load all current complex query index definitions. | 313 // load all current complex query index definitions. |
| 319 compIdx := getCompIdxs(getIdxColl(store)) | 314 compIdx := getCompIdxs(getIdxColl(store)) |
| 320 | 315 |
| 321 mergeIndexes(key.Namespace(), store, | 316 mergeIndexes(key.Namespace(), store, |
| 322 indexEntriesWithBuiltins(key, oldEnt, compIdx), | 317 indexEntriesWithBuiltins(key, oldEnt, compIdx), |
| 323 indexEntriesWithBuiltins(key, newEnt, compIdx)) | 318 indexEntriesWithBuiltins(key, newEnt, compIdx)) |
| 324 } | 319 } |
| OLD | NEW |