in executor/collision_matrix.go [65:138]
func fillupOperationValues(log *PartialLogWithCallbak) {
if log.partialLog.Operation != "i" && log.partialLog.Operation != "u" {
return
}
// for update. need to initialize the UniqueIndexesUpdates
if log.partialLog.Operation == "u" {
log.partialLog.UniqueIndexesUpdates = bson.M{}
}
o := log.partialLog.Object
for k := range log.partialLog.UniqueIndexes {
// multi key index like "name|phone", seperate by MultiColumnIndexSplitter
// every index value should be fetched respectively from oplog.o
for _, singleIndex := range strings.Split(k, MultiColumnIndexSplitter) {
// single index may be "aaa" or "aaa.bbb.ccc"
parent, _ := oplog.ConvertBsonD2M(o)
// all types of $inc, $mul, $rename, $unset, $set change to $set,$unset in oplog
// $set looks like o:{$set:{a:{b:1}}} or o:{$set:{"a.b":1}}
if m, exist := parent["$set"]; exist {
if child, ok := m.(bson.M); ok {
// skip $set operator
parent = child
}
}
var value interface{}
// check if there already has "a.b.c" in $set
if v, exist := parent[singleIndex]; exist {
value = v
} else {
cascades := strings.Split(singleIndex, ".")
descend := len(cascades) - 1
// going down
inPosition := true
for i := 0; i != descend; i++ {
if down, ok := parent[cascades[i]].(bson.M); ok {
parent = down
} else {
inPosition = false
}
}
if inPosition {
value = parent[cascades[len(cascades)-1]]
}
}
var fill interface{}
switch log.partialLog.Operation {
case "i":
fill = log.partialLog.UniqueIndexes[k]
case "u":
fill = log.partialLog.UniqueIndexesUpdates[k]
}
if fill == nil {
fill = make([]interface{}, 0)
}
if array, ok := fill.([]interface{}); ok {
// doesn't find the target value. just fill NULL into it
array = append(array, value)
// reset to uk
switch log.partialLog.Operation {
case "i":
log.partialLog.UniqueIndexes[k] = array
case "u":
log.partialLog.UniqueIndexesUpdates[k] = array
}
}
}
}
}