Search in sources :

Example 6 with UpdateLog

use of org.apache.solr.update.UpdateLog in project lucene-solr by apache.

the class ReplicateFromLeader method startReplication.

/**
   * Start a replication handler thread that will periodically pull indices from the shard leader
   * @param switchTransactionLog if true, ReplicationHandler will rotate the transaction log once
   * the replication is done
   */
public void startReplication(boolean switchTransactionLog) throws InterruptedException {
    try (SolrCore core = cc.getCore(coreName)) {
        if (core == null) {
            if (cc.isShutDown()) {
                return;
            } else {
                throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "SolrCore not found:" + coreName + " in " + cc.getLoadedCoreNames());
            }
        }
        SolrConfig.UpdateHandlerInfo uinfo = core.getSolrConfig().getUpdateHandlerInfo();
        String pollIntervalStr = "00:00:03";
        if (uinfo.autoCommmitMaxTime != -1) {
            pollIntervalStr = toPollIntervalStr(uinfo.autoCommmitMaxTime / 2);
        } else if (uinfo.autoSoftCommmitMaxTime != -1) {
            pollIntervalStr = toPollIntervalStr(uinfo.autoSoftCommmitMaxTime / 2);
        }
        LOG.info("Will start replication from leader with poll interval: {}", pollIntervalStr);
        NamedList slaveConfig = new NamedList();
        slaveConfig.add("fetchFromLeader", true);
        slaveConfig.add("pollInterval", pollIntervalStr);
        NamedList replicationConfig = new NamedList();
        replicationConfig.add("slave", slaveConfig);
        String lastCommitVersion = getCommitVersion(core);
        if (lastCommitVersion != null) {
            lastVersion = Long.parseLong(lastCommitVersion);
        }
        replicationProcess = new ReplicationHandler();
        if (switchTransactionLog) {
            replicationProcess.setPollListener((solrCore, pollSuccess) -> {
                if (pollSuccess) {
                    String commitVersion = getCommitVersion(core);
                    if (commitVersion == null)
                        return;
                    if (Long.parseLong(commitVersion) == lastVersion)
                        return;
                    UpdateLog updateLog = solrCore.getUpdateHandler().getUpdateLog();
                    SolrQueryRequest req = new LocalSolrQueryRequest(core, new ModifiableSolrParams());
                    CommitUpdateCommand cuc = new CommitUpdateCommand(req, false);
                    cuc.setVersion(Long.parseLong(commitVersion));
                    updateLog.copyOverOldUpdates(cuc);
                    lastVersion = Long.parseLong(commitVersion);
                }
            });
        }
        replicationProcess.init(replicationConfig);
        replicationProcess.inform(core);
    }
}
Also used : LocalSolrQueryRequest(org.apache.solr.request.LocalSolrQueryRequest) SolrConfig(org.apache.solr.core.SolrConfig) LocalSolrQueryRequest(org.apache.solr.request.LocalSolrQueryRequest) SolrQueryRequest(org.apache.solr.request.SolrQueryRequest) SolrCore(org.apache.solr.core.SolrCore) NamedList(org.apache.solr.common.util.NamedList) UpdateLog(org.apache.solr.update.UpdateLog) ReplicationHandler(org.apache.solr.handler.ReplicationHandler) CommitUpdateCommand(org.apache.solr.update.CommitUpdateCommand) SolrException(org.apache.solr.common.SolrException) ModifiableSolrParams(org.apache.solr.common.params.ModifiableSolrParams)

Example 7 with UpdateLog

use of org.apache.solr.update.UpdateLog in project lucene-solr by apache.

the class TestRecovery method testBuffering.

