Ejemplo n.º 1
0
  /**
   * Flushes the snapshot of the memstore. Flushes the mob data to the mob files, and flushes the
   * name of these mob files to HBase.
   *
   * @param snapshot The snapshot of the memstore.
   * @throws IOException
   */
  private void internalFlushCache(final MemStoreSnapshot snapshot) throws IOException {
    if (snapshot.getCellsCount() == 0) {
      return;
    }
    // generate the files into a temp directory.
    String tempPathString = context.getConfiguration().get(SweepJob.WORKING_FILES_DIR_KEY);
    StoreFile.Writer mobFileWriter =
        MobUtils.createWriter(
            conf,
            fs,
            hcd,
            partitionId.getDate(),
            new Path(tempPathString),
            snapshot.getCellsCount(),
            hcd.getCompactionCompression(),
            partitionId.getStartKey(),
            cacheConfig,
            cryptoContext);

    String relativePath = mobFileWriter.getPath().getName();
    LOG.info("Create files under a temp directory " + mobFileWriter.getPath().toString());

    byte[] referenceValue = Bytes.toBytes(relativePath);
    KeyValueScanner scanner = snapshot.getScanner();
    Cell cell = null;
    while (null != (cell = scanner.next())) {
      mobFileWriter.append(cell);
    }
    scanner.close();
    // Write out the log sequence number that corresponds to this output
    // hfile. The hfile is current up to and including logCacheFlushId.
    mobFileWriter.appendMetadata(Long.MAX_VALUE, false, snapshot.getCellsCount());
    mobFileWriter.close();

    MobUtils.commitFile(conf, fs, mobFileWriter.getPath(), mobFamilyDir, cacheConfig);
    context.getCounter(SweepCounter.FILE_AFTER_MERGE_OR_CLEAN).increment(1);
    // write reference/fileName back to the store files of HBase.
    scanner = snapshot.getScanner();
    scanner.seek(KeyValueUtil.createFirstOnRow(HConstants.EMPTY_START_ROW));
    cell = null;
    Tag tableNameTag =
        new ArrayBackedTag(
            TagType.MOB_TABLE_NAME_TAG_TYPE, Bytes.toBytes(this.table.getName().toString()));
    long updatedCount = 0;
    while (null != (cell = scanner.next())) {
      KeyValue reference = MobUtils.createMobRefKeyValue(cell, referenceValue, tableNameTag);
      Put put =
          new Put(reference.getRowArray(), reference.getRowOffset(), reference.getRowLength());
      put.add(reference);
      table.mutate(put);
      updatedCount++;
    }
    table.flush();
    context.getCounter(SweepCounter.RECORDS_UPDATED).increment(updatedCount);
    scanner.close();
  }
    private static void DeleteEvent(BufferedMutator VTEvent, String iMO_str, VesselEvent after_VE)
        throws IOException {
      // TODO Auto-generated method stub

      byte[] rowkey =
          Bytes.toBytes(
              iMO_str
                  + LpadNum(Long.MAX_VALUE - after_VE.entrytime, 19)
                  + LpadNum(after_VE.polygonid, 10));
      VTEvent.mutate(new Delete(rowkey));
    }
Ejemplo n.º 3
0
  /**
   * Update a record in the database. Any field/value pairs in the specified values HashMap will be
   * written into the record with the specified record key, overwriting any existing values with the
   * same field name.
   *
   * @param table The name of the table
   * @param key The record key of the record to write
   * @param values A HashMap of field/value pairs to update in the record
   * @return Zero on success, a non-zero error code on error
   */
  @Override
  public Status update(String table, String key, HashMap<String, ByteIterator> values) {
    // if this is a "new" table, init HTable object. Else, use existing one
    if (!tableName.equals(table)) {
      currentTable = null;
      try {
        getHTable(table);
        tableName = table;
      } catch (IOException e) {
        System.err.println("Error accessing HBase table: " + e);
        return Status.ERROR;
      }
    }

    if (debug) {
      System.out.println("Setting up put for key: " + key);
    }
    Put p = new Put(Bytes.toBytes(key));
    p.setDurability(durability);
    for (Map.Entry<String, ByteIterator> entry : values.entrySet()) {
      byte[] value = entry.getValue().toArray();
      if (debug) {
        System.out.println(
            "Adding field/value "
                + entry.getKey()
                + "/"
                + Bytes.toStringBinary(value)
                + " to put request");
      }
      p.addColumn(columnFamilyBytes, Bytes.toBytes(entry.getKey()), value);
    }

    try {
      if (clientSideBuffering) {
        Preconditions.checkNotNull(bufferedMutator);
        bufferedMutator.mutate(p);
      } else {
        currentTable.put(p);
      }
    } catch (IOException e) {
      if (debug) {
        System.err.println("Error doing put: " + e);
      }
      return Status.ERROR;
    } catch (ConcurrentModificationException e) {
      // do nothing for now...hope this is rare
      return Status.ERROR;
    }

    return Status.OK;
  }
