mirror of
https://github.com/NationalSecurityAgency/timely.git
synced 2026-11-10 11:51:29 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be11da7d15 | ||
|
|
4bc5753328 | ||
|
|
2ccb89a06d | ||
|
|
dfc3840ad4 | ||
|
|
6235034d8b | ||
|
|
d8de6ac06f | ||
|
|
f381946abe | ||
|
|
48bbe6a561 | ||
|
|
0f6110ea59 | ||
|
|
461b5e7e78 | ||
|
|
4ec7d94c28 | ||
|
|
77e910ae06 | ||
|
|
a4998af887 | ||
|
|
2858549ede | ||
|
|
57f0e1408f | ||
|
|
151adc025a | ||
|
|
5abd9d7200 | ||
|
|
fa2e211c72 | ||
|
|
a21438976e | ||
|
|
ba37047f3a | ||
|
|
9305470c69 | ||
|
|
200233542e | ||
|
|
3cd78dc624 | ||
|
|
9027cac6e3 | ||
|
|
3663b4e6d5 | ||
|
|
64973d0674 | ||
|
|
5512306f1e | ||
|
|
e2bbe4e212 |
No files matched your search
+3
-2
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>1.2.4</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
<artifactId>timely-analytics</artifactId>
|
||||
<!--
|
||||
@@ -68,6 +68,7 @@
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<compilerId>jdt</compilerId>
|
||||
@@ -76,7 +77,7 @@
|
||||
<dependency>
|
||||
<groupId>org.eclipse.tycho</groupId>
|
||||
<artifactId>tycho-compiler-jdt</artifactId>
|
||||
<version>0.21.0</version>
|
||||
<version>1.4.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
|
||||
@@ -67,7 +67,7 @@ public class SummarizationJob {
|
||||
})
|
||||
.name("Metric Windows")
|
||||
.addSink(
|
||||
new SocketClientSink<MetricHistogram>(jp.getTimelyHostname(), jp.getTimelyTcpPort(),
|
||||
new SocketClientSink<MetricHistogram>(jp.getTimelyHostname(), jp.getTimelyTcpPort(),
|
||||
new MetricHistogram(), 2, true) {
|
||||
|
||||
private final Logger LOG = LoggerFactory
|
||||
|
||||
@@ -111,6 +111,7 @@ timely-balancer:
|
||||
flush-interval-seconds: 30
|
||||
scanner-read-ahead: 1
|
||||
subscription-batch-size: 5000
|
||||
incomingBufferSize: 50000000
|
||||
wsClientPool:
|
||||
minIdlePerKey: 0
|
||||
maxIdlePerKey: 40
|
||||
|
||||
+1
-2
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>1.2.4</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
<artifactId>timely-balancer</artifactId>
|
||||
<dependencies>
|
||||
@@ -162,7 +162,6 @@
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-tcnative-boringssl-static</artifactId>
|
||||
<version>${version.netty-tcnative}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -25,6 +25,7 @@ import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.WriteBufferWaterMark;
|
||||
import io.netty.channel.epoll.EpollChannelOption;
|
||||
import io.netty.channel.epoll.EpollDatagramChannel;
|
||||
import io.netty.channel.epoll.EpollEventLoopGroup;
|
||||
@@ -56,6 +57,7 @@ import io.netty.handler.stream.ChunkedWriteHandler;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
import io.netty.util.NettyRuntime;
|
||||
import io.netty.util.internal.SystemPropertyUtil;
|
||||
import org.apache.accumulo.core.conf.AccumuloConfiguration;
|
||||
import org.apache.curator.RetryPolicy;
|
||||
import org.apache.curator.framework.CuratorFramework;
|
||||
import org.apache.curator.framework.CuratorFrameworkFactory;
|
||||
@@ -359,7 +361,9 @@ public class Balancer {
|
||||
|
||||
// start curator framework
|
||||
RetryPolicy retryPolicy = new RetryForever(1000);
|
||||
curatorFramework = CuratorFrameworkFactory.newClient(balancerConfig.getZooKeeper().getServers(), 30000, 1000,
|
||||
int timeout = Long.valueOf(AccumuloConfiguration.getTimeInMillis(balancerConfig.getZooKeeper().getTimeout()))
|
||||
.intValue();
|
||||
curatorFramework = CuratorFrameworkFactory.newClient(balancerConfig.getZooKeeper().getServers(), timeout, 10000,
|
||||
retryPolicy);
|
||||
curatorFramework.start();
|
||||
ensureZkPaths(curatorFramework, zkPaths);
|
||||
@@ -450,10 +454,9 @@ public class Balancer {
|
||||
wsServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
||||
wsServer.option(ChannelOption.SO_BACKLOG, 128);
|
||||
wsServer.option(ChannelOption.SO_KEEPALIVE, true);
|
||||
/* Not sure if next three lines are necessary */
|
||||
/* Not sure if next two lines are necessary */
|
||||
wsServer.option(ChannelOption.SO_SNDBUF, 1048576);
|
||||
wsServer.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 838860);
|
||||
wsServer.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 620145);
|
||||
wsServer.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(620145, 838860));
|
||||
wsChannelHandle = wsServer.bind(wsIp, wsPort).sync().channel();
|
||||
final String wsAddress = ((InetSocketAddress) wsChannelHandle.localAddress()).getAddress().getHostAddress();
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package timely.balancer.configuration;
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import timely.configuration.Http;
|
||||
|
||||
@@ -10,9 +11,9 @@ public class BalancerHttp extends Http {
|
||||
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private GenericKeyedObjectPoolConfig httpClientPool = new GenericKeyedObjectPoolConfig();
|
||||
private GenericKeyedObjectPoolConfig<CloseableHttpClient> httpClientPool = new GenericKeyedObjectPoolConfig<>();
|
||||
|
||||
public GenericKeyedObjectPoolConfig getHttpClientPool() {
|
||||
public GenericKeyedObjectPoolConfig<CloseableHttpClient> getHttpClientPool() {
|
||||
return httpClientPool;
|
||||
}
|
||||
}
|
||||
@@ -4,27 +4,29 @@ import javax.validation.Valid;
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import timely.client.tcp.TcpClient;
|
||||
import timely.client.udp.UdpClient;
|
||||
import timely.configuration.Server;
|
||||
|
||||
public class BalancerServer extends Server {
|
||||
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private GenericKeyedObjectPoolConfig udpClientPool = new GenericKeyedObjectPoolConfig();
|
||||
private GenericKeyedObjectPoolConfig<UdpClient> udpClientPool = new GenericKeyedObjectPoolConfig<>();
|
||||
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private GenericKeyedObjectPoolConfig tcpClientPool = new GenericKeyedObjectPoolConfig();
|
||||
private GenericKeyedObjectPoolConfig<TcpClient> tcpClientPool = new GenericKeyedObjectPoolConfig<>();
|
||||
|
||||
private int numTcpPools = 1;
|
||||
|
||||
private int tcpBufferSize = -1;
|
||||
|
||||
public GenericKeyedObjectPoolConfig getUdpClientPool() {
|
||||
public GenericKeyedObjectPoolConfig<UdpClient> getUdpClientPool() {
|
||||
return udpClientPool;
|
||||
}
|
||||
|
||||
public GenericKeyedObjectPoolConfig getTcpClientPool() {
|
||||
public GenericKeyedObjectPoolConfig<TcpClient> getTcpClientPool() {
|
||||
return tcpClientPool;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,15 +4,26 @@ import javax.validation.Valid;
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
import timely.client.websocket.subscription.WebSocketSubscriptionClient;
|
||||
import timely.configuration.Websocket;
|
||||
|
||||
public class BalancerWebsocket extends Websocket {
|
||||
|
||||
@Valid
|
||||
@NestedConfigurationProperty
|
||||
private GenericKeyedObjectPoolConfig wsClientPool = new GenericKeyedObjectPoolConfig();
|
||||
private GenericKeyedObjectPoolConfig<WebSocketSubscriptionClient> wsClientPool = new GenericKeyedObjectPoolConfig<>();
|
||||
|
||||
public GenericKeyedObjectPoolConfig getWsClientPool() {
|
||||
public GenericKeyedObjectPoolConfig<WebSocketSubscriptionClient> getWsClientPool() {
|
||||
return wsClientPool;
|
||||
}
|
||||
|
||||
public int incomingBufferSize = 50000000;
|
||||
|
||||
public int getIncomingBufferSize() {
|
||||
return incomingBufferSize;
|
||||
}
|
||||
|
||||
public void setIncomingBufferSize(int incomingBufferSize) {
|
||||
this.incomingBufferSize = incomingBufferSize;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,14 @@
|
||||
package timely.balancer.configuration;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
public class ZooKeeper {
|
||||
|
||||
private String servers;
|
||||
|
||||
@NotBlank
|
||||
private String timeout = "120s";
|
||||
|
||||
public String getServers() {
|
||||
return servers;
|
||||
}
|
||||
@@ -11,4 +16,12 @@ public class ZooKeeper {
|
||||
public void setServers(String servers) {
|
||||
this.servers = servers;
|
||||
}
|
||||
|
||||
public String getTimeout() {
|
||||
return timeout;
|
||||
}
|
||||
|
||||
public void setTimeout(String timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
}
|
||||
@@ -4,16 +4,12 @@ import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import timely.balancer.configuration.BalancerHttp;
|
||||
import timely.balancer.configuration.BalancerSecurity;
|
||||
import timely.balancer.connection.TimelyBalancedHost;
|
||||
|
||||
public class HttpClientPool extends GenericKeyedObjectPool<TimelyBalancedHost, CloseableHttpClient> {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HttpClientPool.class);
|
||||
|
||||
public HttpClientPool(BalancerSecurity balancerSecurity, BalancerHttp http, SSLContext sslContext) {
|
||||
super(new HttpClientFactory(balancerSecurity, sslContext), http.getHttpClientPool());
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ public class WsClientFactory implements KeyedPooledObjectFactory<TimelyBalancedH
|
||||
@Override
|
||||
public PooledObject<WebSocketSubscriptionClient> makeObject(TimelyBalancedHost k) throws Exception {
|
||||
|
||||
int bufferSize = balancerConfig.getWebsocket().getSubscriptionBatchSize() * 500;
|
||||
int bufferSize = balancerConfig.getWebsocket().getIncomingBufferSize();
|
||||
WebSocketSubscriptionClient client = new WebSocketSubscriptionClient(sslContext, k.getHost(), k.getHttpPort(),
|
||||
k.getWsPort(), balancerConfig.getSecurity().getClientSsl().isUseClientCert(),
|
||||
balancerConfig.isLoginRequired(), "", "",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package timely.balancer.netty.http;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.net.URLEncoder;
|
||||
@@ -67,7 +67,7 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
||||
try {
|
||||
try {
|
||||
request = msg.getHttpRequest();
|
||||
String originalURI = request.getUri();
|
||||
String originalURI = request.uri();
|
||||
originalURI = encodeURI(originalURI);
|
||||
|
||||
String metric = null;
|
||||
@@ -101,7 +101,7 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
||||
|
||||
List<Header> relayedHeaderList = new ArrayList<>();
|
||||
for (Map.Entry<String, String> h : headers.entries()) {
|
||||
if (!h.getKey().equals(CONTENT_LENGTH)) {
|
||||
if (!h.getKey().equals(CONTENT_LENGTH.toString())) {
|
||||
relayedHeaderList.add(new BasicHeader(h.getKey(), h.getValue()));
|
||||
}
|
||||
}
|
||||
@@ -109,14 +109,14 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
||||
relayedHeaderList.toArray(headerArray);
|
||||
|
||||
String relayURI = "https://" + k.getHost() + ":" + k.getHttpPort() + originalURI;
|
||||
if (request.getMethod().equals(HttpMethod.GET)) {
|
||||
if (request.method().equals(HttpMethod.GET)) {
|
||||
HttpUriRequest relayedRequest = new HttpGet(relayURI);
|
||||
if (headerArray.length > 0) {
|
||||
relayedRequest.setHeaders(headerArray);
|
||||
}
|
||||
relayedResponse = client.execute(relayedRequest);
|
||||
|
||||
} else if (request.getMethod().equals(HttpMethod.POST)) {
|
||||
} else if (request.method().equals(HttpMethod.POST)) {
|
||||
HttpPost relayedRequest = new HttpPost(relayURI);
|
||||
|
||||
String content = request.content().toString(StandardCharsets.UTF_8);
|
||||
@@ -170,7 +170,7 @@ public class HttpRelayHandler extends SimpleChannelInboundHandler<HttpRequest> i
|
||||
if (client != null && k != null) {
|
||||
httpClientPool.returnObject(k, client);
|
||||
} else {
|
||||
LOG.error("NOT RETURNING CONNECTION! " + msg.getHttpRequest().getUri());
|
||||
LOG.error("NOT RETURNING CONNECTION! " + msg.getHttpRequest().uri());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public class WsClientHandler extends ClientHandler {
|
||||
Multimap<String, String> proxyRequestHeaders = HashMultimap.create();
|
||||
ProxiedEntityUtils.addProxyHeaders(proxyRequestHeaders, token.getClientCert());
|
||||
for (String s : proxyRequestHeaders.keySet()) {
|
||||
headers.put(s, new ArrayList(proxyRequestHeaders.get(s)));
|
||||
headers.put(s, new ArrayList<>(proxyRequestHeaders.get(s)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public class WsClientHandler extends ClientHandler {
|
||||
for (String s : originalRequestHeaders.keySet()) {
|
||||
if (!headers.containsKey(s)) {
|
||||
// add pre-existing values if key does not exist in proxyRequest
|
||||
headers.put(s, new ArrayList(originalRequestHeaders.get(s)));
|
||||
headers.put(s, new ArrayList<>(originalRequestHeaders.get(s)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,22 +108,12 @@ public class BalancedMetricResolver implements MetricResolver {
|
||||
LOG.debug("Handling assignments event {}. assignmentsLastUpdatedInHdfs:{}", event.getType().toString(),
|
||||
new Date(assignmentsLastUpdatedInHdfs.get().postValue()));
|
||||
if (event.getType().equals(TreeCacheEvent.Type.NODE_UPDATED)) {
|
||||
long lastLocalUpdate = assignmentsLastUpdatedLocal.get();
|
||||
long lastHdfsUpdate = assignmentsLastUpdatedInHdfs.get().postValue();
|
||||
if (lastHdfsUpdate > lastLocalUpdate) {
|
||||
LOG.debug("Reading assignments from hdfs lastHdfsUpdate ({}) > lastLocalUpdate ({})",
|
||||
new Date(lastHdfsUpdate), new Date(lastLocalUpdate));
|
||||
readAssignmentsFromHdfs();
|
||||
} else {
|
||||
LOG.debug("Not reading assignments from hdfs lastHdfsUpdate ({}) <= lastLocalUpdate ({})",
|
||||
new Date(lastHdfsUpdate), new Date(lastLocalUpdate));
|
||||
}
|
||||
readAssignmentsFromHdfs(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
TreeCache assignmentTreeCache = new TreeCache(curatorFramework, ASSIGNMENTS_LAST_UPDATED_PATH);
|
||||
try (TreeCache assignmentTreeCache = new TreeCache(curatorFramework, ASSIGNMENTS_LAST_UPDATED_PATH)) {
|
||||
assignmentTreeCache.getListenable().addListener(assignmentListener);
|
||||
assignmentTreeCache.start();
|
||||
} catch (Exception e) {
|
||||
@@ -144,8 +134,7 @@ public class BalancedMetricResolver implements MetricResolver {
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
TreeCache nonCachedMetricsTreeCache = new TreeCache(curatorFramework, NON_CACHED_METRICS);
|
||||
try (TreeCache nonCachedMetricsTreeCache = new TreeCache(curatorFramework, NON_CACHED_METRICS)) {
|
||||
nonCachedMetricsTreeCache.getListenable().addListener(nonCachedMetricsListener);
|
||||
nonCachedMetricsTreeCache.start();
|
||||
} catch (Exception e) {
|
||||
@@ -160,7 +149,7 @@ public class BalancedMetricResolver implements MetricResolver {
|
||||
}
|
||||
readNonCachedMetricsIP();
|
||||
|
||||
readAssignmentsFromHdfs();
|
||||
readAssignmentsFromHdfs(false);
|
||||
|
||||
timer.schedule(new TimerTask() {
|
||||
|
||||
@@ -185,10 +174,16 @@ public class BalancedMetricResolver implements MetricResolver {
|
||||
long lastLocalUpdate = assignmentsLastUpdatedLocal.get();
|
||||
long lastHdfsUpdate = assignmentsLastUpdatedInHdfs.get().postValue();
|
||||
if (lastLocalUpdate > lastHdfsUpdate) {
|
||||
LOG.debug("Writing assignments to hdfs lastLocalUpdate ({}) > lastHdfsUpdate ({})",
|
||||
LOG.debug("Leader writing assignments to hdfs lastLocalUpdate ({}) > lastHdfsUpdate ({})",
|
||||
new Date(lastLocalUpdate), new Date(lastHdfsUpdate));
|
||||
writeAssignmentsToHdfs();
|
||||
} else {
|
||||
LOG.trace(
|
||||
"Leader not writing assignments to hdfs lastLocalUpdate ({}) <= lastHdfsUpdate ({})",
|
||||
new Date(lastLocalUpdate), new Date(lastHdfsUpdate));
|
||||
writeAssigmentsToHdfs();
|
||||
}
|
||||
} else {
|
||||
readAssignmentsFromHdfs(true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
@@ -201,14 +196,17 @@ public class BalancedMetricResolver implements MetricResolver {
|
||||
|
||||
Set<String> currentNonCachedMetricsDistributed = new TreeSet<>();
|
||||
try {
|
||||
nonCachedMetricsIPRWLock.readLock().acquire();
|
||||
boolean acquired = false;
|
||||
while (!acquired) {
|
||||
acquired = nonCachedMetricsIPRWLock.readLock().acquire(60, TimeUnit.SECONDS);
|
||||
}
|
||||
byte[] currentNonCachedMetricsDistributedBytes = nonCachedMetricsIP.get().postValue();
|
||||
if (currentNonCachedMetricsDistributedBytes != null) {
|
||||
try {
|
||||
currentNonCachedMetricsDistributed = SerializationUtils
|
||||
.deserialize(currentNonCachedMetricsDistributedBytes);
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage());
|
||||
LOG.error(e.getMessage(), e);
|
||||
currentNonCachedMetricsDistributed = new TreeSet<>();
|
||||
}
|
||||
}
|
||||
@@ -249,7 +247,7 @@ public class BalancedMetricResolver implements MetricResolver {
|
||||
public void isLeader() {
|
||||
LOG.info("this balancer is the leader");
|
||||
isLeader.set(true);
|
||||
writeAssigmentsToHdfs();
|
||||
writeAssignmentsToHdfs();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -265,15 +263,15 @@ public class BalancedMetricResolver implements MetricResolver {
|
||||
|
||||
private void startServiceListener(CuratorFramework curatorFramework) {
|
||||
try {
|
||||
ServiceDiscovery discovery = ServiceDiscoveryBuilder.builder(ServerDetails.class).client(curatorFramework)
|
||||
.basePath(SERVICE_DISCOVERY_PATH).build();
|
||||
ServiceDiscovery<ServerDetails> discovery = ServiceDiscoveryBuilder.builder(ServerDetails.class)
|
||||
.client(curatorFramework).basePath(SERVICE_DISCOVERY_PATH).build();
|
||||
discovery.start();
|
||||
Collection<ServiceInstance> instances = discovery.queryForInstances("timely-server");
|
||||
Collection<ServiceInstance<ServerDetails>> instances = discovery.queryForInstances("timely-server");
|
||||
|
||||
balancerLock.writeLock().lock();
|
||||
try {
|
||||
for (ServiceInstance si : instances) {
|
||||
ServerDetails pl = (ServerDetails) si.getPayload();
|
||||
for (ServiceInstance<ServerDetails> si : instances) {
|
||||
ServerDetails pl = si.getPayload();
|
||||
TimelyBalancedHost tbh = TimelyBalancedHost.of(pl.getHost(), pl.getTcpPort(), pl.getHttpPort(),
|
||||
pl.getWsPort(), pl.getUdpPort());
|
||||
LOG.info("adding service {} host:{} tcpPort:{} httpPort:{} wsPort:{} udpPort:{}", si.getId(),
|
||||
@@ -286,7 +284,8 @@ public class BalancedMetricResolver implements MetricResolver {
|
||||
balancerLock.writeLock().unlock();
|
||||
}
|
||||
|
||||
final ServiceCache serviceCache = discovery.serviceCacheBuilder().name("timely-server").build();
|
||||
final ServiceCache<ServerDetails> serviceCache = discovery.serviceCacheBuilder().name("timely-server")
|
||||
.build();
|
||||
ServiceCacheListener listener = new ServiceCacheListener() {
|
||||
|
||||
@Override
|
||||
@@ -294,9 +293,9 @@ public class BalancedMetricResolver implements MetricResolver {
|
||||
boolean rebalanceNeeded = false;
|
||||
balancerLock.writeLock().lock();
|
||||
try {
|
||||
List<ServiceInstance> instances = serviceCache.getInstances();
|
||||
List<ServiceInstance<ServerDetails>> instances = serviceCache.getInstances();
|
||||
Set<TimelyBalancedHost> availableHosts = new HashSet<>();
|
||||
for (ServiceInstance si : instances) {
|
||||
for (ServiceInstance<ServerDetails> si : instances) {
|
||||
ServerDetails pl = (ServerDetails) si.getPayload();
|
||||
TimelyBalancedHost tbh = TimelyBalancedHost.of(pl.getHost(), pl.getTcpPort(),
|
||||
pl.getHttpPort(), pl.getWsPort(), pl.getUdpPort());
|
||||
@@ -341,14 +340,16 @@ public class BalancedMetricResolver implements MetricResolver {
|
||||
assignMetric(s, h);
|
||||
LOG.debug("Assigned server removed. Assigning {} to server {}:{}", s, h.getTcpPort());
|
||||
}
|
||||
writeAssigmentsToHdfs();
|
||||
}
|
||||
|
||||
} finally {
|
||||
balancerLock.writeLock().unlock();
|
||||
}
|
||||
if (isLeader.get() && rebalanceNeeded) {
|
||||
balance();
|
||||
if (isLeader.get()) {
|
||||
if (rebalanceNeeded) {
|
||||
balance();
|
||||
}
|
||||
writeAssignmentsToHdfs();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,7 +643,10 @@ public class BalancedMetricResolver implements MetricResolver {
|
||||
}
|
||||
|
||||
try {
|
||||
nonCachedMetricsIPRWLock.writeLock().acquire();
|
||||
boolean acquired = false;
|
||||
while (!acquired) {
|
||||
acquired = nonCachedMetricsIPRWLock.writeLock().acquire(60, TimeUnit.SECONDS);
|
||||
}
|
||||
byte[] currentNonCachedMetricsDistributedBytes = nonCachedMetricsIP.get().postValue();
|
||||
Set<String> currentNonCachedMetricsIP;
|
||||
if (currentNonCachedMetricsDistributedBytes == null) {
|
||||
@@ -689,7 +693,7 @@ public class BalancedMetricResolver implements MetricResolver {
|
||||
try {
|
||||
lock.writeLock().release();
|
||||
} catch (Exception e3) {
|
||||
LOG.error(e3.getMessage());
|
||||
LOG.error(e3.getMessage(), e3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -874,11 +878,32 @@ public class BalancedMetricResolver implements MetricResolver {
|
||||
return tbh;
|
||||
}
|
||||
|
||||
private void readAssignmentsFromHdfs() {
|
||||
private void readAssignmentsFromHdfs(boolean checkIfNecessary) {
|
||||
|
||||
try {
|
||||
long lastLocalUpdate = assignmentsLastUpdatedLocal.get();
|
||||
long lastHdfsUpdate = assignmentsLastUpdatedInHdfs.get().postValue();
|
||||
if (checkIfNecessary) {
|
||||
if (lastHdfsUpdate <= lastLocalUpdate) {
|
||||
LOG.debug("Not reading assignments from hdfs lastHdfsUpdate ({}) <= lastLocalUpdate ({})",
|
||||
new Date(lastHdfsUpdate), new Date(lastLocalUpdate));
|
||||
return;
|
||||
}
|
||||
}
|
||||
LOG.debug("Reading assignments from hdfs lastHdfsUpdate ({}) > lastLocalUpdate ({})",
|
||||
new Date(lastHdfsUpdate), new Date(lastLocalUpdate));
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
// proceed with reading from HDFS
|
||||
|
||||
Map<String, TimelyBalancedHost> assignedMetricToHostMap = new TreeMap<>();
|
||||
try {
|
||||
assignmentsIPRWLock.readLock().acquire();
|
||||
boolean acquired = false;
|
||||
while (!acquired) {
|
||||
acquired = assignmentsIPRWLock.readLock().acquire(60, TimeUnit.SECONDS);
|
||||
}
|
||||
balancerLock.writeLock().lock();
|
||||
Configuration configuration = new Configuration();
|
||||
FileSystem fs = FileSystem.get(configuration);
|
||||
@@ -911,8 +936,14 @@ public class BalancedMetricResolver implements MetricResolver {
|
||||
|
||||
metricToHostMap.clear();
|
||||
for (Map.Entry<String, TimelyBalancedHost> e : assignedMetricToHostMap.entrySet()) {
|
||||
if (shouldCache(e.getKey())) {
|
||||
metricToHostMap.put(e.getKey(), e.getValue());
|
||||
if (StringUtils.isNotBlank(e.getKey()) && e.getValue() != null) {
|
||||
if (shouldCache(e.getKey())) {
|
||||
metricToHostMap.put(e.getKey(), e.getValue());
|
||||
}
|
||||
} else {
|
||||
Exception e1 = new IllegalStateException(
|
||||
"Bad assignment metric:" + e.getKey() + " host:" + e.getValue());
|
||||
LOG.warn(e1.getMessage(), e1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -943,11 +974,14 @@ public class BalancedMetricResolver implements MetricResolver {
|
||||
}
|
||||
}
|
||||
|
||||
private void writeAssigmentsToHdfs() {
|
||||
private void writeAssignmentsToHdfs() {
|
||||
|
||||
CsvWriter writer = null;
|
||||
try {
|
||||
assignmentsIPRWLock.writeLock().acquire();
|
||||
boolean acquired = false;
|
||||
while (!acquired) {
|
||||
acquired = assignmentsIPRWLock.writeLock().acquire(60, TimeUnit.SECONDS);
|
||||
}
|
||||
balancerLock.readLock().lock();
|
||||
nonCachedMetricsLocalLock.readLock().lock();
|
||||
try {
|
||||
@@ -1005,12 +1039,17 @@ public class BalancedMetricResolver implements MetricResolver {
|
||||
|
||||
private void assignMetric(String metric, TimelyBalancedHost tbh) {
|
||||
if (isLeader.get()) {
|
||||
balancerLock.writeLock().lock();
|
||||
try {
|
||||
metricToHostMap.put(metric, tbh);
|
||||
assignmentsLastUpdatedLocal.set(System.currentTimeMillis());
|
||||
} finally {
|
||||
balancerLock.writeLock().unlock();
|
||||
if (StringUtils.isNotBlank(metric) && tbh != null) {
|
||||
balancerLock.writeLock().lock();
|
||||
try {
|
||||
metricToHostMap.put(metric, tbh);
|
||||
assignmentsLastUpdatedLocal.set(System.currentTimeMillis());
|
||||
} finally {
|
||||
balancerLock.writeLock().unlock();
|
||||
}
|
||||
} else {
|
||||
Exception e = new IllegalStateException("Bad assignment metric:" + metric + " host:" + tbh);
|
||||
LOG.warn(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -4,13 +4,13 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>1.2.4</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
<artifactId>timely-client</artifactId>
|
||||
<properties>
|
||||
<!-- PEP 440 compliant version gets substituted into src/main/python/template/setup.py -->
|
||||
<!-- use .dev0 instead of -SNAPSHOT -->
|
||||
<python.client.version>1.2.4</python.client.version>
|
||||
<python.client.version>1.2.6</python.client.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package timely.client.tcp;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.Socket;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@@ -14,7 +15,7 @@ public class TcpClient implements AutoCloseable {
|
||||
private final String host;
|
||||
private final int port;
|
||||
private Socket sock = null;
|
||||
private PrintWriter out = null;
|
||||
private BufferedWriter out = null;
|
||||
private long connectTime = 0L;
|
||||
private long backoff = 2000;
|
||||
private int bufferSize = -1;
|
||||
@@ -47,7 +48,6 @@ public class TcpClient implements AutoCloseable {
|
||||
*
|
||||
* @param metric
|
||||
* newline terminated string representation of Timely metric
|
||||
* @throws IOException
|
||||
*/
|
||||
public synchronized void write(String metric) throws IOException {
|
||||
if (connect() != 0) {
|
||||
@@ -60,7 +60,7 @@ public class TcpClient implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void flush() {
|
||||
public synchronized void flush() throws IOException {
|
||||
if (null != out) {
|
||||
out.flush();
|
||||
writesSinceFlush = 0;
|
||||
@@ -94,12 +94,12 @@ public class TcpClient implements AutoCloseable {
|
||||
}
|
||||
|
||||
private synchronized int connect() {
|
||||
if (null == sock || !sock.isConnected() || out.checkError()) {
|
||||
if (null == sock || !sock.isConnected()) {
|
||||
if (System.currentTimeMillis() > (connectTime + backoff)) {
|
||||
try {
|
||||
connectTime = System.currentTimeMillis();
|
||||
sock = new Socket(host, port);
|
||||
out = new PrintWriter(sock.getOutputStream(), false);
|
||||
out = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));
|
||||
backoff = 2000;
|
||||
LOG.trace("Connected to Timely at {}:{}", host, port);
|
||||
} catch (IOException e) {
|
||||
|
||||
@@ -62,7 +62,6 @@ public interface ObjectSizeOf {
|
||||
* ObjectSizeOf interface and if implemented on the object will use that.
|
||||
* Otherwise it will do a simple navigation of the fields using reflection.
|
||||
*
|
||||
* @param o
|
||||
* @return an approximation of the object size
|
||||
*/
|
||||
public static long getObjectSize(Object o, boolean useSizeInBytesMethod, boolean debug) {
|
||||
|
||||
@@ -77,8 +77,6 @@ public class Tag implements Comparable<Tag>, Serializable {
|
||||
|
||||
/**
|
||||
* Joins key and value into key=value
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String join() {
|
||||
return tagParser.combine(this);
|
||||
|
||||
@@ -47,7 +47,6 @@ public class TagListParser implements Parser<List<Tag>>, Combiner<Collection<Tag
|
||||
* An alternative combiner for a map of string to string instead of a list of
|
||||
* tags
|
||||
*
|
||||
* @param tags
|
||||
* @return string representation
|
||||
*/
|
||||
public String combine(Map<String, String> tags) {
|
||||
|
||||
@@ -5,4 +5,9 @@
|
||||
<Method name="connect" />
|
||||
<Class name="timely.client.tcp.TcpClient"/>
|
||||
</Match>
|
||||
<Match>
|
||||
<!-- Must ignore these everywhere, because of a javac byte code generation bug -->
|
||||
<!-- https://github.com/spotbugs/spotbugs/issues/756 -->
|
||||
<Bug pattern="RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE" />
|
||||
</Match>
|
||||
</FindBugsFilter>
|
||||
@@ -47,9 +47,9 @@ public class SerializationTest {
|
||||
testSerialization(remove);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> void testSerialization(T o) throws Exception {
|
||||
String ser = mapper.writeValueAsString(o);
|
||||
@SuppressWarnings("unchecked")
|
||||
T des = mapper.readValue(ser, (Class<T>) o.getClass());
|
||||
Assert.assertEquals(o, des);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>1.2.4</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
<artifactId>collectd-nsq-plugin</artifactId>
|
||||
<dependencies>
|
||||
|
||||
+8
-8
@@ -10,7 +10,7 @@ import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.collectd.api.OConfigItem;
|
||||
|
||||
public class PooledCloseableHttpClientFactory implements PooledObjectFactory {
|
||||
public class PooledCloseableHttpClientFactory implements PooledObjectFactory<CloseableHttpClient> {
|
||||
|
||||
private int connectionRequestTimeout = 10000; // 10 seconds in milliseconds
|
||||
private int connectTimeout = 30000; // 30 seconds in milliseconds
|
||||
@@ -43,19 +43,19 @@ public class PooledCloseableHttpClientFactory implements PooledObjectFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PooledObject makeObject() throws Exception {
|
||||
public PooledObject<CloseableHttpClient> makeObject() throws Exception {
|
||||
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(connectionRequestTimeout)
|
||||
.setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).build();
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setDefaultRequestConfig(requestConfig);
|
||||
builder.setConnectionTimeToLive(connectionTimeToLive, TimeUnit.MILLISECONDS);
|
||||
return new DefaultPooledObject(builder.build());
|
||||
return new DefaultPooledObject<>(builder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyObject(PooledObject pooledObject) throws Exception {
|
||||
public void destroyObject(PooledObject<CloseableHttpClient> pooledObject) throws Exception {
|
||||
try {
|
||||
((CloseableHttpClient) pooledObject.getObject()).close();
|
||||
pooledObject.getObject().close();
|
||||
} catch (Exception e) {
|
||||
// do nothing
|
||||
} finally {
|
||||
@@ -65,17 +65,17 @@ public class PooledCloseableHttpClientFactory implements PooledObjectFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateObject(PooledObject pooledObject) {
|
||||
public boolean validateObject(PooledObject<CloseableHttpClient> pooledObject) {
|
||||
return pooledObject.getObject() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activateObject(PooledObject pooledObject) throws Exception {
|
||||
public void activateObject(PooledObject<CloseableHttpClient> pooledObject) throws Exception {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivateObject(PooledObject pooledObject) throws Exception {
|
||||
public void passivateObject(PooledObject<CloseableHttpClient> pooledObject) throws Exception {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ public class WriteNSQPlugin extends CollectDPluginParent
|
||||
Collectd.registerWrite(WriteNSQPlugin.class.getName(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int write(ValueList vl) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
DataOutputStream out = new DataOutputStream(baos);
|
||||
@@ -110,15 +111,17 @@ public class WriteNSQPlugin extends CollectDPluginParent
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int shutdown() {
|
||||
Collectd.logInfo("Shutting down connection to NSQ at " + host + ":" + port);
|
||||
clientPool.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int config(OConfigItem config) {
|
||||
super.config(config);
|
||||
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
|
||||
GenericObjectPoolConfig<CloseableHttpClient> poolConfig = new GenericObjectPoolConfig<>();
|
||||
// use max size for maxTotal and maxIdle
|
||||
// no need to activate or passivate
|
||||
poolConfig.setMaxTotal(POOL_MAX_SIZE);
|
||||
@@ -156,7 +159,7 @@ public class WriteNSQPlugin extends CollectDPluginParent
|
||||
Collectd.logError("NSQ host, port, and topic must be configured");
|
||||
return -1;
|
||||
}
|
||||
this.clientPool = new GenericObjectPool(pooledCloseableHttpClientFactory, poolConfig);
|
||||
this.clientPool = new GenericObjectPool<>(pooledCloseableHttpClientFactory, poolConfig);
|
||||
this.endpoint = "http://" + host + ":" + port + "/mpub?topic=" + topic;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>1.2.4</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
<artifactId>collectd-plugin-parent</artifactId>
|
||||
<dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>1.2.4</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
<artifactId>collectd-timely-plugin</artifactId>
|
||||
<dependencies>
|
||||
|
||||
+7
-7
@@ -8,7 +8,7 @@ import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||
import org.collectd.api.Collectd;
|
||||
import org.collectd.api.OConfigItem;
|
||||
|
||||
public class PooledSocketFactory implements PooledObjectFactory {
|
||||
public class PooledSocketFactory implements PooledObjectFactory<Socket> {
|
||||
|
||||
private String host = null;
|
||||
private int port = 0;
|
||||
@@ -81,12 +81,12 @@ public class PooledSocketFactory implements PooledObjectFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public PooledObject makeObject() throws Exception {
|
||||
return new DefaultPooledObject(connect());
|
||||
public PooledObject<Socket> makeObject() throws Exception {
|
||||
return new DefaultPooledObject<>(connect());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyObject(PooledObject pooledObject) throws Exception {
|
||||
public void destroyObject(PooledObject<Socket> pooledObject) throws Exception {
|
||||
try {
|
||||
Collectd.logDebug("Shutting down connection to Timely at " + host + ":" + port);
|
||||
Socket socket = (Socket) pooledObject.getObject();
|
||||
@@ -103,7 +103,7 @@ public class PooledSocketFactory implements PooledObjectFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validateObject(PooledObject pooledObject) {
|
||||
public boolean validateObject(PooledObject<Socket> pooledObject) {
|
||||
if (connectionTimeToLive > -1) {
|
||||
if (System.currentTimeMillis() > pooledObject.getCreateTime() + connectionTimeToLive) {
|
||||
return false;
|
||||
@@ -114,12 +114,12 @@ public class PooledSocketFactory implements PooledObjectFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activateObject(PooledObject pooledObject) throws Exception {
|
||||
public void activateObject(PooledObject<Socket> pooledObject) throws Exception {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passivateObject(PooledObject pooledObject) throws Exception {
|
||||
public void passivateObject(PooledObject<Socket> pooledObject) throws Exception {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
@@ -86,13 +86,13 @@ public class WriteTimelyPlugin extends CollectDPluginParent
|
||||
PooledSocketFactory socketFactory = new PooledSocketFactory();
|
||||
retval = socketFactory.config(config);
|
||||
if (retval == 0) {
|
||||
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
|
||||
GenericObjectPoolConfig<Socket> poolConfig = new GenericObjectPoolConfig<>();
|
||||
// use max size for maxTotal and maxIdle
|
||||
// no need to activate and passivate
|
||||
poolConfig.setMaxTotal(POOL_MAX_SIZE);
|
||||
poolConfig.setMaxIdle(POOL_MAX_SIZE);
|
||||
poolConfig.setTestOnReturn(true);
|
||||
socketPool = new GenericObjectPool(socketFactory, poolConfig);
|
||||
socketPool = new GenericObjectPool<>(socketFactory, poolConfig);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>1.2.4</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
<artifactId>timely-common</artifactId>
|
||||
<dependencies>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>1.2.4</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
<artifactId>grafana-auth</artifactId>
|
||||
<dependencies>
|
||||
@@ -166,7 +166,6 @@
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-tcnative-boringssl-static</artifactId>
|
||||
<version>${version.netty-tcnative}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
-2
@@ -43,8 +43,6 @@ public class GrafanaAuthConfiguration {
|
||||
/**
|
||||
* Time to wait (in seconds) for connections to finish and to make sure no new
|
||||
* connections happen before shutting down Netty event loop groups.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getShutdownQuietPeriod() {
|
||||
return this.shutdownQuietPeriod;
|
||||
|
||||
+14
-14
@@ -1,6 +1,6 @@
|
||||
package timely.grafana.auth.netty.http;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_LENGTH;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.net.URLEncoder;
|
||||
@@ -71,7 +71,7 @@ public class GrafanaRelayHandler extends SimpleChannelInboundHandler<HttpRequest
|
||||
try {
|
||||
try {
|
||||
request = msg.getHttpRequest();
|
||||
String originalURI = request.getUri();
|
||||
String originalURI = request.uri();
|
||||
originalURI = encodeURI(originalURI);
|
||||
|
||||
if (msg instanceof GrafanaRequest) {
|
||||
@@ -92,37 +92,37 @@ public class GrafanaRelayHandler extends SimpleChannelInboundHandler<HttpRequest
|
||||
Multimap<String, String> headers = HttpHeaderUtils.toMultimap(request.headers());
|
||||
|
||||
// If incoming user sets these headers, do not relay them
|
||||
headers.removeAll("X-WEBAUTH-USER");
|
||||
headers.removeAll("X-WEBAUTH-NAME");
|
||||
headers.removeAll("x-webauth-user");
|
||||
headers.removeAll("x-webauth-name");
|
||||
TimelyPrincipal principal = token.getTimelyPrincipal();
|
||||
TimelyUser user = principal.getPrimaryUser();
|
||||
String subjectDn = user.getDn().subjectDN();
|
||||
String userName = DnUtils.getCommonName(subjectDn);
|
||||
String loginName = DnUtils.getShortName(subjectDn);
|
||||
headers.put("X-WEBAUTH-USER", loginName);
|
||||
headers.put("X-WEBAUTH-NAME", userName);
|
||||
headers.put("x-webauth-user", loginName);
|
||||
headers.put("x-webauth-name", userName);
|
||||
List<Header> relayedHeaderList = new ArrayList<>();
|
||||
for (Map.Entry<String, String> h : headers.entries()) {
|
||||
if (!h.getKey().equals(CONTENT_LENGTH)) {
|
||||
if (!h.getKey().equals(CONTENT_LENGTH.toString())) {
|
||||
relayedHeaderList.add(new BasicHeader(h.getKey(), h.getValue()));
|
||||
}
|
||||
}
|
||||
Header[] headerArray = new Header[relayedHeaderList.size()];
|
||||
relayedHeaderList.toArray(headerArray);
|
||||
relayURI = protocol + "://" + host + ":" + port + originalURI;
|
||||
if (request.getMethod().equals(HttpMethod.HEAD)) {
|
||||
if (request.method().equals(HttpMethod.HEAD)) {
|
||||
HttpHead relayedRequest = new HttpHead(relayURI);
|
||||
if (headerArray.length > 0) {
|
||||
relayedRequest.setHeaders(headerArray);
|
||||
}
|
||||
relayedResponse = client.execute(relayedRequest);
|
||||
} else if (request.getMethod().equals(HttpMethod.GET)) {
|
||||
} else if (request.method().equals(HttpMethod.GET)) {
|
||||
HttpGet relayedRequest = new HttpGet(relayURI);
|
||||
if (headerArray.length > 0) {
|
||||
relayedRequest.setHeaders(headerArray);
|
||||
}
|
||||
relayedResponse = client.execute(relayedRequest);
|
||||
} else if (request.getMethod().equals(HttpMethod.POST)) {
|
||||
} else if (request.method().equals(HttpMethod.POST)) {
|
||||
HttpPost relayedRequest = new HttpPost(relayURI);
|
||||
String content = request.content().toString(StandardCharsets.UTF_8);
|
||||
StringEntity entity = new StringEntity(content);
|
||||
@@ -131,7 +131,7 @@ public class GrafanaRelayHandler extends SimpleChannelInboundHandler<HttpRequest
|
||||
relayedRequest.setHeaders(headerArray);
|
||||
}
|
||||
relayedResponse = client.execute(relayedRequest);
|
||||
} else if (request.getMethod().equals(HttpMethod.PUT)) {
|
||||
} else if (request.method().equals(HttpMethod.PUT)) {
|
||||
HttpPut relayedRequest = new HttpPut(relayURI);
|
||||
String content = request.content().toString(StandardCharsets.UTF_8);
|
||||
StringEntity entity = new StringEntity(content);
|
||||
@@ -140,13 +140,13 @@ public class GrafanaRelayHandler extends SimpleChannelInboundHandler<HttpRequest
|
||||
relayedRequest.setHeaders(headerArray);
|
||||
}
|
||||
relayedResponse = client.execute(relayedRequest);
|
||||
} else if (request.getMethod().equals(HttpMethod.DELETE)) {
|
||||
} else if (request.method().equals(HttpMethod.DELETE)) {
|
||||
HttpDelete relayedRequest = new HttpDelete(relayURI);
|
||||
if (headerArray.length > 0) {
|
||||
relayedRequest.setHeaders(headerArray);
|
||||
}
|
||||
relayedResponse = client.execute(relayedRequest);
|
||||
} else if (request.getMethod().equals(HttpMethod.OPTIONS)) {
|
||||
} else if (request.method().equals(HttpMethod.OPTIONS)) {
|
||||
HttpOptions relayedRequest = new HttpOptions(relayURI);
|
||||
if (headerArray.length > 0) {
|
||||
relayedRequest.setHeaders(headerArray);
|
||||
@@ -199,7 +199,7 @@ public class GrafanaRelayHandler extends SimpleChannelInboundHandler<HttpRequest
|
||||
if (client != null && k != null) {
|
||||
httpClientPool.returnObject(k, client);
|
||||
} else {
|
||||
LOG.error("NOT RETURNING CONNECTION! " + msg.getHttpRequest().getUri());
|
||||
LOG.error("NOT RETURNING CONNECTION! " + msg.getHttpRequest().uri());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -8,7 +8,7 @@ import com.google.common.collect.Multimap;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.QueryStringDecoder;
|
||||
import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -47,7 +47,7 @@ public class GrafanaRequestDecoder extends MessageToMessageDecoder<FullHttpReque
|
||||
|
||||
public static String getSessionId(FullHttpRequest msg) {
|
||||
Multimap<String, String> headers = HttpHeaderUtils.toMultimap(msg.headers());
|
||||
Collection<String> cookies = headers.get(Names.COOKIE);
|
||||
Collection<String> cookies = headers.get(HttpHeaderNames.COOKIE.toString());
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
cookies.forEach(h -> {
|
||||
ServerCookieDecoder.STRICT.decode(h).forEach(c -> {
|
||||
@@ -70,7 +70,7 @@ public class GrafanaRequestDecoder extends MessageToMessageDecoder<FullHttpReque
|
||||
|
||||
LOG.trace(LOG_RECEIVED_REQUEST, msg);
|
||||
|
||||
final String uri = msg.getUri();
|
||||
final String uri = msg.uri();
|
||||
final QueryStringDecoder decoder = new QueryStringDecoder(uri);
|
||||
if (decoder.path().equals(nonSecureRedirectAddress)) {
|
||||
out.add(new StrictTransportResponse());
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>1.2.4</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
<artifactId>timely-app</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
Vendored
+2
-2
@@ -23,8 +23,8 @@
|
||||
{"name": "Project site", "url": "https://github.com/NationalSecurityAgency/timely"},
|
||||
{"name": "License & Terms", "url": "https://raw.githubusercontent.com/NationalSecurityAgency/timely/master/LICENSE"}
|
||||
],
|
||||
"version": "1.2.4",
|
||||
"updated": "2019-05-22"
|
||||
"version": "1.2.6",
|
||||
"updated": "2019-10-30"
|
||||
},
|
||||
|
||||
"includes": [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "timely-app",
|
||||
"private": true,
|
||||
"version": "1.2.4",
|
||||
"version": "1.2.6",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
{"name": "Project site", "url": "https://github.com/NationalSecurityAgency/timely"},
|
||||
{"name": "License & Terms", "url": "https://raw.githubusercontent.com/NationalSecurityAgency/timely/master/LICENSE"}
|
||||
],
|
||||
"version": "1.2.4",
|
||||
"updated": "2019-05-22"
|
||||
"version": "1.2.6",
|
||||
"updated": "2019-10-30"
|
||||
},
|
||||
|
||||
"includes": [
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>1.2.4</version>
|
||||
<version>1.2.6</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Timely</name>
|
||||
<description>A secure and scalable time series database based on Apache Accumulo</description>
|
||||
@@ -41,7 +41,7 @@
|
||||
<os.detection.classifierWithLikes>fedora</os.detection.classifierWithLikes>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<version.accumulo>1.9.2</version.accumulo>
|
||||
<version.accumulo>1.9.3</version.accumulo>
|
||||
<version.buildnumber-maven>1.4</version.buildnumber-maven>
|
||||
<version.caffeine>2.6.2</version.caffeine>
|
||||
<version.collectd>5.7.1</version.collectd>
|
||||
@@ -50,37 +50,39 @@
|
||||
<version.commons-pool2>2.6.1</version.commons-pool2>
|
||||
<version.curator>4.1.0</version.curator>
|
||||
<version.disruptor>3.4.2</version.disruptor>
|
||||
<version.easymock>4.0.2</version.easymock>
|
||||
<version.eclipse-lifecycle>1.0.0</version.eclipse-lifecycle>
|
||||
<version.fast-classpath-scanner>3.1.13</version.fast-classpath-scanner>
|
||||
<version.flink>1.1.4</version.flink>
|
||||
<version.google-flatbuffers>1.10.0</version.google-flatbuffers>
|
||||
<version.guava>27.1-jre</version.guava>
|
||||
<version.hadoop>2.7.3</version.hadoop>
|
||||
<version.hadoop>2.7.7</version.hadoop>
|
||||
<version.httpcomponents>4.5.6</version.httpcomponents>
|
||||
<version.impsort>1.2.0</version.impsort>
|
||||
<version.jackson>2.9.8</version.jackson>
|
||||
<version.jacoco>0.7.6.201602180812</version.jacoco>
|
||||
<version.impsort>1.3.0</version.impsort>
|
||||
<version.jackson>2.9.10</version.jackson>
|
||||
<version.jackson.databind>2.9.10</version.jackson.databind>
|
||||
<version.jacoco>0.8.4</version.jacoco>
|
||||
<version.javacsv>2.0</version.javacsv>
|
||||
<version.javassist>3.24.1-GA</version.javassist>
|
||||
<version.jcip-annotations>1.0</version.jcip-annotations>
|
||||
<version.jsoup>1.11.3</version.jsoup>
|
||||
<version.junit>4.12</version.junit>
|
||||
<version.log4j>2.11.2</version.log4j>
|
||||
<version.maven-assembly>2.6</version.maven-assembly>
|
||||
<version.maven-build-helper>1.12</version.maven-build-helper>
|
||||
<version.maven-compiler>3.3</version.maven-compiler>
|
||||
<version.maven-dependency>2.10</version.maven-dependency>
|
||||
<version.maven-jar>3.0.1</version.maven-jar>
|
||||
<version.maven-pmd>3.6</version.maven-pmd>
|
||||
<version.maven-rpm>2.1.4</version.maven-rpm>
|
||||
<version.maven-shade>2.4.2</version.maven-shade>
|
||||
<version.maven-surefire>2.19.1</version.maven-surefire>
|
||||
<version.netty>4.1.35.Final</version.netty>
|
||||
<version.maven-assembly>3.1.1</version.maven-assembly>
|
||||
<version.maven-build-helper>3.0.0</version.maven-build-helper>
|
||||
<version.maven-compiler>3.8.1</version.maven-compiler>
|
||||
<version.maven-dependency>3.1.1</version.maven-dependency>
|
||||
<version.maven-jar>3.1.2</version.maven-jar>
|
||||
<version.maven-pmd>3.12.0</version.maven-pmd>
|
||||
<version.maven-rpm>2.2.0</version.maven-rpm>
|
||||
<version.maven-shade>3.2.1</version.maven-shade>
|
||||
<version.maven-surefire>3.0.0-M3</version.maven-surefire>
|
||||
<version.netty>4.1.42.Final</version.netty>
|
||||
<version.netty-tcnative>2.0.25.Final</version.netty-tcnative>
|
||||
<version.os-maven>1.5.0.Final</version.os-maven>
|
||||
<version.powermock>1.6.4</version.powermock>
|
||||
<version.slf4j>1.7.26</version.slf4j>
|
||||
<version.spotbugs-maven>3.1.7</version.spotbugs-maven>
|
||||
<version.spotbugs-maven>3.1.12.1</version.spotbugs-maven>
|
||||
<version.spring-boot>2.1.3.RELEASE</version.spring-boot>
|
||||
<version.tyrus>1.15</version.tyrus>
|
||||
</properties>
|
||||
@@ -99,7 +101,7 @@
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>${version.jackson}</version>
|
||||
<version>${version.jackson.databind}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
@@ -146,6 +148,11 @@
|
||||
<artifactId>netty-all</artifactId>
|
||||
<version>${version.netty}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-tcnative-boringssl-static</artifactId>
|
||||
<version>${version.netty-tcnative}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.javacsv</groupId>
|
||||
<artifactId>javacsv</artifactId>
|
||||
@@ -391,6 +398,12 @@
|
||||
<version>${version.jcip-annotations}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.easymock</groupId>
|
||||
<artifactId>easymock</artifactId>
|
||||
<version>${version.easymock}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-easymock-release-full</artifactId>
|
||||
@@ -406,7 +419,7 @@
|
||||
<plugin>
|
||||
<groupId>net.revelc.code.formatter</groupId>
|
||||
<artifactId>formatter-maven-plugin</artifactId>
|
||||
<version>2.8.0</version>
|
||||
<version>2.10.0</version>
|
||||
<configuration>
|
||||
<compilerCompliance>${maven.compiler.source}</compilerCompliance>
|
||||
<compilerSource>${maven.compiler.source}</compilerSource>
|
||||
@@ -424,7 +437,7 @@
|
||||
<plugin>
|
||||
<groupId>com.github.ekryd.sortpom</groupId>
|
||||
<artifactId>sortpom-maven-plugin</artifactId>
|
||||
<version>2.8.0</version>
|
||||
<version>2.10.0</version>
|
||||
<configuration>
|
||||
<predefinedSortOrder>recommended_2008_06</predefinedSortOrder>
|
||||
<createBackupFile>false</createBackupFile>
|
||||
@@ -568,7 +581,7 @@
|
||||
<configuration>
|
||||
<rules>
|
||||
<requireMavenVersion>
|
||||
<version>3.0.5</version>
|
||||
<version>3.5.0</version>
|
||||
</requireMavenVersion>
|
||||
<requireJavaVersion>
|
||||
<version>[${maven.compiler.target},)</version>
|
||||
@@ -739,6 +752,9 @@
|
||||
<name>m2e.version</name>
|
||||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<maven.compiler.release>8</maven.compiler.release>
|
||||
</properties>
|
||||
<build>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
@@ -799,5 +815,14 @@
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>jdk-release-flag</id>
|
||||
<activation>
|
||||
<jdk>[9,)</jdk>
|
||||
</activation>
|
||||
<properties>
|
||||
<maven.compiler.release>8</maven.compiler.release>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ `uname` == "Darwin" ]]; then
|
||||
THIS_SCRIPT=`python -c 'import os,sys; print os.path.realpath(sys.argv[1])' $0`
|
||||
else
|
||||
THIS_SCRIPT=`readlink -f $0`
|
||||
fi
|
||||
|
||||
THIS_DIR="${THIS_SCRIPT%/*}"
|
||||
BASE_DIR=${THIS_DIR}/..
|
||||
CONF_DIR="${BASE_DIR}/conf"
|
||||
LIB_DIR="${BASE_DIR}/lib"
|
||||
|
||||
export CLASSPATH="${CONF_DIR}:${LIB_DIR}/*"
|
||||
JVM_ARGS="-Xmx1024m -Xms128m"
|
||||
JVM_ARGS="${JVM_ARGS} -Dlogging.config=${CONF_DIR}/log4j2-error-console.xml"
|
||||
JVM_ARGS="${JVM_ARGS} -Dlog4j.configurationFile=${CONF_DIR}/log4j2-error-console.xml"
|
||||
JVM_ARGS="${JVM_ARGS} -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector"
|
||||
|
||||
echo "$JAVA_HOME/bin/java ${JVM_ARGS} timely.store.compaction.util.TabletMetadataConsole --spring.config.name=timely"
|
||||
$JAVA_HOME/bin/java ${JVM_ARGS} timely.store.compaction.util.TabletMetadataConsole --spring.config.name=timely
|
||||
@@ -22,7 +22,7 @@ timely:
|
||||
cache-refresh-minutes: 5
|
||||
allow-anonymous-http-access: true
|
||||
allow-anonymous-ws-access: true
|
||||
ssl:
|
||||
server-ssl:
|
||||
certificate-file: /timely-server-src/server/pki/timely.csr
|
||||
key-file: /timely-server-src/server/pki/timely-pkcs8.key
|
||||
key-password: password
|
||||
|
||||
@@ -3,6 +3,8 @@ timely:
|
||||
meta-table: timely.meta
|
||||
metric-age-off-days:
|
||||
default: 7
|
||||
cache:
|
||||
enabled: false
|
||||
metrics-report-ignored-tags:
|
||||
accumulo:
|
||||
instance-name: TimelyStandalone
|
||||
@@ -22,7 +24,7 @@ timely:
|
||||
cache-refresh-minutes: 5
|
||||
allow-anonymous-http-access: true
|
||||
allow-anonymous-ws-access: true
|
||||
ssl:
|
||||
server-ssl:
|
||||
certificate-file:
|
||||
key-file:
|
||||
key-password: timely
|
||||
|
||||
@@ -27,7 +27,7 @@ timely:
|
||||
cache-refresh-minutes: 5
|
||||
allow-anonymous-http-access: true
|
||||
allow-anonymous-ws-access: true
|
||||
serverSsl:
|
||||
server-ssl:
|
||||
certificate-file:
|
||||
key-file:
|
||||
key-password:
|
||||
|
||||
+12
-2
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>timely</groupId>
|
||||
<artifactId>timely</artifactId>
|
||||
<version>1.2.4</version>
|
||||
<version>1.2.6</version>
|
||||
</parent>
|
||||
<artifactId>timely-server</artifactId>
|
||||
<dependencies>
|
||||
@@ -150,7 +150,6 @@
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-tcnative-boringssl-static</artifactId>
|
||||
<version>${version.netty-tcnative}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -178,11 +177,22 @@
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.easymock</groupId>
|
||||
<artifactId>easymock</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-easymock-release-full</artifactId>
|
||||
<classifier>full</classifier>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-test-autoconfigure</artifactId>
|
||||
|
||||
@@ -24,6 +24,7 @@ import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.WriteBufferWaterMark;
|
||||
import io.netty.channel.epoll.EpollChannelOption;
|
||||
import io.netty.channel.epoll.EpollDatagramChannel;
|
||||
import io.netty.channel.epoll.EpollEventLoopGroup;
|
||||
@@ -44,6 +45,7 @@ import io.netty.handler.codec.http.HttpRequestDecoder;
|
||||
import io.netty.handler.codec.http.HttpResponseEncoder;
|
||||
import io.netty.handler.codec.http.HttpServerCodec;
|
||||
import io.netty.handler.codec.http.cors.CorsConfig;
|
||||
import io.netty.handler.codec.http.cors.CorsConfigBuilder;
|
||||
import io.netty.handler.codec.http.cors.CorsHandler;
|
||||
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
@@ -58,6 +60,7 @@ import io.netty.handler.stream.ChunkedWriteHandler;
|
||||
import io.netty.handler.timeout.IdleStateHandler;
|
||||
import io.netty.util.NettyRuntime;
|
||||
import io.netty.util.internal.SystemPropertyUtil;
|
||||
import org.apache.accumulo.core.conf.AccumuloConfiguration;
|
||||
import org.apache.curator.RetryPolicy;
|
||||
import org.apache.curator.framework.CuratorFramework;
|
||||
import org.apache.curator.framework.CuratorFrameworkFactory;
|
||||
@@ -209,13 +212,13 @@ public class Server {
|
||||
payload.setWsPort(config.getWebsocket().getPort());
|
||||
payload.setUdpPort(config.getServer().getUdpPort());
|
||||
|
||||
ServiceInstanceBuilder builder = ServiceInstance.builder();
|
||||
ServiceInstanceBuilder<ServerDetails> builder = ServiceInstance.builder();
|
||||
String serviceName = host + ":" + config.getServer().getTcpPort();
|
||||
ServiceInstance serviceInstance = builder.id(serviceName).name("timely-server")
|
||||
ServiceInstance<ServerDetails> serviceInstance = builder.id(serviceName).name("timely-server")
|
||||
.address(config.getServer().getIp()).port(config.getServer().getTcpPort()).payload(payload).build();
|
||||
|
||||
ServiceDiscovery discovery = ServiceDiscoveryBuilder.builder(ServerDetails.class).client(curatorFramework)
|
||||
.basePath(SERVICE_DISCOVERY_PATH).build();
|
||||
ServiceDiscovery<ServerDetails> discovery = ServiceDiscoveryBuilder.builder(ServerDetails.class)
|
||||
.client(curatorFramework).basePath(SERVICE_DISCOVERY_PATH).build();
|
||||
discovery.start();
|
||||
discovery.registerService(serviceInstance);
|
||||
|
||||
@@ -415,7 +418,9 @@ public class Server {
|
||||
public void run() throws Exception {
|
||||
|
||||
RetryPolicy retryPolicy = new RetryForever(1000);
|
||||
curatorFramework = CuratorFrameworkFactory.newClient(config.getAccumulo().getZookeepers(), 30000, 10000,
|
||||
int timeout = Long.valueOf(AccumuloConfiguration.getTimeInMillis(config.getAccumulo().getZookeeperTimeout()))
|
||||
.intValue();
|
||||
curatorFramework = CuratorFrameworkFactory.newClient(config.getAccumulo().getZookeepers(), timeout, 10000,
|
||||
retryPolicy);
|
||||
curatorFramework.start();
|
||||
ensureZkPaths(curatorFramework, zkPaths);
|
||||
@@ -508,10 +513,9 @@ public class Server {
|
||||
wsServer.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
|
||||
wsServer.option(ChannelOption.SO_BACKLOG, 128);
|
||||
wsServer.option(ChannelOption.SO_KEEPALIVE, true);
|
||||
/* Not sure if next three lines are necessary */
|
||||
/* Not sure if next two lines are necessary */
|
||||
wsServer.option(ChannelOption.SO_SNDBUF, 1048576);
|
||||
wsServer.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 838860);
|
||||
wsServer.option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 620145);
|
||||
wsServer.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(620145, 838860));
|
||||
wsChannelHandle = wsServer.bind(wsIp, wsPort).sync().channel();
|
||||
final String wsAddress = ((InetSocketAddress) wsChannelHandle.localAddress()).getAddress().getHostAddress();
|
||||
|
||||
@@ -591,11 +595,11 @@ public class Server {
|
||||
ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
|
||||
ch.pipeline().addLast("chunker", new ChunkedWriteHandler());
|
||||
final Cors corsCfg = config.getHttp().getCors();
|
||||
final CorsConfig.Builder ccb;
|
||||
final CorsConfigBuilder ccb;
|
||||
if (corsCfg.isAllowAnyOrigin()) {
|
||||
ccb = new CorsConfig.Builder();
|
||||
ccb = CorsConfigBuilder.forAnyOrigin();
|
||||
} else {
|
||||
ccb = new CorsConfig.Builder(corsCfg.getAllowedOrigins().stream().toArray(String[]::new));
|
||||
ccb = CorsConfigBuilder.forOrigins(corsCfg.getAllowedOrigins().stream().toArray(String[]::new));
|
||||
}
|
||||
if (corsCfg.isAllowNullOrigin()) {
|
||||
ccb.allowNullOrigin();
|
||||
|
||||
@@ -1,28 +1,14 @@
|
||||
package timely.adapter.accumulo;
|
||||
|
||||
import org.apache.accumulo.core.client.lexicoder.LongLexicoder;
|
||||
import org.apache.accumulo.core.client.lexicoder.PairLexicoder;
|
||||
import org.apache.accumulo.core.client.lexicoder.StringLexicoder;
|
||||
import org.apache.accumulo.core.data.Key;
|
||||
import timely.api.model.Meta;
|
||||
import timely.model.Metric;
|
||||
import timely.model.parse.TagListParser;
|
||||
import timely.model.parse.TagParser;
|
||||
|
||||
/**
|
||||
* Creates Accumulo data structures from {@link Metric}
|
||||
*/
|
||||
public class MetaAdapter {
|
||||
|
||||
private static final PairLexicoder<String, Long> rowCoder = new PairLexicoder<>(new StringLexicoder(),
|
||||
new LongLexicoder());
|
||||
|
||||
private static final PairLexicoder<Long, String> colQualCoder = new PairLexicoder<>(new LongLexicoder(),
|
||||
new StringLexicoder());
|
||||
|
||||
private static final TagParser tagParser = new TagParser();
|
||||
private static final TagListParser tagListParser = new TagListParser();
|
||||
|
||||
public static Key createMetricKey(String metricName, Long timestamp) {
|
||||
return new Key(Meta.METRIC_PREFIX + metricName, "", "", timestamp);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,10 @@ import java.util.List;
|
||||
|
||||
import org.apache.accumulo.core.data.Key;
|
||||
import org.apache.accumulo.core.data.Value;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.builder.CompareToBuilder;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
|
||||
public class Meta implements Comparable<Meta> {
|
||||
|
||||
@@ -49,9 +53,15 @@ public class Meta implements Comparable<Meta> {
|
||||
|
||||
public List<Key> toKeys() {
|
||||
List<Key> keys = new ArrayList<>();
|
||||
keys.add(new Key(METRIC_PREFIX + metric));
|
||||
keys.add(new Key(TAG_PREFIX + metric, tagKey));
|
||||
keys.add(new Key(VALUE_PREFIX + metric, tagKey, tagValue));
|
||||
if (StringUtils.isNotBlank(metric)) {
|
||||
keys.add(new Key(METRIC_PREFIX + metric));
|
||||
}
|
||||
if (StringUtils.isNotBlank(tagKey)) {
|
||||
keys.add(new Key(TAG_PREFIX + metric, tagKey));
|
||||
}
|
||||
if (StringUtils.isNotBlank(tagKey) && StringUtils.isNotBlank(tagValue)) {
|
||||
keys.add(new Key(VALUE_PREFIX + metric, tagKey, tagValue));
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
@@ -97,39 +107,25 @@ public class Meta implements Comparable<Meta> {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((metric == null) ? 0 : metric.hashCode());
|
||||
result = prime * result + ((tagKey == null) ? 0 : tagKey.hashCode());
|
||||
result = prime * result + ((tagValue == null) ? 0 : tagValue.hashCode());
|
||||
return result;
|
||||
HashCodeBuilder builder = new HashCodeBuilder();
|
||||
builder.append(metric);
|
||||
builder.append(tagKey);
|
||||
builder.append(tagValue);
|
||||
return builder.toHashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof Meta) {
|
||||
Meta obj = (Meta) o;
|
||||
EqualsBuilder builder = new EqualsBuilder();
|
||||
builder.append(this.metric, obj.metric);
|
||||
builder.append(this.tagKey, obj.tagKey);
|
||||
builder.append(this.tagValue, obj.tagValue);
|
||||
return builder.isEquals();
|
||||
} else {
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
Meta other = (Meta) obj;
|
||||
if (metric == null) {
|
||||
if (other.metric != null)
|
||||
return false;
|
||||
} else if (!metric.equals(other.metric))
|
||||
return false;
|
||||
if (tagKey == null) {
|
||||
if (other.tagKey != null)
|
||||
return false;
|
||||
} else if (!tagKey.equals(other.tagKey))
|
||||
return false;
|
||||
if (tagValue == null) {
|
||||
if (other.tagValue != null)
|
||||
return false;
|
||||
} else if (!tagValue.equals(other.tagValue))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -139,15 +135,10 @@ public class Meta implements Comparable<Meta> {
|
||||
|
||||
@Override
|
||||
public int compareTo(Meta o) {
|
||||
int result = metric.compareTo(o.metric);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = tagKey.compareTo(o.tagKey);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
return tagValue.compareTo(o.tagValue);
|
||||
CompareToBuilder builder = new CompareToBuilder();
|
||||
builder.append(this.metric, o.metric);
|
||||
builder.append(this.tagKey, o.tagKey);
|
||||
builder.append(this.tagValue, o.tagValue);
|
||||
return builder.toComparison();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,8 +4,6 @@ public interface TcpRequest extends Request {
|
||||
|
||||
/**
|
||||
* Parse a line of text received and populate this object
|
||||
*
|
||||
* @param line
|
||||
*/
|
||||
public void parse(String line);
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ public interface UdpRequest {
|
||||
|
||||
/**
|
||||
* Parse a line of text received and populate this object
|
||||
*
|
||||
* @param line
|
||||
*/
|
||||
public void parse(String line);
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||
@@ -129,8 +129,8 @@ public class MetricsResponse {
|
||||
}
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
|
||||
Unpooled.copiedBuffer(buf));
|
||||
response.headers().set(Names.CONTENT_TYPE, responseType);
|
||||
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, responseType);
|
||||
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -156,8 +156,10 @@ public class MetricsResponse {
|
||||
b.append(TR_END);
|
||||
String prevMetric = null;
|
||||
StringBuilder tags = new StringBuilder();
|
||||
Map<String, Long> tagMap = new HashMap<>();
|
||||
for (Meta m : tree) {
|
||||
if (prevMetric != null && !m.getMetric().equals(prevMetric)) {
|
||||
tagMap.clear();
|
||||
b.append(TR_START);
|
||||
b.append(TD_START).append(prevMetric).append(TD_END);
|
||||
b.append(TD_START).append(tags.toString()).append(TD_END);
|
||||
@@ -168,8 +170,12 @@ public class MetricsResponse {
|
||||
if (prevMetric == null) {
|
||||
prevMetric = m.getMetric();
|
||||
}
|
||||
long numValues = tagMap.getOrDefault(m.getTagKey(), 0l);
|
||||
if (!(this.ignoredTags.contains(m.getTagKey()))) {
|
||||
tags.append(m.getTagKey()).append("=").append(m.getTagValue()).append(" ");
|
||||
if (numValues <= conf.getMetaCache().getMaxTagValues()) {
|
||||
tags.append(m.getTagKey()).append("=").append(m.getTagValue()).append(" ");
|
||||
tagMap.put(m.getTagKey(), ++numValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
b.append(TR_START);
|
||||
|
||||
@@ -43,9 +43,13 @@ public class AuthenticationService {
|
||||
try {
|
||||
springContext = new ClassPathXmlApplicationContext("security.xml");
|
||||
authManager = springContext.getBean("authenticationManager", AuthenticationManager.class);
|
||||
requiredRoles = springContext.getBean("requiredRoles", List.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> uncheckedRoles = springContext.getBean("requiredRoles", List.class);
|
||||
requiredRoles = uncheckedRoles;
|
||||
requiredRoles.removeIf(String::isEmpty);
|
||||
requiredAuths = springContext.getBean("requiredAuths", List.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<String> uncheckedAuths = springContext.getBean("requiredAuths", List.class);
|
||||
requiredAuths = uncheckedAuths;
|
||||
requiredAuths.removeIf(String::isEmpty);
|
||||
} catch (BeansException e) {
|
||||
throw new ServiceConfigurationError("Error setting up Authentication objects: " + e.getMessage(),
|
||||
|
||||
@@ -16,8 +16,6 @@ import org.apache.accumulo.core.data.Value;
|
||||
import org.apache.accumulo.core.data.thrift.IterInfo;
|
||||
import org.apache.accumulo.core.security.Authorizations;
|
||||
import org.apache.hadoop.io.Text;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A simple wrapper around a {@link ScannerBase} that overrides the methods that
|
||||
@@ -27,7 +25,6 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class ScannerBaseDelegate implements ScannerBase {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ScannerBaseDelegate.class);
|
||||
private static final String SYSTEM_ITERATOR_NAME_PREFIX = "sys_";
|
||||
|
||||
protected final ScannerBase delegate;
|
||||
@@ -139,10 +136,11 @@ public class ScannerBaseDelegate implements ScannerBase {
|
||||
@Override
|
||||
public void clearScanIterators() {
|
||||
if (delegate instanceof ScannerOptions) {
|
||||
ScannerOptionsHelper opts = new ScannerOptionsHelper((ScannerOptions) delegate);
|
||||
for (IteratorSetting iteratorSetting : opts.getIterators()) {
|
||||
if (!iteratorSetting.getName().startsWith(SYSTEM_ITERATOR_NAME_PREFIX)) {
|
||||
delegate.removeScanIterator(iteratorSetting.getName());
|
||||
try (ScannerOptionsHelper opts = new ScannerOptionsHelper((ScannerOptions) delegate)) {
|
||||
for (IteratorSetting iteratorSetting : opts.getIterators()) {
|
||||
if (!iteratorSetting.getName().startsWith(SYSTEM_ITERATOR_NAME_PREFIX)) {
|
||||
delegate.removeScanIterator(iteratorSetting.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -13,6 +13,7 @@ import timely.auth.util.ProxiedEntityUtils;
|
||||
*/
|
||||
public class SubjectIssuerDNPair implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final String subjectDN;
|
||||
private final String issuerDN;
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import timely.auth.util.DnUtils;
|
||||
@XmlAccessorType(XmlAccessType.NONE)
|
||||
public class TimelyPrincipal implements Principal, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private final String username;
|
||||
private final TimelyUser primaryUser;
|
||||
@XmlElement
|
||||
@@ -103,7 +104,7 @@ public class TimelyPrincipal implements Principal, Serializable {
|
||||
|
||||
public Set<String> getProxyServers() {
|
||||
|
||||
// @formatter:off
|
||||
// @formatter:off
|
||||
Set<String> proxyServers = getProxiedUsers().stream()
|
||||
.filter(u -> u.getUserType() == TimelyUser.UserType.SERVER)
|
||||
.map(TimelyUser::getDn)
|
||||
|
||||
@@ -20,6 +20,8 @@ import timely.auth.util.DnUtils;
|
||||
*/
|
||||
public class TimelyUser implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public enum UserType {
|
||||
USER, SERVER
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@ public class HttpHeaderUtils {
|
||||
Multimap<String, String> headerMultimap = HashMultimap.create();
|
||||
if (headers != null) {
|
||||
for (Map.Entry<String, String> e : headers.entries()) {
|
||||
headerMultimap.put(e.getKey(), e.getValue());
|
||||
// lower case for HTTP/2 compatibility; even for HTTP/1, these were always
|
||||
// case-insensitive
|
||||
headerMultimap.put(e.getKey().toLowerCase(), e.getValue());
|
||||
}
|
||||
}
|
||||
return headerMultimap;
|
||||
@@ -22,6 +24,9 @@ public class HttpHeaderUtils {
|
||||
public static String getSingleHeader(Multimap<String, String> headers, String headerName, boolean enforceOneValue)
|
||||
throws IllegalArgumentException {
|
||||
String value = null;
|
||||
// lower case for HTTP/2 compatibility; even for HTTP/1, these were always
|
||||
// case-insensitive
|
||||
headerName = headerName.toLowerCase();
|
||||
Collection<String> values = (headers == null) ? null : headers.get(headerName);
|
||||
if (values != null && !values.isEmpty()) {
|
||||
if (values.size() > 1 && enforceOneValue) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package timely.configuration;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
|
||||
public class Accumulo {
|
||||
@@ -12,6 +12,8 @@ public class Accumulo {
|
||||
@NotBlank
|
||||
private String instanceName;
|
||||
@NotBlank
|
||||
private String zookeeperTimeout = "120s";
|
||||
@NotBlank
|
||||
private String username;
|
||||
@NotBlank
|
||||
private String password;
|
||||
@@ -46,6 +48,14 @@ public class Accumulo {
|
||||
this.instanceName = instanceName;
|
||||
}
|
||||
|
||||
public String getZookeeperTimeout() {
|
||||
return zookeeperTimeout;
|
||||
}
|
||||
|
||||
public void setZookeeperTimeout(String zookeeperTimeout) {
|
||||
this.zookeeperTimeout = zookeeperTimeout;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ public class Cache {
|
||||
private List<String> nonCachedMetrics = new ArrayList<>();
|
||||
private long maxUniqueTagSets = 50000;
|
||||
private long flushInterval = 5000;
|
||||
private long staleCacheExpiration = 1800000;
|
||||
|
||||
public HashMap<String, Integer> getMetricAgeOffHours() {
|
||||
return metricAgeOffHours;
|
||||
@@ -57,4 +58,12 @@ public class Cache {
|
||||
public void setFlushInterval(long flushInterval) {
|
||||
this.flushInterval = flushInterval;
|
||||
}
|
||||
|
||||
public long getStaleCacheExpiration() {
|
||||
return staleCacheExpiration;
|
||||
}
|
||||
|
||||
public void setStaleCacheExpiration(long staleCacheExpiration) {
|
||||
this.staleCacheExpiration = staleCacheExpiration;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package timely.configuration;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||
|
||||
public class Http {
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package timely.configuration;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
|
||||
public class Server {
|
||||
|
||||
@NotBlank
|
||||
@@ -42,8 +41,6 @@ public class Server {
|
||||
/**
|
||||
* Time to wait (in seconds) for connections to finish and to make sure no new
|
||||
* connections happen before shutting down Netty event loop groups.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getShutdownQuietPeriod() {
|
||||
return this.shutdownQuietPeriod;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package timely.configuration;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.hibernate.validator.constraints.NotBlank;
|
||||
|
||||
public class Websocket {
|
||||
|
||||
@NotBlank
|
||||
|
||||
@@ -5,7 +5,7 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import timely.api.request.CacheRequest;
|
||||
@@ -35,8 +35,8 @@ public class HttpCacheRequestHandler extends SimpleChannelInboundHandler<CacheRe
|
||||
}
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
|
||||
Unpooled.copiedBuffer(buf));
|
||||
response.headers().set(Names.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
|
||||
sendResponse(ctx, response);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import org.slf4j.Logger;
|
||||
@@ -35,8 +35,8 @@ public class HttpMetricPutHandler extends SimpleChannelInboundHandler<MetricRequ
|
||||
}
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
|
||||
Unpooled.EMPTY_BUFFER);
|
||||
response.headers().set(Names.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
|
||||
sendResponse(ctx, response);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpMethod;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.QueryStringDecoder;
|
||||
@@ -52,7 +52,7 @@ public class HttpRequestDecoder extends MessageToMessageDecoder<FullHttpRequest>
|
||||
|
||||
public static String getSessionId(FullHttpRequest msg) {
|
||||
Multimap<String, String> headers = HttpHeaderUtils.toMultimap(msg.headers());
|
||||
Collection<String> cookies = headers.get(Names.COOKIE);
|
||||
Collection<String> cookies = headers.get(HttpHeaderNames.COOKIE.toString());
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
cookies.forEach(h -> {
|
||||
ServerCookieDecoder.STRICT.decode(h).forEach(c -> {
|
||||
@@ -75,7 +75,7 @@ public class HttpRequestDecoder extends MessageToMessageDecoder<FullHttpRequest>
|
||||
|
||||
LOG.trace(LOG_RECEIVED_REQUEST, msg);
|
||||
|
||||
final String uri = msg.getUri();
|
||||
final String uri = msg.uri();
|
||||
final QueryStringDecoder decoder = new QueryStringDecoder(uri);
|
||||
if (decoder.path().equals(nonSecureRedirectAddress)) {
|
||||
out.add(new StrictTransportResponse());
|
||||
@@ -87,10 +87,10 @@ public class HttpRequestDecoder extends MessageToMessageDecoder<FullHttpRequest>
|
||||
|
||||
HttpRequest request;
|
||||
try {
|
||||
if (msg.getMethod().equals(HttpMethod.GET)) {
|
||||
if (msg.method().equals(HttpMethod.GET)) {
|
||||
HttpGetRequest get = AnnotationResolver.getClassForHttpGet(decoder.path());
|
||||
request = get.parseQueryParameters(decoder);
|
||||
} else if (msg.getMethod().equals(HttpMethod.POST)) {
|
||||
} else if (msg.method().equals(HttpMethod.POST)) {
|
||||
HttpPostRequest post = AnnotationResolver.getClassForHttpPost(decoder.path());
|
||||
String content = "";
|
||||
ByteBuf body = msg.content();
|
||||
@@ -101,8 +101,9 @@ public class HttpRequestDecoder extends MessageToMessageDecoder<FullHttpRequest>
|
||||
} else {
|
||||
TimelyException e = new TimelyException(HttpResponseStatus.METHOD_NOT_ALLOWED.code(),
|
||||
"unhandled method type", "");
|
||||
e.addResponseHeader(Names.ALLOW, HttpMethod.GET.name() + "," + HttpMethod.POST.name());
|
||||
LOG.warn("Unhandled HTTP request type {}", msg.getMethod());
|
||||
e.addResponseHeader(HttpHeaderNames.ALLOW.toString(),
|
||||
HttpMethod.GET.name() + "," + HttpMethod.POST.name());
|
||||
LOG.warn("Unhandled HTTP request type {}", msg.method());
|
||||
throw e;
|
||||
}
|
||||
if (request instanceof AuthenticatedRequest) {
|
||||
|
||||
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
package timely.netty.http;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpHeaders.Names.CACHE_CONTROL;
|
||||
import static io.netty.handler.codec.http.HttpHeaders.Names.CONNECTION;
|
||||
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
|
||||
import static io.netty.handler.codec.http.HttpHeaders.Names.DATE;
|
||||
import static io.netty.handler.codec.http.HttpHeaders.Names.EXPIRES;
|
||||
import static io.netty.handler.codec.http.HttpHeaders.Names.IF_MODIFIED_SINCE;
|
||||
import static io.netty.handler.codec.http.HttpHeaders.Names.LAST_MODIFIED;
|
||||
import static io.netty.handler.codec.http.HttpHeaders.Names.LOCATION;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CACHE_CONTROL;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.DATE;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.EXPIRES;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.IF_MODIFIED_SINCE;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.LAST_MODIFIED;
|
||||
import static io.netty.handler.codec.http.HttpHeaderNames.LOCATION;
|
||||
import static io.netty.handler.codec.http.HttpMethod.GET;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
|
||||
import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
|
||||
@@ -59,9 +59,10 @@ import io.netty.handler.codec.http.DefaultHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpChunkedInput;
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||
import io.netty.handler.codec.http.HttpResponse;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpUtil;
|
||||
import io.netty.handler.stream.ChunkedFile;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.internal.SystemPropertyUtil;
|
||||
@@ -94,7 +95,7 @@ import timely.netty.Constants;
|
||||
* Request #1 Headers
|
||||
* ===================
|
||||
* GET /file1.txt HTTP/1.1
|
||||
*
|
||||
*
|
||||
* Response #1 Headers
|
||||
* ===================
|
||||
* HTTP/1.1 200 OK
|
||||
@@ -102,12 +103,12 @@ import timely.netty.Constants;
|
||||
* Last-Modified: Wed, 30 Jun 2010 21:36:48 GMT
|
||||
* Expires: Tue, 01 Mar 2012 22:44:26 GMT
|
||||
* Cache-Control: private, max-age=31536000
|
||||
*
|
||||
*
|
||||
* Request #2 Headers
|
||||
* ===================
|
||||
* GET /file1.txt HTTP/1.1
|
||||
* If-Modified-Since: Wed, 30 Jun 2010 21:36:48 GMT
|
||||
*
|
||||
*
|
||||
* Response #2 Headers
|
||||
* ===================
|
||||
* HTTP/1.1 304 Not Modified
|
||||
@@ -125,17 +126,17 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
|
||||
|
||||
@Override
|
||||
public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
|
||||
if (!request.getDecoderResult().isSuccess()) {
|
||||
if (!request.decoderResult().isSuccess()) {
|
||||
sendError(ctx, BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.getMethod() != GET) {
|
||||
if (request.method() != GET) {
|
||||
sendError(ctx, METHOD_NOT_ALLOWED);
|
||||
return;
|
||||
}
|
||||
|
||||
String uri = request.getUri();
|
||||
String uri = request.uri();
|
||||
if (uri.startsWith("/favicon.ico")) {
|
||||
uri = uri.replaceFirst("\\/", "/webapp/");
|
||||
}
|
||||
@@ -201,12 +202,12 @@ public class HttpStaticFileServerHandler extends SimpleChannelInboundHandler<Ful
|
||||
long fileLength = raf.length();
|
||||
|
||||
HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
|
||||
HttpHeaders.setContentLength(response, fileLength);
|
||||
HttpUtil.setContentLength(response, fileLength);
|
||||
setContentTypeHeader(response, file);
|
||||
setDateAndCacheHeaders(response, file);
|
||||
HttpHeaders.setTransferEncodingChunked(response);
|
||||
if (HttpHeaders.isKeepAlive(request)) {
|
||||
response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
|
||||
HttpUtil.setTransferEncodingChunked(response, true);
|
||||
if (HttpUtil.isKeepAlive(request)) {
|
||||
response.headers().set(CONNECTION, HttpHeaderValues.KEEP_ALIVE);
|
||||
}
|
||||
|
||||
// Write the initial line and the header.
|
||||
|
||||
@@ -7,7 +7,7 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import timely.api.request.VersionRequest;
|
||||
@@ -20,8 +20,8 @@ public class HttpVersionRequestHandler extends SimpleChannelInboundHandler<Versi
|
||||
protected void channelRead0(ChannelHandlerContext ctx, VersionRequest v) throws Exception {
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
|
||||
Unpooled.copiedBuffer(VersionRequest.VERSION.getBytes(StandardCharsets.UTF_8)));
|
||||
response.headers().set(Names.CONTENT_TYPE, Constants.TEXT_TYPE);
|
||||
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.TEXT_TYPE);
|
||||
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
|
||||
sendResponse(ctx, response);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpResponseEncoder;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
@@ -51,7 +51,7 @@ public class NonSslRedirectHandler extends OptionalSslHandler implements TimelyH
|
||||
LOG.trace("Received non-SSL request, returning redirect");
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
|
||||
HttpResponseStatus.MOVED_PERMANENTLY, Unpooled.EMPTY_BUFFER);
|
||||
response.headers().set(Names.LOCATION, redirectAddress);
|
||||
response.headers().set(HttpHeaderNames.LOCATION, redirectAddress);
|
||||
LOG.trace(Constants.LOG_RETURNING_RESPONSE, response);
|
||||
encoder.write(ctx, response, ctx.voidPromise());
|
||||
ctx.flush();
|
||||
|
||||
@@ -6,7 +6,7 @@ import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import org.slf4j.Logger;
|
||||
@@ -25,8 +25,8 @@ public interface TimelyHttpHandler {
|
||||
.writeValueAsBytes("ResponseCode: " + e.getCode() + " Message: " + e.getMessage());
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
|
||||
HttpResponseStatus.valueOf(e.getCode()), Unpooled.copiedBuffer(buf));
|
||||
response.headers().set(Names.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
|
||||
e.getResponseHeaders().entrySet().forEach(entry -> response.headers().set(entry.getKey(), entry.getValue()));
|
||||
// Send the error response
|
||||
sendResponse(ctx, response);
|
||||
|
||||
@@ -17,9 +17,10 @@ import timely.auth.util.HttpHeaderUtils;
|
||||
|
||||
public class TimelyAuthenticationToken extends PreAuthenticatedAuthenticationToken {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger LOG = LoggerFactory.getLogger(TimelyAuthenticationToken.class);
|
||||
public static final String PROXIED_ENTITIES_HEADER = "X-ProxiedEntitiesChain";
|
||||
public static final String PROXIED_ISSUERS_HEADER = "X-ProxiedIssuersChain";
|
||||
public static final String PROXIED_ENTITIES_HEADER = "x-proxiedentitieschain";
|
||||
public static final String PROXIED_ISSUERS_HEADER = "x-proxiedissuerschain";
|
||||
|
||||
private Multimap<String, String> httpHeaders = null;
|
||||
private X509Certificate clientCert = null;
|
||||
|
||||
@@ -8,7 +8,7 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.handler.codec.http.cookie.DefaultCookie;
|
||||
@@ -43,22 +43,22 @@ public abstract class TimelyLoginRequestHandler<T> extends SimpleChannelInboundH
|
||||
principal.getPrimaryUser().getDn().subjectDN());
|
||||
String sessionIdEncoded = URLEncoder.encode(sessionId, StandardCharsets.UTF_8.name());
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
|
||||
response.headers().set(Names.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
|
||||
DefaultCookie cookie = new DefaultCookie(Constants.COOKIE_NAME, sessionIdEncoded);
|
||||
cookie.setDomain(domain);
|
||||
cookie.setMaxAge(maxAge);
|
||||
cookie.setPath("/");
|
||||
cookie.setHttpOnly(true);
|
||||
cookie.setSecure(true);
|
||||
response.headers().set(Names.SET_COOKIE, ServerCookieEncoder.STRICT.encode(cookie));
|
||||
response.headers().set(HttpHeaderNames.SET_COOKIE, ServerCookieEncoder.STRICT.encode(cookie));
|
||||
sendResponse(ctx, response);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Login failure", e);
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1,
|
||||
HttpResponseStatus.UNAUTHORIZED);
|
||||
response.headers().set(Names.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
|
||||
sendResponse(ctx, response);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -5,7 +5,7 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import timely.api.request.timeseries.AggregatorsRequest;
|
||||
@@ -22,8 +22,8 @@ public class HttpAggregatorsRequestHandler extends SimpleChannelInboundHandler<A
|
||||
byte[] buf = JsonUtil.getObjectMapper().writeValueAsBytes(AggregatorsResponse.RESPONSE);
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
|
||||
Unpooled.copiedBuffer(buf));
|
||||
response.headers().set(Names.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
|
||||
sendResponse(ctx, response);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package timely.netty.http.timeseries;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import timely.api.request.timeseries.MetricsRequest;
|
||||
import timely.api.response.timeseries.MetricsResponse;
|
||||
import timely.configuration.Configuration;
|
||||
@@ -20,7 +20,7 @@ public class HttpMetricsRequestHandler extends SimpleChannelInboundHandler<Metri
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, MetricsRequest msg) throws Exception {
|
||||
MetricsResponse r = new MetricsResponse(conf);
|
||||
String acceptHeader = msg.getRequestHeader(Names.ACCEPT);
|
||||
String acceptHeader = msg.getRequestHeader(HttpHeaderNames.ACCEPT.toString());
|
||||
sendResponse(ctx, r.toHttpResponse(acceptHeader));
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import org.slf4j.Logger;
|
||||
@@ -42,8 +42,8 @@ public class HttpQueryRequestHandler extends SimpleChannelInboundHandler<QueryRe
|
||||
}
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
|
||||
Unpooled.copiedBuffer(buf));
|
||||
response.headers().set(Names.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
|
||||
sendResponse(ctx, response);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -5,7 +5,7 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import org.slf4j.Logger;
|
||||
@@ -39,8 +39,8 @@ public class HttpSearchLookupRequestHandler extends SimpleChannelInboundHandler<
|
||||
}
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
|
||||
Unpooled.copiedBuffer(buf));
|
||||
response.headers().set(Names.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
|
||||
sendResponse(ctx, response);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpHeaders.Names;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import org.slf4j.Logger;
|
||||
@@ -39,8 +39,8 @@ public class HttpSuggestRequestHandler extends SimpleChannelInboundHandler<Sugge
|
||||
}
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
|
||||
Unpooled.copiedBuffer(buf));
|
||||
response.headers().set(Names.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(Names.CONTENT_LENGTH, response.content().readableBytes());
|
||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, Constants.JSON_TYPE);
|
||||
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
|
||||
sendResponse(ctx, response);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ public class AggregationIterator extends WrappingIterator {
|
||||
private Set<Tag> tags;
|
||||
private Key last;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void init(SortedKeyValueIterator<Key, Value> source, Map<String, String> options, IteratorEnvironment env)
|
||||
throws IOException {
|
||||
@@ -45,7 +44,10 @@ public class AggregationIterator extends WrappingIterator {
|
||||
String aggClassname = options.get(AGGCLASS);
|
||||
Class<? extends Aggregator> aggClass = null;
|
||||
try {
|
||||
aggClass = (Class<? extends Aggregator>) this.getClass().getClassLoader().loadClass(aggClassname);
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends Aggregator> uncheckedAggClass = (Class<? extends Aggregator>) this.getClass()
|
||||
.getClassLoader().loadClass(aggClassname);
|
||||
aggClass = uncheckedAggClass;
|
||||
tags = new HashSet<>(new TagListParser().parse(options.get(TAGS)));
|
||||
aggregation = new Aggregation(aggClass.newInstance());
|
||||
} catch (ClassNotFoundException e) {
|
||||
@@ -119,10 +121,11 @@ public class AggregationIterator extends WrappingIterator {
|
||||
is.addOption(AGGCLASS, classname);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<Set<Tag>, Aggregation> decodeValue(Value value) throws IOException, ClassNotFoundException {
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(value.get());
|
||||
ObjectInputStream ois = new ObjectInputStream(bis);
|
||||
return (Map<Set<Tag>, Aggregation>) ois.readObject();
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<Set<Tag>, Aggregation> unchecked = (Map<Set<Tag>, Aggregation>) ois.readObject();
|
||||
return unchecked;
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,6 @@ public class DownsampleIterator extends WrappingIterator {
|
||||
|
||||
private DownsampleMemoryEstimator memoryEstimator = null;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void init(SortedKeyValueIterator<Key, Value> source, Map<String, String> options, IteratorEnvironment env)
|
||||
throws IOException {
|
||||
@@ -73,7 +72,9 @@ public class DownsampleIterator extends WrappingIterator {
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
factory = new DownsampleFactory(start, end, period, (Class<? extends Aggregator>) aggClass);
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends Aggregator> uncheckedAggClass = (Class<? extends Aggregator>) aggClass;
|
||||
factory = new DownsampleFactory(start, end, period, uncheckedAggClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -154,11 +155,12 @@ public class DownsampleIterator extends WrappingIterator {
|
||||
is.addOption(AGGCLASS, classname);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<Set<Tag>, Downsample> decodeValue(Value value) throws IOException, ClassNotFoundException {
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(value.get());
|
||||
ObjectInputStream ois = new ObjectInputStream(bis);
|
||||
return (Map<Set<Tag>, Downsample>) ois.readObject();
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<Set<Tag>, Downsample> unchecked = (Map<Set<Tag>, Downsample>) ois.readObject();
|
||||
return unchecked;
|
||||
}
|
||||
|
||||
public static long getDownsamplePeriod(QueryRequest.SubQuery query) {
|
||||
|
||||
@@ -48,14 +48,17 @@ import org.apache.accumulo.core.client.TableExistsException;
|
||||
import org.apache.accumulo.core.client.TableNotFoundException;
|
||||
import org.apache.accumulo.core.client.ZooKeeperInstance;
|
||||
import org.apache.accumulo.core.client.security.tokens.PasswordToken;
|
||||
import org.apache.accumulo.core.data.*;
|
||||
import org.apache.accumulo.core.data.Key;
|
||||
import org.apache.accumulo.core.data.Mutation;
|
||||
import org.apache.accumulo.core.data.PartialKey;
|
||||
import org.apache.accumulo.core.data.Range;
|
||||
import org.apache.accumulo.core.data.Value;
|
||||
import org.apache.accumulo.core.iterators.IteratorUtil.IteratorScope;
|
||||
import org.apache.accumulo.core.iterators.user.RegExFilter;
|
||||
import org.apache.accumulo.core.security.Authorizations;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
import org.apache.accumulo.core.security.VisibilityEvaluator;
|
||||
import org.apache.accumulo.core.util.Pair;
|
||||
import org.apache.commons.configuration.BaseConfiguration;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.hadoop.io.Text;
|
||||
import org.slf4j.Logger;
|
||||
@@ -140,11 +143,12 @@ public class DataStoreImpl implements DataStore {
|
||||
public DataStoreImpl(Configuration conf, int numWriteThreads) throws TimelyException {
|
||||
|
||||
try {
|
||||
final BaseConfiguration apacheConf = new BaseConfiguration();
|
||||
final Map<String, String> properties = new HashMap<>();
|
||||
Accumulo accumuloConf = conf.getAccumulo();
|
||||
apacheConf.setProperty("instance.name", accumuloConf.getInstanceName());
|
||||
apacheConf.setProperty("instance.zookeeper.host", accumuloConf.getZookeepers());
|
||||
final ClientConfiguration aconf = new ClientConfiguration(Collections.singletonList(apacheConf));
|
||||
properties.put("instance.name", accumuloConf.getInstanceName());
|
||||
properties.put("instance.zookeeper.host", accumuloConf.getZookeepers());
|
||||
properties.put("instance.zookeeper.timeout", accumuloConf.getZookeeperTimeout());
|
||||
final ClientConfiguration aconf = ClientConfiguration.fromMap(properties);
|
||||
final Instance instance = new ZooKeeperInstance(aconf);
|
||||
connector = instance.getConnector(accumuloConf.getUsername(),
|
||||
new PasswordToken(accumuloConf.getPassword()));
|
||||
@@ -351,10 +355,7 @@ public class DataStoreImpl implements DataStore {
|
||||
internalMetrics.incrementMetricsReceived(1);
|
||||
List<Meta> toCache = new ArrayList<>(metric.getTags().size());
|
||||
for (final Tag tag : metric.getTags()) {
|
||||
Meta key = new Meta(metric.getName(), tag.getKey(), tag.getValue());
|
||||
if (!metaCache.contains(key)) {
|
||||
toCache.add(key);
|
||||
}
|
||||
toCache.add(new Meta(metric.getName(), tag.getKey(), tag.getValue()));
|
||||
}
|
||||
if (!toCache.isEmpty()) {
|
||||
final Set<Mutation> muts = new TreeSet<>(new Comparator<Mutation>() {
|
||||
@@ -375,7 +376,7 @@ public class DataStoreImpl implements DataStore {
|
||||
MetaKeySet mks = new MetaKeySet();
|
||||
toCache.forEach(m -> mks.addAll(m.toKeys()));
|
||||
internalMetrics.incrementMetaKeysInserted(mks.size());
|
||||
muts.addAll(mks.toMutations());
|
||||
muts.addAll(mks.toMutations(metric.getValue().getTimestamp()));
|
||||
try {
|
||||
metaWriter.get().addMutations(muts);
|
||||
} catch (MutationsRejectedException e) {
|
||||
@@ -809,6 +810,7 @@ public class DataStoreImpl implements DataStore {
|
||||
return !REGEX_TEST.matcher(value).matches();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Tag> getColumnFamilies(String metric, Map<String, String> requestedTags) throws TableNotFoundException {
|
||||
|
||||
Scanner meta = null;
|
||||
@@ -952,6 +954,7 @@ public class DataStoreImpl implements DataStore {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Range> getQueryRanges(String metric, long start, long end, Set<Tag> colFamValues) {
|
||||
List<Range> ranges = new ArrayList<>();
|
||||
long beginRangeRounded = MetricAdapter.roundTimestampToLastHour(start);
|
||||
@@ -1014,6 +1017,7 @@ public class DataStoreImpl implements DataStore {
|
||||
return AuthCache.getAuthorizations(request, security);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAgeOffForMetric(String metricName) {
|
||||
String age = this.ageOff.get(MetricAgeOffIterator.AGE_OFF_PREFIX + metricName);
|
||||
if (null == age) {
|
||||
@@ -1023,6 +1027,7 @@ public class DataStoreImpl implements DataStore {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Scanner createScannerForMetric(AuthenticatedRequest request, String metric, Map<String, String> tags,
|
||||
int scannerBatchSize, int scannerReadAhead) throws TimelyException {
|
||||
try {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package timely.store;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
@@ -12,17 +11,19 @@ import java.util.TreeSet;
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import org.apache.accumulo.core.client.AccumuloException;
|
||||
import org.apache.accumulo.core.client.AccumuloSecurityException;
|
||||
import org.apache.accumulo.core.client.ClientConfiguration;
|
||||
import org.apache.accumulo.core.client.Connector;
|
||||
import org.apache.accumulo.core.client.Instance;
|
||||
import org.apache.accumulo.core.client.Scanner;
|
||||
import org.apache.accumulo.core.client.TableNotFoundException;
|
||||
import org.apache.accumulo.core.client.ZooKeeperInstance;
|
||||
import org.apache.accumulo.core.client.security.tokens.PasswordToken;
|
||||
import org.apache.accumulo.core.data.Key;
|
||||
import org.apache.accumulo.core.data.Range;
|
||||
import org.apache.accumulo.core.data.Value;
|
||||
import org.apache.accumulo.core.security.Authorizations;
|
||||
import org.apache.commons.configuration.BaseConfiguration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import timely.api.model.Meta;
|
||||
@@ -56,15 +57,16 @@ public class MetaCacheImpl implements MetaCache {
|
||||
|
||||
private void refreshCache(long expirationMinutes) {
|
||||
long oldestTimestamp = System.currentTimeMillis() - (expirationMinutes * 60 * 1000);
|
||||
final BaseConfiguration apacheConf = new BaseConfiguration();
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
Accumulo accumuloConf = configuration.getAccumulo();
|
||||
apacheConf.setProperty("instance.name", accumuloConf.getInstanceName());
|
||||
apacheConf.setProperty("instance.zookeeper.host", accumuloConf.getZookeepers());
|
||||
final ClientConfiguration aConf = new ClientConfiguration(Collections.singletonList(apacheConf));
|
||||
properties.put("instance.name", accumuloConf.getInstanceName());
|
||||
properties.put("instance.zookeeper.host", accumuloConf.getZookeepers());
|
||||
final ClientConfiguration aConf = ClientConfiguration.fromMap(properties);
|
||||
String metaTable = configuration.getMetaTable();
|
||||
Map<String, Map<String, Long>> metricMap = new HashMap<>();
|
||||
Scanner scanner = null;
|
||||
try {
|
||||
Map<Meta, Object> newCache = new HashMap<>();
|
||||
final Instance instance = new ZooKeeperInstance(aConf);
|
||||
Connector connector = instance.getConnector(accumuloConf.getUsername(),
|
||||
new PasswordToken(accumuloConf.getPassword()));
|
||||
@@ -98,20 +100,20 @@ public class MetaCacheImpl implements MetaCache {
|
||||
if (entry.getKey().getTimestamp() > oldestTimestamp) {
|
||||
tagMap.put(tagKey, ++numTagValues);
|
||||
if (numTagValues <= configuration.getMetaCache().getMaxTagValues()) {
|
||||
cache.put(meta, DUMMY);
|
||||
newCache.put(meta, DUMMY);
|
||||
} else {
|
||||
// found maxTagValues on this refresh, so remove this key
|
||||
cache.invalidate(meta);
|
||||
// found maxTagValues on this refresh
|
||||
maxedOutValues = true;
|
||||
}
|
||||
} else {
|
||||
// this entry is more than expirationMinutes old, so remove it
|
||||
cache.invalidate(meta);
|
||||
}
|
||||
}
|
||||
}
|
||||
synchronized (cache) {
|
||||
cache.invalidateAll();
|
||||
cache.putAll(newCache);
|
||||
}
|
||||
LOG.debug("Finished scanning " + metaTable);
|
||||
} catch (Exception e) {
|
||||
} catch (AccumuloException | AccumuloSecurityException | TableNotFoundException e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
} finally {
|
||||
if (scanner != null) {
|
||||
|
||||
@@ -143,8 +143,8 @@ public class MetricAgeOffIterator extends WrappingIterator implements OptionDesc
|
||||
byte[] newStartRow = MetricAdapter.encodeRowKey(start.getFirst(), timeTarget);
|
||||
// @formatter:off
|
||||
Key newStartKey = new Key(newStartRow,
|
||||
null != startKey.getColumnFamily() ? startKey.getColumnFamilyData().getBackingArray() : null,
|
||||
null != startKey.getColumnQualifier() ? startKey.getColumnQualifierData().getBackingArray() : null,
|
||||
null != startKey.getColumnFamily() ? startKey.getColumnFamilyData().getBackingArray() : null,
|
||||
null != startKey.getColumnQualifier() ? startKey.getColumnQualifierData().getBackingArray() : null,
|
||||
null != startKey.getColumnVisibility() ? startKey.getColumnVisibility().getBytes() : null,
|
||||
timeTarget, startKey.isDeleted());
|
||||
// @formatter:on
|
||||
|
||||
+86
-4
@@ -71,6 +71,7 @@ public class DataStoreCache {
|
||||
private Set<String> nonCachedMetrics = Collections.synchronizedSet(new HashSet<>());
|
||||
private DistributedAtomicValue nonCachedMetricsIP = null;
|
||||
private InterProcessReadWriteLock nonCachedMetricsIPRWLock;
|
||||
private long staleCacheExpiration;
|
||||
private long maxUniqueTagSets;
|
||||
private final Security security;
|
||||
private Map<String, Long> minimumAgeOff;
|
||||
@@ -89,6 +90,7 @@ public class DataStoreCache {
|
||||
LOG.info("Reading initial values from nonCachedMetricsIP");
|
||||
readNonCachedMetricsIP();
|
||||
maxUniqueTagSets = conf.getCache().getMaxUniqueTagSets();
|
||||
staleCacheExpiration = conf.getCache().getStaleCacheExpiration();
|
||||
security = conf.getSecurity();
|
||||
Map<String, Integer> cacheAgeOff = conf.getCache().getMetricAgeOffHours();
|
||||
Map<String, Integer> accumuloAgeOff = conf.getMetricAgeOffDays();
|
||||
@@ -118,6 +120,18 @@ public class DataStoreCache {
|
||||
}
|
||||
}, conf.getCache().getFlushInterval(), conf.getCache().getFlushInterval());
|
||||
|
||||
maintenanceTimer.schedule(new TimerTask() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
removeStaleMetrics();
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}, (300 * 1000), (300 * 1000));
|
||||
|
||||
maintenanceTimer.schedule(new TimerTask() {
|
||||
|
||||
@Override
|
||||
@@ -227,8 +241,7 @@ public class DataStoreCache {
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
TreeCache nonCachedMetricsTreeCache = new TreeCache(curatorFramework, NON_CACHED_METRICS);
|
||||
try (TreeCache nonCachedMetricsTreeCache = new TreeCache(curatorFramework, NON_CACHED_METRICS)) {
|
||||
nonCachedMetricsTreeCache.getListenable().addListener(nonCachedMetricsListener);
|
||||
nonCachedMetricsTreeCache.start();
|
||||
} catch (Exception e) {
|
||||
@@ -437,6 +450,68 @@ public class DataStoreCache {
|
||||
}
|
||||
}
|
||||
|
||||
private void removeStaleMetrics() {
|
||||
|
||||
Set<String> metricsToRemove = new HashSet<>();
|
||||
long stamp = gorillaMapLock.readLock();
|
||||
try {
|
||||
long now = System.currentTimeMillis();
|
||||
for (Map.Entry<String, Map<TaggedMetric, GorillaStore>> entry : gorillaMap.entrySet()) {
|
||||
String metricName = entry.getKey();
|
||||
long totalMsecToMetric = 0;
|
||||
long numStoresWithMultipleEntries = 0;
|
||||
int tagVariations = entry.getValue().values().size();
|
||||
for (GorillaStore store : entry.getValue().values()) {
|
||||
long numEntries = store.getNumEntries();
|
||||
long oldestTimestamp = store.getOldestTimestamp();
|
||||
long newestTimestamp = store.getNewestTimestamp();
|
||||
if (numEntries > 1) {
|
||||
long msecToMetric = (newestTimestamp - oldestTimestamp) / (numEntries - 1);
|
||||
totalMsecToMetric += msecToMetric;
|
||||
numStoresWithMultipleEntries++;
|
||||
}
|
||||
}
|
||||
if (numStoresWithMultipleEntries > 0) {
|
||||
long avgMsecToMetric = totalMsecToMetric / numStoresWithMultipleEntries;
|
||||
long ageOfNewest = now - getNewestTimestamp(metricName, stamp);
|
||||
// do not delete slow-arriving metrics based on this criteria
|
||||
// only consider metrics that should have arrived in staleCacheExpiration * 0.5
|
||||
LOG.trace("metric:{} tagVariations:{} avgMsecToMetric:{}", metricName, tagVariations,
|
||||
avgMsecToMetric);
|
||||
if (avgMsecToMetric < (staleCacheExpiration * 0.5)) {
|
||||
if (ageOfNewest > staleCacheExpiration) {
|
||||
LOG.info(
|
||||
"Removing metric:{} tagVariations:{} avgMsecToMetric:{} ageOfNewestEntry:{} > staleCacheExpiration:{}",
|
||||
metricName, tagVariations, avgMsecToMetric, ageOfNewest, staleCacheExpiration);
|
||||
metricsToRemove.add(metricName);
|
||||
}
|
||||
} else {
|
||||
LOG.trace(
|
||||
"Skipping staleness evaluation of metric:{} tagVariations:{} avgMsecToMetric:{} < (0.5 * staleCacheExpiration):{}",
|
||||
metricName, tagVariations, avgMsecToMetric, (staleCacheExpiration / 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
} finally {
|
||||
gorillaMapLock.unlockRead(stamp);
|
||||
}
|
||||
|
||||
if (metricsToRemove.size() > 0) {
|
||||
stamp = gorillaMapLock.writeLock();
|
||||
try {
|
||||
for (String metricName : metricsToRemove) {
|
||||
gorillaMap.remove(metricName);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
} finally {
|
||||
gorillaMapLock.unlockWrite(stamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long getAgeOffForMetric(String metricName) {
|
||||
if (this.minimumAgeOff.containsKey(metricName)) {
|
||||
return this.minimumAgeOff.get(metricName);
|
||||
@@ -512,6 +587,7 @@ public class DataStoreCache {
|
||||
try {
|
||||
metricMap = gorillaMap.get(metric);
|
||||
if (metricMap == null) {
|
||||
LOG.info("Creating new cache for metric:{}", metric);
|
||||
metricMap = new HashMap<>();
|
||||
needWrite = true;
|
||||
}
|
||||
@@ -769,9 +845,13 @@ public class DataStoreCache {
|
||||
}
|
||||
|
||||
public long getNewestTimestamp(String metric) {
|
||||
return getNewestTimestamp(metric, 0);
|
||||
}
|
||||
|
||||
public long getNewestTimestamp(String metric, long lockStamp) {
|
||||
|
||||
long newest = 0;
|
||||
long stamp = gorillaMapLock.readLock();
|
||||
long stamp = lockStamp == 0 ? gorillaMapLock.readLock() : lockStamp;
|
||||
try {
|
||||
Map<TaggedMetric, GorillaStore> gorillaStoreMap = gorillaMap.get(metric);
|
||||
for (Map.Entry<TaggedMetric, GorillaStore> entry : gorillaStoreMap.entrySet()) {
|
||||
@@ -780,7 +860,9 @@ public class DataStoreCache {
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
gorillaMapLock.unlockRead(stamp);
|
||||
if (lockStamp == 0) {
|
||||
gorillaMapLock.unlockRead(stamp);
|
||||
}
|
||||
}
|
||||
return newest;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ public class OrderedTags {
|
||||
}
|
||||
|
||||
public Map<String, String> getTags() {
|
||||
Map<String, String> t = new LinkedHashMap();
|
||||
Map<String, String> t = new LinkedHashMap<>();
|
||||
for (Pair<String, String> p : tagSet) {
|
||||
t.put(p.getLeft(), p.getRight());
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.apache.commons.lang3.Range;
|
||||
|
||||
public class WrappedGorillaCompressor implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private boolean closed = false;
|
||||
private long numEntries = 0;
|
||||
private long oldestTimestamp;
|
||||
@@ -19,10 +20,6 @@ public class WrappedGorillaCompressor implements Serializable {
|
||||
private long[] backingArray = null;
|
||||
private GorillaCompressor compressor;
|
||||
|
||||
private WrappedGorillaCompressor() {
|
||||
|
||||
}
|
||||
|
||||
public WrappedGorillaCompressor(long timestamp) {
|
||||
this.compressorOutput = new LongArrayOutput(16);
|
||||
this.compressor = new GorillaCompressor(timestamp, this.compressorOutput);
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
package timely.store.compaction;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalLong;
|
||||
|
||||
import org.apache.accumulo.core.conf.Property;
|
||||
import org.apache.accumulo.core.data.TabletId;
|
||||
import org.apache.accumulo.server.fs.FileRef;
|
||||
import org.apache.accumulo.tserver.compaction.CompactionPlan;
|
||||
import org.apache.accumulo.tserver.compaction.CompactionStrategy;
|
||||
import org.apache.accumulo.tserver.compaction.MajorCompactionRequest;
|
||||
import org.apache.commons.collections4.trie.PatriciaTrie;
|
||||
import org.apache.commons.configuration.Configuration;
|
||||
import org.apache.commons.configuration.MapConfiguration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import timely.store.MetricAgeOffIterator;
|
||||
|
||||
public class MetricCompactionStrategy extends CompactionStrategy {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MetricCompactionStrategy.class);
|
||||
|
||||
private boolean hasMinAgeOff;
|
||||
private MetricAgeOffConfiguration minAgeOffConfig;
|
||||
private boolean logOnly;
|
||||
private String filterPrefix;
|
||||
private String majcIteratorName;
|
||||
private long explicitTimeMillis;
|
||||
private boolean useExplicitTime;
|
||||
|
||||
public static final String LOG_ONLY_KEY = "logonly";
|
||||
public static final String MAJC_ITERATOR_NAME_KEY = "majc.name";
|
||||
public static final String DEFAULT_MAJC_ITERATOR_NAME = "ageoffmetrics";
|
||||
public static final String AGE_OFF_PREFIX = MetricAgeOffIterator.AGE_OFF_PREFIX;
|
||||
public static final String FILTER_PREFIX_KEY = AGE_OFF_PREFIX + "filter";
|
||||
public static final String MIN_AGEOFF_KEY = AGE_OFF_PREFIX + "min";
|
||||
public static final String DEFAULT_AGEOFF_KEY_SUFFIX = MetricAgeOffIterator.DEFAULT_AGEOFF_KEY;
|
||||
public static final String DEFAULT_AGEOFF_KEY = AGE_OFF_PREFIX + DEFAULT_AGEOFF_KEY_SUFFIX;
|
||||
|
||||
@Override
|
||||
public void init(Map<String, String> options) {
|
||||
// options:
|
||||
// logonly - disables compaction and will only log result
|
||||
// majciterator - the iterator name to gather age-off values
|
||||
// filter - limit the compaction to just a subset of prefixes
|
||||
// min - minimum age-off which may override the metric age-off;
|
||||
// allows more data to accumulate in tablets without being removed
|
||||
|
||||
logOnly = options.containsKey(LOG_ONLY_KEY) && Boolean.parseBoolean(options.get(LOG_ONLY_KEY));
|
||||
majcIteratorName = options.getOrDefault(MAJC_ITERATOR_NAME_KEY, DEFAULT_MAJC_ITERATOR_NAME);
|
||||
filterPrefix = options.get(FILTER_PREFIX_KEY);
|
||||
if (options.containsKey(MIN_AGEOFF_KEY)) {
|
||||
long minAgeOff = Long.parseLong(options.get(MIN_AGEOFF_KEY));
|
||||
hasMinAgeOff = true;
|
||||
minAgeOffConfig = MetricAgeOffConfiguration.newFromDefaultingMinimum(minAgeOff);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldCompact(MajorCompactionRequest request) {
|
||||
TabletId tabletId = request.getTabletId();
|
||||
|
||||
if (null == tabletId.getEndRow() || null == tabletId.getPrevEndRow()) {
|
||||
return false;
|
||||
} else if (request.getFiles().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if prev/end key are both at age-off intervals
|
||||
// skip tablet if there is no prev-end key, or previous age-off is not at max;
|
||||
// other age-off will compact
|
||||
Optional<String> endName = TabletRowAdapter.decodeRowPrefix(tabletId.getEndRow());
|
||||
OptionalLong endOffset = TabletRowAdapter.decodeRowOffset(tabletId.getEndRow());
|
||||
Optional<String> prevEndName = TabletRowAdapter.decodeRowPrefix(tabletId.getPrevEndRow());
|
||||
|
||||
if (!endName.isPresent() || !prevEndName.isPresent() || !endOffset.isPresent()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// compute age-off from majc iterator
|
||||
// then maximize on the min-default-ageoff so that the
|
||||
// configuration with largest age-off is used
|
||||
MetricAgeOffConfiguration ageOffConfig = MetricAgeOffConfiguration.newFromRequest(request, majcIteratorName);
|
||||
if (hasMinAgeOff) {
|
||||
ageOffConfig = MetricAgeOffConfiguration.maximizeDefaultAgeOff(ageOffConfig, minAgeOffConfig);
|
||||
}
|
||||
|
||||
long currentTime = useExplicitTime ? explicitTimeMillis : System.currentTimeMillis();
|
||||
long ageOffComputed = currentTime - ageOffConfig.computeAgeOff(endName.get());
|
||||
boolean shouldCompact = (ageOffComputed > endOffset.getAsLong() && endName.equals(prevEndName))
|
||||
&& (null == filterPrefix || endName.get().startsWith(filterPrefix));
|
||||
|
||||
if (LOG.isDebugEnabled() && logOnly && shouldCompact) {
|
||||
LOG.debug("Tablet will be metric age-off compacted {threshold: {}, endKey: {}, offset: {}, prevKey: {}}",
|
||||
ageOffComputed, endName, endOffset.getAsLong(), prevEndName);
|
||||
} else if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Tablet check metric compaction {threshold: {}, endKey: {}, offset: {}, prevKey: {}, result: {}}",
|
||||
ageOffComputed, endName, endOffset.getAsLong(), prevEndName, shouldCompact);
|
||||
}
|
||||
|
||||
return shouldCompact && !logOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompactionPlan getCompactionPlan(MajorCompactionRequest request) {
|
||||
CompactionPlan plan = null;
|
||||
if (shouldCompact(request)) {
|
||||
plan = new CompactionPlan();
|
||||
for (FileRef ref : request.getFiles().keySet()) {
|
||||
plan.inputFiles.add(ref);
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Tablet selected for age-off: " + TabletRowAdapter.toDebugOutput(request.getTabletId()));
|
||||
}
|
||||
}
|
||||
|
||||
return plan;
|
||||
}
|
||||
|
||||
void setExplicitTime(long timeMillis) {
|
||||
explicitTimeMillis = timeMillis;
|
||||
useExplicitTime = true;
|
||||
}
|
||||
|
||||
private static class MetricAgeOffConfiguration {
|
||||
|
||||
private final PatriciaTrie<Long> ageoffs;
|
||||
private final long defaultAgeOff;
|
||||
|
||||
private MetricAgeOffConfiguration(PatriciaTrie<Long> ageoffs, long defaultAgeOff) {
|
||||
this.ageoffs = ageoffs;
|
||||
this.defaultAgeOff = defaultAgeOff;
|
||||
}
|
||||
|
||||
public static MetricAgeOffConfiguration maximizeDefaultAgeOff(MetricAgeOffConfiguration x,
|
||||
MetricAgeOffConfiguration y) {
|
||||
return (x.defaultAgeOff > y.defaultAgeOff) ? x : y;
|
||||
}
|
||||
|
||||
public static MetricAgeOffConfiguration newFromDefaultingMinimum(long minAgeOff) {
|
||||
return new MetricAgeOffConfiguration(new PatriciaTrie<>(), minAgeOff);
|
||||
}
|
||||
|
||||
public static MetricAgeOffConfiguration newFromRequest(MajorCompactionRequest request,
|
||||
String majcIteratorName) {
|
||||
Configuration config = new MapConfiguration(request.getTableProperties());
|
||||
String majcIteratorKey = Property.TABLE_ITERATOR_MAJC_PREFIX.getKey() + majcIteratorName;
|
||||
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Using key lookup for iterator: {}", majcIteratorKey);
|
||||
}
|
||||
|
||||
Configuration configAgeOff = config.subset((majcIteratorKey + ".opt"));
|
||||
if (null == configAgeOff.getString(DEFAULT_AGEOFF_KEY)) {
|
||||
throw new IllegalArgumentException(
|
||||
DEFAULT_AGEOFF_KEY_SUFFIX + " must be configured for " + majcIteratorKey);
|
||||
}
|
||||
|
||||
PatriciaTrie<Long> ageoffs = new PatriciaTrie<>();
|
||||
long configureMinAgeOff = Long.MAX_VALUE;
|
||||
long configureMaxAgeOff = Long.MIN_VALUE;
|
||||
@SuppressWarnings("unchecked")
|
||||
Iterator<String> keys = configAgeOff.getKeys();
|
||||
while (keys.hasNext()) {
|
||||
String k = keys.next();
|
||||
String v = configAgeOff.getString(k);
|
||||
if (k.startsWith((AGE_OFF_PREFIX))) {
|
||||
String name = k.substring(AGE_OFF_PREFIX.length());
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Adding {} to Trie with value {}", name, Long.parseLong(v));
|
||||
}
|
||||
long ageoff = Long.parseLong(v);
|
||||
configureMinAgeOff = Math.min(configureMinAgeOff, ageoff);
|
||||
configureMaxAgeOff = Math.max(configureMaxAgeOff, ageoff);
|
||||
ageoffs.put(name, ageoff);
|
||||
}
|
||||
}
|
||||
long defaultAgeOff = ageoffs.get(DEFAULT_AGEOFF_KEY_SUFFIX);
|
||||
return new MetricAgeOffConfiguration(ageoffs, defaultAgeOff);
|
||||
}
|
||||
|
||||
public long computeAgeOff(String metricName) {
|
||||
return ageoffs.getOrDefault(metricName, defaultAgeOff);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package timely.store.compaction;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalLong;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import org.apache.accumulo.core.client.lexicoder.Lexicoder;
|
||||
import org.apache.accumulo.core.client.lexicoder.LongLexicoder;
|
||||
import org.apache.accumulo.core.client.lexicoder.StringLexicoder;
|
||||
import org.apache.accumulo.core.client.lexicoder.impl.ByteUtils;
|
||||
import org.apache.accumulo.core.data.TabletId;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.hadoop.io.Text;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class TabletRowAdapter {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(TabletRowAdapter.class);
|
||||
private static final Lexicoder<String> PREFIX_DECODER = new StringLexicoder();
|
||||
private static final Lexicoder<Long> OFFSET_DECODER = new LongLexicoder();
|
||||
|
||||
private static final byte DELIMETER = 0x00;
|
||||
private static final int MIN_OFFSET_LEN = 9;
|
||||
|
||||
public static OptionalLong decodeRowOffset(Text row) {
|
||||
OptionalLong offset = OptionalLong.empty();
|
||||
byte[] bytes = row.getBytes();
|
||||
int delimidx = findRowDelimiterIndex(bytes);
|
||||
if (delimidx > 0) {
|
||||
try {
|
||||
byte[] buffer = Arrays.copyOfRange(bytes, delimidx + 1, bytes.length);
|
||||
buffer = ByteUtils.unescape(buffer);
|
||||
|
||||
// key might not have all bytes for long decoding
|
||||
// ensure of sufficient length
|
||||
int extendBy = (MIN_OFFSET_LEN - (buffer.length));
|
||||
if (extendBy > 0) {
|
||||
buffer = ArrayUtils.addAll(buffer, new byte[extendBy]);
|
||||
}
|
||||
|
||||
long decodedOffset = OFFSET_DECODER.decode(buffer);
|
||||
if (decodedOffset > 0) {
|
||||
offset = OptionalLong.of(decodedOffset);
|
||||
} else if (LOG.isTraceEnabled()) {
|
||||
Optional<String> prefix = decodeRowPrefix(row);
|
||||
LOG.trace(
|
||||
"Delimiter identified but offset could not parse { prefix: {}, byte-len: {}, "
|
||||
+ "offset-len: {}, offset-bytes: {}, row-bytes: {} }",
|
||||
prefix, bytes.length, buffer.length, Hex.encodeHex(buffer), Hex.encodeHex(bytes));
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Unable to parse offset: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
public static Optional<String> decodeRowPrefix(Text row) {
|
||||
byte[] bytes = row.getBytes();
|
||||
int delimidx = findRowDelimiterIndex(bytes);
|
||||
byte[] prefixBytes = (delimidx >= 0) ? Arrays.copyOfRange(bytes, 0, delimidx) : bytes;
|
||||
Optional<String> tabletName = Optional.empty();
|
||||
try {
|
||||
tabletName = Optional.of(PREFIX_DECODER.decode(ByteUtils.unescape(prefixBytes)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (LOG.isTraceEnabled()) {
|
||||
LOG.trace("Unable to parse offset: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return tabletName;
|
||||
}
|
||||
|
||||
public static String toDebugOutput(TabletId tid) {
|
||||
StringJoiner joiner = new StringJoiner(", ", "[", "]");
|
||||
Text endRow = tid.getEndRow();
|
||||
if (null != endRow) {
|
||||
Optional<String> prefix = decodeRowPrefix(endRow);
|
||||
OptionalLong offset = decodeRowOffset(endRow);
|
||||
prefix.ifPresent(s -> joiner.add("prefix: " + s));
|
||||
if (offset.isPresent()) {
|
||||
LocalDateTime date = Instant.ofEpochMilli(offset.getAsLong()).atZone(ZoneId.of("UTC"))
|
||||
.toLocalDateTime();
|
||||
joiner.add("date: " + date.toString());
|
||||
joiner.add("millis: " + offset.getAsLong());
|
||||
}
|
||||
}
|
||||
|
||||
return joiner.toString();
|
||||
}
|
||||
|
||||
private static int findRowDelimiterIndex(byte[] bytes) {
|
||||
int delimidx = -1;
|
||||
for (int i = bytes.length - 1; i >= 0; i--) {
|
||||
if (bytes[i] == DELIMETER) {
|
||||
delimidx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return delimidx;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package timely.store.compaction;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.accumulo.core.conf.Property;
|
||||
import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader;
|
||||
import org.apache.accumulo.tserver.compaction.CompactionPlan;
|
||||
import org.apache.accumulo.tserver.compaction.CompactionStrategy;
|
||||
import org.apache.accumulo.tserver.compaction.MajorCompactionRequest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class TieredCompactionStrategy extends CompactionStrategy {
|
||||
|
||||
public static final String TIERED_PREFIX = "tier.";
|
||||
public static final String TIERED_CLASS = "class";
|
||||
public static final String TIERED_OPTS = "opts";
|
||||
|
||||
protected final Collection<TieredCompactorSupplier> compactors;
|
||||
|
||||
public TieredCompactionStrategy() {
|
||||
compactors = new ArrayList<>();
|
||||
}
|
||||
|
||||
public Collection<TieredCompactorSupplier> getCompactors() {
|
||||
return Collections.unmodifiableCollection(compactors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Map<String, String> config) {
|
||||
// example:
|
||||
// <table-compaction-prefix>.tiered.0.class=<majcompaction-class>
|
||||
// <table-compaction-prefix>.tiered.0.opts.key=value
|
||||
// <table-compaction-prefix>.tiered.1.class=<majcompaction-class>
|
||||
// <table-compaction-prefix>.tiered.1.opts.key_a=value
|
||||
// <table-compaction-prefix>.tiered.1.opts.key_b=value
|
||||
//
|
||||
// the key=value pairs will be sent to the specific tiered compaction
|
||||
// strategy as arguments
|
||||
|
||||
compactors.clear();
|
||||
createSuppliers(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void gatherInformation(MajorCompactionRequest request) throws IOException {
|
||||
for (TieredCompactorSupplier compactor : compactors) {
|
||||
CompactionStrategy strategy = compactor.get(request.getTableProperties());
|
||||
strategy.gatherInformation(request);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldCompact(MajorCompactionRequest request) throws IOException {
|
||||
boolean shouldCompact = false;
|
||||
for (TieredCompactorSupplier supplier : compactors) {
|
||||
CompactionStrategy strategy = supplier.get(request.getTableProperties());
|
||||
shouldCompact = strategy.shouldCompact(request);
|
||||
if (shouldCompact) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return shouldCompact;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompactionPlan getCompactionPlan(MajorCompactionRequest request) throws IOException {
|
||||
CompactionPlan plan = null;
|
||||
Iterator<TieredCompactorSupplier> iter = compactors.iterator();
|
||||
while ((null == plan || plan.inputFiles.isEmpty()) && iter.hasNext()) {
|
||||
CompactionStrategy strategy = iter.next().get(request.getTableProperties());
|
||||
plan = strategy.getCompactionPlan(request);
|
||||
}
|
||||
|
||||
return plan;
|
||||
}
|
||||
|
||||
protected void createSuppliers(Map<String, String> config) {
|
||||
int tier = 0;
|
||||
boolean continueLoop = true;
|
||||
while (continueLoop) {
|
||||
String clazzKey = TIERED_PREFIX + tier + "." + TIERED_CLASS;
|
||||
String clazzName = config.get(clazzKey);
|
||||
if (null != clazzName) {
|
||||
compactors.add(new TieredConfiguredSupplier(clazzName, tier, config));
|
||||
tier++;
|
||||
} else {
|
||||
continueLoop = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class TieredConfiguredSupplier implements TieredCompactorSupplier {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(TieredConfiguredSupplier.class);
|
||||
|
||||
private final String clazzName;
|
||||
private final int tier;
|
||||
private final Map<String, String> initConfig;
|
||||
|
||||
private CompactionStrategy strategy;
|
||||
private Map<String, String> options;
|
||||
|
||||
TieredConfiguredSupplier(String clazzName, int tier, Map<String, String> initConfig) {
|
||||
this.strategy = null;
|
||||
this.clazzName = clazzName;
|
||||
this.tier = tier;
|
||||
this.initConfig = initConfig;
|
||||
}
|
||||
|
||||
public Map<String, String> options() {
|
||||
if (null == options) {
|
||||
options = new HashMap<>();
|
||||
String tierCompare = Integer.toString(tier);
|
||||
int tierIdx = TIERED_PREFIX.length();
|
||||
int optsIdx = TIERED_PREFIX.length() + tierCompare.length() + 1;
|
||||
for (Map.Entry<String, String> entry : initConfig.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
if (key.regionMatches(tierIdx, tierCompare, 0, tierCompare.length())
|
||||
&& key.regionMatches(optsIdx, TIERED_OPTS, 0, TIERED_OPTS.length())) {
|
||||
options.put(key.substring(optsIdx + TIERED_OPTS.length() + 1), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.unmodifiableMap(options);
|
||||
}
|
||||
|
||||
public CompactionStrategy get(Map<String, String> tableProperties) {
|
||||
if (null == strategy) {
|
||||
try {
|
||||
String tableContext = tableProperties.get(Property.TABLE_CLASSPATH.getKey());
|
||||
Class<? extends CompactionStrategy> clazz;
|
||||
if (null != tableContext && !tableContext.equals("")) {
|
||||
clazz = AccumuloVFSClassLoader.getContextManager().loadClass(tableContext, clazzName,
|
||||
CompactionStrategy.class);
|
||||
} else {
|
||||
clazz = AccumuloVFSClassLoader.loadClass(clazzName, CompactionStrategy.class);
|
||||
}
|
||||
strategy = clazz.newInstance();
|
||||
strategy.init(options());
|
||||
} catch (Exception e) {
|
||||
LOG.debug("Failed to load class for tiered compaction: " + e.toString());
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
return strategy;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package timely.store.compaction;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.accumulo.tserver.compaction.CompactionStrategy;
|
||||
|
||||
public interface TieredCompactorSupplier {
|
||||
|
||||
Map<String, String> options();
|
||||
|
||||
CompactionStrategy get(Map<String, String> tableProperties);
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package timely.store.compaction.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalLong;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.hadoop.io.Text;
|
||||
import timely.store.compaction.TabletRowAdapter;
|
||||
|
||||
public class MetadataAccumulator {
|
||||
|
||||
private final List<Entry> list;
|
||||
private Entry currentEntry;
|
||||
|
||||
public MetadataAccumulator() {
|
||||
this.list = new LinkedList<>();
|
||||
}
|
||||
|
||||
public Entry checkEntryState(Text tablet) {
|
||||
// entry may be null on initial invocation or after the pushOrDiscard operation
|
||||
// check to see if the tablet has changed, if so then
|
||||
// push or discard the current state
|
||||
if (currentEntry != null && !tablet.equals(currentEntry.getTablet())) {
|
||||
pushOrDiscardEntry();
|
||||
}
|
||||
if (currentEntry == null) {
|
||||
currentEntry = new Entry(tablet);
|
||||
}
|
||||
|
||||
return currentEntry;
|
||||
}
|
||||
|
||||
public Collection<Entry> getEntries() {
|
||||
return Collections.unmodifiableCollection(list);
|
||||
}
|
||||
|
||||
public void ensureState() {
|
||||
pushOrDiscardEntry();
|
||||
}
|
||||
|
||||
private void pushOrDiscardEntry() {
|
||||
if (currentEntry != null && currentEntry.hasFiles()) {
|
||||
list.add(currentEntry);
|
||||
}
|
||||
currentEntry = null;
|
||||
}
|
||||
|
||||
public static class Entry {
|
||||
|
||||
private final Text tablet;
|
||||
private final String tabletPrefix;
|
||||
private final boolean hasTabletOffset;
|
||||
private final long tabletOffset;
|
||||
private Text tabletPrev;
|
||||
private long milliseconds;
|
||||
private long totalBytes;
|
||||
private int totalFiles;
|
||||
|
||||
public Entry(Text tablet) {
|
||||
this.tablet = tablet;
|
||||
Optional<String> prefixOptional = TabletRowAdapter.decodeRowPrefix(tablet);
|
||||
OptionalLong offsetOptional = TabletRowAdapter.decodeRowOffset(tablet);
|
||||
tabletPrefix = prefixOptional.orElseGet(tablet::toString);
|
||||
if (offsetOptional.isPresent()) {
|
||||
hasTabletOffset = true;
|
||||
tabletOffset = offsetOptional.getAsLong();
|
||||
} else {
|
||||
hasTabletOffset = false;
|
||||
tabletOffset = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public String getTabletPrefix() {
|
||||
return tabletPrefix;
|
||||
}
|
||||
|
||||
public Text getTablet() {
|
||||
return tablet;
|
||||
}
|
||||
|
||||
public Text getTabletPrev() {
|
||||
return tabletPrev;
|
||||
}
|
||||
|
||||
public long getMilliseconds() {
|
||||
return milliseconds;
|
||||
}
|
||||
|
||||
public long getTotalFileBytes() {
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
public int getTotalFiles() {
|
||||
return totalFiles;
|
||||
}
|
||||
|
||||
public OptionalLong getTabletOffset() {
|
||||
return hasTabletOffset ? OptionalLong.of(tabletOffset) : OptionalLong.empty();
|
||||
}
|
||||
|
||||
public boolean hasFiles() {
|
||||
return totalFiles > 0;
|
||||
}
|
||||
|
||||
public void addFile(long size) {
|
||||
totalFiles++;
|
||||
totalBytes += size;
|
||||
}
|
||||
|
||||
public void setTablePrev(Text prev) {
|
||||
tabletPrev = prev;
|
||||
}
|
||||
|
||||
public void setMilliseconds(long val) {
|
||||
milliseconds = val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("metadata.entry {tablet: %s, millis: %d, offset-ms: %d, age-days: %d, files %d}",
|
||||
tablet, milliseconds, tabletOffset,
|
||||
(hasTabletOffset ? TimeUnit.MILLISECONDS.toDays(System.currentTimeMillis() - tabletOffset) : -1),
|
||||
totalFiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package timely.store.compaction.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.accumulo.core.client.ClientConfiguration;
|
||||
import org.apache.accumulo.core.client.Connector;
|
||||
import org.apache.accumulo.core.client.Instance;
|
||||
import org.apache.accumulo.core.client.ZooKeeperInstance;
|
||||
import org.apache.accumulo.core.client.security.tokens.PasswordToken;
|
||||
import org.springframework.boot.Banner;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import timely.configuration.Accumulo;
|
||||
import timely.configuration.Configuration;
|
||||
import timely.configuration.SpringBootstrap;
|
||||
|
||||
public class TabletMetadataConsole {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
try (ConfigurableApplicationContext ctx = new SpringApplicationBuilder(SpringBootstrap.class)
|
||||
.bannerMode(Banner.Mode.OFF).web(WebApplicationType.NONE).run(args)) {
|
||||
Configuration conf = ctx.getBean(Configuration.class);
|
||||
HashMap<String, String> apacheConf = new HashMap<>();
|
||||
Accumulo accumuloConf = conf.getAccumulo();
|
||||
apacheConf.put("instance.name", accumuloConf.getInstanceName());
|
||||
apacheConf.put("instance.zookeeper.host", accumuloConf.getZookeepers());
|
||||
ClientConfiguration aconf = ClientConfiguration.fromMap(apacheConf);
|
||||
Instance instance = new ZooKeeperInstance(aconf);
|
||||
Connector con = instance.getConnector(accumuloConf.getUsername(),
|
||||
new PasswordToken(accumuloConf.getPassword()));
|
||||
|
||||
TabletMetadataQuery query = new TabletMetadataQuery(con, conf.getMetricsTable());
|
||||
TabletMetadataView view = query.run();
|
||||
|
||||
System.out.println(view.toText(TimeUnit.DAYS));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package timely.store.compaction.util;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.accumulo.core.data.Key;
|
||||
import org.apache.accumulo.core.data.Value;
|
||||
import org.apache.accumulo.core.util.format.AggregatingFormatter;
|
||||
|
||||
public class TabletMetadataFormatter extends AggregatingFormatter {
|
||||
|
||||
private final TabletMetadataView view;
|
||||
|
||||
public TabletMetadataFormatter() {
|
||||
this(new TabletMetadataView());
|
||||
}
|
||||
|
||||
public TabletMetadataFormatter(TabletMetadataView view) {
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void aggregateStats(Map.Entry<Key, Value> entry) {
|
||||
view.addEntry(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getStats() {
|
||||
return view.toText(TimeUnit.DAYS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package timely.store.compaction.util;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.accumulo.core.client.AccumuloException;
|
||||
import org.apache.accumulo.core.client.AccumuloSecurityException;
|
||||
import org.apache.accumulo.core.client.Connector;
|
||||
import org.apache.accumulo.core.client.Scanner;
|
||||
import org.apache.accumulo.core.client.TableNotFoundException;
|
||||
import org.apache.accumulo.core.data.Key;
|
||||
import org.apache.accumulo.core.data.Range;
|
||||
import org.apache.accumulo.core.data.Value;
|
||||
import org.apache.accumulo.core.metadata.MetadataTable;
|
||||
|
||||
public class TabletMetadataQuery {
|
||||
|
||||
private final Connector connector;
|
||||
private final String tableName;
|
||||
|
||||
public TabletMetadataQuery(Connector connector, String tableName) {
|
||||
this.connector = connector;
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
public TabletMetadataView run() throws AccumuloException, AccumuloSecurityException, TableNotFoundException {
|
||||
TabletMetadataView view = new TabletMetadataView();
|
||||
Map<String, String> tableMap = connector.tableOperations().tableIdMap();
|
||||
String tableId = tableMap.get(tableName);
|
||||
if (null == tableId) {
|
||||
throw new IllegalStateException("Unable to find " + MetadataTable.NAME);
|
||||
}
|
||||
|
||||
try (Scanner s = connector.createScanner(MetadataTable.NAME,
|
||||
connector.securityOperations().getUserAuthorizations(connector.whoami()))) {
|
||||
// s.setRange(new Range(tableId, true, tableId, true));
|
||||
s.setRange(Range.prefix(tableId));
|
||||
for (Map.Entry<Key, Value> e : s) {
|
||||
view.addEntry(e);
|
||||
}
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package timely.store.compaction.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.accumulo.core.data.Key;
|
||||
import org.apache.accumulo.core.data.Value;
|
||||
import org.apache.accumulo.core.data.impl.KeyExtent;
|
||||
import org.apache.accumulo.core.metadata.schema.MetadataSchema;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.math3.stat.descriptive.StatisticalSummary;
|
||||
import org.apache.hadoop.io.Text;
|
||||
|
||||
public class TabletMetadataView {
|
||||
|
||||
private final MetadataAccumulator accumulator;
|
||||
|
||||
private static final int DEFAULT_TOP_COUNT = 25;
|
||||
|
||||
public TabletMetadataView() {
|
||||
accumulator = new MetadataAccumulator();
|
||||
}
|
||||
|
||||
public void addEntry(Collection<Map.Entry<Key, Value>> entries) {
|
||||
for (Map.Entry<Key, Value> entry : entries) {
|
||||
addEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
public void addEntry(Map.Entry<Key, Value> entry) {
|
||||
KeyExtent ke = new KeyExtent(entry.getKey().getRow(), (Text) null);
|
||||
if (ke.getEndRow() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Text cf = entry.getKey().getColumnFamily();
|
||||
Text cq = entry.getKey().getColumnQualifier();
|
||||
MetadataAccumulator.Entry candidate = accumulator.checkEntryState(ke.getEndRow());
|
||||
|
||||
if (cf.equals(MetadataSchema.TabletsSection.DataFileColumnFamily.NAME)) {
|
||||
String val = entry.getValue().toString();
|
||||
String[] valSplit = val.split(",");
|
||||
if (valSplit.length == 2) {
|
||||
long size = Long.parseLong(valSplit[0]);
|
||||
candidate.addFile(size);
|
||||
}
|
||||
} else if (cf.equals(MetadataSchema.TabletsSection.ServerColumnFamily.NAME)) {
|
||||
if (cq.equals(MetadataSchema.TabletsSection.ServerColumnFamily.TIME_COLUMN.getColumnQualifier())) {
|
||||
String timeVal = entry.getValue().toString();
|
||||
if (timeVal.startsWith("M")) {
|
||||
long ms = Long.parseLong(timeVal.substring(1));
|
||||
candidate.setMilliseconds(ms);
|
||||
}
|
||||
}
|
||||
} else if (cf.equals(MetadataSchema.TabletsSection.TabletColumnFamily.PREV_ROW_COLUMN.getColumnFamily())
|
||||
&& cq.equals(MetadataSchema.TabletsSection.TabletColumnFamily.PREV_ROW_COLUMN.getColumnQualifier())) {
|
||||
ke = new KeyExtent(entry.getKey().getRow(), entry.getValue());
|
||||
candidate.setTablePrev(ke.getPrevEndRow());
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<MetadataAccumulator.Entry> getEntries() {
|
||||
accumulator.ensureState();
|
||||
return accumulator.getEntries();
|
||||
}
|
||||
|
||||
public TabletSummary.Builder computeSummary() {
|
||||
return TabletSummary.newBuilder(getEntries());
|
||||
}
|
||||
|
||||
public String toText() {
|
||||
return toText(TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public String toText(TimeUnit unit) {
|
||||
if (getEntries().isEmpty()) {
|
||||
return "No results";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
TabletSummary summary = computeSummary().build();
|
||||
Map<TabletStatisticType, StatisticalSummary> tabletAggregate = summary.aggregateSummary();
|
||||
StatisticalSummary tabletSizes = tabletAggregate.get(TabletStatisticType.SIZE);
|
||||
StatisticalSummary tabletTime = tabletAggregate.get(TabletStatisticType.TIME);
|
||||
long tabletMax = unit.convert((long) tabletTime.getMax(), TimeUnit.MILLISECONDS);
|
||||
long tabletMean = unit.convert((long) tabletTime.getMean(), TimeUnit.MILLISECONDS);
|
||||
Collection<TabletStatistic> topOldestMetrics = summary.findTabletPrefixesByOldest(DEFAULT_TOP_COUNT);
|
||||
Collection<TabletStatistic> topSizeMetrics = summary.findTabletPrefixesByLargest(DEFAULT_TOP_COUNT);
|
||||
|
||||
sb.append(String.format("Tablets { prefix: %d, total: %d } %s", summary.totalTabletPrefixes(),
|
||||
summary.totalTablets(), System.lineSeparator()));
|
||||
sb.append(System.lineSeparator());
|
||||
sb.append(String.format("Size: { sum: %s, avg: %s } %s",
|
||||
FileUtils.byteCountToDisplaySize((long) tabletSizes.getSum()),
|
||||
FileUtils.byteCountToDisplaySize((long) tabletSizes.getMean()), System.lineSeparator()));
|
||||
|
||||
sb.append(String.format("Age: { max: %d, avg: %d } %s", tabletMax, tabletMean, System.lineSeparator()));
|
||||
|
||||
sb.append(System.lineSeparator());
|
||||
sb.append(System.lineSeparator());
|
||||
|
||||
sb.append(String.format("Top %d Tablets (by-age) %s", DEFAULT_TOP_COUNT, System.lineSeparator()));
|
||||
sb.append("---");
|
||||
sb.append(System.lineSeparator());
|
||||
|
||||
for (TabletStatistic entry : topOldestMetrics) {
|
||||
sb.append(String.format("%s = { tablets: %d, max-age: %d } %s", entry.getKeyName(), entry.getKeyCount(),
|
||||
unit.convert(entry.maxAge(), TimeUnit.MILLISECONDS), System.lineSeparator()));
|
||||
}
|
||||
|
||||
sb.append(System.lineSeparator());
|
||||
sb.append(System.lineSeparator());
|
||||
|
||||
sb.append(String.format("Top %d Tablets (by-size) %s", DEFAULT_TOP_COUNT, System.lineSeparator()));
|
||||
sb.append("---");
|
||||
sb.append(System.lineSeparator());
|
||||
|
||||
for (TabletStatistic entry : topSizeMetrics) {
|
||||
long totalSize = (long) entry.getSummary(TabletStatisticType.SIZE).getSum();
|
||||
sb.append(String.format("%s = { tablets: %d, size: %s } %s", entry.getKeyName(), entry.getKeyCount(),
|
||||
FileUtils.byteCountToDisplaySize(totalSize), System.lineSeparator()));
|
||||
}
|
||||
|
||||
sb.append(System.lineSeparator());
|
||||
sb.append(System.lineSeparator());
|
||||
|
||||
sb.append(String.format("Tablets (by-name) %s", System.lineSeparator()));
|
||||
sb.append("---");
|
||||
sb.append(System.lineSeparator());
|
||||
|
||||
for (TabletStatistic entry : summary.getSummary()) {
|
||||
long totalSize = (long) entry.getSummary(TabletStatisticType.SIZE).getSum();
|
||||
sb.append(String.format("%s = { tablets: %d, size: %s, max-age: %d } %s", entry.getKeyName(),
|
||||
entry.getKeyCount(), FileUtils.byteCountToDisplaySize(totalSize),
|
||||
unit.convert(entry.maxAge(), TimeUnit.MILLISECONDS), System.lineSeparator()));
|
||||
}
|
||||
|
||||
sb.append(System.lineSeparator());
|
||||
sb.append(System.lineSeparator());
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package timely.store.compaction.util;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.math3.stat.descriptive.StatisticalSummary;
|
||||
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
|
||||
|
||||
public class TabletStatistic {
|
||||
|
||||
private final String keyName;
|
||||
private final int keyCount;
|
||||
private final Map<TabletStatisticType, SummaryStatistics> stats;
|
||||
private final SummaryStatistics timeStat;
|
||||
private final SummaryStatistics sizeStat;
|
||||
|
||||
TabletStatistic(String keyName, int keyCount, Map<TabletStatisticType, SummaryStatistics> stats) {
|
||||
this.keyName = keyName;
|
||||
this.keyCount = keyCount;
|
||||
this.stats = stats;
|
||||
|
||||
timeStat = stats.getOrDefault(TabletStatisticType.TIME, new SummaryStatistics());
|
||||
sizeStat = stats.getOrDefault(TabletStatisticType.SIZE, new SummaryStatistics());
|
||||
}
|
||||
|
||||
public String getKeyName() {
|
||||
return keyName;
|
||||
}
|
||||
|
||||
public int getKeyCount() {
|
||||
return keyCount;
|
||||
}
|
||||
|
||||
public StatisticalSummary getSummary(TabletStatisticType statType) {
|
||||
return this.stats.getOrDefault(statType, new SummaryStatistics());
|
||||
}
|
||||
|
||||
public Map<TabletStatisticType, SummaryStatistics> getSummaryMap() {
|
||||
return stats;
|
||||
}
|
||||
|
||||
public long maxAge() {
|
||||
return (long) timeStat.getMax();
|
||||
}
|
||||
|
||||
public long totalSize() {
|
||||
return (long) sizeStat.getSum();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("key: %s, count: %d, age: %d, size %d", keyName, keyCount, maxAge(), totalSize());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package timely.store.compaction.util;
|
||||
|
||||
public enum TabletStatisticType {
|
||||
SIZE, TIME
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package timely.store.compaction.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.math3.stat.descriptive.AggregateSummaryStatistics;
|
||||
import org.apache.commons.math3.stat.descriptive.StatisticalSummary;
|
||||
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
|
||||
import timely.store.compaction.TabletRowAdapter;
|
||||
|
||||
public class TabletSummary {
|
||||
|
||||
private final Collection<TabletStatistic> tabletStats;
|
||||
|
||||
private TabletSummary(Collection<TabletStatistic> tabletStats) {
|
||||
this.tabletStats = tabletStats;
|
||||
}
|
||||
|
||||
public static Builder newBuilder(Collection<MetadataAccumulator.Entry> entries) {
|
||||
return new Builder(entries);
|
||||
}
|
||||
|
||||
public Map<TabletStatisticType, StatisticalSummary> aggregateSummary() {
|
||||
// @formatter:off
|
||||
return tabletStats.stream()
|
||||
.flatMap(m -> m.getSummaryMap().entrySet().stream())
|
||||
.collect(Collectors.groupingBy(Map.Entry::getKey,
|
||||
Collectors.mapping(Map.Entry::getValue, Collectors.toList())))
|
||||
.entrySet().stream()
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, v -> AggregateSummaryStatistics.aggregate(v.getValue())));
|
||||
}
|
||||
|
||||
public long totalTabletPrefixes() {
|
||||
return tabletStats.size();
|
||||
}
|
||||
|
||||
public long totalTablets() {
|
||||
// @formatter:off
|
||||
return tabletStats.stream()
|
||||
.mapToLong(TabletStatistic::getKeyCount)
|
||||
.sum();
|
||||
}
|
||||
|
||||
public Collection<TabletStatistic> findTabletPrefixesByOldest(int count) {
|
||||
// @formatter:off
|
||||
return tabletStats.stream()
|
||||
.sorted(Comparator.comparingLong(TabletStatistic::maxAge)
|
||||
.reversed()
|
||||
.thenComparing(TabletStatistic::getKeyName))
|
||||
.limit(count)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Collection<TabletStatistic> findTabletPrefixesByLargest(int count) {
|
||||
// @formatter:off
|
||||
return tabletStats.stream()
|
||||
.sorted(Comparator.comparingLong(TabletStatistic::totalSize)
|
||||
.reversed()
|
||||
.thenComparing(TabletStatistic::getKeyName))
|
||||
.limit(count)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Collection<TabletStatistic> getSummary() {
|
||||
return tabletStats;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private final Collection<MetadataAccumulator.Entry> entries;
|
||||
private long explictTimeMillis;
|
||||
private boolean useExplicitTime;
|
||||
private boolean disableTabletRowCheckFilter;
|
||||
|
||||
public Builder(Collection<MetadataAccumulator.Entry> entries) {
|
||||
this.entries = entries;
|
||||
}
|
||||
|
||||
public Builder currentTime(long millis) {
|
||||
explictTimeMillis = millis;
|
||||
useExplicitTime = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder disableTabletRowCheckFilter() {
|
||||
disableTabletRowCheckFilter = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TabletSummary build() {
|
||||
Stream<MetadataAccumulator.Entry> stream = entries.stream();
|
||||
if (!disableTabletRowCheckFilter) {
|
||||
stream = stream.filter(Builder::tabletEndAnPrevAreSame);
|
||||
}
|
||||
|
||||
// @formatter:off
|
||||
Collection<TabletStatistic> tabletStats = stream
|
||||
.collect(Collectors.groupingBy(MetadataAccumulator.Entry::getTabletPrefix)).entrySet()
|
||||
.stream()
|
||||
.map(m -> computeStatistic(m.getValue(), m.getKey()))
|
||||
.sorted(Comparator.comparing(TabletStatistic::getKeyName))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// @formatter:on
|
||||
return new TabletSummary(tabletStats);
|
||||
}
|
||||
|
||||
private TabletStatistic computeStatistic(Collection<MetadataAccumulator.Entry> entries, String keyName) {
|
||||
Map<TabletStatisticType, SummaryStatistics> stats = new HashMap<>(TabletStatisticType.values().length);
|
||||
int maxSize = entries.size();
|
||||
long timeMillis = useExplicitTime ? explictTimeMillis : System.currentTimeMillis();
|
||||
for (TabletStatisticType statType : TabletStatisticType.values()) {
|
||||
SummaryStatistics summaryStat = new SummaryStatistics();
|
||||
Iterator<MetadataAccumulator.Entry> iterator = entries.iterator();
|
||||
int idx = 0;
|
||||
while (iterator.hasNext() && idx < maxSize) {
|
||||
MetadataAccumulator.Entry e = iterator.next();
|
||||
double d;
|
||||
switch (statType) {
|
||||
case SIZE:
|
||||
d = e.getTotalFileBytes();
|
||||
break;
|
||||
case TIME:
|
||||
// check the row key offset first; this was done to support
|
||||
// tests so that they age could function from the row-key
|
||||
// the tablets that do not have a key will use the modification time
|
||||
d = timeMillis - e.getTabletOffset().orElse(e.getMilliseconds());
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Undefined switch case: " + statType.name());
|
||||
}
|
||||
summaryStat.addValue(d);
|
||||
idx++;
|
||||
}
|
||||
stats.put(statType, summaryStat);
|
||||
}
|
||||
|
||||
return new TabletStatistic(keyName, entries.size(), stats);
|
||||
}
|
||||
|
||||
private static boolean tabletEndAnPrevAreSame(MetadataAccumulator.Entry entry) {
|
||||
if ((null == entry.getTablet()) || (null == entry.getTabletPrev())) {
|
||||
return false;
|
||||
}
|
||||
Optional<String> o1 = TabletRowAdapter.decodeRowPrefix(entry.getTablet());
|
||||
Optional<String> o2 = TabletRowAdapter.decodeRowPrefix(entry.getTabletPrev());
|
||||
return o1.equals(o2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,14 @@ package timely.store.iterators;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.accumulo.core.data.ByteSequence;
|
||||
import org.apache.accumulo.core.data.Key;
|
||||
@@ -28,19 +35,19 @@ import timely.model.Metric;
|
||||
* number of elements in the filter. So, if you have a five day moving average
|
||||
* filter and a time series as 100 data points, then you will receive 95
|
||||
* results.
|
||||
*
|
||||
*
|
||||
* For multiple time series, K/V pairs will be reported in time order where time
|
||||
* is taken from the key of the last element in the filter. For example, if you
|
||||
* have series {A,B,C} and {A,C} are on the same time interval and B is lagging
|
||||
* behind them, then this iterator will return K/V answers for the time series
|
||||
* in the following manner:
|
||||
*
|
||||
*
|
||||
* A, C, B, A, C, B, ...
|
||||
*
|
||||
*
|
||||
* Also of note is that this iterator handles new time series appearing in the
|
||||
* middle of the time range. Time series that disappear during the time range
|
||||
* will stop reporting an answer.
|
||||
*
|
||||
*
|
||||
* NOTE: This iterator does not handle being re-seeked. It is currently designed
|
||||
* to be used with the DownsampleIterator above it.
|
||||
*
|
||||
@@ -222,8 +229,6 @@ public class TimeSeriesGroupingIterator extends WrappingIterator {
|
||||
/**
|
||||
* This will parse the next set of keys with the same timestamp (encoded in the
|
||||
* row) from the underlying source.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private void refillBuffer() throws IOException {
|
||||
LOG.trace("refill()");
|
||||
|
||||
@@ -153,7 +153,7 @@ public class MetricQueryLoadTest {
|
||||
|
||||
long numQueries = 1000;
|
||||
long queriesCompleted = 0;
|
||||
List<Future> futures = new ArrayList<>();
|
||||
List<Future<?>> futures = new ArrayList<>();
|
||||
|
||||
while (!testDone) {
|
||||
testDone = (System.currentTimeMillis() - beginQueries) >= (testDurationMins * 60 * 1000);
|
||||
@@ -164,9 +164,9 @@ public class MetricQueryLoadTest {
|
||||
while (futures.size() < numQueries) {
|
||||
futures.add(executorService.submit(runnableTask));
|
||||
}
|
||||
Iterator<Future> itr = futures.iterator();
|
||||
Iterator<Future<?>> itr = futures.iterator();
|
||||
while (itr.hasNext()) {
|
||||
Future f = itr.next();
|
||||
Future<?> f = itr.next();
|
||||
if (f.isDone()) {
|
||||
itr.remove();
|
||||
queriesCompleted++;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package timely.util;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.accumulo.core.client.ClientConfiguration;
|
||||
@@ -12,7 +13,6 @@ import org.apache.accumulo.core.client.security.tokens.PasswordToken;
|
||||
import org.apache.accumulo.core.data.Key;
|
||||
import org.apache.accumulo.core.data.Range;
|
||||
import org.apache.accumulo.core.data.Value;
|
||||
import org.apache.commons.configuration.BaseConfiguration;
|
||||
import org.springframework.boot.Banner.Mode;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
@@ -30,11 +30,11 @@ public class GetMetricTableSplitPoints {
|
||||
.bannerMode(Mode.OFF).web(WebApplicationType.NONE).run(args)) {
|
||||
Configuration conf = ctx.getBean(Configuration.class);
|
||||
|
||||
final BaseConfiguration apacheConf = new BaseConfiguration();
|
||||
final Map<String, String> properties = new HashMap<>();
|
||||
Accumulo accumuloConf = conf.getAccumulo();
|
||||
apacheConf.setProperty("instance.name", accumuloConf.getInstanceName());
|
||||
apacheConf.setProperty("instance.zookeeper.host", accumuloConf.getZookeepers());
|
||||
final ClientConfiguration aconf = new ClientConfiguration(Collections.singletonList(apacheConf));
|
||||
properties.put("instance.name", accumuloConf.getInstanceName());
|
||||
properties.put("instance.zookeeper.host", accumuloConf.getZookeepers());
|
||||
final ClientConfiguration aconf = ClientConfiguration.fromMap(properties);
|
||||
final Instance instance = new ZooKeeperInstance(aconf);
|
||||
Connector con = instance.getConnector(accumuloConf.getUsername(),
|
||||
new PasswordToken(accumuloConf.getPassword()));
|
||||
|
||||
@@ -41,7 +41,7 @@ public class MetaKeySet extends TreeSet<Key> {
|
||||
super(new MetaKeyComparator());
|
||||
}
|
||||
|
||||
public List<Mutation> toMutations() {
|
||||
public List<Mutation> toMutations(long ts) {
|
||||
List<Mutation> results = new ArrayList<>();
|
||||
String prevRow = null;
|
||||
Iterator<Key> keys = this.iterator();
|
||||
@@ -55,7 +55,7 @@ public class MetaKeySet extends TreeSet<Key> {
|
||||
m = new Mutation(next.getRow());
|
||||
prevRow = next.getRow().toString();
|
||||
}
|
||||
m.put(next.getColumnFamily(), next.getColumnQualifier(), NULL_VALUE);
|
||||
m.put(next.getColumnFamily(), next.getColumnQualifier(), ts, NULL_VALUE);
|
||||
}
|
||||
results.add(m);
|
||||
return results;
|
||||
|
||||
@@ -13,4 +13,9 @@
|
||||
<Method name="getCompressorOutput" />
|
||||
<Bug pattern="EI_EXPOSE_REP" />
|
||||
</Match>
|
||||
<Match>
|
||||
<!-- Must ignore these everywhere, because of a javac byte code generation bug -->
|
||||
<!-- https://github.com/spotbugs/spotbugs/issues/756 -->
|
||||
<Bug pattern="RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE" />
|
||||
</Match>
|
||||
</FindBugsFilter>
|
||||
+53
-53
@@ -12,11 +12,11 @@ public class WebSocketRequestDeserializationTest {
|
||||
@Test
|
||||
public void testCreateDeserialization() throws Exception {
|
||||
// @formatter:off
|
||||
String json = "{ "
|
||||
+ "\"operation\" : \"create\","
|
||||
+ " \"sessionId\": \"1234\""
|
||||
+ "}";
|
||||
// @formatter:on
|
||||
String json = "{ "
|
||||
+ "\"operation\" : \"create\","
|
||||
+ " \"sessionId\": \"1234\""
|
||||
+ "}";
|
||||
// @formatter:on
|
||||
WebSocketRequest request = JsonUtil.getObjectMapper().readValue(json.getBytes(), WebSocketRequest.class);
|
||||
Assert.assertNotNull(request);
|
||||
Assert.assertEquals(CreateSubscription.class, request.getClass());
|
||||
@@ -26,12 +26,12 @@ public class WebSocketRequestDeserializationTest {
|
||||
@Test
|
||||
public void testRemoveDeserialization() throws Exception {
|
||||
// @formatter:off
|
||||
String json = "{ "
|
||||
+ "\"operation\" : \"remove\","
|
||||
+ " \"sessionId\": \"1234\","
|
||||
+ " \"metric\" : \"sys.cpu.user\""
|
||||
+ "}";
|
||||
// @formatter:on
|
||||
String json = "{ "
|
||||
+ "\"operation\" : \"remove\","
|
||||
+ " \"sessionId\": \"1234\","
|
||||
+ " \"metric\" : \"sys.cpu.user\""
|
||||
+ "}";
|
||||
// @formatter:on
|
||||
WebSocketRequest request = JsonUtil.getObjectMapper().readValue(json.getBytes(), WebSocketRequest.class);
|
||||
Assert.assertNotNull(request);
|
||||
Assert.assertEquals(RemoveSubscription.class, request.getClass());
|
||||
@@ -42,11 +42,11 @@ public class WebSocketRequestDeserializationTest {
|
||||
@Test
|
||||
public void testCloseDeserialization() throws Exception {
|
||||
// @formatter:off
|
||||
String json = "{ "
|
||||
+ "\"operation\" : \"close\","
|
||||
+ " \"sessionId\": \"1234\""
|
||||
+ "}";
|
||||
// @formatter:on
|
||||
String json = "{ "
|
||||
+ "\"operation\" : \"close\","
|
||||
+ " \"sessionId\": \"1234\""
|
||||
+ "}";
|
||||
// @formatter:on
|
||||
WebSocketRequest request = JsonUtil.getObjectMapper().readValue(json.getBytes(), WebSocketRequest.class);
|
||||
Assert.assertNotNull(request);
|
||||
Assert.assertEquals(CloseSubscription.class, request.getClass());
|
||||
@@ -56,12 +56,12 @@ public class WebSocketRequestDeserializationTest {
|
||||
@Test
|
||||
public void testAddDeserialization() throws Exception {
|
||||
// @formatter:off
|
||||
String json = "{" +
|
||||
"\"operation\" : \"add\"," +
|
||||
"\"sessionId\" : \"1234\"," +
|
||||
" \"metric\" : \"sys.cpu.user\"" +
|
||||
"}";
|
||||
// @formatter:on
|
||||
String json = "{" +
|
||||
"\"operation\" : \"add\"," +
|
||||
"\"sessionId\" : \"1234\"," +
|
||||
" \"metric\" : \"sys.cpu.user\"" +
|
||||
"}";
|
||||
// @formatter:on
|
||||
WebSocketRequest request = JsonUtil.getObjectMapper().readValue(json.getBytes(), WebSocketRequest.class);
|
||||
Assert.assertNotNull(request);
|
||||
Assert.assertEquals(AddSubscription.class, request.getClass());
|
||||
@@ -74,13 +74,13 @@ public class WebSocketRequestDeserializationTest {
|
||||
@Test
|
||||
public void testAddDeserializationWithTime() throws Exception {
|
||||
// @formatter:off
|
||||
String json = "{" +
|
||||
"\"operation\" : \"add\"," +
|
||||
"\"sessionId\" : \"1234\"," +
|
||||
"\"metric\" : \"sys.cpu.user\"," +
|
||||
"\"startTime\" : \"1000\"" +
|
||||
"}";
|
||||
// @formatter:on
|
||||
String json = "{" +
|
||||
"\"operation\" : \"add\"," +
|
||||
"\"sessionId\" : \"1234\"," +
|
||||
"\"metric\" : \"sys.cpu.user\"," +
|
||||
"\"startTime\" : \"1000\"" +
|
||||
"}";
|
||||
// @formatter:on
|
||||
WebSocketRequest request = JsonUtil.getObjectMapper().readValue(json.getBytes(), WebSocketRequest.class);
|
||||
Assert.assertNotNull(request);
|
||||
Assert.assertEquals(AddSubscription.class, request.getClass());
|
||||
@@ -95,18 +95,18 @@ public class WebSocketRequestDeserializationTest {
|
||||
@Test
|
||||
public void testAddDeserializationWithTimeAndTags() throws Exception {
|
||||
// @formatter:off
|
||||
String json = "{" +
|
||||
"\"operation\" : \"add\"," +
|
||||
"\"sessionId\" : \"1234\"," +
|
||||
"\"metric\" : \"sys.cpu.user\"," +
|
||||
"\"tags\" : {" +
|
||||
"\"tag2\" : \"value2\"," +
|
||||
"\"tag1\" : \"value1\"" +
|
||||
"}," +
|
||||
"\"startTime\" : \"1000\"," +
|
||||
"\"endTime\" : \"2000\""+
|
||||
"}";
|
||||
// @formatter:on
|
||||
String json = "{" +
|
||||
"\"operation\" : \"add\"," +
|
||||
"\"sessionId\" : \"1234\"," +
|
||||
"\"metric\" : \"sys.cpu.user\"," +
|
||||
"\"tags\" : {" +
|
||||
"\"tag2\" : \"value2\"," +
|
||||
"\"tag1\" : \"value1\"" +
|
||||
"}," +
|
||||
"\"startTime\" : \"1000\"," +
|
||||
"\"endTime\" : \"2000\""+
|
||||
"}";
|
||||
// @formatter:on
|
||||
WebSocketRequest request = JsonUtil.getObjectMapper().readValue(json.getBytes(), WebSocketRequest.class);
|
||||
Assert.assertNotNull(request);
|
||||
Assert.assertEquals(AddSubscription.class, request.getClass());
|
||||
@@ -129,18 +129,18 @@ public class WebSocketRequestDeserializationTest {
|
||||
@Test
|
||||
public void testAddDeserializationWithStartAndDelayTimeAndTags() throws Exception {
|
||||
// @formatter:off
|
||||
String json = "{" +
|
||||
"\"operation\" : \"add\"," +
|
||||
"\"sessionId\" : \"1234\"," +
|
||||
"\"metric\" : \"sys.cpu.user\"," +
|
||||
"\"tags\" : {" +
|
||||
"\"tag2\" : \"value2\"," +
|
||||
"\"tag1\" : \"value1\"" +
|
||||
"}," +
|
||||
"\"startTime\" : \"1000\"," +
|
||||
"\"delayTime\" : \"500\"" +
|
||||
"}";
|
||||
// @formatter:on
|
||||
String json = "{" +
|
||||
"\"operation\" : \"add\"," +
|
||||
"\"sessionId\" : \"1234\"," +
|
||||
"\"metric\" : \"sys.cpu.user\"," +
|
||||
"\"tags\" : {" +
|
||||
"\"tag2\" : \"value2\"," +
|
||||
"\"tag1\" : \"value1\"" +
|
||||
"}," +
|
||||
"\"startTime\" : \"1000\"," +
|
||||
"\"delayTime\" : \"500\"" +
|
||||
"}";
|
||||
// @formatter:on
|
||||
WebSocketRequest request = JsonUtil.getObjectMapper().readValue(json.getBytes(), WebSocketRequest.class);
|
||||
Assert.assertNotNull(request);
|
||||
Assert.assertEquals(AddSubscription.class, request.getClass());
|
||||
|
||||
Loaded 100 of 136 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user