/** * Copyright 2014 LinkedIn Corp. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this * file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ package com.linkedin.multitenant.db; import java.io.IOException; import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.ResponseHandler; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import org.apache.log4j.Logger; import com.linkedin.multitenant.common.Query; import com.linkedin.multitenant.main.RunExperiment; public class RocksdbDatabase implements Database { private class MyResponseHandler implements ResponseHandler<String> { public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException { int status = response.getStatusLine().getStatusCode(); if(status >= 200 && status < 300) { HttpEntity ent = response.getEntity(); if(ent == null) return null; else return EntityUtils.toString(ent); } else { throw new ClientProtocolException("Something wrong"); } } } private static final Logger m_log = Logger.getLogger(RocksdbDatabase.class); public static final String FLAG_ROCKSDB_DB_NAME = "rocksdb.dbName"; protected CloseableHttpClient m_client; protected String m_hostName; protected int m_hostPort; protected String m_dbName; protected MyResponseHandler m_handler; protected String m_connStr; public RocksdbDatabase() { RequestConfig rq = RequestConfig.custom().setStaleConnectionCheckEnabled(false).build(); m_client = HttpClients.custom() .setDefaultRequestConfig(rq) .setMaxConnTotal(2) .build(); m_handler = new MyResponseHandler(); } @Override public DatabaseResult init(Map<String, String> workPlanProperties, Map<String, String> jobProperties) throws Exception { String hostName; int hostPort; String dbName; String jobName; //get job name String temp = getParamStr(jobProperties, RunExperiment.FLAG_JOB_NAME); if(temp == null) { m_log.fatal("Job name is not specified"); return DatabaseResult.FAIL; } else { jobName = temp; } //get hostname temp = getParamStr(workPlanProperties, RunExperiment.FLAG_WORK_HOST); if(temp == null) { m_log.fatal("Hostname is not specified"); return DatabaseResult.FAIL; } else { hostName = temp; } //get host port hostPort = getParamInt(workPlanProperties, RunExperiment.FLAG_WORK_PORT); if(hostPort == -1) { m_log.fatal("Host port is not specified"); return DatabaseResult.FAIL; } //get db name temp = getParamStr(jobProperties, FLAG_ROCKSDB_DB_NAME); if(temp == null) { m_log.fatal("Rocksdb database name is not specified for job " + jobName); return DatabaseResult.FAIL; } else { dbName = temp; } return init(hostName, hostPort, dbName); } public DatabaseResult init(String hostName, int hostPort, String dbName) { m_hostName = hostName; m_hostPort = hostPort; m_dbName = dbName; m_connStr = "http://" + m_hostName + ":" + m_hostPort + "/" + m_dbName + "/"; return DatabaseResult.OK; } @Override public DatabaseResult doInsert(Query q) { HttpPut put = new HttpPut(m_connStr + q.getKey()); ByteArrayEntity bae = new ByteArrayEntity(q.getValue()); bae.setContentType("octet-stream"); put.setEntity(bae); try { String responseBody = m_client.execute(put, m_handler); m_log.debug("Write response: " + responseBody); return DatabaseResult.OK; } catch (Exception e) { m_log.error("Error in executing doInsert", e); return DatabaseResult.FAIL; } } @Override public DatabaseResult doUpdate(Query q) { HttpPut put = new HttpPut(m_connStr + q.getKey()); ByteArrayEntity bae = new ByteArrayEntity(q.getValue()); bae.setContentType("octet-stream"); put.setEntity(bae); try { String responseBody = m_client.execute(put, m_handler); m_log.debug("Write response: " + responseBody); return DatabaseResult.OK; } catch (Exception e) { m_log.error("Error in executing doUpdate", e); return DatabaseResult.FAIL; } } @Override public DatabaseResult doRead(Query q) { HttpGet get = new HttpGet(m_connStr + q.getKey()); try { String responseBody = m_client.execute(get, m_handler); m_log.debug("Read response: " + responseBody); return DatabaseResult.OK; } catch (Exception e) { m_log.error("Error in executing doRead", e); return DatabaseResult.FAIL; } } @Override public DatabaseResult doDelete(Query q) { HttpDelete delete = new HttpDelete(m_connStr + q.getKey()); try { String responseBody = m_client.execute(delete, m_handler); m_log.debug("Delete response: " + responseBody); return DatabaseResult.OK; } catch (Exception e) { m_log.error("Error in executing doDelete", e); return DatabaseResult.FAIL; } } @Override public DatabaseResult close() { try { m_client.close(); return DatabaseResult.OK; } catch(Exception e) { return DatabaseResult.FAIL; } } private String getParamStr(Map<String, String> properties, String propertyName) { String val = properties.get(propertyName); if(val == null) return null; else return val; } private int getParamInt(Map<String, String> properties, String propertyName) { String val = properties.get(propertyName); if(val == null) return -1; else return Integer.parseInt(val); } }