Ejemplo n.º 4
0
 public MemStoreWrapper(
     Context context,
     FileSystem fs,
     BufferedMutator table,
     HColumnDescriptor hcd,
     MemStore memstore,
     CacheConfig cacheConfig)
     throws IOException {
   this.memstore = memstore;
   this.context = context;
   this.fs = fs;
   this.table = table;
   this.hcd = hcd;
   this.conf = context.getConfiguration();
   this.cacheConfig = cacheConfig;
   flushSize =
       this.conf.getLong(
           MobConstants.MOB_SWEEP_TOOL_COMPACTION_MEMSTORE_FLUSH_SIZE,
           MobConstants.DEFAULT_MOB_SWEEP_TOOL_COMPACTION_MEMSTORE_FLUSH_SIZE);
   mobFamilyDir = MobUtils.getMobFamilyPath(conf, table.getName(), hcd.getNameAsString());
   cryptoContext = EncryptionUtil.createEncryptionContext(conf, hcd);
 }
Ejemplo n.º 5
0
 /**
  * Cleanup any state for this DB. Called once per DB instance; there is one DB instance per client
  * thread.
  */
 @Override
 public void cleanup() throws DBException {
   // Get the measurements instance as this is the only client that should
   // count clean up time like an update if client-side buffering is
   // enabled.
   Measurements measurements = Measurements.getMeasurements();
   try {
     long st = System.nanoTime();
     if (bufferedMutator != null) {
       bufferedMutator.close();
     }
     if (currentTable != null) {
       currentTable.close();
     }
     long en = System.nanoTime();
     final String type = clientSideBuffering ? "UPDATE" : "CLEANUP";
     measurements.measure(type, (int) ((en - st) / 1000));
     connection.close();
   } catch (IOException e) {
     throw new DBException(e);
   }
 }
