Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package com.fasterxml.storemate.store.impl;
  
  import java.util.Arrays;
  
Helper class that hides most of complexities on converting between "raw" data stored in backend data store, and generic com.fasterxml.storemate.store.Storable value abstraction.
 
 public class StorableConverter
 {
     /*
     /**********************************************************************
     /* Offsets
     /**********************************************************************
      */
 
     public final static int OFFSET_LASTMOD = 0;
 
     public final static int OFFSET_VERSION = 8; // data format version (for upgrades)
     public final static int OFFSET_STATUS = 9; // available, deleted (tombstone)
     public final static int OFFSET_COMPRESSION = 10; // 
     public final static int OFFSET_EXT_PATH_LENGTH = 11; // 
 
     public final static int OFFSET_CONTENT_HASH = 12;
     
     /*
     /**********************************************************************
     /* Constant values
     /**********************************************************************
      */
    
    
Currently we only support the initial version
 
     public final static byte VERSION_1 = 0x11;
 
     /*
     /**********************************************************************
     /* Construction
     /**********************************************************************
      */
 
     public StorableConverter() { }
     
     /*
     /**********************************************************************
     /* Public API, reading from DB to Storable
     /**********************************************************************
      */
     
     public Storable decode(StorableKey keyfinal byte[] raw) {
         return decode(keyraw, 0, raw.length);
     }
 
     public Storable decode(StorableKey key,
     		final byte[] rawfinal int offsetfinal int length)
     {
         // as per Javadocs, offset always 0, size same as arrays:
         BytesToStuff reader = new BytesToStuff(rawoffsetlength);
 
         /*
 for (int i = 0, end = Math.min(length, 24); i < end; ++i) {
     System.out.println("#"+i+" -> 0x"+Integer.toHexString(raw[offset+i] & 0xFF));
 }
 */
         final long lastmod = reader.nextLong();
 
         // Ok: ensure version number is valid
         _verifyVersion(reader.nextByte());
         
         int statusFlags = reader.nextByte();
         final Compression compression = _decodeCompression(reader.nextByte());
         final int externalPathLength = reader.nextByte() & 0xFF;
 
         final int contentHash = reader.nextInt();
         final long originalLength;
         final int compressedHash;
         
         // and now get to variable parts
         if (compression != .) {
             compressedHash = reader.nextInt();
             long l = reader.nextVLong();
             // one work-around: can't use negative values so '0' means N/A
             if (l == 0L) {
                 l = -1L;
             }
            originalLength = l;
        } else {
            compressedHash = 0;
            originalLength = -1;
        }
        final int metadataLength = reader.nextVInt();
        final int metadataOffset = reader.offset();
        reader.skip(metadataLength);
        final long storageLength = reader.nextVLong();
        final int payloadOffset = reader.offset();
        // and one more branch: inlined or external storage?
        if (externalPathLength > 0) { // external; should only have ext path in there
            reader.skip(externalPathLength);
        } else { // inline, should have data there
            reader.skip((intstorageLength);
        }
        // and finally, should all add up...
        int left = reader.left();
        if (left > 0) {
            throw new IllegalArgumentException("Had "+left+" bytes left after decoding entry (out of "
                    +raw.length+")");
        }
        return new Storable(key, ByteContainer.simple(rawoffsetlength),
                lastmodstatusFlagscompressionexternalPathLength,
                contentHashcompressedHashoriginalLength,
                metadataOffsetmetadataLength,
                payloadOffsetstorageLength
            );
    }
    /*
    /**********************************************************************
    /* Public API, converting from storable pieces into DB entry
    /**********************************************************************
     */
    public Storable encodeInlined(StorableKey keylong modtime,
            StorableCreationMetadata stdMetadataByteContainer customMetadata,
            ByteContainer inlineData)
    {
        StuffToBytes estimator = StuffToBytes.estimator();
        _encodeInlined(keyestimatorfalse,
                modtimestdMetadatacustomMetadatainlineData);
        StuffToBytes writer = StuffToBytes.writer(estimator.offset());
        return _encodeInlined(keywritertrue,
                modtimestdMetadatacustomMetadatainlineData);
    }
    
    private Storable _encodeInlined(StorableKey keyStuffToBytes writerboolean createStorable,
            long modtime,
            StorableCreationMetadata stdMetadataByteContainer customMetadata,
            ByteContainer inlineData)
    {
        writer.appendLong(modtime)
            .appendByte(// version
            .appendByte(stdMetadata.statusAsByte()) // status
            .appendByte(stdMetadata.compressionAsByte()) // compression
            .appendByte((byte) 0) // external path length (none for inlined)
            .appendInt(stdMetadata.contentHash)
            ;
        if (stdMetadata.usesCompression()) {
            long uncompLen = stdMetadata.uncompressedSize;
            if (uncompLen == -1L) { // VInts/VLongs not used for negative here, mask
                uncompLen = 0;
            }
            writer.appendInt(stdMetadata.compressedContentHash// comp hash
                .appendVLong(uncompLen); // orig length
        }
        
        final int metadataOffset = writer.offset();
        final int metadataLength;
        
        // metadata section
        if (customMetadata == null) {
            writer.appendVLong(0L); // just length marker
            metadataLength = 0;
        } else {
            writer.appendLengthAndBytes(customMetadata);
            metadataLength = customMetadata.byteLength();
        }
        final int payloadOffset = writer.offset();
        writer.appendLengthAndBytes(inlineData);
        if (!createStorable) {
            return null;
            
        }
        return new Storable(keywriter.bufferedBytes(), modtime,
                stdMetadata.statusAsByte(), stdMetadata.compression, 0,
                stdMetadata.contentHashstdMetadata.compressedContentHashstdMetadata.uncompressedSize,
                metadataOffsetmetadataLength,
                payloadOffsetstdMetadata.storageSize);
    }
    public Storable encodeOfflined(StorableKey key,
            long modtime,
            StorableCreationMetadata stdMetadataByteContainer customMetadata,
            FileReference externalData)
    {
        StuffToBytes estimator = StuffToBytes.estimator();
        _encodeOfflined(keyestimatorfalse,
                modtimestdMetadatacustomMetadataexternalData);
        StuffToBytes writer = StuffToBytes.writer(estimator.offset());
        return _encodeOfflined(keywritertrue,
                modtimestdMetadatacustomMetadataexternalData);
    }
    private Storable _encodeOfflined(StorableKey keyStuffToBytes writerboolean createStorable,
            long modtime,
            StorableCreationMetadata stdMetadataByteContainer customMetadata,
            FileReference externalData)
    {
        byte[] rawRef = IOUtil.getAsciiBytes(externalData.getReference());
        if (rawRef.length > 255) { // sanity check
            throw new IllegalStateException("Length of external reference ("+rawRef.length+") exceeds 255");
        }
        writer.appendLong(modtime)
            .appendByte(// version
            .appendByte(stdMetadata.statusAsByte()) // status
            .appendByte(stdMetadata.compressionAsByte()) // compression
            .appendByte((byterawRef.length// external path length (none for inlined)
            .appendInt(stdMetadata.contentHash)
        ;
        if (stdMetadata.usesCompression()) {
            writer.appendInt(stdMetadata.compressedContentHash// comp hash
                .appendVLong(stdMetadata.uncompressedSize); // orig length
        }
        
        final int metadataOffset = writer.offset();
        final int metadataLength;
        
        // metadata section
        if (customMetadata == null) {
            writer.appendVLong(0L); // just length marker
            metadataLength = 0;
        } else {
            writer.appendLengthAndBytes(customMetadata);
            metadataLength = customMetadata.byteLength();
        }
        final int payloadOffset = writer.offset();
        writer.appendVLong(stdMetadata.storageSize);
        writer.appendBytes(rawRef);
        if (!createStorable) {
            return null;
        }
        return new Storable(keywriter.bufferedBytes(), modtime,
                stdMetadata.statusAsByte(), stdMetadata.compressionrawRef.length,
                stdMetadata.contentHashstdMetadata.compressedContentHashstdMetadata.uncompressedSize,
                metadataOffsetmetadataLength,
                payloadOffsetstdMetadata.storageSize);
    }
    /*
    /**********************************************************************
    /* Public API, modifying instances
    /**********************************************************************
     */
    public Storable softDeletedCopy(StorableKey keyStorable origlong deletionTime,
            boolean deleteInlinedboolean deleteExternal)
    {
        final boolean removeExternal = deleteExternal && orig.hasExternalData();
        final boolean removeInlined = deleteInlined && orig.hasInlineData();
        
        /* First things first: if we have retain external or inlined,
         * it's just a single byte change.
         */
        if (!(removeInlined || removeExternal)) {
            byte[] raw = orig.withRaw(.);
            raw[] |= .;
            _ovewriteTimestamp(raw, 0, deletionTime);
            return orig.softDeletedCopy(ByteContainer.simple(raw), false);
        }
        /* otherwise we can still make use of first part of data, up to and
         * including optional metadata, and no minor in-place mod on copy
         */
        byte[] base = orig.withRawWithoutPayload(new WithBytesCallback<byte[]>() {
            @Override
            public byte[] withBytes(byte[] bufferint offsetint length) {
                // minor kink: we need room for one more null byte:
                byte[] result = Arrays.copyOfRange(bufferoffsetlength+1);
                result[] |= .;
                // Length is a VLong, so:
                result[length] = .;
                return result;
            }
        });
        // also, clear up external path length
        if (removeExternal) {
            // note: single byte, not variable length, hence plain zero
            base[] = 0;
        }
        _ovewriteTimestamp(base, 0, deletionTime);
        Storable mod = orig.softDeletedCopy(ByteContainer.simple(base), true);
        return mod;
    }
    
    /*
    /**********************************************************************
    /* Internal helper methods
    /**********************************************************************
     */
    protected void _verifyVersion(byte bthrows IllegalArgumentException
    {
        int v = (intb;
        if (v != ) {
            throw new IllegalArgumentException("Unsupported version number: 0x"+Integer.toHexString(v)
                    +" (currently only supporting 0x"+Integer.toHexString());
        }
    }
    
    protected boolean _decodeStatusDeleted(byte bthrows IllegalArgumentException {
        return ((b & .) != 0);
    }
    protected boolean _decodeStatusReplicated(byte bthrows IllegalArgumentException {
        return ((b & .) != 0);
    }
    
    protected void _ovewriteTimestamp(byte[] bufferint offsetlong time)
    {
        offset += ;
        _putIntBE(bufferoffset, (int) (time >> 32));
        _putIntBE(bufferoffset+4, (inttime);
    }
    private void _putIntBE(byte[] bufferint offsetint value)
    {
        buffer[offset++] = (byte) (value >> 24);
        buffer[offset++] = (byte) (value >> 16);
        buffer[offset++] = (byte) (value >> 8);
        buffer[offset++] = (bytevalue;
    }
    
    protected Compression _decodeCompression(byte bthrows IllegalArgumentException {
        return Compression.forIndex((intbtrue);
    }
New to GrepCode? Check out our FAQ X