View Javadoc

1   /*
2    * Copyright 2011 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  
21  package org.apache.hadoop.hbase.client;
22  
23  import java.util.ArrayList;
24  import java.util.HashMap;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.TreeMap;
28  import java.util.UUID;
29  
30  import org.apache.hadoop.hbase.HConstants;
31  import org.apache.hadoop.hbase.KeyValue;
32  import org.apache.hadoop.hbase.util.Bytes;
33  
34  public abstract class Mutation extends OperationWithAttributes implements Row {
35    // Attribute used in Mutations to indicate the originating cluster.
36    private static final String CLUSTER_ID_ATTR = "_c.id_";
37  
38    protected byte [] row = null;
39    protected long ts = HConstants.LATEST_TIMESTAMP;
40    protected long lockId = -1L;
41    protected boolean writeToWAL = true;
42    protected Map<byte [], List<KeyValue>> familyMap =
43        new TreeMap<byte [], List<KeyValue>>(Bytes.BYTES_COMPARATOR);
44  
45    /**
46     * Compile the column family (i.e. schema) information
47     * into a Map. Useful for parsing and aggregation by debugging,
48     * logging, and administration tools.
49     * @return Map
50     */
51    @Override
52    public Map<String, Object> getFingerprint() {
53      Map<String, Object> map = new HashMap<String, Object>();
54      List<String> families = new ArrayList<String>();
55      // ideally, we would also include table information, but that information
56      // is not stored in each Operation instance.
57      map.put("families", families);
58      for (Map.Entry<byte [], List<KeyValue>> entry : this.familyMap.entrySet()) {
59        families.add(Bytes.toStringBinary(entry.getKey()));
60      } 
61      return map;
62    }
63  
64    /**
65     * Compile the details beyond the scope of getFingerprint (row, columns,
66     * timestamps, etc.) into a Map along with the fingerprinted information.
67     * Useful for debugging, logging, and administration tools.
68     * @param maxCols a limit on the number of columns output prior to truncation
69     * @return Map
70     */
71    @Override
72    public Map<String, Object> toMap(int maxCols) {
73      // we start with the fingerprint map and build on top of it.
74      Map<String, Object> map = getFingerprint();
75      // replace the fingerprint's simple list of families with a 
76      // map from column families to lists of qualifiers and kv details
77      Map<String, List<Map<String, Object>>> columns =
78        new HashMap<String, List<Map<String, Object>>>();
79      map.put("families", columns);
80      map.put("row", Bytes.toStringBinary(this.row));
81      int colCount = 0;
82      // iterate through all column families affected
83      for (Map.Entry<byte [], List<KeyValue>> entry : this.familyMap.entrySet()) {
84        // map from this family to details for each kv affected within the family
85        List<Map<String, Object>> qualifierDetails =
86          new ArrayList<Map<String, Object>>();
87        columns.put(Bytes.toStringBinary(entry.getKey()), qualifierDetails);
88        colCount += entry.getValue().size();
89        if (maxCols <= 0) {
90          continue;
91        }
92        // add details for each kv
93        for (KeyValue kv : entry.getValue()) {
94          if (--maxCols <= 0 ) {
95            continue;
96          }
97          Map<String, Object> kvMap = kv.toStringMap();
98          // row and family information are already available in the bigger map
99          kvMap.remove("row");
100         kvMap.remove("family");
101         qualifierDetails.add(kvMap);
102       }
103     }
104     map.put("totalColumns", colCount);
105     // add the id if set
106     if (getId() != null) {
107       map.put("id", getId());
108     }
109     return map;
110   }
111 
112   /**
113    * @return true if edits should be applied to WAL, false if not
114    */
115   public boolean getWriteToWAL() {
116     return this.writeToWAL;
117   }
118 
119   /**
120    * Set whether this Delete should be written to the WAL or not.
121    * Not writing the WAL means you may lose edits on server crash.
122    * @param write true if edits should be written to WAL, false if not
123    */
124   public void setWriteToWAL(boolean write) {
125     this.writeToWAL = write;
126   }
127 
128   /**
129    * Method for retrieving the put's familyMap
130    * @return familyMap
131    */
132   public Map<byte [], List<KeyValue>> getFamilyMap() {
133     return this.familyMap;
134   }
135 
136   /**
137    * Method for setting the put's familyMap
138    */
139   public void setFamilyMap(Map<byte [], List<KeyValue>> map) {
140     this.familyMap = map;
141   }
142 
143   /**
144    * Method to check if the familyMap is empty
145    * @return true if empty, false otherwise
146    */
147   public boolean isEmpty() {
148     return familyMap.isEmpty();
149   }
150 
151   /**
152    * Method for retrieving the delete's row
153    * @return row
154    */
155   @Override
156   public byte [] getRow() {
157     return this.row;
158   }
159 
160   public int compareTo(final Row d) {
161     return Bytes.compareTo(this.getRow(), d.getRow());
162   }
163 
164   /**
165    * Method for retrieving the delete's RowLock
166    * @return RowLock
167    * @deprecated {@link RowLock} and associated operations are deprecated
168    */
169   public RowLock getRowLock() {
170     return new RowLock(this.row, this.lockId);
171   }
172 
173   /**
174    * Method for retrieving the delete's lock ID.
175    *
176    * @return The lock ID.
177    * @deprecated {@link RowLock} and associated operations are deprecated
178    */
179   public long getLockId() {
180   return this.lockId;
181   }
182 
183   /**
184    * Method for retrieving the timestamp
185    * @return timestamp
186    */
187   public long getTimeStamp() {
188     return this.ts;
189   }
190 
191   /**
192    * Set the replication custer id.
193    * @param clusterId
194    */
195   public void setClusterId(UUID clusterId) {
196     if (clusterId == null) return;
197     byte[] val = new byte[2*Bytes.SIZEOF_LONG];
198     Bytes.putLong(val, 0, clusterId.getMostSignificantBits());
199     Bytes.putLong(val, Bytes.SIZEOF_LONG, clusterId.getLeastSignificantBits());
200     setAttribute(CLUSTER_ID_ATTR, val);
201   }
202 
203   /**
204    * @return The replication cluster id.
205    */
206   public UUID getClusterId() {
207     byte[] attr = getAttribute(CLUSTER_ID_ATTR);
208     if (attr == null) {
209       return HConstants.DEFAULT_CLUSTER_ID;
210     }
211     return new UUID(Bytes.toLong(attr,0), Bytes.toLong(attr, Bytes.SIZEOF_LONG));
212   }
213 
214   /**
215    * @return the total number of KeyValues
216    */
217   public int size() {
218     int size = 0;
219     for(List<KeyValue> kvList : this.familyMap.values()) {
220       size += kvList.size();
221     }
222     return size;
223   }
224 
225   /**
226    * @return the number of different families
227    */
228   public int numFamilies() {
229     return familyMap.size();
230   }
231 }