Package com.foundationdb.server.store.format.tuple

Source Code of com.foundationdb.server.store.format.tuple.TupleStorageDescription

/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.foundationdb.server.store.format.tuple;

import com.foundationdb.ais.model.Group;
import com.foundationdb.ais.model.Index;
import com.foundationdb.ais.model.Join;
import com.foundationdb.ais.model.HasStorage;
import com.foundationdb.ais.model.Sequence;
import com.foundationdb.ais.model.StorageDescription;
import com.foundationdb.ais.model.Table;
import com.foundationdb.ais.model.validation.AISValidationFailure;
import com.foundationdb.ais.model.validation.AISValidationOutput;
import com.foundationdb.ais.protobuf.AISProtobuf.Storage;
import com.foundationdb.ais.protobuf.FDBProtobuf.TupleUsage;
import com.foundationdb.ais.protobuf.FDBProtobuf;
import com.foundationdb.server.error.AkibanInternalException;
import com.foundationdb.server.error.StorageDescriptionInvalidException;
import com.foundationdb.server.rowdata.RowData;
import com.foundationdb.server.rowdata.RowDef;
import com.foundationdb.server.service.session.Session;
import com.foundationdb.server.store.FDBStore;
import com.foundationdb.server.store.FDBStoreData;
import com.foundationdb.server.store.format.FDBStorageDescription;
import com.foundationdb.tuple.ByteArrayUtil;
import com.foundationdb.tuple.Tuple2;
import com.google.protobuf.Descriptors.FileDescriptor;
import com.google.protobuf.DynamicMessage;
import com.google.protobuf.InvalidProtocolBufferException;
import com.persistit.Key;
import com.persistit.KeyShim;

import java.util.Collections;
import java.util.List;

public class TupleStorageDescription extends FDBStorageDescription
{
    private TupleUsage usage;

    public TupleStorageDescription(HasStorage forObject, String storageFormat) {
        super(forObject, storageFormat);
    }

    public TupleStorageDescription(HasStorage forObject, TupleStorageDescription other, String storageFormat) {
        super(forObject, other, storageFormat);
        this.usage = other.usage;
    }

    @Override
    public StorageDescription cloneForObject(HasStorage forObject) {
        return new TupleStorageDescription(forObject, this, storageFormat);
    }
   
    @Override
    public StorageDescription cloneForObjectWithoutState(HasStorage forObject) {
        TupleStorageDescription sd = new TupleStorageDescription(forObject, storageFormat);
        sd.setUsage(this.getUsage());
        return sd;
    }

    public TupleUsage getUsage() {
        return usage;
    }
    public void setUsage(TupleUsage usage) {
        this.usage = usage;
    }

    @Override
    public void writeProtobuf(Storage.Builder builder) {
        super.writeProtobuf(builder);
        if (usage != null) {
            builder.setExtension(FDBProtobuf.tupleUsage, usage);
        }
        writeUnknownFields(builder);
    }

    @Override
    public void validate(AISValidationOutput output) {
        super.validate(output);
        if (usage == null) {
            return;
        }
        if (usage == TupleUsage.KEY_AND_ROW) {
            if (!(object instanceof Group)) {
                output.reportFailure(new AISValidationFailure(new StorageDescriptionInvalidException(object, "is not a Group and has no row")));
                return;
            }
        }
        List<String> illegal;
        if (object instanceof Group) {
            illegal = TupleRowDataConverter.checkTypes((Group)object, usage);
        }
        else if (object instanceof Index) {
            illegal = TupleRowDataConverter.checkTypes((Index)object, usage);
        }
        else if (object instanceof Sequence) {
            // No types to check
            illegal = Collections.emptyList();
        }
        else {
            output.reportFailure(new AISValidationFailure(new StorageDescriptionInvalidException(object, "is not a Group or Index and cannot use Tuples")));
            return;
        }
        if (!illegal.isEmpty()) {
            output.reportFailure(new AISValidationFailure(new StorageDescriptionInvalidException(object, "has some types that cannot be stored in a Tuple: " + illegal)));
        }
    }

    @Override
    public byte[] getKeyBytes(Key key, FDBStoreData.NudgeDir nudged) {
        if (usage != null) {
            return getKeyBytesInternal(key, nudged);
        }
        else {
            return super.getKeyBytes(key);
        }
    }
   
