hbase increase
increase代码
1.将数据封装为increment对象
2.从increment对象中封装get
3.封装新kv
4.对HRegion下的Storm做upsert或add操作
5.查看是否需要flush并添加队列
6.返回kvs
HRegion代码,如下
/** * Perform one or more increment operations on a row. * @param increment * @return new keyvalues after increment * @throws IOException */ public Result increment(Increment increment, long nonceGroup, long nonce) throws IOException { byte [] row = increment.getRow(); checkRow(row, "increment"); TimeRange tr = increment.getTimeRange(); boolean flush = false; Durability durability = getEffectiveDurability(increment.getDurability()); boolean writeToWAL = durability != Durability.SKIP_WAL; WALEdit walEdits = null; List<Cell> allKVs = new ArrayList<Cell>(increment.size()); Map<Store, List<Cell>> tempMemstore = new HashMap<Store, List<Cell>>(); long size = 0; long txid = 0; checkReadOnly(); checkResources(); // Lock row startRegionOperation(Operation.INCREMENT); this.writeRequestsCount.increment(); WriteEntry w = null; try { RowLock rowLock = getRowLock(row); try { lock(this.updatesLock.readLock()); // wait for all prior MVCC transactions to finish - while we hold the row lock // (so that we are guaranteed to see the latest state) mvcc.completeMemstoreInsert(mvcc.beginMemstoreInsert()); // now start my own transaction w = mvcc.beginMemstoreInsert(); try { long now = EnvironmentEdgeManager.currentTimeMillis(); // Process each family for (Map.Entry<byte [], List<Cell>> family: increment.getFamilyCellMap().entrySet()) { Store store = stores.get(family.getKey()); List<Cell> kvs = new ArrayList<Cell>(family.getValue().size()); // Sort the cells so that they match the order that they // appear in the Get results. Otherwise, we won't be able to // find the existing values if the cells are not specified // in order by the client since cells are in an array list. Collections.sort(family.getValue(), store.getComparator()); // Get previous values for all columns in this family // 从increment封装get请求 Get get = new Get(row); for (Cell cell: family.getValue()) { KeyValue kv = KeyValueUtil.ensureKeyValue(cell); get.addColumn(family.getKey(), kv.getQualifier()); } get.setTimeRange(tr.getMin(), tr.getMax()); List<Cell> results = get(get, false);//获得此increase的row // Iterate the input columns and update existing values if they were // found, otherwise add new column initialized to the increment amount int idx = 0; for (Cell kv: family.getValue()) { long amount = Bytes.toLong(CellUtil.cloneValue(kv));//获得当前value值 boolean noWriteBack = (amount == 0); Cell c = null; if (idx < results.size() && CellUtil.matchingQualifier(results.get(idx), kv)) { c = results.get(idx); if(c.getValueLength() == Bytes.SIZEOF_LONG) { amount += Bytes.toLong(c.getValueArray(), c.getValueOffset(), Bytes.SIZEOF_LONG); } else { // throw DoNotRetryIOException instead of IllegalArgumentException throw new org.apache.hadoop.hbase.DoNotRetryIOException( "Attempted to increment field that isn't 64 bits wide"); } idx++; } // Append new incremented KeyValue to list byte[] q = CellUtil.cloneQualifier(kv); byte[] val = Bytes.toBytes(amount); int oldCellTagsLen = (c == null) ? 0 : c.getTagsLength(); int incCellTagsLen = kv.getTagsLength(); KeyValue newKV = new KeyValue(row.length, family.getKey().length, q.length, now, KeyValue.Type.Put, val.length, oldCellTagsLen + incCellTagsLen); System.arraycopy(row, 0, newKV.getBuffer(), newKV.getRowOffset(), row.length); System.arraycopy(family.getKey(), 0, newKV.getBuffer(), newKV.getFamilyOffset(), family.getKey().length); System.arraycopy(q, 0, newKV.getBuffer(), newKV.getQualifierOffset(), q.length); // copy in the value System.arraycopy(val, 0, newKV.getBuffer(), newKV.getValueOffset(), val.length); // copy tags if (oldCellTagsLen > 0) { System.arraycopy(c.getTagsArray(), c.getTagsOffset(), newKV.getBuffer(), newKV.getTagsOffset(), oldCellTagsLen); } if (incCellTagsLen > 0) { System.arraycopy(kv.getTagsArray(), kv.getTagsOffset(), newKV.getBuffer(), newKV.getTagsOffset() + oldCellTagsLen, incCellTagsLen); } newKV.setMvccVersion(w.getWriteNumber()); // Give coprocessors a chance to update the new cell if (coprocessorHost != null) { newKV = KeyValueUtil.ensureKeyValue(coprocessorHost.postMutationBeforeWAL( RegionObserver.MutationType.INCREMENT, increment, c, (Cell) newKV)); } allKVs.add(newKV); if (!noWriteBack) { kvs.add(newKV); // Prepare WAL updates if (writeToWAL) { if (walEdits == null) { walEdits = new WALEdit(); } walEdits.add(newKV); } } } //store the kvs to the temporary memstore before writing HLog if (!kvs.isEmpty()) { tempMemstore.put(store, kvs); } } // Actually write to WAL now if (walEdits != null && !walEdits.isEmpty()) { if (writeToWAL) { // Using default cluster id, as this can only happen in the orginating // cluster. A slave cluster receives the final value (not the delta) // as a Put. txid = this.log.appendNoSync(this.getRegionInfo(), this.htableDescriptor.getTableName(), walEdits, new ArrayList<UUID>(), EnvironmentEdgeManager.currentTimeMillis(), this.htableDescriptor, this.sequenceId, true, nonceGroup, nonce); } else { recordMutationWithoutWal(increment.getFamilyCellMap()); } } //Actually write to Memstore now if (!tempMemstore.isEmpty()) {//更新hbase kv for (Map.Entry<Store, List<Cell>> entry : tempMemstore.entrySet()) { Store store = entry.getKey(); if (store.getFamily().getMaxVersions() == 1) { // upsert if VERSIONS for this CF == 1 size += store.upsert(entry.getValue(), getSmallestReadPoint()); } else { // otherwise keep older versions around for (Cell cell : entry.getValue()) { KeyValue kv = KeyValueUtil.ensureKeyValue(cell); size += store.add(kv); } } } size = this.addAndGetGlobalMemstoreSize(size); flush = isFlushSize(size); } } finally { this.updatesLock.readLock().unlock(); } } finally { rowLock.release(); } if (writeToWAL && (walEdits != null) && !walEdits.isEmpty()) { // sync the transaction log outside the rowlock syncOrDefer(txid, durability); } } finally { if (w != null) { mvcc.completeMemstoreInsert(w); } closeRegionOperation(Operation.INCREMENT); if (this.metricsRegion != null) { this.metricsRegion.updateIncrement(); } } if (flush) { // Request a cache flush. Do it outside update lock. requestFlush(); } return Result.create(allKVs); }
在一些情况下,如increment压力过大时,会出现下列错误,startNonceOperation方法:
regionserver.ServerNonceManager: Conflict detected by nonce
一个mutation里边有多个相同的nonce的操作,如increment,这样会产生此日志,影响相应速度