Ejemplo n.º 6
0
  /**
   * Delete a record from the database.
   *
   * @param table The name of the table
   * @param key The record key of the record to delete.
   * @return Zero on success, a non-zero error code on error
   */
  @Override
  public Status delete(String table, String key) {
    // if this is a "new" table, init HTable object. Else, use existing one
    if (!tableName.equals(table)) {
      currentTable = null;
      try {
        getHTable(table);
        tableName = table;
      } catch (IOException e) {
        System.err.println("Error accessing HBase table: " + e);
        return Status.ERROR;
      }
    }

    if (debug) {
      System.out.println("Doing delete for key: " + key);
    }

    final Delete d = new Delete(Bytes.toBytes(key));
    d.setDurability(durability);
    try {
      if (clientSideBuffering) {
        Preconditions.checkNotNull(bufferedMutator);
        bufferedMutator.mutate(d);
      } else {
        currentTable.delete(d);
      }
    } catch (IOException e) {
      if (debug) {
        System.err.println("Error doing delete: " + e);
      }
      return Status.ERROR;
    }

    return Status.OK;
  }
 public static void DeleteEvents(BufferedMutator VTEvent, List<Delete> deletes)
     throws IOException {
   VTEvent.mutate(deletes);
 }
    @Override
    protected void reduce(
        Key_IMOAndRecordTime key, Iterable<TextArrayWritable> LocationList, Context context)
        throws IOException, InterruptedException {

      try {
        context.getCounter(Counters.VESSEL_PROCESSED).increment(1);

        String IMO_str = LpadNum(key.getIMO().get(), 7);
        long first_pos_time = key.getRecordTime().get();

        /////////////////////////////////////////////////////////////////////////////////
        // Populate newPoints with new locations
        List<VesselLocation> newPoints = new ArrayList<VesselLocation>();

        for (TextArrayWritable rowcontent : LocationList) {
          // population location
          context.getCounter(Counters.LOCATION_ROWS).increment(1);
          VesselLocation newlocation = new VesselLocation();

          try {

            Writable[] content = rowcontent.get();
            String Latitude = content[16].toString().trim();
            String Longitude = content[15].toString().trim();
            String Coordinates = Latitude + "," + Longitude;
            String Speed = content[18].toString().trim();
            String Destination = content[9].toString().trim();
            String Timestamp = content[21].toString().trim().substring(0, 19);

            long record_time = DateTime.parse(Timestamp, rawformatter).getMillis();
            newlocation.coordinates = Coordinates;
            newlocation.recordtime = record_time;
            newlocation.speed = Speed;
            newlocation.destination = Destination;
            context.getCounter(Counters.LOCATION_VALID).increment(1);

          } catch (Exception e) {
            e.printStackTrace();
            context.getCounter(Counters.LOCATION_ERROR).increment(1);
            continue;
          }

          newPoints.add(newlocation);
        }

        /////////////////////////////////////////////////////////////////////////////////
        // Get last new post time
        long last_pos_time = newPoints.get(newPoints.size() - 1).recordtime;

        ////////////////////////////////////////////////////////////////////////////////
        // Get Existing trackinfo
        VesselTrackInfo VTI = getTrackInfo(TrackInfo_Table, IMO_str);

        List<VesselLocation> AllBetweenPoints = new ArrayList<VesselLocation>();

        String BeforeRowKey = null;
        String AfterRowKey = null;

        // //////////////////////////////////////////////////////////////////////////////
        // Retrieve all the existing locations between the first new location and the last new
        // location.
        if ((VTI.FirstRecordTime != null) && (VTI.LastRecordTime != null)) {

          if (last_pos_time < VTI.FirstRecordTime) {
            AfterRowKey = IMO_str + LpadNum(Long.MAX_VALUE - VTI.FirstRecordTime, 19);
          } else if (first_pos_time > VTI.LastRecordTime) {
            BeforeRowKey = IMO_str + LpadNum(Long.MAX_VALUE - VTI.LastRecordTime, 19);
          } else {
            AllBetweenPoints =
                ImportReducer.getLocationsBetween(
                    VTLocation_Table, IMO_str, first_pos_time, last_pos_time);

            if (AllBetweenPoints.size() == 0) {
              // Search for the first DB point before the first new point
              VesselLocation BeforeLocation =
                  getLocationBefore(VTLocation_Table, IMO_str, first_pos_time);
              BeforeRowKey = IMO_str + LpadNum(Long.MAX_VALUE - BeforeLocation.recordtime, 19);
              AfterRowKey = BeforeLocation.nextlocation;

            } else {
              java.util.Collections.sort(AllBetweenPoints);
              BeforeRowKey = AllBetweenPoints.get(0).previouslocation;
              AfterRowKey = AllBetweenPoints.get(AllBetweenPoints.size() - 1).nextlocation;
            }

            List<Delete> deletes =
                ImportReducer.GetDeleteEventsBetween(
                    VTEvent_Table, IMO_str, first_pos_time, last_pos_time);
            ImportReducer.DeleteEvents(VTEvent, deletes);
            VTEvent.flush();
          }
        }

        // Find out the location before the first new location in
        VesselLocation BeforeLocation = getLocation(VTLocation_Table, BeforeRowKey);

        // Find out the location after the last new location in
        VesselLocation AfterLocation = getLocation(VTLocation_Table, AfterRowKey);

        Map<Integer, VesselEvent> PreviousZoneEvents = new HashMap<Integer, VesselEvent>();
        ;
        Map<Integer, VesselEvent> AfterZoneEvents = new HashMap<Integer, VesselEvent>();

        if (BeforeLocation != null) {
          // Get all events with exit at last location
          PreviousZoneEvents =
              getAllEventsStartBeforeEndAfterBeforeLocation(VTEvent_Table, IMO_str, BeforeLocation);
        }

        ////////////////////////////////////////////////////
        // Analyze and calculate previous and next location
        for (VesselLocation newlocation : newPoints) {

          int index = AllBetweenPoints.indexOf(newlocation);
          if (index != -1) {
            VesselLocation dblocation = AllBetweenPoints.get(index);
            dblocation.coordinates = newlocation.coordinates;
            dblocation.destination = newlocation.destination;
            dblocation.speed = newlocation.speed;
          } else {
            AllBetweenPoints.add(newlocation);
          }
        }

        java.util.Collections.sort(AllBetweenPoints);

        String previousRowKey = null;

        for (VesselLocation location : AllBetweenPoints) {
          location.previouslocation = previousRowKey;
          previousRowKey = IMO_str + LpadNum(Long.MAX_VALUE - location.recordtime, 19);
        }

        String NextRowKey = null;

        for (int i = (AllBetweenPoints.size() - 1); i >= 0; i--) {
          VesselLocation location = AllBetweenPoints.get(i);
          location.nextlocation = NextRowKey;
          NextRowKey = IMO_str + LpadNum(Long.MAX_VALUE - location.recordtime, 19);
        }

        AllBetweenPoints.get(0).previouslocation = BeforeRowKey;
        AllBetweenPoints.get(AllBetweenPoints.size() - 1).nextlocation = AfterRowKey;

        ////////////////////////////////////////////////////
        // Upsert all locations

        for (VesselLocation location : AllBetweenPoints) {
          // population location
          try {

            byte[] rowkey =
                Bytes.toBytes(IMO_str + LpadNum(Long.MAX_VALUE - location.recordtime, 19));
            Put put = new Put(rowkey);

            put.addColumn(details, speed, Bytes.toBytes(location.speed));
            put.addColumn(details, destination, Bytes.toBytes(location.destination));
            put.addColumn(details, coordinates, Bytes.toBytes(location.coordinates));

            put.addColumn(
                details,
                timestamp,
                Bytes.toBytes(new DateTime(location.recordtime).toString(rawformatter)));

            if (location.previouslocation != null) {
              put.addColumn(details, previouslocation, Bytes.toBytes(location.previouslocation));
            }

            if (location.nextlocation != null) {
              put.addColumn(details, nextlocation, Bytes.toBytes(location.nextlocation));
            }

            VTLocation.mutate(put);

          } catch (Exception e) {
            e.printStackTrace();
            context.getCounter(Counters.LOCATION_ERROR).increment(1);
            continue;
          }
        }

        // update before next location and after previous location

        if (BeforeRowKey != null) {
          Put BeforeLocationPut = new Put(Bytes.toBytes(BeforeRowKey));
          BeforeLocationPut.addColumn(
              details,
              nextlocation,
              Bytes.toBytes(
                  IMO_str + LpadNum(Long.MAX_VALUE - AllBetweenPoints.get(0).recordtime, 19)));
          VTLocation.mutate(BeforeLocationPut);
        }

        if (AfterRowKey != null) {

          Put AfterLocationPut = new Put(Bytes.toBytes(AfterRowKey));
          AfterLocationPut.addColumn(
              details,
              previouslocation,
              Bytes.toBytes(
                  IMO_str
                      + LpadNum(
                          Long.MAX_VALUE
                              - AllBetweenPoints.get(AllBetweenPoints.size() - 1).recordtime,
                          19)));
          VTLocation.mutate(AfterLocationPut);
        }

        VTLocation.flush();

        /////////////////////////////////////////////////////////////////////
        // Store latest location
        // rowkey: global zone id (4)+ longlat22
        // ((long11(sign(1)+integer(3)+digit(7)))(lat11(sign(1)+integer(3)+(7))))+imo(7)+recordtime(19)
        /////////////////////////////////////////////////////////////////////

        Put vessel_track_info = new Put(Bytes.toBytes(IMO_str));

        if (AfterLocation == null) {
          // Get the last location
          VesselLocation lastLocation = AllBetweenPoints.get(AllBetweenPoints.size() - 1);
          // update the last location
          String[] longlat = lastLocation.coordinates.split(",");
          GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
          Coordinate coord =
              new Coordinate(Double.parseDouble(longlat[1]), Double.parseDouble(longlat[0]));
          Point point = geometryFactory.createPoint(coord);

          Integer BelongedGlobalZoneIndex = null;

          for (int i = 0; i < VesselZone.GlobalZones.length; i++) {
            if (VesselZone.GlobalZones[i].covers(point)) {
              BelongedGlobalZoneIndex = i;
              break;
            }
          }

          if (VTI.LastLocation != null) {
            LastLocation_BM.mutate(new Delete(VTI.LastLocation));
          }

          byte[] lastlocationrowkey =
              Bytes.toBytes(
                  LpadNum(BelongedGlobalZoneIndex, 4)
                      + ConvertCoordinatesToStr(longlat[1])
                      + ConvertCoordinatesToStr(longlat[0]));
          Put lastlocation_put = new Put(lastlocationrowkey);
          lastlocation_put.addColumn(details, imo, Bytes.toBytes(IMO_str));
          lastlocation_put.addColumn(
              details,
              timestamp,
              Bytes.toBytes(new DateTime(lastLocation.recordtime).toString(rawformatter)));
          LastLocation_BM.mutate(lastlocation_put);

          LastLocation_BM.flush();

          vessel_track_info.addColumn(details, lastlocation, lastlocationrowkey);
          vessel_track_info.addColumn(
              details,
              lastrecordtime,
              Bytes.toBytes(new DateTime(lastLocation.recordtime).toString(rawformatter)));

        } else {
          // Get events that start before last new location and end after last new location
          AfterZoneEvents =
              getAllEventsStartBeforeEndAfter(VTEvent_Table, IMO_str, AfterLocation.recordtime);
        }

        // update firstrecordtime and lastrecordtime
        if (BeforeLocation == null) {
          vessel_track_info.addColumn(
              details,
              firstrecordtime,
              Bytes.toBytes(
                  new DateTime(AllBetweenPoints.get(0).recordtime).toString(rawformatter)));
        }

        if (!vessel_track_info.isEmpty()) {
          TrackInfo_BM.mutate(vessel_track_info);
          TrackInfo_BM.flush();
        }

        ////////////////////////////////////////////////////////////////////

        ArrayList<VesselEvent> DerivedEventList = new ArrayList<VesselEvent>();

        ///////////////////////////////////////////////////////////
        // Get Vessel
        String VesselType = getVesselType(Vessel_Table, IMO_str);

        if (VesselType == null) {
          context.getCounter(Counters.VESSEL_WITHOUTTYPE).increment(1);
          return;
        }

        // calculating event
        for (VesselLocation VL : AllBetweenPoints) {
          ArrayList<Integer> CurrentZones = LocateCurrentZone(VL.coordinates, VesselType, Zonemap);

          Iterator<Map.Entry<Integer, VesselEvent>> it = PreviousZoneEvents.entrySet().iterator();

          while (it.hasNext()) {
            Map.Entry<Integer, VesselEvent> thisEntry = it.next();
            int Zone_Axsmarine_id = thisEntry.getKey();
            if (!CurrentZones.contains(Zone_Axsmarine_id)) {
              VesselEvent PreviousEvent = thisEntry.getValue();

              if (!DerivedEventList.contains(PreviousEvent)) {
                DerivedEventList.add(PreviousEvent);
              }
              // remove close event from PreviousZoneEvents;
              it.remove();
            }
          }

          for (Integer thisZone_Axsmarine_id : CurrentZones) {

            if (PreviousZoneEvents.containsKey(thisZone_Axsmarine_id)) {
              //////////////////////////////////////////////////
              // For current zones which both previous and current locations belong to, update exit
              // point of previous open events with current locations.
              //////////////////////////////////////////////////
              VesselEvent PreviousEvent = PreviousZoneEvents.get(thisZone_Axsmarine_id);
              PreviousEvent.exitcoordinates = VL.coordinates;
              PreviousEvent.exittime = VL.recordtime;
              PreviousEvent.destination = VL.destination;

              if (!DerivedEventList.contains(PreviousEvent)) {
                DerivedEventList.add(PreviousEvent);
              }
            } else {
              //////////////////////////////////////////////////
              // For current zones which only current locations belong to, fire new open events
              //////////////////////////////////////////////////
              VesselEvent NewEvent = new VesselEvent();
              NewEvent.entrycoordinates = VL.coordinates;
              NewEvent.entrytime = VL.recordtime;
              NewEvent.exitcoordinates = VL.coordinates;
              NewEvent.exittime = VL.recordtime;
              NewEvent.destination = VL.destination;
              NewEvent.polygonid = thisZone_Axsmarine_id;

              PreviousZoneEvents.put(thisZone_Axsmarine_id, NewEvent);

              DerivedEventList.add(NewEvent);
            }
          }
        }

        ///////////////////////////////////////////////////////////////////////////////////////
        // Merge with PreviousZoneEvents with AfterZoneEvents

        Iterator<Map.Entry<Integer, VesselEvent>> it = AfterZoneEvents.entrySet().iterator();
        while (it.hasNext()) {
          Map.Entry<Integer, VesselEvent> thisEntry = it.next();
          int Zone_Axsmarine_id = thisEntry.getKey();
          VesselEvent After_VE = thisEntry.getValue();

          VesselEvent Previous_VE = PreviousZoneEvents.get(Zone_Axsmarine_id);

          if (Previous_VE != null) {
            Previous_VE.exitcoordinates = After_VE.exitcoordinates;
            Previous_VE.exittime = After_VE.exittime;
            Previous_VE.destination = After_VE.destination;
            if (!DerivedEventList.contains(Previous_VE)) {
              DerivedEventList.add(Previous_VE);
            }

          } else {
            VesselEvent NewEvent = new VesselEvent();
            NewEvent.entrycoordinates = AfterLocation.coordinates;
            NewEvent.entrytime = AfterLocation.recordtime;
            NewEvent.exitcoordinates = After_VE.exitcoordinates;
            NewEvent.exittime = After_VE.exittime;
            NewEvent.destination = After_VE.destination;
            NewEvent.polygonid = Zone_Axsmarine_id;
            DerivedEventList.add(NewEvent);
          }
          // Delete This Event from HBase
          DeleteEvent(VTEvent, IMO_str, After_VE);
        }

        VTEvent.flush();

        // pupulate Derived Events into Hbase

        for (VesselEvent newEvent : DerivedEventList) {
          // rowkey: IMO(7)+timestamp(19 desc)+polygonid(8)
          // qualifier:entrytime,entrycoordinates,exittime,exitcoordinates,destination

          context.getCounter(Counters.EVENT_UPSERTS).increment(1);

          byte[] rowkey =
              Bytes.toBytes(
                  IMO_str
                      + LpadNum(Long.MAX_VALUE - newEvent.entrytime, 19)
                      + LpadNum(newEvent.polygonid, 10));
          Put put = new Put(rowkey);

          put.addColumn(
              details,
              entrytime,
              Bytes.toBytes(new DateTime(newEvent.entrytime).toString(rawformatter)));
          put.addColumn(details, entrycoordinates, Bytes.toBytes(newEvent.entrycoordinates));
          put.addColumn(
              details,
              exittime,
              Bytes.toBytes(new DateTime(newEvent.exittime).toString(rawformatter)));
          put.addColumn(details, exitcoordinates, Bytes.toBytes(newEvent.exitcoordinates));
          put.addColumn(details, destination, Bytes.toBytes(newEvent.destination));

          VTEvent.mutate(put);
          context.getCounter(Counters.EVENT_VALID).increment(1);
        }

        // VTLocation.flush(); Moved to the first step
        VTEvent.flush();
      } catch (RuntimeException e) {
        // TODO Auto-generated catch block
        System.out.println("Exception occured while loading data for:" + key.getIMO());
        throw e;
      }
    }
