/* * 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. */ package org.apache.jena.tdb.base.record; import static java.lang.String.format ; import java.nio.ByteBuffer; /** Record creator */ final public class RecordFactory { private final int keyLength ; private final int valueLength ; private final int slotLen ; private final boolean checking = false ; public RecordFactory(int keyLength, int valueLength) { if ( keyLength <= 0 ) throw new IllegalArgumentException("Bad key length: "+keyLength) ; if ( valueLength < 0 ) throw new IllegalArgumentException("Bad value length: "+valueLength) ; this.keyLength = keyLength ; this.valueLength = valueLength ; this.slotLen = keyLength + (valueLength>0 ? valueLength : 0 ) ; } /** Return a RecordFactory that makes key-only records of the same key size */ public RecordFactory keyFactory() { return new RecordFactory(keyLength, 0) ; } /** Create a key-only record, allocating blank space for the key */ public Record createKeyOnly() { return create(new byte[keyLength], null) ; } /** Create a key-only record */ public Record createKeyOnly(Record record) { checkKey(record.getKey()) ; if ( record.getValue() == null ) return record ; return create(record.getKey(), null) ; } /** Create a key and value record (value uninitialized) */ public Record create(byte[] key) { checkKey(key) ; byte[] v = null ; if ( valueLength > 0 ) v = new byte[valueLength] ; return create(key, v) ; } /** Create a record, allocaing space for the key and value (if any) */ public Record create() { return create(new byte[keyLength], (valueLength > 0) ? new byte[valueLength] : null) ; } /** Create a key and value record */ public Record create(byte[] key, byte[] value) { check(key, value) ; return new Record(key, value) ; } public void insertInto(Record record, ByteBuffer bb, int idx) { check(record) ; bb.position(idx*slotLen) ; bb.put(record.getKey(), 0, keyLength) ; if ( hasValue() && record.getValue() != null ) bb.put(record.getValue(), 0, valueLength) ; } public Record buildFrom(ByteBuffer bb, int idx) { byte[] key = new byte[keyLength] ; byte[] value = (hasValue() ? new byte[valueLength] :null ) ; // int posnKey = idx*slotLen ; // // Avoid using position() so we can avoid needing synchronized. // copyInto(key, bb, posnKey, keyLength) ; // if ( value != null ) // { // int posnValue = idx*slotLen+keyLength ; // copyInto(value, bb, posnValue, valueLength) ; // } // Using bb.get(byte[],,) may be potentially faster but requires the synchronized // There's no absolute version. synchronized(bb) { bb.position(idx*slotLen) ; bb.get(key, 0, keyLength) ; if ( value != null ) bb.get(value, 0, valueLength) ; } return create(key, value) ; } private final void copyInto(byte[] dst, ByteBuffer src, int start, int length) { // Thread safe. for ( int i = 0 ; i < length ; i++ ) dst[i] = src.get(start+i) ; // Would otherwise be ... // src.position(start) ; // src.get(dst, 0, length) ; } public boolean hasValue() { return valueLength > 0 ; } public int recordLength() { return keyLength + valueLength ; } public int keyLength() { return keyLength ; } public int valueLength() { return valueLength ; } @Override public String toString() { return format("<RecordFactory k=%d v=%d>", keyLength, valueLength) ; } private final void check(Record record) { if ( ! checking ) return ; check(record.getKey(), record.getValue()) ; } private final void checkKey(byte[] k) { if ( ! checking ) return ; if ( k == null ) throw new RecordException("Null key byte[]") ; if ( keyLength != k.length ) throw new RecordException(format("Key length error: This RecordFactory manages records of key length %d, not %d", keyLength, k.length)) ; } private final void check(byte[] k, byte[] v) { if ( ! checking ) return ; checkKey(k) ; if ( valueLength <= 0 ) { if ( v != null ) throw new RecordException("Value array error: This RecordFactory manages records that are all key") ; } else { // v == null for a key-only record from this factory. if ( v != null && v.length != valueLength ) throw new RecordException(format("This RecordFactory manages record of value length %d, not (%d,-)", valueLength, v.length)) ; } } }