RecordId KVRecordStore::KVRecordCursor::getNext() {
        if (isEOF()) {
            return RecordId();
        }

        // We need valid copies of _savedLoc / _savedVal since we are
        // about to advance the underlying cursor.
        _saveLocAndVal();
        _cursor->advance(_txn);

        if (!isEOF()) {
            if (_idTracker) {
                RecordId currentId = curr();
                if (!_lowestInvisible.isNull()) {
                    // oplog
                    if (currentId >= _lowestInvisible) {
                        _cursor.reset();
                    } else if (RecordId(currentId.repr() + 1) == _lowestInvisible && !_idTracker->canReadId(currentId)) {
                        _cursor.reset();
                    }
                } else if (!_idTracker->canReadId(currentId)) {
                    _cursor.reset();
                }
            }
        }

        return _savedLoc;
    }
Status
TerarkDbRecordStore::updateRecord(OperationContext* txn,
								const RecordId& id,
								const char* data,
								int len,
								bool enforceQuota,
								UpdateNotifier* notifier) {
	CompositeTable* tab = m_table->m_tab.get();
	terark::db::IncrementGuard_size_t incrGuard(tab->m_inprogressWritingCount);
	llong recId = id.repr() - 1;
	{
		terark::db::MyRwLock lock(tab->m_rwMutex, false);
		size_t segIdx = tab->getSegmentIndexOfRecordIdNoLock(recId);
		if (segIdx >= tab->getSegNum()) {
			return {ErrorCodes::InvalidIdField, "record id is out of range"};
		}
		auto seg = tab->getSegmentPtr(segIdx);
		if (seg->m_isFreezed) {
			return {ErrorCodes::NeedsDocumentMove, "segment of record is frozen"};
		}
	}
    auto& td = m_table->getMyThreadData();
    BSONObj bson(data);
    td.m_coder.encode(&tab->rowSchema(), nullptr, bson, &td.m_buf);
	llong newRecId = tab->updateRow(recId, td.m_buf, &*td.m_dbCtx);
	invariant(newRecId == recId);
	return Status::OK();
}
예제 #3
0
Status MobileRecordStore::insertRecords(OperationContext* opCtx,
                                        std::vector<Record>* inOutRecords,
                                        const std::vector<Timestamp>& timestamps) {
    // Inserts record into SQLite table (or replaces if duplicate record id).
    MobileSession* session = MobileRecoveryUnit::get(opCtx)->getSession(opCtx, false);

    SqliteStatement insertStmt(
        *session, "INSERT OR REPLACE INTO \"", _ident, "\"(rec_id, data) VALUES(?, ?);");

    for (auto& record : *inOutRecords) {
        const auto data = record.data.data();
        const auto len = record.data.size();

        _changeNumRecs(opCtx, 1);
        _changeDataSize(opCtx, len);

        RecordId recId = _nextId();
        insertStmt.bindInt(0, recId.repr());
        insertStmt.bindBlob(1, data, len);
        insertStmt.step(SQLITE_DONE);

        record.id = recId;
        insertStmt.reset();
    }

    return Status::OK();
}
예제 #4
0
void MobileRecordStore::deleteRecord(OperationContext* opCtx, const RecordId& recId) {
    MobileSession* session = MobileRecoveryUnit::get(opCtx)->getSession(opCtx, false);

    SqliteStatement dataSizeStmt(
        *session, "SELECT IFNULL(LENGTH(data), 0) FROM \"", _ident, "\" WHERE rec_id = ?;");
    dataSizeStmt.bindInt(0, recId.repr());
    dataSizeStmt.step(SQLITE_ROW);

    int64_t dataSizeBefore = dataSizeStmt.getColInt(0);
    _changeNumRecs(opCtx, -1);
    _changeDataSize(opCtx, -dataSizeBefore);

    SqliteStatement deleteStmt(*session, "DELETE FROM \"", _ident, "\" WHERE rec_id = ?;");
    deleteStmt.bindInt(0, recId.repr());
    deleteStmt.step(SQLITE_DONE);
}
예제 #5
0
Status MobileRecordStore::updateRecord(OperationContext* opCtx,
                                       const RecordId& recId,
                                       const char* data,
                                       int len) {
    MobileSession* session = MobileRecoveryUnit::get(opCtx)->getSession(opCtx, false);

    SqliteStatement dataSizeStmt(
        *session, "SELECT IFNULL(LENGTH(data), 0) FROM \"", _ident, "\" WHERE rec_id = ?;");
    dataSizeStmt.bindInt(0, recId.repr());
    dataSizeStmt.step(SQLITE_ROW);

    int64_t dataSizeBefore = dataSizeStmt.getColInt(0);
    _changeDataSize(opCtx, -dataSizeBefore + len);

    SqliteStatement updateStmt(
        *session, "UPDATE \"", _ident, "\" SET data = ? ", "WHERE rec_id = ?;");
    updateStmt.bindBlob(0, data, len);
    updateStmt.bindInt(1, recId.repr());
    updateStmt.step(SQLITE_DONE);

    return Status::OK();
}
bool TerarkDbRecordStore::findRecord(OperationContext* txn,
								   const RecordId& id,
								   RecordData* out) const {
	if (id.isNull())
		return false;
    llong recIdx = id.repr() - 1;
	CompositeTable* tab = m_table->m_tab.get();
    auto& td = m_table->getMyThreadData();
    tab->getValue(recIdx, &td.m_buf, &*td.m_dbCtx);
    SharedBuffer bson = td.m_coder.decode(&tab->rowSchema(), td.m_buf);

//  size_t bufsize = sizeof(SharedBuffer::Holder) + bson.objsize();
    int bufsize = ConstDataView(bson.get()).read<LittleEndian<int>>();
    *out = RecordData(bson, bufsize);
    return true;
}
예제 #7
0
    boost::optional<Record> seekExact(const RecordId& id) final {
        // Set the saved position and use save/restore to reprepare the SQL statement so that
        // the cursor restarts at the parameter id.
        int decr = (_forward ? -1 : 1);
        _savedId = RecordId(id.repr() + decr);
        _eof = false;

        save();
        restore();

        boost::optional<Record> rec = next();
        if (rec && rec->id != id) {
            // The record we found isn't the one the caller asked for.
            return boost::none;
        }

        return rec;
    }
예제 #8
0
bool MobileRecordStore::findRecord(OperationContext* opCtx,
                                   const RecordId& recId,
                                   RecordData* rd) const {
    MobileSession* session = MobileRecoveryUnit::get(opCtx)->getSession(opCtx);
    SqliteStatement stmt(*session, "SELECT data FROM \"", _ident, "\" WHERE rec_id = ?;");

    stmt.bindInt(0, recId.repr());

    int status = stmt.step();
    if (status == SQLITE_DONE) {
        return false;
    }
    embedded::checkStatus(status, SQLITE_ROW, "sqlite3_step");

    const void* recData = stmt.getColBlob(0);
    int nBytes = stmt.getColBytes(0);
    *rd = RecordData(static_cast<const char*>(recData), nBytes).getOwned();
    return true;
}
예제 #9
0
 void putRecordId(void* dest, RecordId loc) {
     const RecordIdRepr repr = loc.repr();
     memcpy(dest, &repr, sizeof(repr));
 }
void TerarkDbRecordStore::deleteRecord(OperationContext* txn, const RecordId& id) {
    auto& td = m_table->getMyThreadData();
    m_table->m_tab->removeRow(id.repr()-1, &*td.m_dbCtx);
}
예제 #11
0
int64_t WiredTigerRecordStore::_makeKey(const RecordId& loc) {
    return loc.repr();
}
예제 #12
0
TEST(KeyStringTest, RecordIds) {
    for (int i = 0; i < 63; i++) {
        const RecordId rid = RecordId(1ll << i);

        {  // Test encoding / decoding of single RecordIds
            const KeyString ks(rid);
            ASSERT_GTE(ks.getSize(), 2u);
            ASSERT_LTE(ks.getSize(), 10u);

            ASSERT_EQ(KeyString::decodeRecordIdAtEnd(ks.getBuffer(), ks.getSize()), rid);

            {
                BufReader reader(ks.getBuffer(), ks.getSize());
                ASSERT_EQ(KeyString::decodeRecordId(&reader), rid);
                ASSERT(reader.atEof());
            }

            if (rid.isNormal()) {
                ASSERT_GT(ks, KeyString(RecordId()));
                ASSERT_GT(ks, KeyString(RecordId::min()));
                ASSERT_LT(ks, KeyString(RecordId::max()));

                ASSERT_GT(ks, KeyString(RecordId(rid.repr() - 1)));
                ASSERT_LT(ks, KeyString(RecordId(rid.repr() + 1)));
            }
        }

        for (int j = 0; j < 63; j++) {
            RecordId other = RecordId(1ll << j);

            if (rid == other)
                ASSERT_EQ(KeyString(rid), KeyString(other));
            if (rid < other)
                ASSERT_LT(KeyString(rid), KeyString(other));
            if (rid > other)
                ASSERT_GT(KeyString(rid), KeyString(other));

            {
                // Test concatenating RecordIds like in a unique index.
                KeyString ks;
                ks.appendRecordId(RecordId::max());  // uses all bytes
                ks.appendRecordId(rid);
                ks.appendRecordId(RecordId(0xDEADBEEF));  // uses some extra bytes
                ks.appendRecordId(rid);
                ks.appendRecordId(RecordId(1));  // uses no extra bytes
                ks.appendRecordId(rid);
                ks.appendRecordId(other);

                ASSERT_EQ(KeyString::decodeRecordIdAtEnd(ks.getBuffer(), ks.getSize()), other);

                // forward scan
                BufReader reader(ks.getBuffer(), ks.getSize());
                ASSERT_EQ(KeyString::decodeRecordId(&reader), RecordId::max());
                ASSERT_EQ(KeyString::decodeRecordId(&reader), rid);
                ASSERT_EQ(KeyString::decodeRecordId(&reader), RecordId(0xDEADBEEF));
                ASSERT_EQ(KeyString::decodeRecordId(&reader), rid);
                ASSERT_EQ(KeyString::decodeRecordId(&reader), RecordId(1));
                ASSERT_EQ(KeyString::decodeRecordId(&reader), rid);
                ASSERT_EQ(KeyString::decodeRecordId(&reader), other);
                ASSERT(reader.atEof());
            }
        }
    }
}