/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// This file contains protocol buffers that are used for Client service.

option java_package = "org.apache.hadoop.hbase.protobuf.generated";
option java_outer_classname = "ClientProtos";
option java_generic_services = true;
option java_generate_equals_and_hash = true;
option optimize_for = SPEED;

import "HBase.proto";
import "Filter.proto";
import "Cell.proto";
import "Comparator.proto";

/**
 * The protocol buffer version of Authorizations.
 */
message Authorizations {
  repeated string label = 1;
}

/**
 * The protocol buffer version of CellVisibility.
 */
message CellVisibility {
  required string expression = 1;
}

/**
 * Container for a list of column qualifier names of a family.
 */
message Column {
  required bytes family = 1;
  repeated bytes qualifier = 2;
}

/**
 * The protocol buffer version of Get.
 * Unless existence_only is specified, return all the requested data
 * for the row that matches exactly, or the one that immediately
 * precedes it if closest_row_before is specified.
 */
message Get {
  required bytes row = 1;
  repeated Column column = 2;
  repeated NameBytesPair attribute = 3;
  optional Filter filter = 4;
  optional TimeRange time_range = 5;
  optional uint32 max_versions = 6 [default = 1];
  optional bool cache_blocks = 7 [default = true];
  optional uint32 store_limit = 8;
  optional uint32 store_offset = 9;

  // The result isn't asked for, just check for
  // the existence.
  optional bool existence_only = 10 [default = false];

  // If the row to get doesn't exist, return the
  // closest row before.
  optional bool closest_row_before = 11 [default = false];
}

message Result {
  // Result includes the Cells or else it just has a count of Cells
  // that are carried otherwise.
  repeated Cell cell = 1;
  // The below count is set when the associated cells are
  // not part of this protobuf message; they are passed alongside
  // and then this Message is just a placeholder with metadata.
  // The count is needed to know how many to peel off the block of Cells as
  // ours.  NOTE: This is different from the pb managed cell_count of the
  // 'cell' field above which is non-null when the cells are pb'd.
  optional int32 associated_cell_count = 2;

  // used for Get to check existence only. Not set if existence_only was not set to true
  //  in the query.
  optional bool exists = 3;
}

/**
 * The get request. Perform a single Get operation.
 */
message GetRequest {
  required RegionSpecifier region = 1;
  required Get get = 2;
}

message GetResponse {
  optional Result result = 1;
}

/**
 * Condition to check if the value of a given cell (row,
 * family, qualifier) matches a value via a given comparator.
 *
 * Condition is used in check and mutate operations.
 */
message Condition {
  required bytes row = 1;
  required bytes family = 2;
  required bytes qualifier = 3;
  required CompareType compare_type = 4;
  required Comparator comparator = 5;
}


/**
 * A specific mutation inside a mutate request.
 * It can be an append, increment, put or delete based
 * on the mutation type.  It can be fully filled in or
 * only metadata present because data is being carried
 * elsewhere outside of pb.
 */
message MutationProto {
  optional bytes row = 1;
  optional MutationType mutate_type = 2;
  repeated ColumnValue column_value = 3;
  optional uint64 timestamp = 4;
  repeated NameBytesPair attribute = 5;
  optional Durability durability = 6 [default = USE_DEFAULT];

  // For some mutations, a result may be returned, in which case,
  // time range can be specified for potential performance gain
  optional TimeRange time_range = 7;
  // The below count is set when the associated cells are NOT
  // part of this protobuf message; they are passed alongside
  // and then this Message is a placeholder with metadata.  The
  // count is needed to know how many to peel off the block of Cells as
  // ours.  NOTE: This is different from the pb managed cell_count of the
  // 'cell' field above which is non-null when the cells are pb'd.
  optional int32 associated_cell_count = 8;

  optional uint64 nonce = 9;

  enum Durability {
    USE_DEFAULT  = 0;
    SKIP_WAL     = 1;
    ASYNC_WAL    = 2;
    SYNC_WAL     = 3;
    FSYNC_WAL    = 4;
  }

  enum MutationType {
    APPEND = 0;
    INCREMENT = 1;
    PUT = 2;
    DELETE = 3;
  }

  enum DeleteType {
    DELETE_ONE_VERSION = 0;
    DELETE_MULTIPLE_VERSIONS = 1;
    DELETE_FAMILY = 2;
    DELETE_FAMILY_VERSION = 3;
  }

  message ColumnValue {
    required bytes family = 1;
    repeated QualifierValue qualifier_value = 2;

    message QualifierValue {
      optional bytes qualifier = 1;
      optional bytes value = 2;
      optional uint64 timestamp = 3;
      optional DeleteType delete_type = 4;
      optional bytes tags = 5;
    }
  }
}

/**
 * The mutate request. Perform a single Mutate operation.
 *
 * Optionally, you can specify a condition. The mutate
 * will take place only if the condition is met.  Otherwise,
 * the mutate will be ignored.  In the response result,
 * parameter processed is used to indicate if the mutate
 * actually happened.
 */
message MutateRequest {
  required RegionSpecifier region = 1;
  required MutationProto mutation = 2;
  optional Condition condition = 3;
  optional uint64 nonce_group = 4;
}

message MutateResponse {
  optional Result result = 1;

  // used for mutate to indicate processed only
  optional bool processed = 2;
}

/**
 * Instead of get from a table, you can scan it with optional filters.
 * You can specify the row key range, time range, the columns/families
 * to scan and so on.
 *
 * This scan is used the first time in a scan request. The response of
 * the initial scan will return a scanner id, which should be used to
 * fetch result batches later on before it is closed.
 */