@Test
public void testBuffering() throws Exception {
    DirectUpdateHandler2.commitOnClose = false;
    final Semaphore logReplay = new Semaphore(0);
    final Semaphore logReplayFinish = new Semaphore(0);
    UpdateLog.testing_logReplayHook = () -> {
        try {
            assertTrue(logReplay.tryAcquire(timeout, TimeUnit.SECONDS));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    };
    UpdateLog.testing_logReplayFinishHook = logReplayFinish::release;
    SolrQueryRequest req = req();
    UpdateHandler uhandler = req.getCore().getUpdateHandler();
    UpdateLog ulog = uhandler.getUpdateLog();
    try {
        clearIndex();
        assertU(commit());
        Map<String, Metric> metrics = getMetrics();
        assertEquals(UpdateLog.State.ACTIVE, ulog.getState());
        ulog.bufferUpdates();
        assertEquals(UpdateLog.State.BUFFERING, ulog.getState());
        Future<UpdateLog.RecoveryInfo> rinfoFuture = ulog.applyBufferedUpdates();
        assertTrue(rinfoFuture == null);
        assertEquals(UpdateLog.State.ACTIVE, ulog.getState());
        ulog.bufferUpdates();
        assertEquals(UpdateLog.State.BUFFERING, ulog.getState());
        Gauge<Integer> state = (Gauge<Integer>) metrics.get("TLOG.state");
        assertEquals(UpdateLog.State.BUFFERING.ordinal(), state.getValue().intValue());
        Gauge<Integer> bufferedOps = (Gauge<Integer>) metrics.get("TLOG.buffered.ops");
        int initialOps = bufferedOps.getValue();
        Meter applyingBuffered = (Meter) metrics.get("TLOG.applyingBuffered.ops");
        long initialApplyingOps = applyingBuffered.getCount();
        String v3 = getNextVersion();
        String v940_del = "-" + getNextVersion();
        String v950_del = "-" + getNextVersion();
        String v1010 = getNextVersion();
        String v1015 = getNextVersion();
        String v1017_del = "-" + getNextVersion();
        String v1020 = getNextVersion();
        String v1030 = getNextVersion();
        String v1040 = getNextVersion();
        String v1050 = getNextVersion();
        String v1060 = getNextVersion();
        String v1070 = getNextVersion();
        String v1080 = getNextVersion();
        String v2010_del = "-" + getNextVersion();
        String v2060_del = "-" + getNextVersion();
        String v3000_del = "-" + getNextVersion();
        String versionListFirstCheck = String.join(",", v2010_del, v1030, v1020, v1017_del, v1015, v1010);
        String versionListSecondCheck = String.join(",", v3000_del, v1080, v1050, v1060, v940_del, v1040, v3, v2010_del, v1030, v1020, v1017_del, v1015, v1010);
        // simulate updates from a leader
        updateJ(jsonAdd(sdoc("id", "B1", "_version_", v1010)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        updateJ(jsonAdd(sdoc("id", "B11", "_version_", v1015)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        updateJ(jsonDelQ("id:B1 id:B11 id:B2 id:B3"), params(DISTRIB_UPDATE_PARAM, FROM_LEADER, "_version_", v1017_del));
        updateJ(jsonAdd(sdoc("id", "B2", "_version_", v1020)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        updateJ(jsonAdd(sdoc("id", "B3", "_version_", v1030)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        deleteAndGetVersion("B1", params(DISTRIB_UPDATE_PARAM, FROM_LEADER, "_version_", v2010_del));
        assertJQ(req("qt", "/get", "getVersions", "6"), "=={'versions':[" + versionListFirstCheck + "]}");
        assertU(commit());
        assertJQ(req("qt", "/get", "getVersions", "6"), "=={'versions':[" + versionListFirstCheck + "]}");
        // updates should be buffered, so we should not see any results yet.
        assertJQ(req("q", "*:*"), "/response/numFound==0");
        // real-time get should also not show anything (this could change in the future,
        // but it's currently used for validating version numbers too, so it would
        // be bad for updates to be visible if we're just buffering.
        assertJQ(req("qt", "/get", "id", "B3"), "=={'doc':null}");
        assertEquals(6, bufferedOps.getValue().intValue() - initialOps);
        rinfoFuture = ulog.applyBufferedUpdates();
        assertTrue(rinfoFuture != null);
        assertEquals(UpdateLog.State.APPLYING_BUFFERED, ulog.getState());
        logReplay.release(1000);
        UpdateLog.RecoveryInfo rinfo = rinfoFuture.get();
        assertEquals(UpdateLog.State.ACTIVE, ulog.getState());
        assertEquals(6L, applyingBuffered.getCount() - initialApplyingOps);
        assertJQ(req("qt", "/get", "getVersions", "6"), "=={'versions':[" + versionListFirstCheck + "]}");
        assertJQ(req("q", "*:*"), "/response/numFound==2");
        // move back to recovering
        ulog.bufferUpdates();
        assertEquals(UpdateLog.State.BUFFERING, ulog.getState());
        Long ver = getVer(req("qt", "/get", "id", "B3"));
        assertEquals(Long.valueOf(v1030), ver);
        // add a reordered doc that shouldn't overwrite one in the index
        updateJ(jsonAdd(sdoc("id", "B3", "_version_", v3)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        // reorder two buffered updates
        updateJ(jsonAdd(sdoc("id", "B4", "_version_", v1040)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        // this update should not take affect
        deleteAndGetVersion("B4", params(DISTRIB_UPDATE_PARAM, FROM_LEADER, "_version_", v940_del));
        updateJ(jsonAdd(sdoc("id", "B6", "_version_", v1060)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        updateJ(jsonAdd(sdoc("id", "B5", "_version_", v1050)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        updateJ(jsonAdd(sdoc("id", "B8", "_version_", v1080)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        // test that delete by query is at least buffered along with everything else so it will delete the
        // currently buffered id:8 (even if it doesn't currently support versioning)
        updateJ("{\"delete\": { \"query\":\"id:B2 OR id:B8\" }}", params(DISTRIB_UPDATE_PARAM, FROM_LEADER, "_version_", v3000_del));
        assertJQ(req("qt", "/get", "getVersions", "13"), // the "3" appears because versions aren't checked while buffering
        "=={'versions':[" + versionListSecondCheck + "]}");
        logReplay.drainPermits();
        rinfoFuture = ulog.applyBufferedUpdates();
        assertTrue(rinfoFuture != null);
        assertEquals(UpdateLog.State.APPLYING_BUFFERED, ulog.getState());
        // apply a single update
        logReplay.release(1);
        // now add another update
        updateJ(jsonAdd(sdoc("id", "B7", "_version_", v1070)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        // a reordered update that should be dropped
        deleteAndGetVersion("B5", params(DISTRIB_UPDATE_PARAM, FROM_LEADER, "_version_", v950_del));
        deleteAndGetVersion("B6", params(DISTRIB_UPDATE_PARAM, FROM_LEADER, "_version_", v2060_del));
        logReplay.release(1000);
        UpdateLog.RecoveryInfo recInfo = rinfoFuture.get();
        assertJQ(req("q", "*:*", "sort", "id asc", "fl", "id,_version_"), "/response/docs==[" + "{'id':'B3','_version_':" + v1030 + "}" + ",{'id':'B4','_version_':" + v1040 + "}" + ",{'id':'B5','_version_':" + v1050 + "}" + ",{'id':'B7','_version_':" + v1070 + "}" + "]");
        assertEquals(1, recInfo.deleteByQuery);
        // leave each test method in a good state
        assertEquals(UpdateLog.State.ACTIVE, ulog.getState());
        assertEquals(0, bufferedOps.getValue().intValue());
    } finally {
        DirectUpdateHandler2.commitOnClose = true;
        UpdateLog.testing_logReplayHook = null;
        UpdateLog.testing_logReplayFinishHook = null;
        req().close();
    }
}
Also used : UpdateHandler(org.apache.solr.update.UpdateHandler) Meter(com.codahale.metrics.Meter) Semaphore(java.util.concurrent.Semaphore) Gauge(com.codahale.metrics.Gauge) SolrQueryRequest(org.apache.solr.request.SolrQueryRequest) UpdateLog(org.apache.solr.update.UpdateLog) Metric(com.codahale.metrics.Metric) Test(org.junit.Test)

Example 8 with UpdateLog

use of org.apache.solr.update.UpdateLog in project lucene-solr by apache.

the class TestRecovery method deleteLogs.

// stops the core, removes the transaction logs, restarts the core.
void deleteLogs() throws Exception {
    UpdateLog ulog = h.getCore().getUpdateHandler().getUpdateLog();
    File logDir = new File(h.getCore().getUpdateHandler().getUpdateLog().getLogDir());
    h.close();
    try {
        String[] files = ulog.getLogList(logDir);
        for (String file : files) {
            Files.delete(new File(logDir, file).toPath());
        }
        assertEquals(0, ulog.getLogList(logDir).length);
    } finally {
        // make sure we create the core again, even if the assert fails so it won't mess
        // up the next test.
        createCore();
        // ensure it works
        assertJQ(req("q", "*:*"), "/response/numFound==");
    }
}
Also used : UpdateLog(org.apache.solr.update.UpdateLog) RandomAccessFile(java.io.RandomAccessFile) File(java.io.File)

Example 9 with UpdateLog

use of org.apache.solr.update.UpdateLog in project lucene-solr by apache.

the class TestRecovery method testBufferedMultipleCalls.

@Test
public void testBufferedMultipleCalls() throws Exception {
    DirectUpdateHandler2.commitOnClose = false;
    final Semaphore logReplay = new Semaphore(0);
    final Semaphore logReplayFinish = new Semaphore(0);
    UpdateLog.testing_logReplayHook = () -> {
        try {
            assertTrue(logReplay.tryAcquire(timeout, TimeUnit.SECONDS));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    };
    UpdateLog.testing_logReplayFinishHook = () -> logReplayFinish.release();
    SolrQueryRequest req = req();
    UpdateHandler uhandler = req.getCore().getUpdateHandler();
    UpdateLog ulog = uhandler.getUpdateLog();
    Future<UpdateLog.RecoveryInfo> rinfoFuture;
    try {
        String v101 = getNextVersion();
        String v102 = getNextVersion();
        String v103 = getNextVersion();
        String v104 = getNextVersion();
        String v105 = getNextVersion();
        String v200 = getNextVersion();
        String v201 = getNextVersion();
        String v203 = getNextVersion();
        String v204 = getNextVersion();
        String v205 = getNextVersion();
        String v206 = getNextVersion();
        clearIndex();
        assertU(commit());
        assertEquals(UpdateLog.State.ACTIVE, ulog.getState());
        ulog.bufferUpdates();
        assertEquals(UpdateLog.State.BUFFERING, ulog.getState());
        // simulate updates from a leader
        updateJ(jsonAdd(sdoc("id", "c1", "_version_", v101)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        updateJ(jsonAdd(sdoc("id", "c2", "_version_", v102)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        updateJ(jsonAdd(sdoc("id", "c3", "_version_", v103)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        // call bufferUpdates again (this currently happens when recovery fails)... we should get a new starting point
        ulog.bufferUpdates();
        assertEquals(UpdateLog.State.BUFFERING, ulog.getState());
        updateJ(jsonAdd(sdoc("id", "c4", "_version_", v104)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        updateJ(jsonAdd(sdoc("id", "c5", "_version_", v105)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        logReplay.release(1000);
        rinfoFuture = ulog.applyBufferedUpdates();
        UpdateLog.RecoveryInfo rinfo = rinfoFuture.get();
        assertEquals(2, rinfo.adds);
        assertJQ(req("qt", "/get", "getVersions", "2"), "=={'versions':[" + v105 + "," + v104 + "]}");
        // this time add some docs first before buffering starts (so tlog won't be at pos 0)
        updateJ(jsonAdd(sdoc("id", "c100", "_version_", v200)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        updateJ(jsonAdd(sdoc("id", "c101", "_version_", v201)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        ulog.bufferUpdates();
        updateJ(jsonAdd(sdoc("id", "c103", "_version_", v203)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        updateJ(jsonAdd(sdoc("id", "c104", "_version_", v204)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        // call bufferUpdates again (this currently happens when recovery fails)... we should get a new starting point
        ulog.bufferUpdates();
        updateJ(jsonAdd(sdoc("id", "c105", "_version_", v205)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        updateJ(jsonAdd(sdoc("id", "c106", "_version_", v206)), params(DISTRIB_UPDATE_PARAM, FROM_LEADER));
        rinfoFuture = ulog.applyBufferedUpdates();
        rinfo = rinfoFuture.get();
        assertEquals(2, rinfo.adds);
        assertJQ(req("q", "*:*", "sort", "_version_ asc", "fl", "id,_version_"), "/response/docs==[" + "{'id':'c4','_version_':" + v104 + "}" + ",{'id':'c5','_version_':" + v105 + "}" + ",{'id':'c100','_version_':" + v200 + "}" + ",{'id':'c101','_version_':" + v201 + "}" + ",{'id':'c105','_version_':" + v205 + "}" + ",{'id':'c106','_version_':" + v206 + "}" + "" + "]");
        // The updates that were buffered (but never applied) still appear in recent versions!
        // This is good for some uses, but may not be good for others.
        assertJQ(req("qt", "/get", "getVersions", "11"), "=={'versions':[" + String.join(",", v206, v205, v204, v203, v201, v200, v105, v104, v103, v102, v101) + "]}");
        // leave each test method in a good state
        assertEquals(UpdateLog.State.ACTIVE, ulog.getState());
    } finally {
        DirectUpdateHandler2.commitOnClose = true;
        UpdateLog.testing_logReplayHook = null;
        UpdateLog.testing_logReplayFinishHook = null;
        req().close();
    }
}
Also used : UpdateHandler(org.apache.solr.update.UpdateHandler) SolrQueryRequest(org.apache.solr.request.SolrQueryRequest) UpdateLog(org.apache.solr.update.UpdateLog) Semaphore(java.util.concurrent.Semaphore) Test(org.junit.Test)

Example 10 with UpdateLog

use of org.apache.solr.update.UpdateLog in project lucene-solr by apache.

the class HttpPartitionTest method testRf2.

protected void testRf2() throws Exception {
    // create a collection that has 1 shard but 2 replicas
    String testCollectionName = "c8n_1x2";
    createCollectionRetry(testCollectionName, 1, 2, 1);
    cloudClient.setDefaultCollection(testCollectionName);
    sendDoc(1);
    Replica notLeader = ensureAllReplicasAreActive(testCollectionName, "shard1", 1, 2, maxWaitSecsToSeeAllActive).get(0);
    // ok, now introduce a network partition between the leader and the replica
    SocketProxy proxy = getProxyForReplica(notLeader);
    proxy.close();
    // indexing during a partition
    sendDoc(2);
    // Have the partition last at least 1 sec
    // While this gives the impression that recovery is timing related, this is
    // really only
    // to give time for the state to be written to ZK before the test completes.
    // In other words,
    // without a brief pause, the test finishes so quickly that it doesn't give
    // time for the recovery process to kick-in
    Thread.sleep(sleepMsBeforeHealPartition);
    proxy.reopen();
    List<Replica> notLeaders = ensureAllReplicasAreActive(testCollectionName, "shard1", 1, 2, maxWaitSecsToSeeAllActive);
    sendDoc(3);
    // sent 3 docs in so far, verify they are on the leader and replica
    assertDocsExistInAllReplicas(notLeaders, testCollectionName, 1, 3);
    // Get the max version from the replica core to make sure it gets updated after recovery (see SOLR-7625)
    JettySolrRunner replicaJetty = getJettyOnPort(getReplicaPort(notLeader));
    CoreContainer coreContainer = replicaJetty.getCoreContainer();
    ZkCoreNodeProps replicaCoreNodeProps = new ZkCoreNodeProps(notLeader);
    String coreName = replicaCoreNodeProps.getCoreName();
    Long maxVersionBefore = null;
    try (SolrCore core = coreContainer.getCore(coreName)) {
        assertNotNull("Core '" + coreName + "' not found for replica: " + notLeader.getName(), core);
        UpdateLog ulog = core.getUpdateHandler().getUpdateLog();
        maxVersionBefore = ulog.getCurrentMaxVersion();
    }
    assertNotNull("max version bucket seed not set for core " + coreName, maxVersionBefore);
    log.info("Looked up max version bucket seed " + maxVersionBefore + " for core " + coreName);
    // now up the stakes and do more docs
    int numDocs = TEST_NIGHTLY ? 1000 : 100;
    boolean hasPartition = false;
    for (int d = 0; d < numDocs; d++) {
        // create / restore partition every 100 docs
        if (d % 10 == 0) {
            if (hasPartition) {
                proxy.reopen();
                hasPartition = false;
            } else {
                if (d >= 10) {
                    proxy.close();
                    hasPartition = true;
                    Thread.sleep(sleepMsBeforeHealPartition);
                }
            }
        }
        // 4 is offset as we've already indexed 1-3
        sendDoc(d + 4);
    }
    // restore connectivity if lost
    if (hasPartition) {
        proxy.reopen();
    }
    notLeaders = ensureAllReplicasAreActive(testCollectionName, "shard1", 1, 2, maxWaitSecsToSeeAllActive);
    try (SolrCore core = coreContainer.getCore(coreName)) {
        assertNotNull("Core '" + coreName + "' not found for replica: " + notLeader.getName(), core);
        Long currentMaxVersion = core.getUpdateHandler().getUpdateLog().getCurrentMaxVersion();
        log.info("After recovery, looked up NEW max version bucket seed " + currentMaxVersion + " for core " + coreName + ", was: " + maxVersionBefore);
        assertTrue("max version bucket seed not updated after recovery!", currentMaxVersion > maxVersionBefore);
    }
    // verify all docs received
    assertDocsExistInAllReplicas(notLeaders, testCollectionName, 1, numDocs + 3);
    log.info("testRf2 succeeded ... deleting the " + testCollectionName + " collection");
    // try to clean up
    attemptCollectionDelete(cloudClient, testCollectionName);
}
Also used : CoreContainer(org.apache.solr.core.CoreContainer) ZkCoreNodeProps(org.apache.solr.common.cloud.ZkCoreNodeProps) JettySolrRunner(org.apache.solr.client.solrj.embedded.JettySolrRunner) SolrCore(org.apache.solr.core.SolrCore) UpdateLog(org.apache.solr.update.UpdateLog) Replica(org.apache.solr.common.cloud.Replica)

Aggregations

UpdateLog (org.apache.solr.update.UpdateLog)34 SolrQueryRequest (org.apache.solr.request.SolrQueryRequest)16 Test (org.junit.Test)15 Semaphore (java.util.concurrent.Semaphore)14 UpdateHandler (org.apache.solr.update.UpdateHandler)12 IOException (java.io.IOException)11 SolrException (org.apache.solr.common.SolrException)11 SolrCore (org.apache.solr.core.SolrCore)8 File (java.io.File)6 ArrayList (java.util.ArrayList)6 IndexFingerprint (org.apache.solr.update.IndexFingerprint)6 RandomAccessFile (java.io.RandomAccessFile)5 Replica (org.apache.solr.common.cloud.Replica)5 ModifiableSolrParams (org.apache.solr.common.params.ModifiableSolrParams)5 SolrDocument (org.apache.solr.common.SolrDocument)4 ZkNodeProps (org.apache.solr.common.cloud.ZkNodeProps)4 SolrParams (org.apache.solr.common.params.SolrParams)4 NamedList (org.apache.solr.common.util.NamedList)4 URISyntaxException (java.net.URISyntaxException)3 HashMap (java.util.HashMap)3