StatusWith<RecordData> KVRecordStore::updateWithDamages( OperationContext* txn, const RecordId& id, const RecordData& oldRec, const char* damageSource, const mutablebson::DamageVector& damages ) { const KeyString key(id); const Slice oldValue(oldRec.data(), oldRec.size()); const KVUpdateWithDamagesMessage message(damageSource, damages); // updateWithDamages can't change the number or size of records, so we don't need to update // stats. const Status s = _db->update(txn, Slice::of(key), oldValue, message); if (!s.isOK()) { return StatusWith<RecordData>(s); } // We also need to reach in and screw with the old doc's data so that the update system gets // the new image, because the update system is assuming mmapv1's behavior. Sigh. for (mutablebson::DamageVector::const_iterator it = damages.begin(); it != damages.end(); it++) { const mutablebson::DamageEvent &event = *it; invariant(event.targetOffset + event.size < static_cast<uint32_t>(oldRec.size())); std::copy(damageSource + event.sourceOffset, damageSource + event.sourceOffset + event.size, /* eek */ const_cast<char *>(oldRec.data()) + event.targetOffset); } return StatusWith<RecordData>(oldRec); }
Status HeapRecordStore::updateWithDamages( OperationContext* txn, const DiskLoc& loc, const RecordData& oldRec, const char* damageSource, const mutablebson::DamageVector& damages ) { HeapRecord* oldRecord = recordFor( loc ); const int len = oldRecord->size; HeapRecord newRecord(len); memcpy(newRecord.data.get(), oldRecord->data.get(), len); txn->recoveryUnit()->registerChange(new RemoveChange(_data, loc, *oldRecord)); *oldRecord = newRecord; cappedDeleteAsNeeded(txn); char* root = newRecord.data.get(); mutablebson::DamageVector::const_iterator where = damages.begin(); const mutablebson::DamageVector::const_iterator end = damages.end(); for( ; where != end; ++where ) { const char* sourcePtr = damageSource + where->sourceOffset; char* targetPtr = root + where->targetOffset; std::memcpy(targetPtr, sourcePtr, where->size); } *oldRecord = newRecord; return Status::OK(); }
StatusWith<RecordData> EphemeralForTestRecordStore::updateWithDamages( OperationContext* opCtx, const RecordId& loc, const RecordData& oldRec, const char* damageSource, const mutablebson::DamageVector& damages) { stdx::lock_guard<stdx::recursive_mutex> lock(_data->recordsMutex); EphemeralForTestRecord* oldRecord = recordFor(loc); const int len = oldRecord->size; EphemeralForTestRecord newRecord(len); memcpy(newRecord.data.get(), oldRecord->data.get(), len); opCtx->recoveryUnit()->registerChange(new RemoveChange(opCtx, _data, loc, *oldRecord)); *oldRecord = newRecord; cappedDeleteAsNeeded_inlock(opCtx); char* root = newRecord.data.get(); mutablebson::DamageVector::const_iterator where = damages.begin(); const mutablebson::DamageVector::const_iterator end = damages.end(); for (; where != end; ++where) { const char* sourcePtr = damageSource + where->sourceOffset; char* targetPtr = root + where->targetOffset; std::memcpy(targetPtr, sourcePtr, where->size); } *oldRecord = newRecord; return newRecord.toRecordData(); }
Status RocksRecordStore::updateWithDamages( OperationContext* txn, const DiskLoc& loc, const char* damangeSource, const mutablebson::DamageVector& damages ) { RocksRecoveryUnit* ru = _getRecoveryUnit( txn ); rocksdb::Slice key = _makeKey( loc ); // get original value std::string value; rocksdb::Status status; status = _db->Get( _readOptions( txn ), _columnFamily, key, &value ); if ( !status.ok() ) { if ( status.IsNotFound() ) return Status( ErrorCodes::InternalError, "doc not found for in-place update" ); log() << "rocks Get failed, blowing up: " << status.ToString(); invariant( false ); } // apply changes to our copy for( size_t i = 0; i < damages.size(); i++ ) { mutablebson::DamageEvent event = damages[i]; const char* sourcePtr = damangeSource + event.sourceOffset; invariant( event.targetOffset + event.size < value.length() ); value.replace( event.targetOffset, event.size, sourcePtr, event.size ); } // write back ru->writeBatch()->Put( _columnFamily, key, value ); return Status::OK(); }
Status HeapRecordStore::updateWithDamages( OperationContext* txn, const DiskLoc& loc, const char* damangeSource, const mutablebson::DamageVector& damages ) { HeapRecord* rec = recordFor( loc ); char* root = rec->data(); // All updates were in place. Apply them via durability and writing pointer. mutablebson::DamageVector::const_iterator where = damages.begin(); const mutablebson::DamageVector::const_iterator end = damages.end(); for( ; where != end; ++where ) { const char* sourcePtr = damangeSource + where->sourceOffset; char* targetPtr = root + where->targetOffset; std::memcpy(targetPtr, sourcePtr, where->size); } return Status::OK(); }
StatusWith<RecordData> RecordStoreV1Base::updateWithDamages( OperationContext* txn, const RecordId& loc, const RecordData& oldRec, const char* damageSource, const mutablebson::DamageVector& damages) { MmapV1RecordHeader* rec = recordFor(DiskLoc::fromRecordId(loc)); char* root = rec->data(); // All updates were in place. Apply them via durability and writing pointer. mutablebson::DamageVector::const_iterator where = damages.begin(); const mutablebson::DamageVector::const_iterator end = damages.end(); for (; where != end; ++where) { const char* sourcePtr = damageSource + where->sourceOffset; void* targetPtr = txn->recoveryUnit()->writingPtr(root + where->targetOffset, where->size); std::memcpy(targetPtr, sourcePtr, where->size); } return rec->toRecordData(); }