io.sirix.page.NamePage Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sirix-core Show documentation
Show all versions of sirix-core Show documentation
SirixDB is a hybrid on-disk and in-memory document oriented, versioned database system. It has a lightweight buffer manager, stores everything in a huge persistent and durable tree and allows efficient reconstruction of every revision. Furthermore, SirixDB implements change tracking, diffing and supports time travel queries.
/*
* Copyright (c) 2023, Sirix Contributors
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package io.sirix.page;
import com.google.common.base.MoreObjects;
import io.sirix.access.DatabaseType;
import io.sirix.node.NodeKind;
import io.sirix.page.delegates.BitmapReferencesPage;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2LongMap;
import it.unimi.dsi.fastutil.ints.Int2LongOpenHashMap;
import org.checkerframework.checker.nullness.qual.NonNull;
import io.sirix.api.PageReadOnlyTrx;
import io.sirix.api.PageTrx;
import io.sirix.cache.Cache;
import io.sirix.cache.NamesCacheKey;
import io.sirix.cache.TransactionIntentLog;
import io.sirix.index.IndexType;
import io.sirix.index.name.Names;
import io.sirix.page.delegates.ReferencesPage4;
import io.sirix.page.interfaces.Page;
import io.sirix.settings.Constants;
/**
* The name page holds all names and their keys for a revision. Furthermore, it has references to name indexes.
*/
public final class NamePage extends AbstractForwardingPage {
/**
* Offset of reference to attributes index-tree.
*/
public static final int ATTRIBUTES_REFERENCE_OFFSET = 0;
/**
* Offset of reference to elements index-tree.
*/
public static final int ELEMENTS_REFERENCE_OFFSET = 1;
/**
* Offset of reference to namespace index-tree.
*/
public static final int NAMESPACE_REFERENCE_OFFSET = 2;
/**
* Offset of reference to processing instruction index-tree.
*/
public static final int PROCESSING_INSTRUCTION_REFERENCE_OFFSET = 3;
/**
* Offset of reference to processing instruction index-tree.
*/
public static final int JSON_OBJECT_KEY_REFERENCE_OFFSET = 0;
/**
* Attribute names.
*/
private Names attributes;
/**
* Element names.
*/
private Names elements;
/**
* Namespace URIs.
*/
private Names namespaces;
/**
* Processing instruction names.
*/
private Names processingInstructions;
/**
* JSON Object key names.
*/
private Names jsonObjectKeys;
/**
* The references page delegate instance.
*/
private Page delegate;
/**
* The number of arrays stored.
*/
private final int numberOfArrays;
/**
* Maximum node keys.
*/
private final Int2LongMap maxNodeKeys;
/**
* Current maximum levels of indirect pages in the tree.
*/
private final Int2IntMap currentMaxLevelsOfIndirectPages;
/**
* Create name page.
*/
public NamePage() {
delegate = new ReferencesPage4();
maxNodeKeys = new Int2LongOpenHashMap();
attributes = Names.getInstance(ATTRIBUTES_REFERENCE_OFFSET);
elements = Names.getInstance(ELEMENTS_REFERENCE_OFFSET);
namespaces = Names.getInstance(NAMESPACE_REFERENCE_OFFSET);
processingInstructions = Names.getInstance(PROCESSING_INSTRUCTION_REFERENCE_OFFSET);
jsonObjectKeys = Names.getInstance(JSON_OBJECT_KEY_REFERENCE_OFFSET);
currentMaxLevelsOfIndirectPages = new Int2IntOpenHashMap();
numberOfArrays = 0;
}
/**
* Constructor when is deserialized data
*
* @param delegate The references page delegate instance.
* @param maxNodeKeys Maximum node keys.
* @param currentMaxLevelsOfIndirectPages Current maximum levels of indirect pages in the tree.
* @param numberOfArrays The number of arrays stored.
*/
NamePage(final Page delegate, final Int2LongMap maxNodeKeys,
final Int2IntMap currentMaxLevelsOfIndirectPages, final int numberOfArrays){
this.delegate = delegate;
this.maxNodeKeys = maxNodeKeys;
this.currentMaxLevelsOfIndirectPages = currentMaxLevelsOfIndirectPages;
this.numberOfArrays = numberOfArrays;
}
/**
* Get raw name belonging to name key.
*
* @param key name key identifying name
* @return raw name of name key
*/
public byte[] getRawName(final int key, final NodeKind nodeKind, final PageReadOnlyTrx pageRtx) {
final byte[] rawName;
// $CASES-OMITTED$
switch (nodeKind) {
case ELEMENT -> {
if (elements == null) {
elements = getNames(pageRtx, ELEMENTS_REFERENCE_OFFSET);
}
rawName = elements.getRawName(key);
}
case NAMESPACE -> {
if (namespaces == null) {
namespaces = getNames(pageRtx, NAMESPACE_REFERENCE_OFFSET);
}
rawName = namespaces.getRawName(key);
}
case ATTRIBUTE -> {
if (attributes == null) {
attributes = getNames(pageRtx, ATTRIBUTES_REFERENCE_OFFSET);
}
rawName = attributes.getRawName(key);
}
case PROCESSING_INSTRUCTION -> {
if (processingInstructions == null) {
processingInstructions = getNames(pageRtx, PROCESSING_INSTRUCTION_REFERENCE_OFFSET);
}
rawName = processingInstructions.getRawName(key);
}
case OBJECT_KEY -> {
if (jsonObjectKeys == null) {
jsonObjectKeys = getNames(pageRtx, JSON_OBJECT_KEY_REFERENCE_OFFSET);
}
rawName = jsonObjectKeys.getRawName(key);
}
default -> throw new IllegalStateException("No other node types supported!");
}
return rawName;
}
private Names getNames(PageReadOnlyTrx pageRtx, int offset) {
final var maxNodeKey = maxNodeKeys.getOrDefault(offset, 0L);
if (pageRtx.hasTrxIntentLog()) {
return Names.fromStorage(pageRtx, offset, maxNodeKey);
}
final Cache namesCache = pageRtx.getBufferManager().getNamesCache();
final NamesCacheKey namesCacheKey = new NamesCacheKey(pageRtx.getRevisionNumber(), offset);
Names names = namesCache.get(namesCacheKey);
if (names == null) {
names = Names.fromStorage(pageRtx, offset, maxNodeKey);
namesCache.put(namesCacheKey, names);
} else {
names = Names.copy(names);
}
return names;
}
/**
* Get raw name belonging to name key.
*
* @param key name key identifying name
* @return raw name of name key, or {@code null} if not present
*/
public String getName(final int key, @NonNull final NodeKind nodeKind, final PageReadOnlyTrx pageRtx) {
return switch (nodeKind) {
case ELEMENT -> {
if (elements == null) {
elements = getNames(pageRtx, ELEMENTS_REFERENCE_OFFSET);
}
yield elements.getName(key);
}
case NAMESPACE -> {
if (namespaces == null) {
namespaces = getNames(pageRtx, NAMESPACE_REFERENCE_OFFSET);
}
yield namespaces.getName(key);
}
case ATTRIBUTE -> {
if (attributes == null) {
attributes = getNames(pageRtx, ATTRIBUTES_REFERENCE_OFFSET);
}
yield attributes.getName(key);
}
case PROCESSING_INSTRUCTION -> {
if (processingInstructions == null) {
processingInstructions = getNames(pageRtx, PROCESSING_INSTRUCTION_REFERENCE_OFFSET);
}
yield processingInstructions.getName(key);
}
case OBJECT_KEY -> {
if (jsonObjectKeys == null) {
jsonObjectKeys = getNames(pageRtx, JSON_OBJECT_KEY_REFERENCE_OFFSET);
}
yield jsonObjectKeys.getName(key);
}
case ARRAY -> "__array__";
case OBJECT -> "__object__";
default -> throw new IllegalStateException("No other node types supported!");
};
}
/**
* Get number of nodes with the given name key.
*
* @param key name key identifying name
* @return number of nodes with the given name key
*/
public int getCount(final int key, @NonNull final NodeKind nodeKind, final PageReadOnlyTrx pageRtx) {
return switch (nodeKind) {
case ELEMENT -> {
if (elements == null) {
elements = getNames(pageRtx, ELEMENTS_REFERENCE_OFFSET);
}
yield elements.getCount(key);
}
case NAMESPACE -> {
if (namespaces == null) {
namespaces = getNames(pageRtx, NAMESPACE_REFERENCE_OFFSET);
}
yield namespaces.getCount(key);
}
case ATTRIBUTE -> {
if (attributes == null) {
attributes = getNames(pageRtx, ATTRIBUTES_REFERENCE_OFFSET);
}
yield attributes.getCount(key);
}
case PROCESSING_INSTRUCTION -> {
if (processingInstructions == null) {
processingInstructions = getNames(pageRtx, PROCESSING_INSTRUCTION_REFERENCE_OFFSET);
}
yield processingInstructions.getCount(key);
}
case OBJECT_KEY -> {
if (jsonObjectKeys == null) {
jsonObjectKeys = getNames(pageRtx, JSON_OBJECT_KEY_REFERENCE_OFFSET);
}
yield jsonObjectKeys.getCount(key);
}
case ARRAY -> numberOfArrays;
default -> throw new IllegalStateException("No other node types supported!");
};
}
/**
* Create name key given a name.
*
* @param name name to create key for
* @param nodeKind kind of node
* @return the created key
*/
public int setName(final String name, final NodeKind nodeKind, final PageTrx pageRtx) {
// $CASES-OMITTED$
switch (nodeKind) {
case ELEMENT -> {
if (elements == null) {
elements = getNames(pageRtx, ELEMENTS_REFERENCE_OFFSET);
}
return elements.setName(name, pageRtx);
}
case NAMESPACE -> {
if (namespaces == null) {
namespaces = getNames(pageRtx, NAMESPACE_REFERENCE_OFFSET);
}
return namespaces.setName(name, pageRtx);
}
case ATTRIBUTE -> {
if (attributes == null) {
attributes = getNames(pageRtx, ATTRIBUTES_REFERENCE_OFFSET);
}
return attributes.setName(name, pageRtx);
}
case PROCESSING_INSTRUCTION -> {
if (processingInstructions == null) {
processingInstructions = getNames(pageRtx, PROCESSING_INSTRUCTION_REFERENCE_OFFSET);
}
return processingInstructions.setName(name, pageRtx);
}
case OBJECT_KEY -> {
if (jsonObjectKeys == null) {
jsonObjectKeys = getNames(pageRtx, JSON_OBJECT_KEY_REFERENCE_OFFSET);
}
return jsonObjectKeys.setName(name, pageRtx);
}
default -> throw new IllegalStateException("No other node types supported!");
}
}
/**
* Get the size of CurrentMaxLevelOfIndirectPage to Serialize
* @return int Size of CurrentMaxLevelOfIndirectPage
*/
public int getCurrentMaxLevelOfIndirectPagesSize(){
return currentMaxLevelsOfIndirectPages.size();
}
public int getCurrentMaxLevelOfIndirectPages(int index) {
return currentMaxLevelsOfIndirectPages.get(index);
}
public int incrementAndGetCurrentMaxLevelOfIndirectPages(int index) {
return currentMaxLevelsOfIndirectPages.merge(index, 1, Integer::sum);
}
@Override
public @NonNull String toString() {
return MoreObjects.toStringHelper(this)
.add("elements", elements)
.add("attributes", attributes)
.add("URIs", namespaces)
.add("PIs", processingInstructions)
.toString();
}
/**
* Remove an attribute-name.
*
* @param key the key to remove
*/
public void removeName(final int key, final NodeKind nodeKind, final PageTrx pageRtx) {
// $CASES-OMITTED$
switch (nodeKind) {
case ELEMENT -> {
if (elements == null) {
elements = getNames(pageRtx, ELEMENTS_REFERENCE_OFFSET);
}
elements.removeName(key, pageRtx);
}
case NAMESPACE -> {
if (namespaces == null) {
namespaces = getNames(pageRtx, NAMESPACE_REFERENCE_OFFSET);
}
namespaces.removeName(key, pageRtx);
}
case ATTRIBUTE -> {
if (attributes == null) {
attributes = getNames(pageRtx, ATTRIBUTES_REFERENCE_OFFSET);
}
attributes.removeName(key, pageRtx);
}
case PROCESSING_INSTRUCTION -> {
if (processingInstructions == null) {
processingInstructions = getNames(pageRtx, PROCESSING_INSTRUCTION_REFERENCE_OFFSET);
}
processingInstructions.removeName(key, pageRtx);
}
case OBJECT_KEY -> {
if (jsonObjectKeys == null) {
jsonObjectKeys = getNames(pageRtx, JSON_OBJECT_KEY_REFERENCE_OFFSET);
}
jsonObjectKeys.removeName(key, pageRtx);
}
default -> throw new IllegalStateException("No other node types supported!");
}
}
/**
* Initialize name index tree.
*
* @param databaseType The type of database.
* @param pageReadTrx {@link PageReadOnlyTrx} instance
* @param index the index number
* @param log the transaction intent log
*/
public void createNameIndexTree(final DatabaseType databaseType, final PageReadOnlyTrx pageReadTrx, final int index,
final TransactionIntentLog log) {
PageReference reference = getOrCreateReference(index);
if (reference == null) {
delegate = new BitmapReferencesPage(Constants.INP_REFERENCE_COUNT, (ReferencesPage4) delegate());
reference = delegate.getOrCreateReference(index);
}
if (reference.getPage() == null && reference.getKey() == Constants.NULL_ID_LONG
&& reference.getLogKey() == Constants.NULL_ID_INT) {
PageUtils.createTree(databaseType, reference, IndexType.NAME, pageReadTrx, log);
if (maxNodeKeys.get(index) == 0L) {
maxNodeKeys.put(index, 0L);
} else {
maxNodeKeys.put(index, maxNodeKeys.get(index) + 1);
}
currentMaxLevelsOfIndirectPages.merge(index, 1, Integer::sum);
}
}
/**
* Get indirect page reference.
*
* @param offset the offset of the indirect page, that is the index number
* @return indirect page reference
*/
public PageReference getIndirectPageReference(final int offset) {
return getOrCreateReference(offset);
}
public int getNumberOfArrays() {
return numberOfArrays;
}
/**
* Get the maximum node key of the specified index by its index number.
*
* @param indexNumber the index number
* @return the maximum node key stored
*/
public long getMaxNodeKey(final int indexNumber) {
return maxNodeKeys.get(indexNumber);
}
/**
* Get the size of MaxNodeKey to Serialize
* @return int Size of MaxNodeKey
*/
public int getMaxNodeKeySize(){
return maxNodeKeys.size();
}
public long incrementAndGetMaxNodeKey(final int indexNumber) {
final long newMaxNodeKey = maxNodeKeys.getOrDefault(indexNumber, 0L) + 1;
maxNodeKeys.put(indexNumber, newMaxNodeKey);
return newMaxNodeKey;
}
@Override
protected Page delegate() {
return delegate;
}
@Override
public boolean setOrCreateReference(int offset, PageReference pageReference) {
delegate = PageUtils.setReference(delegate, offset, pageReference);
return false;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy