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.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.hadoop.hbase.HConstants;
33  import org.apache.hadoop.hbase.KeyValue;
34  import org.apache.hadoop.hbase.util.Bytes;
35  
36  public abstract class Mutation extends OperationWithAttributes implements Row {
37    private static final Log LOG = LogFactory.getLog(Mutation.class);
38    // Attribute used in Mutations to indicate the originating cluster.
39    private static final String CLUSTER_ID_ATTR = "_c.id_";
40    private static final String DURABILITY_ID_ATTR = "_dur_";
41  
42    protected byte [] row = null;
43    protected long ts = HConstants.LATEST_TIMESTAMP;
44    protected long lockId = -1L;
45    protected boolean writeToWAL = true;
46    protected Map<byte [], List<KeyValue>> familyMap =
47        new TreeMap<byte [], List<KeyValue>>(Bytes.BYTES_COMPARATOR);
48  
49    /**
50     * Compile the column family (i.e. schema) information
51     * into a Map. Useful for parsing and aggregation by debugging,
52     * logging, and administration tools.
53     * @return Map
54     */
55    @Override
56    public Map<String, Object> getFingerprint() {
57      Map<String, Object> map = new HashMap<String, Object>();
58      List<String> families = new ArrayList<String>();
59      // ideally, we would also include table information, but that information
60      // is not stored in each Operation instance.
61      map.put("families", families);
62      for (Map.Entry<byte [], List<KeyValue>> entry : this.familyMap.entrySet()) {
63        families.add(Bytes.toStringBinary(entry.getKey()));
64      } 
65      return map;
66    }
67  
68    /**
69     * Compile the details beyond the scope of getFingerprint (row, columns,
70     * timestamps, etc.) into a Map along with the fingerprinted information.
71     * Useful for debugging, logging, and administration tools.
72     * @param maxCols a limit on the number of columns output prior to truncation
73     * @return Map
74     */
75    @Override
76    public Map<String, Object> toMap(int maxCols) {
77      // we start with the fingerprint map and build on top of it.
78      Map<String, Object> map = getFingerprint();
79      // replace the fingerprint's simple list of families with a 
80      // map from column families to lists of qualifiers and kv details
81      Map<String, List<Map<String, Object>>> columns =
82        new HashMap<String, List<Map<String, Object>>>();
83      map.put("families", columns);
84      map.put("row", Bytes.toStringBinary(this.row));
85      int colCount = 0;
86      // iterate through all column families affected
87      for (Map.Entry<byte [], List<KeyValue>> entry : this.familyMap.entrySet()) {
88        // map from this family to details for each kv affected within the family
89        List<Map<String, Object>> qualifierDetails =
90          new ArrayList<Map<String, Object>>();
91        columns.put(Bytes.toStringBinary(entry.getKey()), qualifierDetails);
92        colCount += entry.getValue().size();
93        if (maxCols <= 0) {
94          continue;
95        }
96        // add details for each kv
97        for (KeyValue kv : entry.getValue()) {
98          if (--maxCols <= 0 ) {
99            continue;
100         }
101         Map<String, Object> kvMap = kv.toStringMap();
102         // row and family information are already available in the bigger map
103         kvMap.remove("row");
104         kvMap.remove("family");
105         qualifierDetails.add(kvMap);
106       }
107     }
108     map.put("totalColumns", colCount);
109     // add the id if set
110     if (getId() != null) {
111       map.put("id", getId());
112     }
113     return map;
114   }
115 
116   /**
117    * @deprecated Use {@link #getDurability()} instead.
118    * @return true if edits should be applied to WAL, false if not
119    */
120   public boolean getWriteToWAL() {
121     return this.writeToWAL;
122   }
123 
124   /**
125    * Set whether this Delete should be written to the WAL or not.
126    * Not writing the WAL means you may lose edits on server crash.
127    * This method will reset any changes made via {@link #setDurability(Durability)} 
128    * @param write true if edits should be written to WAL, false if not
129    * @deprecated Use {@link #setDurability(Durability)} instead.
130    */
131   public void setWriteToWAL(boolean write) {
132     setDurability(write ? Durability.USE_DEFAULT : Durability.SKIP_WAL);
133   }
134 
135   /**
136    * Set the durability for this mutation.
137    * Note that RegionServers prior to 0.94.7 will only honor {@link Durability#SKIP_WAL}.
138    * This method will reset any changes made via {@link #setWriteToWAL(boolean)} 
139    * @param d
140    */
141   public void setDurability(Durability d) {
142     setAttribute(DURABILITY_ID_ATTR, Bytes.toBytes(d.ordinal()));
143     this.writeToWAL = d != Durability.SKIP_WAL;
144   }
145 
146   /** Get the current durability */
147   public Durability getDurability() {
148     byte[] attr = getAttribute(DURABILITY_ID_ATTR);
149     if (attr != null) {
150       try {
151         return Durability.valueOf(Bytes.toInt(attr));
152       } catch (IllegalArgumentException iax) {
153         LOG.warn("Invalid or unknown durability settting", iax);
154       }
155     }
156     return writeToWAL ? Durability.USE_DEFAULT : Durability.SKIP_WAL;
157   }
158 
159   /**
160    * Method for retrieving the put's familyMap
161    * @return familyMap
162    */
163   public Map<byte [], List<KeyValue>> getFamilyMap() {
164     return this.familyMap;
165   }
166 
167   /**
168    * Method for setting the put's familyMap
169    */
170   public void setFamilyMap(Map<byte [], List<KeyValue>> map) {
171     this.familyMap = map;
172   }
173 
174   /**
175    * Method to check if the familyMap is empty
176    * @return true if empty, false otherwise
177    */
178   public boolean isEmpty() {
179     return familyMap.isEmpty();
180   }
181 
182   /**
183    * Method for retrieving the delete's row
184    * @return row
185    */
186   @Override
187   public byte [] getRow() {
188     return this.row;
189   }
190 
191   public int compareTo(final Row d) {
192     return Bytes.compareTo(this.getRow(), d.getRow());
193   }
194 
195   /**
196    * Method for retrieving the delete's RowLock
197    * @return RowLock
198    * @deprecated {@link RowLock} and associated operations are deprecated
199    */
200   public RowLock getRowLock() {
201     return new RowLock(this.row, this.lockId);
202   }
203 
204   /**
205    * Method for retrieving the delete's lock ID.
206    *
207    * @return The lock ID.
208    * @deprecated {@link RowLock} and associated operations are deprecated
209    */
210   public long getLockId() {
211   return this.lockId;
212   }
213 
214   /**
215    * Method for retrieving the timestamp
216    * @return timestamp
217    */
218   public long getTimeStamp() {
219     return this.ts;
220   }
221 
222   /**
223    * Set the replication custer id.
224    * @param clusterId
225    */
226   public void setClusterId(UUID clusterId) {
227     if (clusterId == null) return;
228     byte[] val = new byte[2*Bytes.SIZEOF_LONG];
229     Bytes.putLong(val, 0, clusterId.getMostSignificantBits());
230     Bytes.putLong(val, Bytes.SIZEOF_LONG, clusterId.getLeastSignificantBits());
231     setAttribute(CLUSTER_ID_ATTR, val);
232   }
233 
234   /**
235    * @return The replication cluster id.
236    */
237   public UUID getClusterId() {
238     byte[] attr = getAttribute(CLUSTER_ID_ATTR);
239     if (attr == null) {
240       return HConstants.DEFAULT_CLUSTER_ID;
241     }
242     return new UUID(Bytes.toLong(attr,0), Bytes.toLong(attr, Bytes.SIZEOF_LONG));
243   }
244 
245   /**
246    * @return the total number of KeyValues
247    */
248   public int size() {
249     int size = 0;
250     for(List<KeyValue> kvList : this.familyMap.values()) {
251       size += kvList.size();
252     }
253     return size;
254   }
255 
256   /**
257    * @return the number of different families
258    */
259   public int numFamilies() {
260     return familyMap.size();
261   }
262 }