StatusWith<DiskLoc> RocksRecordStore::updateRecord( OperationContext* txn, const DiskLoc& loc, const char* data, int len, bool enforceQuota, UpdateMoveNotifier* notifier ) { RocksRecoveryUnit* ru = _getRecoveryUnit( txn ); std::string old_value; // XXX Be sure to also first query the write batch once Facebook implements that rocksdb::Status status = _db->Get( _readOptions( txn ), _columnFamily, _makeKey( loc ), &old_value ); if ( !status.ok() ) { return StatusWith<DiskLoc>( ErrorCodes::InternalError, status.ToString() ); } int old_length = old_value.size(); ru->writeBatch()->Put( _columnFamily, _makeKey( loc ), rocksdb::Slice( data, len ) ); _increaseDataSize(txn, len - old_length); cappedDeleteAsNeeded(txn); return StatusWith<DiskLoc>( loc ); }
StatusWith<RecordId> WiredTigerRecordStore::updateRecord(OperationContext* txn, const RecordId& loc, const char* data, int len, bool enforceQuota, UpdateNotifier* notifier) { WiredTigerCursor curwrap(_uri, _tableId, true, txn); curwrap.assertInActiveTxn(); WT_CURSOR* c = curwrap.get(); invariant(c); c->set_key(c, _makeKey(loc)); int ret = WT_OP_CHECK(c->search(c)); invariantWTOK(ret); WT_ITEM old_value; ret = c->get_value(c, &old_value); invariantWTOK(ret); int old_length = old_value.size; c->set_key(c, _makeKey(loc)); WiredTigerItem value(data, len); c->set_value(c, value.Get()); ret = WT_OP_CHECK(c->insert(c)); invariantWTOK(ret); _increaseDataSize(txn, len - old_length); cappedDeleteAsNeeded(txn, loc); return StatusWith<RecordId>(loc); }
void RocksRecordStore::deleteRecord( OperationContext* txn, const DiskLoc& dl ) { RocksRecoveryUnit* ru = _getRecoveryUnit( txn ); std::string oldValue; _db->Get( _readOptions( txn ), _columnFamily, _makeKey( dl ), &oldValue ); int oldLength = oldValue.size(); ru->writeBatch()->Delete( _columnFamily, _makeKey( dl ) ); _changeNumRecords(txn, false); _increaseDataSize(txn, -oldLength); }
StatusWith<RecordId> WiredTigerRecordStore::insertRecord(OperationContext* txn, const char* data, int len, bool enforceQuota) { if (_isCapped && len > _cappedMaxSize) { return StatusWith<RecordId>(ErrorCodes::BadValue, "object to insert exceeds cappedMaxSize"); } RecordId loc; if (_useOplogHack) { StatusWith<RecordId> status = extractAndCheckLocForOplog(data, len); if (!status.isOK()) return status; loc = status.getValue(); if (loc > _oplog_highestSeen) { stdx::lock_guard<stdx::mutex> lk(_uncommittedDiskLocsMutex); if (loc > _oplog_highestSeen) { _oplog_highestSeen = loc; } } } else if (_isCapped) { stdx::lock_guard<stdx::mutex> lk(_uncommittedDiskLocsMutex); loc = _nextId(); _addUncommitedDiskLoc_inlock(txn, loc); } else { loc = _nextId(); } WiredTigerCursor curwrap(_uri, _tableId, true, txn); curwrap.assertInActiveTxn(); WT_CURSOR* c = curwrap.get(); invariant(c); c->set_key(c, _makeKey(loc)); WiredTigerItem value(data, len); c->set_value(c, value.Get()); int ret = WT_OP_CHECK(c->insert(c)); if (ret) { return StatusWith<RecordId>(wtRCToStatus(ret, "WiredTigerRecordStore::insertRecord")); } _changeNumRecords(txn, 1); _increaseDataSize(txn, len); cappedDeleteAsNeeded(txn, loc); return StatusWith<RecordId>(loc); }
Status WiredTigerRecordStore::truncate(OperationContext* txn) { WiredTigerCursor startWrap(_uri, _tableId, true, txn); WT_CURSOR* start = startWrap.get(); int ret = WT_OP_CHECK(start->next(start)); // Empty collections don't have anything to truncate. if (ret == WT_NOTFOUND) { return Status::OK(); } invariantWTOK(ret); WT_SESSION* session = WiredTigerRecoveryUnit::get(txn)->getSession(txn)->getSession(); invariantWTOK(WT_OP_CHECK(session->truncate(session, NULL, start, NULL, NULL))); _changeNumRecords(txn, -numRecords(txn)); _increaseDataSize(txn, -dataSize(txn)); return Status::OK(); }
void WiredTigerRecordStore::deleteRecord(OperationContext* txn, const RecordId& loc) { WiredTigerCursor cursor(_uri, _tableId, true, txn); cursor.assertInActiveTxn(); WT_CURSOR* c = cursor.get(); c->set_key(c, _makeKey(loc)); int ret = WT_OP_CHECK(c->search(c)); invariantWTOK(ret); WT_ITEM old_value; ret = c->get_value(c, &old_value); invariantWTOK(ret); int old_length = old_value.size; ret = WT_OP_CHECK(c->remove(c)); invariantWTOK(ret); _changeNumRecords(txn, -1); _increaseDataSize(txn, -old_length); }
StatusWith<DiskLoc> RocksRecordStore::insertRecord( OperationContext* txn, const char* data, int len, bool enforceQuota ) { if ( _isCapped && len > _cappedMaxSize ) { return StatusWith<DiskLoc>( ErrorCodes::BadValue, "object to insert exceeds cappedMaxSize" ); } RocksRecoveryUnit* ru = _getRecoveryUnit( txn ); DiskLoc loc = _nextId(); ru->writeBatch()->Put( _columnFamily, _makeKey( loc ), rocksdb::Slice( data, len ) ); _changeNumRecords( txn, true ); _increaseDataSize( txn, len ); cappedDeleteAsNeeded(txn); return StatusWith<DiskLoc>( loc ); }
int64_t WiredTigerRecordStore::cappedDeleteAsNeeded_inlock(OperationContext* txn, const RecordId& justInserted) { // we do this is a side transaction in case it aborts WiredTigerRecoveryUnit* realRecoveryUnit = checked_cast<WiredTigerRecoveryUnit*>(txn->releaseRecoveryUnit()); invariant(realRecoveryUnit); WiredTigerSessionCache* sc = realRecoveryUnit->getSessionCache(); OperationContext::RecoveryUnitState const realRUstate = txn->setRecoveryUnit(new WiredTigerRecoveryUnit(sc), OperationContext::kNotInUnitOfWork); WiredTigerRecoveryUnit::get(txn)->markNoTicketRequired(); // realRecoveryUnit already has WT_SESSION* session = WiredTigerRecoveryUnit::get(txn)->getSession(txn)->getSession(); int64_t dataSize = _dataSize.load(); int64_t numRecords = _numRecords.load(); int64_t sizeOverCap = (dataSize > _cappedMaxSize) ? dataSize - _cappedMaxSize : 0; int64_t sizeSaved = 0; int64_t docsOverCap = 0, docsRemoved = 0; if (_cappedMaxDocs != -1 && numRecords > _cappedMaxDocs) docsOverCap = numRecords - _cappedMaxDocs; try { WriteUnitOfWork wuow(txn); WiredTigerCursor curwrap(_uri, _tableId, true, txn); WT_CURSOR* c = curwrap.get(); RecordId newestOld; int ret = 0; while ((sizeSaved < sizeOverCap || docsRemoved < docsOverCap) && (docsRemoved < 20000) && (ret = WT_OP_CHECK(c->next(c))) == 0) { int64_t key; ret = c->get_key(c, &key); invariantWTOK(ret); // don't go past the record we just inserted newestOld = _fromKey(key); if (newestOld >= justInserted) // TODO: use oldest uncommitted instead break; if (_shuttingDown) break; WT_ITEM old_value; invariantWTOK(c->get_value(c, &old_value)); ++docsRemoved; sizeSaved += old_value.size; if (_cappedDeleteCallback) { uassertStatusOK(_cappedDeleteCallback->aboutToDeleteCapped( txn, newestOld, RecordData(static_cast<const char*>(old_value.data), old_value.size))); } } if (ret != WT_NOTFOUND) { invariantWTOK(ret); } if (docsRemoved > 0) { // if we scanned to the end of the collection or past our insert, go back one if (ret == WT_NOTFOUND || newestOld >= justInserted) { ret = WT_OP_CHECK(c->prev(c)); } invariantWTOK(ret); WiredTigerCursor startWrap(_uri, _tableId, true, txn); WT_CURSOR* start = startWrap.get(); ret = WT_OP_CHECK(start->next(start)); invariantWTOK(ret); ret = session->truncate(session, NULL, start, c, NULL); if (ret == ENOENT || ret == WT_NOTFOUND) { // TODO we should remove this case once SERVER-17141 is resolved log() << "Soft failure truncating capped collection. Will try again later."; docsRemoved = 0; } else { invariantWTOK(ret); _changeNumRecords(txn, -docsRemoved); _increaseDataSize(txn, -sizeSaved); wuow.commit(); } } } catch (const WriteConflictException& wce) { delete txn->releaseRecoveryUnit(); txn->setRecoveryUnit(realRecoveryUnit, realRUstate); log() << "got conflict truncating capped, ignoring"; return 0; } catch (...) { delete txn->releaseRecoveryUnit(); txn->setRecoveryUnit(realRecoveryUnit, realRUstate); throw; } delete txn->releaseRecoveryUnit(); txn->setRecoveryUnit(realRecoveryUnit, realRUstate); return docsRemoved; }