All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sleepycat.je.DatabaseEntry Maven / Gradle / Ivy

The newest version!
/*-
 * Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
 *
 * This file was distributed by Oracle as part of a version of Oracle Berkeley
 * DB Java Edition made available at:
 *
 * http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
 *
 * Please see the LICENSE file included in the top-level directory of the
 * appropriate version of Oracle Berkeley DB Java Edition for a copy of the
 * license and additional information.
 */

package com.sleepycat.je;

import java.io.Serializable;

import com.sleepycat.je.tree.Key;
import com.sleepycat.util.keyrange.KeyRange;

/**
 * Encodes database key and data items as a byte array.
 *
 * 

Storage and retrieval for the {@link com.sleepycat.je.Database Database} * and {@link com.sleepycat.je.Cursor Cursor} methods are based on key/data * pairs. Both key and data items are represented by DatabaseEntry objects. * Key and data byte arrays may refer to arrays of zero length up to arrays of * essentially unlimited length.

* *

The DatabaseEntry class provides simple access to an underlying object * whose elements can be examined or changed. DatabaseEntry objects can be * subclassed, providing a way to associate with it additional data or * references to other structures.

* *

Access to DatabaseEntry objects is not re-entrant. In particular, if * multiple threads simultaneously access the same DatabaseEntry object using * {@link com.sleepycat.je.Database Database} or {@link com.sleepycat.je.Cursor * Cursor} methods, the results are undefined.

* *

DatabaseEntry objects may be used in conjunction with the object mapping * support provided in the {@link com.sleepycat.bind} package.

* *

Input and Output Parameters

* *

DatabaseEntry objects are used for both input values (for example, when * writing to a database or specifying a search parameter) and output values * (for example, when reading from a database). For every CRUD method * ({@code get}, {@code put}, etc), each of the method's DatabaseEntry * parameters ({@code key}, {@code data}, etc) may be input or output * parameters, and this is specified by the method's documentation.

* *

Input Parameters

* *

An input parameter is required by the JE method. The parameter may not be * null, and the caller is also responsible for initializing the data of the * DatabaseEntry to a non-null byte array.

* *

Input parameters normally may not be {@link #setPartial(int,int,boolean) * partial}. However, this is allowed under certain circumstances, namely * the {@link Cursor#putCurrent} method allows specifying a partial data * parameter in order to update only part of the record's data value. Input * parameters are NOT allowed to be partial unless this is explicitly stated in * the method documentation.

* *

Although an input parameter is always used for input, in some cases it * may be also used for output. For example, the {@link * Cursor#getSearchKeyRange} method is passed a key parameter that is used as * input, but since a record with a different key (greater or equal to the key * given) may be found, the key parameter is also used to return the key * that was found. Such parameters are documented as "input/output" * parameters.

* *

Another example is when a custom key comparator is used and a key * parameter is passed to a search method. The input parameter may match a * record's key even if the bytes are not equal, and the key of the record * found will be returned via the parameter. The same thing is true of data (or * primary key) parameters when a custom duplicate comparator is used. Because * of this, all input parameters of "get" methods can potentially be used for * output, however, they are not explicitly documented to be input/output * parameters.

* *

Output Parameters

* *

An output parameter is not required by the JE method. It is used to * optionally return a value to the caller. Null may be passed for the * parameter if no returned value is needed. Passing null is a common way to * optimize read operations when only the record's key, and not the record's * data, is required. By passing null for the data parameter, a read from * disk can be avoided when the data is not already cached. In addition, all * output parameters may be {@link #setPartial(int,int,boolean) partial} to * allow only returning a part of the data byte array. See Using Null and Partial DatabaseEntry * Parameters for more information.

* *

For output parameters, the byte array specified by the caller will not be * used and may be null. The JE method will will always allocate a new byte * array. Therefore, after calling a method that returns output parameters, * the application can safely keep a reference to the byte array returned by * {@link #getData} without danger that the array will be overwritten in a * subsequent call.

* *

Historical note: Prior to JE 7.0, null could not be passed for output * parameters. Instead, {@code DatabaseEntry.setPartial(0, 0, true)} was called * for a data parameter to avoid reading the record's data. Now, null can be * passed instead.

* *

Offset and Size Properties

* *

By default the Offset property is zero and the Size property is the * length of the byte array. However, to allow for optimizations involving the * partial use of a byte array, the Offset and Size may be set to non-default * values.

* *

For output parameters, the Size will always be set to the length of the * byte array and the Offset will always be set to zero.

* *

However, for input parameters the Offset and Size are set to non-default * values by the built-in tuple and serial bindings. For example, with a tuple * or serial binding the byte array is grown dynamically as data is output, and * the Size is set to the number of bytes actually used. For a serial binding, * the Offset is set to a non-zero value in order to implement an optimization * having to do with the serialization stream header.

* *

WARNING: In callbacks that are passed DatabaseEntry parameters, the * application should always honor the Size and Offset properties, rather than * assuming they have default values.

*/ public class DatabaseEntry implements Serializable { private static final long serialVersionUID = 1L; /* Currently, JE stores all data records as byte array */ private byte[] data; private int dlen = 0; private int doff = 0; private int offset = 0; private int size = 0; private boolean partial = false; /* FindBugs - ignore not "final" since a user can set this. */ /** @hidden * The maximum number of bytes to show when toString() is called. */ public static int MAX_DUMP_BYTES = 100; /** * Returns all the attributes of the database entry in text form, including * the underlying data. The maximum number of bytes that will be formatted * is taken from the static variable DatabaseEntry.MAX_DUMP_BYTES, which * defaults to 100. MAX_DUMP_BYTES may be changed by an application if it * wishes to cause more bytes to be formatted. */ @Override public String toString() { StringBuilder sb = new StringBuilder(" MAX_DUMP_BYTES) { sb.append(" ... ").append((size - MAX_DUMP_BYTES) + " bytes not shown "); } sb.append("\"/>"); return sb.toString(); } /* * Constructors */ /** * Constructs a DatabaseEntry with null data. The offset and size are set * to zero. */ public DatabaseEntry() { } /** * Constructs a DatabaseEntry with a given byte array. The offset is set * to zero; the size is set to the length of the array, or to zero if null * is passed. * * @param data Byte array wrapped by the DatabaseEntry. */ public DatabaseEntry(byte[] data) { this.data = data; if (data != null) { this.size = data.length; } } /** * Constructs a DatabaseEntry with a given byte array, offset and size. * * @param data Byte array wrapped by the DatabaseEntry. * * @param offset Offset in the first byte in the byte array to be included. * * @param size Number of bytes in the byte array to be included. */ public DatabaseEntry(byte[] data, int offset, int size) { this.data = data; this.offset = offset; this.size = size; } /* * Accessors */ /** * Returns the byte array. * *

For a DatabaseEntry that is used as an output parameter, the byte * array will always be a newly allocated array. The byte array specified * by the caller will not be used and may be null.

* * @return The byte array. */ public byte[] getData() { return data; } /** * Sets the byte array. The offset is set to zero; the size is set to the * length of the array, or to zero if null is passed. * * @param data Byte array wrapped by the DatabaseEntry. */ public void setData(byte[] data) { this.data = data; offset = 0; size = (data == null) ? 0 : data.length; } /** * Sets the byte array, offset and size. * * @param data Byte array wrapped by the DatabaseEntry. * * @param offset Offset in the first byte in the byte array to be included. * * @param size Number of bytes in the byte array to be included. */ public void setData(byte[] data, int offset, int size) { this.data = data; this.offset = offset; this.size = size; } /** * Configures this DatabaseEntry to read or write partial records. * *

By default the specified data (byte array, offset and size) * corresponds to the full stored key or data item. Optionally, the * Partial property can be set to true, and the PartialOffset and * PartialLength properties are used to specify the portion of the key or * data item to be read or written.

* *

Note that the Partial properties are set only by the caller. They * will never be set by a Database or Cursor method, nor will they every be * set by bindings. Therefore, the application can assume that the Partial * properties are not set, unless the application itself sets them * explicitly.

* *

All output parameters may be partial. If the * calling application is doing a retrieval, length bytes specified by * dlen, starting at the offset set by doff bytes from * the beginning of the retrieved data record are returned as if they * comprised the entire record. If any or all of the specified bytes do * not exist in the record, the get is successful, and any existing bytes * are returned.

* *

For example, if the data portion of a retrieved record was 100 bytes, * and a partial retrieval was done using a DatabaseEntry having a partial * length of 20 and a partial offset of 85, the retrieval would succeed and * the retrieved data would be the last 15 bytes of the record.

* *

Input parameters normally may not be {@link * #setPartial(int,int,boolean) partial}. However, this is allowed under * certain circumstances, namely the {@link Cursor#putCurrent} method * allows specifying a partial data parameter in order to update only part * of the record's data value. Input parameters are NOT allowed to be * partial unless this is explicitly stated in the method * documentation.

* *

For storing an item using a partial parameter, length bytes specified * by dlen, starting at the offset set by doff bytes from * the beginning of the specified key's data item are replaced by the data * specified by the DatabaseEntry. If the partial length is smaller than * the data, the record will grow; if the partial length is larger than the * data, the record will shrink. If the partial offset is greater than the * length of the data, the record will be extended using zero bytes as * necessary, and the store will succeed.

* * @param doff The offset of the partial record being read or written by * the application, in bytes. * * @param dlen The byte length of the partial record being read or written * by the application, in bytes. * * @param partial Whether this DatabaseEntry is configured to read or write * partial records. */ public void setPartial(int doff, int dlen, boolean partial) { setPartialOffset(doff); setPartialLength(dlen); setPartial(partial); } /** * Returns the byte length of the partial record being read or written by * the application, in bytes. * *

Note that the Partial properties are set only by the caller. They * will never be set by a Database or Cursor method.

* * @return The byte length of the partial record being read or written by * the application, in bytes. * * @see #setPartial(int,int,boolean) */ public int getPartialLength() { return dlen; } /** * Sets the byte length of the partial record being read or written by the * application, in bytes. * *

Note that the Partial properties are set only by the caller. They * will never be set by a Database or Cursor method.

* * @param dlen The byte length of the partial record being read or written * by the * * @see #setPartial(int,int,boolean) */ public void setPartialLength(int dlen) { this.dlen = dlen; } /** * Returns the offset of the partial record being read or written by the * application, in bytes. * *

Note that the Partial properties are set only by the caller. They * will never be set by a Database or Cursor method.

* * @return The offset of the partial record being read or written by the * application, in bytes. * * @see #setPartial(int,int,boolean) */ public int getPartialOffset() { return doff; } /** * Sets the offset of the partial record being read or written by the * application, in bytes. * *

Note that the Partial properties are set only by the caller. They * will never be set by a Database or Cursor method.

* * @param doff The offset of the partial record being read or written by * the application, in bytes. * * @see #setPartial(int,int,boolean) */ public void setPartialOffset(int doff) { this.doff = doff; } /** * Returns whether this DatabaseEntry is configured to read or write * partial records. * *

Note that the Partial properties are set only by the caller. They * will never be set by a Database or Cursor method.

* * @return Whether this DatabaseEntry is configured to read or write * partial records. * * @see #setPartial(int,int,boolean) */ public boolean getPartial() { return partial; } /** * Configures this DatabaseEntry to read or write partial records. * *

Note that the Partial properties are set only by the caller. They * will never be set by a Database or Cursor method.

* * @param partial Whether this DatabaseEntry is configured to read or write * partial records. * * @see #setPartial(int,int,boolean) */ public void setPartial(boolean partial) { this.partial = partial; } /** * Returns the byte offset into the data array. * *

For a DatabaseEntry that is used as an output parameter, the offset * will always be zero.

* * @return Offset in the first byte in the byte array to be included. */ public int getOffset() { return offset; } /** * Sets the byte offset into the data array. * * ArrayIndexOutOfBoundsException if the data, offset, and size parameters * refer to elements of the data array which do not exist. Note that this * exception will not be thrown by setSize() or setOffset(), but will be * thrown by varous JE methods if "this" is inconsistent and is used as an * input parameter to those methods. It is the caller's responsibility to * ensure that size, offset, and data.length are consistent. * * @param offset Offset in the first byte in the byte array to be included. */ public void setOffset(int offset) { this.offset = offset; } /** * Returns the byte size of the data array. * *

For a DatabaseEntry that is used as an output parameter, the size * will always be the length of the data array.

* * @return Number of bytes in the byte array to be included. */ public int getSize() { return size; } /** * Sets the byte size of the data array. * * ArrayIndexOutOfBoundsException if the data, offset, and size parameters * refer to elements of the data array which do not exist. Note that this * exception will not be thrown by setSize() or setOffset(), but will be * thrown by varous JE methods if "this" is inconsistent and is used as an * input parameter to those methods. It is the caller's responsibility to * ensure that size, offset, and data.length are consistent. * * @param size Number of bytes in the byte array to be included. */ public void setSize(int size) { this.size = size; } /** * Dumps the data as a byte array, for tracing purposes */ String dumpData() { return Key.DUMP_TYPE.dumpByteArray( KeyRange.getByteArray(this, MAX_DUMP_BYTES)); } /** * Compares the data of two entries for byte-by-byte equality. * *

In either entry, if the offset is non-zero or the size is not equal * to the data array length, then only the data bounded by these values is * compared. The data array length and offset need not be the same in both * entries for them to be considered equal.

* *

If the data array is null in one entry, then to be considered equal * both entries must have a null data array.

* *

If the partial property is set in either entry, then to be considered * equal both entries must have the same partial properties: partial, * partialOffset and partialLength. */ @Override public boolean equals(Object o) { if (!(o instanceof DatabaseEntry)) { return false; } DatabaseEntry e = (DatabaseEntry) o; if (partial || e.partial) { if (partial != e.partial || dlen != e.dlen || doff != e.doff) { return false; } } if (data == null && e.data == null) { return true; } if (data == null || e.data == null) { return false; } if (size != e.size) { return false; } for (int i = 0; i < size; i += 1) { if (data[offset + i] != e.data[e.offset + i]) { return false; } } return true; } /** * Returns a hash code based on the data value. */ @Override public int hashCode() { int hash = 0; if (data != null) { for (int i = 0; i < size; i += 1) { hash += data[offset + i]; } } return hash; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy