void testSetEndPosition_Seek_Reverse(bool unique, bool inclusive) {
    auto harnessHelper = newHarnessHelper();
    auto opCtx = harnessHelper->newOperationContext();
    auto sorted = harnessHelper->newSortedDataInterface(unique,
                                                        {
                                                         {key1, loc1},
                                                         {key2, loc1},
                                                         // No key3
                                                         {key4, loc1},
                                                        });

    auto cursor = sorted->newCursor(opCtx.get(), false);
    cursor->setEndPosition(key2, inclusive);

    // Directly seeking past end is considered out of range.
    ASSERT_EQ(cursor->seek(key1, true), boost::none);
    ASSERT_EQ(cursor->seekExact(key1), boost::none);

    // Seeking to key2 directly or indirectly is only returned if endPosition is inclusive.
    auto maybeKey2 = inclusive ? boost::make_optional(IndexKeyEntry(key2, loc1)) : boost::none;

    // direct
    ASSERT_EQ(cursor->seek(key2, true), maybeKey2);
    ASSERT_EQ(cursor->seekExact(key2), maybeKey2);

    // indirect
    ASSERT_EQ(cursor->seek(key3, true), maybeKey2);

    cursor->saveUnpositioned();
    removeFromIndex(opCtx, sorted, {{key2, loc1}});
    cursor->restore();

    ASSERT_EQ(cursor->seek(key3, true), boost::none);
    ASSERT_EQ(cursor->seek(key2, true), boost::none);
}
Beispiel #2
0
void CueControl::trackLoaded(TrackPointer pTrack) {
    QMutexLocker lock(&m_mutex);
    if (m_pLoadedTrack)
        trackUnloaded(m_pLoadedTrack);

    if (!pTrack) {
        return;
    }

    m_pLoadedTrack = pTrack;
    connect(pTrack.data(), SIGNAL(cuesUpdated()),
            this, SLOT(trackCuesUpdated()),
            Qt::DirectConnection);

    Cue* loadCue = NULL;
    const QList<Cue*>& cuePoints = pTrack->getCuePoints();
    QListIterator<Cue*> it(cuePoints);
    while (it.hasNext()) {
        Cue* pCue = it.next();
        if (pCue->getType() == Cue::LOAD) {
            loadCue = pCue;
        } else if (pCue->getType() != Cue::CUE) {
            continue;
        }
        int hotcue = pCue->getHotCue();
        if (hotcue != -1)
            attachCue(pCue, hotcue);
    }

    double loadCuePoint = 0.0;
    // If cue recall is ON in the prefs, then we're supposed to seek to the cue
    // point on song load. Note that [Controls],cueRecall == 0 corresponds to "ON", not OFF.
    bool cueRecall = (getConfig()->getValueString(
                ConfigKey("[Controls]","CueRecall"), "0").toInt() == 0);
    if (loadCue != NULL) {
        m_pCuePoint->set(loadCue->getPosition());
        if (cueRecall) {
            loadCuePoint = loadCue->getPosition();
        }
    } else {
        // If no cue point is stored, set one at track start
        m_pCuePoint->set(0.0);
    }

    // Need to unlock before emitting any signals to prevent deadlock.
    lock.unlock();
    // If cueRecall is on, seek to it even if we didn't find a cue value (we'll
    // seek to 0.
    if (cueRecall) {
        seekExact(loadCuePoint);
    } else if (!(m_pVinylControlEnabled->get() &&
            m_pVinylControlMode->get() == MIXXX_VCMODE_ABSOLUTE)) {
        // If cuerecall is off, seek to zero unless
        // vinylcontrol is on and set to absolute.  This allows users to
        // load tracks and have the needle-drop be maintained.
        seekExact(0.0);
    }
}
Beispiel #3
0
void
DbContext::getWrSegWrtStoreData(const ReadableSegment* seg, llong subId, valvec<byte>* buf) {
	assert(seg->getWritableSegment() != NULL);
	assert(!seg->m_hasLockFreePointSearch);
	auto sctx = m_segCtx.data();
	size_t segIdx = m_segCtx.size();
	while (segIdx > 0) {
		auto seg2 = sctx[--segIdx]->seg;
		if (seg2 == seg) {
			auto wrtStoreIter = getWrtStoreIterNoLock(segIdx);
			buf->erase_all();
			wrtStoreIter->reset();
			if (!wrtStoreIter->seekExact(subId, buf)) {
				llong baseId = m_rowNumVec[segIdx];
				throw ReadRecordException("wrtStoreIter->seekExact",
					seg->m_segDir.string().c_str(), baseId, subId);
			}
			wrtStoreIter->reset();
			return;
		}
	}
	fprintf(stderr
		, "WARN: DbContext::getWrSegWrtStoreData: not found segment: %s\n"
		, seg->m_segDir.string().c_str());
	// fallback to slow locked getValue:
	WritableSegment* wrseg = seg->getWritableSegment();
	assert(wrseg != nullptr);
	wrseg->m_wrtStore->getValue(subId, buf, this);
}
    // Tests seekExact when it doesn't hit the query.
    void testSeekExact_Miss(bool unique, bool forward) {
        auto harnessHelper = newHarnessHelper();
        auto opCtx = harnessHelper->newOperationContext();
        auto sorted = harnessHelper->newSortedDataInterface(unique, {
            {key1, loc1},
            // No key2.
            {key3, loc1},
        });

        auto cursor = sorted->newCursor(opCtx.get(), forward);

        ASSERT_EQ(cursor->seekExact(key2), boost::none);

        // Not testing iteration since the cursors position following a failed seekExact is
        // undefined. However, you must be able to seek somewhere else.
        ASSERT_EQ(cursor->seekExact(key1), IndexKeyEntry(key1, loc1));
    }
Beispiel #5
0
void CueControl::hotcueActivatePreview(HotcueControl* pControl, double v) {
    QMutexLocker lock(&m_mutex);
    if (!m_pLoadedTrack)
        return;
    Cue* pCue = pControl->getCue();

    if (v) {
        if (pCue && pCue->getPosition() != -1) {
            m_iCurrentlyPreviewingHotcues++;
            int iPosition = pCue->getPosition();
            m_pPlayButton->set(1.0);
            m_bPreviewingHotcue = true;
            pControl->setPreviewing(true);
            pControl->setPreviewingPosition(iPosition);

            // Need to unlock before emitting any signals to prevent deadlock.
            lock.unlock();

            seekAbs(iPosition);
        }
    } else if (m_bPreviewingHotcue) {
        // This is a activate release and we are previewing at least one
        // hotcue. If this hotcue is previewing:
        if (pControl->isPreviewing()) {
            // Mark this hotcue as not previewing.
            int iPosition = pControl->getPreviewingPosition();
            pControl->setPreviewing(false);
            pControl->setPreviewingPosition(-1);

            // If this is the last hotcue to leave preview.
            if (--m_iCurrentlyPreviewingHotcues == 0) {
                bool bHotcueCancel = m_bHotcueCancel;
                m_bPreviewingHotcue = false;
                m_bHotcueCancel = false;
                // If hotcue cancel is marked then do not snap back to the
                // hotcue and stop. Otherwise, seek back to the start point and
                // stop.
                if (bHotcueCancel) {
                    // Re-trigger the play button value so controllers get the correct one
                    // after.
                    m_pPlayButton->set(m_pPlayButton->get());
                } else {
                    m_pPlayButton->set(0.0);
                    // Need to unlock before emitting any signals to prevent deadlock.
                    lock.unlock();
                    seekExact(iPosition);
                }
            }
        }
    }
}
Beispiel #6
0
void CueControl::cueGotoAndStop(double v)
{
    if (!v)
        return;

    QMutexLocker lock(&m_mutex);
    m_pPlayButton->set(0.0);
    double cuePoint = m_pCuePoint->get();

    // Need to unlock before emitting any signals to prevent deadlock.
    lock.unlock();

    seekExact(cuePoint);
}
Beispiel #7
0
void CueControl::trackLoaded(TrackPointer pTrack) {
    QMutexLocker lock(&m_mutex);
    if (m_pLoadedTrack)
        trackUnloaded(m_pLoadedTrack);

    if (!pTrack) {
        return;
    }

    m_pLoadedTrack = pTrack;
    connect(pTrack.data(), SIGNAL(cuesUpdated()),
            this, SLOT(trackCuesUpdated()),
            Qt::DirectConnection);

    Cue* loadCue = NULL;
    const QList<Cue*>& cuePoints = pTrack->getCuePoints();
    QListIterator<Cue*> it(cuePoints);
    while (it.hasNext()) {
        Cue* pCue = it.next();
        if (pCue->getType() == Cue::LOAD) {
            loadCue = pCue;
        } else if (pCue->getType() != Cue::CUE) {
            continue;
        }
        int hotcue = pCue->getHotCue();
        if (hotcue != -1)
            attachCue(pCue, hotcue);
    }

    double loadCuePoint = 0.0;
    if (loadCue != NULL) {
        m_pCuePoint->set(loadCue->getPosition());

        // If cue recall is ON in the prefs, then we're supposed to seek to the cue
        // point on song load. Note that [Controls],cueRecall == 0 corresponds to "ON", not OFF.
        if (!getConfig()->getValueString(
                ConfigKey("[Controls]","CueRecall")).toInt()) {
            loadCuePoint = loadCue->getPosition();
        }
    } else {
        // If no cue point is stored, set one at track start
        m_pCuePoint->set(0.0);
    }

    // Need to unlock before emitting any signals to prevent deadlock.
    lock.unlock();
    seekExact(loadCuePoint);
}
    // Tests seekExact on reverse cursor when it hits something with dup keys. Doesn't make sense
    // for unique indexes.
    TEST(SortedDataInterface, SeekExact_HitWithDups_Reverse) {
        auto harnessHelper = newHarnessHelper();
        auto opCtx = harnessHelper->newOperationContext();
        auto sorted = harnessHelper->newSortedDataInterface(false, {
            {key1, loc1},
            {key2, loc1},
            {key2, loc2},
            {key3, loc1},
        });

        auto cursor = sorted->newCursor(opCtx.get(), false);

        ASSERT_EQ(cursor->seekExact(key2), IndexKeyEntry(key2, loc2));
        ASSERT_EQ(cursor->next(), IndexKeyEntry(key2, loc1));
        ASSERT_EQ(cursor->next(), IndexKeyEntry(key1, loc1));
        ASSERT_EQ(cursor->next(), boost::none);
    }
    // Tests seekExact when it hits something.
    void testSeekExact_Hit(bool unique, bool forward) {
        auto harnessHelper = newHarnessHelper();
        auto opCtx = harnessHelper->newOperationContext();
        auto sorted = harnessHelper->newSortedDataInterface(unique, {
            {key1, loc1},
            {key2, loc1},
            {key3, loc1},
        });

        auto cursor = sorted->newCursor(opCtx.get(), forward);

        ASSERT_EQ(cursor->seekExact(key2), IndexKeyEntry(key2, loc1));

        // Make sure iterating works. We may consider loosening this requirement if it is a hardship
        // for some storage engines.
        ASSERT_EQ(cursor->next(), IndexKeyEntry(forward ? key3 : key1, loc1));
        ASSERT_EQ(cursor->next(), boost::none);
    }
Beispiel #10
0
void CueControl::hotcueGotoAndStop(HotcueControl* pControl, double v) {
    if (!v)
        return;

    QMutexLocker lock(&m_mutex);
    if (!m_pLoadedTrack)
        return;

    Cue* pCue = pControl->getCue();

    // Need to unlock before emitting any signals to prevent deadlock.
    lock.unlock();

    if (pCue) {
        int position = pCue->getPosition();
        if (position != -1) {
            m_pPlayButton->set(0.0);
            seekExact(position);
        }
    }
}
Beispiel #11
0
void CueControl::hotcueActivatePreview(HotcueControl* pControl, double v) {
    QMutexLocker lock(&m_mutex);
    if (!m_pLoadedTrack) {
        return;
    }
    CuePointer pCue(pControl->getCue());

    if (v) {
        if (pCue && pCue->getPosition() != -1) {
            m_iCurrentlyPreviewingHotcues++;
            int iPosition = pCue->getPosition();
            m_bypassCueSetByPlay = true;
            m_pPlayButton->set(1.0);
            pControl->setPreviewing(true);
            pControl->setPreviewingPosition(iPosition);

            // Need to unlock before emitting any signals to prevent deadlock.
            lock.unlock();

            seekAbs(iPosition);
        }
    } else if (m_iCurrentlyPreviewingHotcues) {
        // This is a activate release and we are previewing at least one
        // hotcue. If this hotcue is previewing:
        if (pControl->isPreviewing()) {
            // Mark this hotcue as not previewing.
            int iPosition = pControl->getPreviewingPosition();
            pControl->setPreviewing(false);
            pControl->setPreviewingPosition(-1);

            // If this is the last hotcue to leave preview.
            if (--m_iCurrentlyPreviewingHotcues == 0 && !m_bPreviewing) {
                m_pPlayButton->set(0.0);
                // Need to unlock before emitting any signals to prevent deadlock.
                lock.unlock();
                seekExact(iPosition);
            }
        }
    }
}
Beispiel #12
0
void VinylControlControl::slotControlVinylSeek(double change) {
    if (isnan(change) || change > 1.14 || change < -0.14) {
        // This seek is ridiculous.
        return;
    }

    double total_samples = getTotalSamples();
    double new_playpos = round(change*total_samples);

    // Do nothing if no track is loaded.
    if (!m_pCurrentTrack) {
        return;
    }

    if (m_pControlVinylEnabled->get() > 0.0 && m_pControlVinylMode->get() == MIXXX_VCMODE_RELATIVE) {
        int cuemode = (int)m_pControlVinylCueing->get();

        //if in preroll, always seek
        if (new_playpos < 0) {
            seek(change);
            return;
        }

        switch (cuemode) {
        case MIXXX_RELATIVE_CUE_OFF:
            return; // If off, do nothing.
        case MIXXX_RELATIVE_CUE_ONECUE:
            //if onecue, just seek to the regular cue
            seekExact(m_pCurrentTrack->getCuePoint());
            return;
        case MIXXX_RELATIVE_CUE_HOTCUE:
            // Continue processing in this function.
            break;
        default:
            qWarning() << "Invalid vinyl cue setting";
            return;
        }

        double distance = 0;
        int nearest_playpos = -1;

        QList<Cue*> cuePoints = m_pCurrentTrack->getCuePoints();
        QListIterator<Cue*> it(cuePoints);
        while (it.hasNext()) {
            Cue* pCue = it.next();
            if (pCue->getType() != Cue::CUE || pCue->getHotCue() == -1) {
                continue;
            }

            int cue_position = pCue->getPosition();
            //pick cues closest to new_playpos
            if ((nearest_playpos == -1) ||
                (fabs(new_playpos - cue_position) < distance)) {
                nearest_playpos = cue_position;
                distance = fabs(new_playpos - cue_position);
            }
        }

        if (nearest_playpos == -1) {
            if (new_playpos >= 0) {
                //never found an appropriate cue, so don't seek?
                return;
            }
            //if negative, allow a seek by falling down to the bottom
        } else {
            m_bSeekRequested = true;
            seekExact(nearest_playpos);
            m_bSeekRequested = false;
            return;
        }
    }

    // Just seek where it wanted to originally.
    m_bSeekRequested = true;
    seek(change);
    m_bSeekRequested = false;
}
Beispiel #13
0
void CueControl::trackLoaded(TrackPointer pNewTrack, TrackPointer pOldTrack) {
    Q_UNUSED(pOldTrack);
    QMutexLocker lock(&m_mutex);

    if (m_pLoadedTrack) {
        disconnect(m_pLoadedTrack.data(), 0, this, 0);
        for (int i = 0; i < m_iNumHotCues; ++i) {
            detachCue(i);
        }

        // Store the cue point in a load cue.
        double cuePoint = m_pCuePoint->get();

        if (cuePoint != -1 && cuePoint != 0.0) {
            CuePointer loadCue;
            const QList<CuePointer> cuePoints(m_pLoadedTrack->getCuePoints());
            QListIterator<CuePointer> it(cuePoints);
            while (it.hasNext()) {
                CuePointer pCue(it.next());
                if (pCue->getType() == Cue::LOAD) {
                    loadCue = pCue;
                    break;
                }
            }
            if (!loadCue) {
                loadCue = m_pLoadedTrack->addCue();
                loadCue->setType(Cue::LOAD);
                loadCue->setLength(0);
            }
            loadCue->setPosition(cuePoint);
        }

        m_pCueIndicator->setBlinkValue(ControlIndicator::OFF);
        m_pCuePoint->set(-1.0);
        m_pLoadedTrack.clear();
    }


    if (pNewTrack.isNull()) {
        return;
    }

    m_pLoadedTrack = pNewTrack;
    connect(pNewTrack.data(), SIGNAL(cuesUpdated()),
            this, SLOT(trackCuesUpdated()),
            Qt::DirectConnection);

    CuePointer loadCue;
    const QList<CuePointer> cuePoints(pNewTrack->getCuePoints());
    QListIterator<CuePointer> it(cuePoints);
    while (it.hasNext()) {
        CuePointer pCue(it.next());
        if (pCue->getType() == Cue::LOAD) {
            loadCue = pCue;
        } else if (pCue->getType() != Cue::CUE) {
            continue;
        }
        int hotcue = pCue->getHotCue();
        if (hotcue != -1)
            attachCue(pCue, hotcue);
    }

    double loadCuePoint = 0.0;
    // If cue recall is ON in the prefs, then we're supposed to seek to the cue
    // point on song load. Note that [Controls],cueRecall == 0 corresponds to "ON", not OFF.
    bool cueRecall = (getConfig()->getValueString(
                ConfigKey("[Controls]","CueRecall"), "0").toInt() == 0);
    if (loadCue != NULL) {
        m_pCuePoint->set(loadCue->getPosition());
        if (cueRecall) {
            loadCuePoint = loadCue->getPosition();
        }
    } else {
        // If no cue point is stored, set one at track start
        m_pCuePoint->set(0.0);
    }

    // Need to unlock before emitting any signals to prevent deadlock.
    lock.unlock();
    // If cueRecall is on, seek to it even if we didn't find a cue value (we'll
    // seek to 0.
    if (cueRecall) {
        seekExact(loadCuePoint);
    } else if (!(m_pVinylControlEnabled->get() &&
            m_pVinylControlMode->get() == MIXXX_VCMODE_ABSOLUTE)) {
        // If cuerecall is off, seek to zero unless
        // vinylcontrol is on and set to absolute.  This allows users to
        // load tracks and have the needle-drop be maintained.
        seekExact(0.0);
    }
}
Beispiel #14
0
void CueControl::trackLoaded(TrackPointer pNewTrack, TrackPointer pOldTrack) {
    QMutexLocker lock(&m_mutex);

    DEBUG_ASSERT(m_pLoadedTrack == pOldTrack);
    if (m_pLoadedTrack) {
        disconnect(m_pLoadedTrack.get(), 0, this, 0);
        for (int i = 0; i < m_iNumHotCues; ++i) {
            detachCue(i);
        }

        m_pCueIndicator->setBlinkValue(ControlIndicator::OFF);
        m_pCuePoint->set(-1.0);
        m_pLoadedTrack.reset();
    }

    if (!pNewTrack) {
        return;
    }
    m_pLoadedTrack = pNewTrack;

    connect(m_pLoadedTrack.get(), SIGNAL(cuesUpdated()),
            this, SLOT(trackCuesUpdated()),
            Qt::DirectConnection);

    CuePointer pLoadCue;
    for (const CuePointer& pCue: m_pLoadedTrack->getCuePoints()) {
        if (pCue->getType() == Cue::CUE) {
            continue; // skip
        }
        if (pCue->getType() == Cue::LOAD) {
            DEBUG_ASSERT(!pLoadCue);
            pLoadCue = pCue;
        }
        int hotcue = pCue->getHotCue();
        if (hotcue != -1) {
            attachCue(pCue, hotcue);
        }
    }
    double cuePoint;
    if (pLoadCue) {
        cuePoint = pLoadCue->getPosition();
    } else {
        // If no load cue point is stored, read from track
        cuePoint = m_pLoadedTrack->getCuePoint();
    }
    m_pCuePoint->set(cuePoint);

    // Need to unlock before emitting any signals to prevent deadlock.
    lock.unlock();

    // Use pNewTrack here, because m_pLoadedTrack might have been reset
    // immediately after leaving the locking scope!
    pNewTrack->setCuePoint(cuePoint);

    // If cue recall is ON in the prefs, then we're supposed to seek to the cue
    // point on song load. Note that [Controls],cueRecall == 0 corresponds to "ON", not OFF.
    bool cueRecall = (getConfig()->getValueString(
                ConfigKey("[Controls]","CueRecall"), "0").toInt() == 0);
    if (cueRecall && (cuePoint >= 0.0)) {
        seekExact(cuePoint);
    } else if (!(m_pVinylControlEnabled->get() &&
            m_pVinylControlMode->get() == MIXXX_VCMODE_ABSOLUTE)) {
        // If cuerecall is off, seek to zero unless
        // vinylcontrol is on and set to absolute.  This allows users to
        // load tracks and have the needle-drop be maintained.
        seekExact(0.0);
    }

    trackCuesUpdated();
}