message Scan {
  repeated Column column = 1;
  repeated NameBytesPair attribute = 2;
  optional bytes start_row = 3;
  optional bytes stop_row = 4;
  optional Filter filter = 5;
  optional TimeRange time_range = 6;
  optional uint32 max_versions = 7 [default = 1];
  optional bool cache_blocks = 8 [default = true];
  optional uint32 batch_size = 9;
  optional uint64 max_result_size = 10;
  optional uint32 store_limit = 11;
  optional uint32 store_offset = 12;
  optional bool load_column_families_on_demand = 13; /* DO NOT add defaults to load_column_families_on_demand. */
  optional bool small = 14;
  optional bool reversed = 15 [default = false];
}

/**
 * A scan request. Initially, it should specify a scan. Later on, you
 * can use the scanner id returned to fetch result batches with a different
 * scan request.
 *
 * The scanner will remain open if there are more results, and it's not
 * asked to be closed explicitly.
 *
 * You can fetch the results and ask the scanner to be closed to save
 * a trip if you are not interested in remaining results.
 */
message ScanRequest {
  optional RegionSpecifier region = 1;
  optional Scan scan = 2;
  optional uint64 scanner_id = 3;
  optional uint32 number_of_rows = 4;
  optional bool close_scanner = 5;
  optional uint64 next_call_seq = 6;
}

/**
 * The scan response. If there are no more results, more_results will
 * be false.  If it is not specified, it means there are more.
 */
message ScanResponse {
  // This field is filled in if we are doing cellblocks.  A cellblock is made up
  // of all Cells serialized out as one cellblock BUT responses from a server
  // have their Cells grouped by Result.  So we can reconstitute the
  // Results on the client-side, this field is a list of counts of Cells
  // in each Result that makes up the response.  For example, if this field
  // has 3, 3, 3 in it, then we know that on the client, we are to make
  // three Results each of three Cells each.
  repeated uint32 cells_per_result = 1;
  optional uint64 scanner_id = 2;
  optional bool more_results = 3;
  optional uint32 ttl = 4;
  // If cells are not carried in an accompanying cellblock, then they are pb'd here.
  // This field is mutually exclusive with cells_per_result (since the Cells will
  // be inside the pb'd Result)
  repeated Result results = 5;
}

/**
 * Atomically bulk load multiple HFiles (say from different column families)
 * into an open region.
 */
message BulkLoadHFileRequest {
  required RegionSpecifier region = 1;
  repeated FamilyPath family_path = 2;
  optional bool assign_seq_num = 3;

  message FamilyPath {
    required bytes family = 1;
    required string path = 2;
  }
}

message BulkLoadHFileResponse {
  required bool loaded = 1;
}

message CoprocessorServiceCall {
  required bytes row = 1;
  required string service_name = 2;
  required string method_name = 3;
  required bytes request = 4;
}

message CoprocessorServiceResult {
  optional NameBytesPair value = 1;
}

message CoprocessorServiceRequest {
  required RegionSpecifier region = 1;
  required CoprocessorServiceCall call = 2;
}

message CoprocessorServiceResponse {
  required RegionSpecifier region = 1;
  required NameBytesPair value = 2;
}

// Either a Get or a Mutation
message Action {
  // If part of a multi action, useful aligning
  // result with what was originally submitted.
  optional uint32 index = 1;
  optional MutationProto mutation = 2;
  optional Get get = 3;
  optional CoprocessorServiceCall service_call = 4;
}

/**
 * Actions to run against a Region.
 */
message RegionAction {
  required RegionSpecifier region = 1;
  // When set, run mutations as atomic unit.
  optional bool atomic = 2;
  repeated Action action = 3;
}

/**
 * Either a Result or an Exception NameBytesPair (keyed by
 * exception name whose value is the exception stringified)
 * or maybe empty if no result and no exception.
 */
message ResultOrException {
  // If part of a multi call, save original index of the list of all
  // passed so can align this response w/ original request.
  optional uint32 index = 1;
  optional Result result = 2;
  optional NameBytesPair exception = 3;
  // result if this was a coprocessor service call
  optional CoprocessorServiceResult service_result = 4;
}

/**
 * The result of a RegionAction.
 */
message RegionActionResult {
  repeated ResultOrException resultOrException = 1;
  // If the operation failed globally for this region, this exception is set
  optional NameBytesPair exception = 2;
}

/**
 * Execute a list of actions on a given region in order.
 * Nothing prevents a request to contains a set of RegionAction on the same region.
 * For this reason, the matching between the MultiRequest and the MultiResponse is not
 *  done by the region specifier but by keeping the order of the RegionActionResult vs.
 *  the order of the RegionAction.
 */
message MultiRequest {
  repeated RegionAction regionAction = 1;
  optional uint64 nonceGroup = 2;
}

message MultiResponse {
  repeated RegionActionResult regionActionResult = 1;
}


service ClientService {
  rpc Get(GetRequest)
    returns(GetResponse);

  rpc Mutate(MutateRequest)
    returns(MutateResponse);

  rpc Scan(ScanRequest)
    returns(ScanResponse);

  rpc BulkLoadHFile(BulkLoadHFileRequest)
    returns(BulkLoadHFileResponse);

  rpc ExecService(CoprocessorServiceRequest)
    returns(CoprocessorServiceResponse);

  rpc Multi(MultiRequest)
    returns(MultiResponse);
}