Ejemplo n.º 9
0
  @Test
  public void testRun() throws Exception {

    TableName tn = TableName.valueOf(tableName);
    byte[] mobValueBytes = new byte[100];

    // get the path where mob files lie in
    Path mobFamilyPath = MobUtils.getMobFamilyPath(TEST_UTIL.getConfiguration(), tn, family);

    Put put = new Put(Bytes.toBytes(row));
    put.addColumn(Bytes.toBytes(family), Bytes.toBytes(qf), 1, mobValueBytes);
    Put put2 = new Put(Bytes.toBytes(row + "ignore"));
    put2.addColumn(Bytes.toBytes(family), Bytes.toBytes(qf), 1, mobValueBytes);
    table.mutate(put);
    table.mutate(put2);
    table.flush();
    admin.flush(tn);

    FileStatus[] fileStatuses = TEST_UTIL.getTestFileSystem().listStatus(mobFamilyPath);
    // check the generation of a mob file
    assertEquals(1, fileStatuses.length);

    String mobFile1 = fileStatuses[0].getPath().getName();

    Configuration configuration = new Configuration(TEST_UTIL.getConfiguration());
    configuration.setFloat(MobConstants.MOB_SWEEP_TOOL_COMPACTION_RATIO, 0.6f);
    configuration.setStrings(TableInputFormat.INPUT_TABLE, tableName);
    configuration.setStrings(TableInputFormat.SCAN_COLUMN_FAMILY, family);
    configuration.setStrings(SweepJob.WORKING_VISITED_DIR_KEY, "jobWorkingNamesDir");
    configuration.setStrings(SweepJob.WORKING_FILES_DIR_KEY, "compactionFileDir");
    configuration.setStrings(
        CommonConfigurationKeys.IO_SERIALIZATIONS_KEY, JavaSerialization.class.getName());
    configuration.set(SweepJob.WORKING_VISITED_DIR_KEY, "compactionVisitedDir");
    configuration.setLong(
        MobConstants.MOB_SWEEP_TOOL_COMPACTION_START_DATE,
        System.currentTimeMillis() + 24 * 3600 * 1000);

    ZooKeeperWatcher zkw = new ZooKeeperWatcher(configuration, "1", new DummyMobAbortable());
    TableName lockName = MobUtils.getTableLockName(tn);
    String znode = ZKUtil.joinZNode(zkw.tableLockZNode, lockName.getNameAsString());
    configuration.set(SweepJob.SWEEP_JOB_ID, "1");
    configuration.set(SweepJob.SWEEP_JOB_TABLE_NODE, znode);
    ServerName serverName = SweepJob.getCurrentServerName(configuration);
    configuration.set(SweepJob.SWEEP_JOB_SERVERNAME, serverName.toString());

    TableLockManager tableLockManager =
        TableLockManager.createTableLockManager(configuration, zkw, serverName);
    TableLock lock = tableLockManager.writeLock(lockName, "Run sweep tool");
    lock.acquire();
    try {
      // use the same counter when mocking
      Counter counter = new GenericCounter();
      Reducer<Text, KeyValue, Writable, Writable>.Context ctx = mock(Reducer.Context.class);
      when(ctx.getConfiguration()).thenReturn(configuration);
      when(ctx.getCounter(Matchers.any(SweepCounter.class))).thenReturn(counter);
      when(ctx.nextKey()).thenReturn(true).thenReturn(false);
      when(ctx.getCurrentKey()).thenReturn(new Text(mobFile1));

      byte[] refBytes = Bytes.toBytes(mobFile1);
      long valueLength = refBytes.length;
      byte[] newValue = Bytes.add(Bytes.toBytes(valueLength), refBytes);
      KeyValue kv2 =
          new KeyValue(
              Bytes.toBytes(row),
              Bytes.toBytes(family),
              Bytes.toBytes(qf),
              1,
              KeyValue.Type.Put,
              newValue);
      List<KeyValue> list = new ArrayList<KeyValue>();
      list.add(kv2);

      when(ctx.getValues()).thenReturn(list);

      SweepReducer reducer = new SweepReducer();
      reducer.run(ctx);
    } finally {
      lock.release();
    }
    FileStatus[] filsStatuses2 = TEST_UTIL.getTestFileSystem().listStatus(mobFamilyPath);
    String mobFile2 = filsStatuses2[0].getPath().getName();
    // new mob file is generated, old one has been archived
    assertEquals(1, filsStatuses2.length);
    assertEquals(false, mobFile2.equalsIgnoreCase(mobFile1));

    // test sequence file
    String workingPath = configuration.get(SweepJob.WORKING_VISITED_DIR_KEY);
    FileStatus[] statuses = TEST_UTIL.getTestFileSystem().listStatus(new Path(workingPath));
    Set<String> files = new TreeSet<String>();
    for (FileStatus st : statuses) {
      files.addAll(
          getKeyFromSequenceFile(TEST_UTIL.getTestFileSystem(), st.getPath(), configuration));
    }
    assertEquals(1, files.size());
    assertEquals(true, files.contains(mobFile1));
  }