    public static byte[] getKeyBytesInternal(Key key, FDBStoreData.NudgeDir nudged) {
        // If the Key is encoded as a single component Tuple, you
        // need to apply the edge before encoding. But with
        // multiple components, it wants to do it after packing.
        // For a Key {1}, whose bytes are 258100, and as a Tuple
        // 01258100FF00, strinc would be 01258100FF01, whereas
        // {1,{after}} would be 258100FE, so 01258100FFFE00.
        // So, take edge out and do below.

        // Un-nudge the key to allow decoding of original state
        if (nudged != null) {
            if (nudged == FDBStoreData.NudgeDir.DEEPER) {
                key.setEncodedSize(key.getEncodedSize() - 1);
            } else if (nudged == FDBStoreData.NudgeDir.LEFT ) {
                key.setEncodedSize(key.getEncodedSize() + 1);
            } else {
                key.getEncodedBytes()[key.getEncodedSize() - 1] = 0;
               
            }
        }

        // Persistit Key computes the depth incorrectly. It does not count for
        // Key.BEFORE or Key.AFTER, where it does increase the depth when
        // Key#appendAfter() or Key#appendBefore() are called via Key#append(...).
        // reset size to enforce recalculation of the depth
        key.setEncodedSize(key.getEncodedSize());

        Key.EdgeValue edge = null;
        int nkeys = key.getDepth();
        if (KeyShim.isBefore(key)) {
            edge = Key.BEFORE;
        }
        else if (KeyShim.isAfter(key)) {
            edge = Key.AFTER;
        }
       
        Object[] keys = new Object[nkeys];
        key.reset();
        for (int i = 0; i < nkeys; i++) {
            keys[i] = key.decode();
        }
        byte[] bytes = Tuple2.from(keys).pack();
        if (edge == Key.BEFORE ) {
            return ByteArrayUtil.join(bytes, new byte[1]);
        }
        else if (edge == Key.AFTER) {
            return ByteArrayUtil.join(bytes, new byte[] {(byte)0xFF});
        }
        else {
            if (nudged == FDBStoreData.NudgeDir.DEEPER) {
                return ByteArrayUtil.join(bytes, new byte[1]);
            }
            else if (nudged == FDBStoreData.NudgeDir.RIGHT) {
                return ByteArrayUtil.strinc(bytes);
            }
            return bytes;
        }
    }

    @Override
    public void getTupleKey(Tuple2 t, Key key) {
        if (usage != null) {
            key.clear();
            if (object instanceof Group) {
                appendHKeySegments(t, key, ((Group)object));
            }
            else {
                for (Object seg : t) {
                    key.append(seg);
                }
            }
        }
        else {
            super.getTupleKey(t, key);
        }
    }

    /** <code>Tuple</code> does not distinguish integer types. This is
     * mostly not a problem, since they are all encoded as longs in
     * Persistit.  Except for ordinals, which are ints.
     */
    public static void appendHKeySegments(Tuple2 t, Key key, Group group) {
        Table table = null;
        int nextOrdinalIndex = 0;
        for (int i = 0; i < t.size(); i++) {
            Object seg = t.get(i);
            if ((i == nextOrdinalIndex) &&
                (seg instanceof Long)) {
                int ordinal = ((Long)seg).intValue();
                boolean found = false;
                if (i == 0) {
                    table = group.getRoot();
                    found = (table.getOrdinal() == ordinal);
                }
                else {
                    for (Join join : table.getChildJoins()) {
                        table = join.getChild();
                        if (table.getOrdinal() == ordinal) {
                            found = true;
                            break;
                        }
                    }
                }
                if (found) {
                    int[] keyDepth = table.hKey().keyDepth();
                    nextOrdinalIndex = keyDepth[keyDepth.length - 1];
                    seg = ordinal;
                }
            }
            key.append(seg);
        }
    }

    @Override
    public void packRowData(FDBStore store, Session session,
                            FDBStoreData storeData, RowData rowData) {
        if (usage == TupleUsage.KEY_AND_ROW) {
            RowDef rowDef = object.getAIS().getTable(rowData.getRowDefId()).rowDef();
            Tuple2 t = TupleRowDataConverter.tupleFromRowData(rowDef, rowData);
            storeData.rawValue = t.pack();
        }
        else {
            super.packRowData(store, session, storeData, rowData);
        }
    }

    @Override
    public void expandRowData(FDBStore store, Session session,
                              FDBStoreData storeData, RowData rowData) {
        if (usage == TupleUsage.KEY_AND_ROW) {
            Tuple2 t = Tuple2.fromBytes(storeData.rawValue);
            RowDef rowDef = rowDefFromOrdinals((Group) object, storeData);
            TupleRowDataConverter.tupleToRowData(t, rowDef, rowData);
        }
        else {
            super.expandRowData(store, session, storeData, rowData);
        }
    }

    public static RowDef rowDefFromOrdinals(Group group, FDBStoreData storeData) {
        Table root = group.getRoot();
        Key hkey = storeData.persistitKey;
        hkey.reset();
        int ordinal = hkey.decodeInt();
        assert (root.getOrdinal() == ordinal) : hkey;
        Table table = root;
        int index = 0;
        while (true) {
            int[] keyDepth = table.hKey().keyDepth();
            index = keyDepth[keyDepth.length - 1];
            if (index >= hkey.getDepth()) {
                return table.rowDef();
            }
            hkey.indexTo(index);
            ordinal = hkey.decodeInt();
            boolean found = false;
            for (Join join : table.getChildJoins()) {
                table = join.getChild();
                if (table.getOrdinal() == ordinal) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                throw new AkibanInternalException("Not a child ordinal " + hkey);
            }
        }
    }
}
TOP

Related Classes of com.foundationdb.server.store.format.tuple.TupleStorageDescription

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.