/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.accumulo.server.tablets; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import org.apache.accumulo.core.client.admin.TimeType; import org.apache.accumulo.core.data.Mutation; import org.apache.accumulo.server.data.ServerMutation; import org.apache.accumulo.server.util.time.RelativeTime; public abstract class TabletTime { public static final char LOGICAL_TIME_ID = 'L'; public static final char MILLIS_TIME_ID = 'M'; public static char getTimeID(TimeType timeType) { switch (timeType) { case LOGICAL: return LOGICAL_TIME_ID; case MILLIS: return MILLIS_TIME_ID; } throw new IllegalArgumentException("Unknown time type " + timeType); } public abstract void useMaxTimeFromWALog(long time); public abstract String getMetadataValue(long time); public abstract String getMetadataValue(); public abstract long setUpdateTimes(List<Mutation> mutations); public abstract long getTime(); public abstract long getAndUpdateTime(); protected void setSystemTimes(Mutation mutation, long lastCommitTime) { ServerMutation m = (ServerMutation) mutation; m.setSystemTimestamp(lastCommitTime); } public static TabletTime getInstance(String metadataValue) { if (metadataValue.charAt(0) == LOGICAL_TIME_ID) { return new LogicalTime(Long.parseLong(metadataValue.substring(1))); } else if (metadataValue.charAt(0) == MILLIS_TIME_ID) { return new MillisTime(Long.parseLong(metadataValue.substring(1))); } throw new IllegalArgumentException("Time type unknown : " + metadataValue); } public static String maxMetadataTime(String mv1, String mv2) { if (mv1 == null && mv2 == null) { return null; } if (mv1 == null) { checkType(mv2); return mv2; } if (mv2 == null) { checkType(mv1); return mv1; } if (mv1.charAt(0) != mv2.charAt(0)) throw new IllegalArgumentException("Time types differ " + mv1 + " " + mv2); checkType(mv1); long t1 = Long.parseLong(mv1.substring(1)); long t2 = Long.parseLong(mv2.substring(1)); if (t1 < t2) return mv2; else return mv1; } private static void checkType(String mv1) { if (mv1.charAt(0) != LOGICAL_TIME_ID && mv1.charAt(0) != MILLIS_TIME_ID) throw new IllegalArgumentException("Invalid time type " + mv1); } static class MillisTime extends TabletTime { private long lastTime; private long lastUpdateTime = 0; public MillisTime(long time) { this.lastTime = time; } @Override public String getMetadataValue(long time) { return MILLIS_TIME_ID + "" + time; } @Override public String getMetadataValue() { return getMetadataValue(lastTime); } @Override public void useMaxTimeFromWALog(long time) { if (time > lastTime) lastTime = time; } @Override public long setUpdateTimes(List<Mutation> mutations) { long currTime = RelativeTime.currentTimeMillis(); synchronized (this) { if (mutations.size() == 0) return lastTime; currTime = updateTime(currTime); } for (Mutation mutation : mutations) setSystemTimes(mutation, currTime); return currTime; } private long updateTime(long currTime) { if (currTime < lastTime) { if (currTime - lastUpdateTime > 0) { // not in same millisecond as last call // to this method so move ahead slowly lastTime++; } lastUpdateTime = currTime; currTime = lastTime; } else { lastTime = currTime; } return currTime; } @Override public long getTime() { return lastTime; } @Override public long getAndUpdateTime() { long currTime = RelativeTime.currentTimeMillis(); synchronized (this) { currTime = updateTime(currTime); } return currTime; } } static class LogicalTime extends TabletTime { AtomicLong nextTime; private LogicalTime(Long time) { this.nextTime = new AtomicLong(time.longValue() + 1); } @Override public void useMaxTimeFromWALog(long time) { time++; if (this.nextTime.get() < time) { this.nextTime.set(time); } } @Override public String getMetadataValue() { return getMetadataValue(getTime()); } @Override public String getMetadataValue(long time) { return LOGICAL_TIME_ID + "" + time; } @Override public long setUpdateTimes(List<Mutation> mutations) { if (mutations.size() == 0) return getTime(); long time = nextTime.getAndAdd(mutations.size()); for (Mutation mutation : mutations) setSystemTimes(mutation, time++); return time - 1; } @Override public long getTime() { return nextTime.get() - 1; } @Override public long getAndUpdateTime() { return nextTime.getAndIncrement(); } } }