Exemplo n.º 1
0
    /**
     * Atomic update.
     *
     * @return <code>null</code>
     */
    @Override
    protected Void doTask() throws Exception {

      updateEvent.start();

      try {

        if (resourceManager.isOverflowAllowed()) throw new IllegalStateException();

        final SegmentMetadata segmentMetadata = buildResult.segmentMetadata;

        if (INFO) log.info("Begin: name=" + getOnlyResource() + ", newSegment=" + segmentMetadata);

        /*
         * Open the unisolated B+Tree on the live journal that is
         * absorbing writes. We are going to update its index metadata.
         *
         * Note: I am using AbstractTask#getIndex(String name) so that
         * the concurrency control logic will notice the changes to the
         * BTree and cause it to be checkpointed if this task succeeds
         * normally.
         */
        final ILocalBTreeView view = (ILocalBTreeView) getIndex(getOnlyResource());

        // make sure that this is the same scale-out index.
        assertSameIndex(indexUUID, view.getMutableBTree());

        if (view instanceof BTree) {

          /*
           * Note: there is an expectation that this is not a simple
           * BTree because this the build task is supposed to be
           * invoked after an overflow event, and that event should
           * have re-defined the view to include the BTree on the new
           * journal plus the historical view.
           *
           * One explanation for finding a simple view here is that
           * the view was a simple BTree on the old journal and the
           * data was copied from the old journal into the new journal
           * and then someone decided to do a build even through a
           * copy had already been done. However, this is not a very
           * good explanation since we try to avoid doing a build if
           * we have already done a copy!
           */

          throw new RuntimeException(
              "View is only a B+Tree: name="
                  + buildResult.name
                  + ", pmd="
                  + view.getIndexMetadata().getPartitionMetadata());
        }

        // The live B+Tree.
        final BTree btree = view.getMutableBTree();

        if (INFO)
          log.info(
              "src="
                  + getOnlyResource()
                  + ",counter="
                  + view.getCounter().get()
                  + ",checkpoint="
                  + btree.getCheckpoint());

        assert btree != null : "Expecting index: " + getOnlyResource();

        // clone the current metadata record for the live index.
        final IndexMetadata indexMetadata = btree.getIndexMetadata().clone();

        /*
         * This is the index partition definition on the live index -
         * the one that will be replaced with a new view as the result
         * of this atomic update.
         */
        final LocalPartitionMetadata currentpmd = indexMetadata.getPartitionMetadata();

        // Check pre-conditions.
        final IResourceMetadata[] currentResources = currentpmd.getResources();
        {
          if (currentpmd == null) {

            throw new IllegalStateException("Not an index partition: " + getOnlyResource());
          }

          if (!currentResources[0].getUUID().equals(getJournal().getRootBlockView().getUUID())) {

            throw new IllegalStateException(
                "Expecting live journal to be the first resource: " + currentResources);
          }

          /*
           * Note: I have commented out a bunch of pre-condition tests
           * that are not valid for histories such as:
           *
           * history=create() register(0) split(0)
           * copy(entryCount=314)
           *
           * This case arises when there are not enough index entries
           * written on the journal after a split to warrant a build
           * so the buffered writes are just copied to the new
           * journal. The resources in the view are:
           *
           * 1. journal 2. segment
           *
           * And this update will replace the segment.
           */

          // // the old journal's resource metadata.
          // final IResourceMetadata oldJournalMetadata =
          // oldResources[1];
          // assert oldJournalMetadata != null;
          // assert oldJournalMetadata instanceof JournalMetadata :
          // "name="
          // + getOnlyResource() + ", old pmd=" + oldpmd
          // + ", segmentMetadata=" + buildResult.segmentMetadata;
          //
          // // live journal must be newer.
          // assert journal.getRootBlockView().getCreateTime() >
          // oldJournalMetadata
          // .getCreateTime();
          // new index segment build from a view that did not include
          // data from the live journal.
          assert segmentMetadata.getCreateTime()
                  < getJournal().getRootBlockView().getFirstCommitTime()
              : "segment createTime LT journal 1st commit time"
                  + ": segmentMetadata="
                  + segmentMetadata
                  + ", journal: "
                  + getJournal().getRootBlockView();

          // if (oldResources.length == 3) {
          //
          // // the old index segment's resource metadata.
          // final IResourceMetadata oldSegmentMetadata =
          // oldResources[2];
          // assert oldSegmentMetadata != null;
          // assert oldSegmentMetadata instanceof SegmentMetadata;
          //
          // assert oldSegmentMetadata.getCreateTime() <=
          // oldJournalMetadata
          // .getCreateTime();
          //
          // }

        }

        // new view definition.
        final IResourceMetadata[] newResources =
            new IResourceMetadata[] {
              // the live journal.
              getJournal().getResourceMetadata(),
              // the newly built index segment.
              segmentMetadata
            };

        // describe the index partition.
        indexMetadata.setPartitionMetadata(
            new LocalPartitionMetadata( //
                currentpmd.getPartitionId(), //
                currentpmd.getSourcePartitionId(), //
                currentpmd.getLeftSeparatorKey(), //
                currentpmd.getRightSeparatorKey(), //
                newResources, //
                currentpmd.getIndexPartitionCause()
                //                        currentpmd.getHistory()
                //                                + OverflowActionEnum.Merge//
                //                                + "(lastCommitTime="
                //                                + segmentMetadata.getCreateTime()//
                //                                + ",btreeEntryCount="
                //                                + btree.getEntryCount()//
                //                                + ",segmentEntryCount="
                //                                + buildResult.builder.getCheckpoint().nentries//
                //                                + ",segment="
                //                                + segmentMetadata.getUUID()//
                //                                + ",counter="
                //                                + btree.getCounter().get()//
                //                                + ",oldResources="
                //                                + Arrays.toString(currentResources) + ") "
                ));

        // update the metadata associated with the btree
        btree.setIndexMetadata(indexMetadata);

        if (INFO)
          log.info(
              "Updated view: name="
                  + getOnlyResource()
                  + ", pmd="
                  + indexMetadata.getPartitionMetadata());

        /*
         * Verify that the btree recognizes that it needs to be
         * checkpointed.
         *
         * Note: The atomic commit point is when this task commits.
         */
        assert btree.needsCheckpoint();
        //            btree.writeCheckpoint();
        //            {
        //                final long id0 = btree.getCounter().get();
        //                final long pid = id0 >> 32;
        //                final long mask = 0xffffffffL;
        //                final int ctr = (int) (id0 & mask);
        //                log.warn("name="+getOnlyResource()+", counter="+id0+", pid="+pid+",
        // ctr="+ctr);
        //            }

        // notify successful index partition build.
        resourceManager.overflowCounters.indexPartitionMergeCounter.incrementAndGet();

        return null;

      } finally {

        updateEvent.end();
      }
    } // doTask()