diff --git a/core/src/main/java/com/yahoo/ycsb/DBWrapper.java b/core/src/main/java/com/yahoo/ycsb/DBWrapper.java index 35cf26a5dfce891f13cb77914325a49b35ea6005..337f4d9b5d04d0ee5ceb337adb65169d6e7b2862 100644 --- a/core/src/main/java/com/yahoo/ycsb/DBWrapper.java +++ b/core/src/main/java/com/yahoo/ycsb/DBWrapper.java @@ -1,23 +1,25 @@ -/** - * Copyright (c) 2010 Yahoo! Inc. All rights reserved. - * - * 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. See the License for the specific language governing - * permissions and limitations under the License. See accompanying - * LICENSE file. +/** + * Copyright (c) 2010 Yahoo! Inc. All rights reserved. + * + * 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. See the License for the specific language governing + * permissions and limitations under the License. See accompanying + * LICENSE file. */ package com.yahoo.ycsb; +import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.Properties; import java.util.Set; import java.util.Vector; @@ -26,157 +28,205 @@ import com.yahoo.ycsb.measurements.Measurements; /** * Wrapper around a "real" DB that measures latencies and counts return codes. + * Also reports latency separately between OK and failed operations. */ public class DBWrapper extends DB { - DB _db; - Measurements _measurements; - - public DBWrapper(DB db) - { - _db=db; - _measurements=Measurements.getMeasurements(); - } - - /** - * Set the properties for this DB. - */ - public void setProperties(Properties p) - { - _db.setProperties(p); - } - - /** - * Get the set of properties for this DB. - */ - public Properties getProperties() - { - return _db.getProperties(); - } - - /** - * Initialize any state for this DB. - * Called once per DB instance; there is one DB instance per client thread. - */ - public void init() throws DBException - { - _db.init(); - } - - /** - * Cleanup any state for this DB. - * Called once per DB instance; there is one DB instance per client thread. - */ - public void cleanup() throws DBException - { - long ist=_measurements.getIntendedtartTimeNs(); - long st = System.nanoTime(); - _db.cleanup(); - long en=System.nanoTime(); - measure("CLEANUP",ist, st, en); - } - - /** - * Read a record from the database. Each field/value pair from the result will be stored in a HashMap. - * - * @param table The name of the table - * @param key The record key of the record to read. - * @param fields The list of fields to read, or null for all of them - * @param result A HashMap of field/value pairs for the result - * @return The result of the operation. - */ - public Status read(String table, String key, Set<String> fields, HashMap<String,ByteIterator> result) - { - long ist=_measurements.getIntendedtartTimeNs(); - long st = System.nanoTime(); - Status res=_db.read(table,key,fields,result); - long en=System.nanoTime(); - measure("READ",ist, st, en); - _measurements.reportStatus("READ",res); - return res; - } - - /** - * Perform a range scan for a set of records in the database. Each field/value pair from the result will be stored in a HashMap. - * - * @param table The name of the table - * @param startkey The record key of the first record to read. - * @param recordcount The number of records to read - * @param fields The list of fields to read, or null for all of them - * @param result A Vector of HashMaps, where each HashMap is a set field/value pairs for one record - * @return The result of the operation. - */ - public Status scan(String table, String startkey, int recordcount, Set<String> fields, Vector<HashMap<String,ByteIterator>> result) - { - long ist=_measurements.getIntendedtartTimeNs(); - long st = System.nanoTime(); - Status res=_db.scan(table,startkey,recordcount,fields,result); - long en=System.nanoTime(); - measure("SCAN",ist, st, en); - _measurements.reportStatus("SCAN",res); - return res; - } - - private void measure(String op, long intendedStartTimeNanos, long startTimeNanos, long endTimeNanos) { - _measurements.measure(op, (int)((endTimeNanos-startTimeNanos)/1000)); - _measurements.measureIntended(op, (int)((endTimeNanos-intendedStartTimeNanos)/1000)); + private DB _db; + private Measurements _measurements; + + private boolean reportLatencyForEachError = false; + private HashSet<String> latencyTrackedErrors = new HashSet<String>(); + + private static final String REPORT_LATENCY_FOR_EACH_ERROR_PROPERTY = + "reportlatencyforeacherror"; + private static final String REPORT_LATENCY_FOR_EACH_ERROR_PROPERTY_DEFAULT = + "false"; + + private static final String LATENCY_TRACKED_ERRORS_PROPERTY = + "latencytrackederrors"; + + public DBWrapper(DB db) + { + _db=db; + _measurements=Measurements.getMeasurements(); + } + + /** + * Set the properties for this DB. + */ + public void setProperties(Properties p) + { + _db.setProperties(p); + } + + /** + * Get the set of properties for this DB. + */ + public Properties getProperties() + { + return _db.getProperties(); + } + + /** + * Initialize any state for this DB. + * Called once per DB instance; there is one DB instance per client thread. + */ + public void init() throws DBException + { + _db.init(); + + this.reportLatencyForEachError = Boolean.parseBoolean(getProperties(). + getProperty(REPORT_LATENCY_FOR_EACH_ERROR_PROPERTY, + REPORT_LATENCY_FOR_EACH_ERROR_PROPERTY_DEFAULT)); + + if (!reportLatencyForEachError) { + String latencyTrackedErrors = getProperties().getProperty( + LATENCY_TRACKED_ERRORS_PROPERTY, null); + if (latencyTrackedErrors != null) { + this.latencyTrackedErrors = new HashSet<String>(Arrays.asList( + latencyTrackedErrors.split(","))); + } } - - /** - * Update a record in the database. Any field/value pairs in the specified values HashMap will be written into the record with the specified - * record key, overwriting any existing values with the same field name. - * - * @param table The name of the table - * @param key The record key of the record to write. - * @param values A HashMap of field/value pairs to update in the record - * @return The result of the operation. - */ - public Status update(String table, String key, HashMap<String,ByteIterator> values) - { - long ist=_measurements.getIntendedtartTimeNs(); - long st = System.nanoTime(); - Status res=_db.update(table,key,values); - long en=System.nanoTime(); - measure("UPDATE",ist, st, en); - _measurements.reportStatus("UPDATE",res); - return res; - } - - /** - * Insert a record in the database. Any field/value pairs in the specified values HashMap will be written into the record with the specified - * record key. - * - * @param table The name of the table - * @param key The record key of the record to insert. - * @param values A HashMap of field/value pairs to insert in the record - * @return The result of the operation. - */ - public Status insert(String table, String key, HashMap<String,ByteIterator> values) - { - long ist=_measurements.getIntendedtartTimeNs(); - long st = System.nanoTime(); - Status res=_db.insert(table,key,values); - long en=System.nanoTime(); - measure("INSERT",ist, st, en); - _measurements.reportStatus("INSERT",res); - return res; - } - - /** - * Delete a record from the database. - * - * @param table The name of the table - * @param key The record key of the record to delete. - * @return The result of the operation. - */ - public Status delete(String table, String key) - { - long ist=_measurements.getIntendedtartTimeNs(); - long st = System.nanoTime(); - Status res=_db.delete(table,key); - long en=System.nanoTime(); - measure("DELETE",ist, st, en); - _measurements.reportStatus("DELETE",res); - return res; - } + + System.err.println("DBWrapper: report latency for each error is " + + this.reportLatencyForEachError + " and specific error codes to track" + + " for latency are: " + this.latencyTrackedErrors.toString()); + } + + /** + * Cleanup any state for this DB. + * Called once per DB instance; there is one DB instance per client thread. + */ + public void cleanup() throws DBException + { + long ist=_measurements.getIntendedtartTimeNs(); + long st = System.nanoTime(); + _db.cleanup(); + long en=System.nanoTime(); + measure("CLEANUP", Status.OK, ist, st, en); + } + + /** + * Read a record from the database. Each field/value pair from the result + * will be stored in a HashMap. + * + * @param table The name of the table + * @param key The record key of the record to read. + * @param fields The list of fields to read, or null for all of them + * @param result A HashMap of field/value pairs for the result + * @return The result of the operation. + */ + public Status read(String table, String key, Set<String> fields, + HashMap<String,ByteIterator> result) + { + long ist=_measurements.getIntendedtartTimeNs(); + long st = System.nanoTime(); + Status res=_db.read(table,key,fields,result); + long en=System.nanoTime(); + measure("READ", res, ist, st, en); + _measurements.reportStatus("READ", res); + return res; + } + + /** + * Perform a range scan for a set of records in the database. + * Each field/value pair from the result will be stored in a HashMap. + * + * @param table The name of the table + * @param startkey The record key of the first record to read. + * @param recordcount The number of records to read + * @param fields The list of fields to read, or null for all of them + * @param result A Vector of HashMaps, where each HashMap is a set field/value pairs for one record + * @return The result of the operation. + */ + public Status scan(String table, String startkey, int recordcount, + Set<String> fields, Vector<HashMap<String,ByteIterator>> result) + { + long ist=_measurements.getIntendedtartTimeNs(); + long st = System.nanoTime(); + Status res=_db.scan(table,startkey,recordcount,fields,result); + long en=System.nanoTime(); + measure("SCAN", res, ist, st, en); + _measurements.reportStatus("SCAN", res); + return res; + } + + private void measure(String op, Status result, long intendedStartTimeNanos, + long startTimeNanos, long endTimeNanos) { + String measurementName = op; + if (result != Status.OK) { + if (this.reportLatencyForEachError || + this.latencyTrackedErrors.contains(result.getName())) { + measurementName = op + "-" + result.getName(); + } else { + measurementName = op + "-FAILED"; + } + } + _measurements.measure(measurementName, + (int)((endTimeNanos-startTimeNanos)/1000)); + _measurements.measureIntended(measurementName, + (int)((endTimeNanos-intendedStartTimeNanos)/1000)); + } + + /** + * Update a record in the database. Any field/value pairs in the specified values HashMap will be written into the record with the specified + * record key, overwriting any existing values with the same field name. + * + * @param table The name of the table + * @param key The record key of the record to write. + * @param values A HashMap of field/value pairs to update in the record + * @return The result of the operation. + */ + public Status update(String table, String key, + HashMap<String,ByteIterator> values) + { + long ist=_measurements.getIntendedtartTimeNs(); + long st = System.nanoTime(); + Status res=_db.update(table,key,values); + long en=System.nanoTime(); + measure("UPDATE", res, ist, st, en); + _measurements.reportStatus("UPDATE", res); + return res; + } + + /** + * Insert a record in the database. Any field/value pairs in the specified + * values HashMap will be written into the record with the specified + * record key. + * + * @param table The name of the table + * @param key The record key of the record to insert. + * @param values A HashMap of field/value pairs to insert in the record + * @return The result of the operation. + */ + public Status insert(String table, String key, + HashMap<String,ByteIterator> values) + { + long ist=_measurements.getIntendedtartTimeNs(); + long st = System.nanoTime(); + Status res=_db.insert(table,key,values); + long en=System.nanoTime(); + measure("INSERT", res, ist, st, en); + _measurements.reportStatus("INSERT", res); + return res; + } + + /** + * Delete a record from the database. + * + * @param table The name of the table + * @param key The record key of the record to delete. + * @return The result of the operation. + */ + public Status delete(String table, String key) + { + long ist=_measurements.getIntendedtartTimeNs(); + long st = System.nanoTime(); + Status res=_db.delete(table,key); + long en=System.nanoTime(); + measure("DELETE", res, ist, st, en); + _measurements.reportStatus("DELETE", res); + return res; + } } diff --git a/workloads/workload_template b/workloads/workload_template index 6aebd64a178d525032214076a2e7c2d15b104485..de0bbae24aa7f4d77083201e182e6919e9095042 100644 --- a/workloads/workload_template +++ b/workloads/workload_template @@ -138,3 +138,21 @@ histogram.buckets=1000 # Granularity for time series (in milliseconds) timeseries.granularity=1000 + +# Latency reporting. +# +# YCSB records latency of failed operations separately from successful ones. +# Latency of all OK operations will be reported under their operation name, +# such as [READ], [UPDATE], etc. +# +# For failed operations: +# By default we don't track latency numbers of specific error status. +# We just report latency of all failed operation under one measurement name +# such as [READ-FAILED]. But optionally, user can configure to have either: +# 1. Record and report latency for each and every error status code by +# setting reportLatencyForEachError to true, or +# 2. Record and report latency for a select set of error status codes by +# providing a CSV list of Status codes via the "latencytrackederrors" +# property. +# reportlatencyforeacherror=false +# latencytrackederrors="<comma separated strings of error codes>"