inode.java
来自「RESIN 3.2 最新源码」· Java 代码 · 共 1,246 行 · 第 1/3 页
JAVA
1,246 行
/* * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source 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, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */package com.caucho.db.store;import com.caucho.util.L10N;import com.caucho.util.Log;import com.caucho.vfs.OutputStreamWithBuffer;import com.caucho.vfs.TempCharBuffer;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.io.Reader;import java.io.Writer;import java.util.logging.Level;import java.util.logging.Logger;/** * Represents the indexes for a BLOB or CLOB. * * The inode contains 16 long values * <pre> * 0) length of the saved file * 1-14) direct fragment addresses (to 112k) * 15) pointer to the indirect block * </pre> * * <h3>Inline storage (120)</h3> * * If the length of the blob is less than 120, the blob is stored directly * in the inode. * * <h3>mini fragment storage (3840)</h3> * * If the length of the blob is less than 3840, the blob is stored * in mini-fragments of size 256 pointed by the inode's addresses. * * The maximum wasted space for mini-fragment storage is 255 bytes. * * <h3>indirect storage</h3> * * The indirect block (an 8k fragment) itself is divided into sections: * <pre> * 0-511) single indirect fragment addresses (4M, 2^12) * 512-767) double indirect block addresses (128G, 2^37) * 768-1023) triple indirect fragment addresses (to 1P, 2^50) * </pre> */public class Inode { private static final L10N L = new L10N(Inode.class); private static final Logger log = Logger.getLogger(Inode.class.getName()); public static final int INODE_SIZE = 128; public static final int INLINE_BLOB_SIZE = 120; public static final int BLOCK_SIZE = Store.BLOCK_SIZE; public static final int INODE_BLOCK_SIZE = Store.FRAGMENT_SIZE; public static final int FRAGMENT_SIZE = Store.FRAGMENT_SIZE; public static final int MINI_FRAG_SIZE = Store.MINI_FRAG_SIZE; public static final int MINI_FRAG_BLOB_SIZE = (INLINE_BLOB_SIZE / 8) * MINI_FRAG_SIZE; public static final int INDIRECT_BLOCKS = INODE_BLOCK_SIZE / 8; // direct addresses are stored in the inode itself (112k of data). public static final int DIRECT_BLOCKS = 14; // single indirect addresses are stored in the indirect block (4M data) public static final int SINGLE_INDIRECT_BLOCKS = 512; // double indirect addresses (2^37 = 128G data) public static final int DOUBLE_INDIRECT_BLOCKS = 256; // triple indirect addresses (2^50 = 2P data) public static final int TRIPLE_INDIRECT_BLOCKS = 256; public static final long INLINE_MAX = 120; public static final int MINI_FRAG_MAX = (INLINE_BLOB_SIZE / 8) * MINI_FRAG_SIZE; public static final long DIRECT_MAX = FRAGMENT_SIZE * DIRECT_BLOCKS; public static final long SINGLE_INDIRECT_MAX = DIRECT_MAX + SINGLE_INDIRECT_BLOCKS * FRAGMENT_SIZE; public static final long FRAGMENT_MAX = SINGLE_INDIRECT_MAX; public static final long DOUBLE_INDIRECT_MAX = (SINGLE_INDIRECT_MAX + DOUBLE_INDIRECT_BLOCKS * (BLOCK_SIZE / 8) * BLOCK_SIZE); private static final byte []NULL_BYTES = new byte[INODE_SIZE]; private Store _store; private StoreTransaction _xa; private byte []_bytes = new byte[INODE_SIZE]; public Inode() { } public Inode(Store store, StoreTransaction xa) { _store = store; _xa = xa; } public Inode(Store store) { this(store, RawTransaction.create()); } /** * Returns the backing store. */ public Store getStore() { return _store; } /** * Returns the buffer. */ public byte []getBuffer() { return _bytes; } /** * Returns the length. */ public long getLength() { return readLong(_bytes, 0); } public void init(Store store, StoreTransaction xa, byte []buffer, int offset) { _store = store; _xa = xa; System.arraycopy(buffer, offset, _bytes, 0, _bytes.length); } /** * Opens a read stream to the inode. */ public InputStream openInputStream() { return new BlobInputStream(this); } /** * Writes the inode value to a stream. */ public void writeToStream(OutputStreamWithBuffer os) throws IOException { writeToStream(os, 0, Long.MAX_VALUE / 2); } /** * Writes the inode value to a stream. */ public void writeToStream(OutputStreamWithBuffer os, long offset, long length) throws IOException { byte []buffer = os.getBuffer(); int writeLength = buffer.length; int writeOffset = os.getBufferOffset(); while (length > 0) { int sublen = writeLength - writeOffset; if (sublen == 0) { buffer = os.nextBuffer(writeOffset); writeOffset = os.getBufferOffset(); sublen = writeLength - writeOffset; } if (length < sublen) sublen = (int) length; int len = read(_bytes, 0, _store, offset, buffer, writeOffset, sublen); if (len <= 0) break; writeOffset += len; offset += len; length -= len; } os.setBufferOffset(writeOffset); } /** * Writes the inode value to a stream. */ public void writeToWriter(Writer writer) throws IOException { TempCharBuffer tempBuffer = TempCharBuffer.allocate(); char []buffer = tempBuffer.getBuffer(); int writeLength = buffer.length; long offset = 0; while (true) { int sublen = writeLength; int len = read(_bytes, 0, _store, offset, buffer, 0, sublen); if (len <= 0) break; writer.write(buffer, 0, len); offset += 2 * len; } TempCharBuffer.free(tempBuffer); } /** * Reads into a buffer. * * @param inode the inode buffer * @param inodeOffset the offset of the inode data in the buffer * @param store the owning store * @param fileOffset the offset into the file to read * @param buffer the buffer receiving the data * @param bufferOffset the offset into the receiving buffer * @param bufferLength the maximum number of bytes to read * * @return the number of bytes read */ static int read(byte []inode, int inodeOffset, Store store, long fileOffset, byte []buffer, int bufferOffset, int bufferLength) throws IOException { long fileLength = readLong(inode, inodeOffset); int sublen = bufferLength; if (fileLength - fileOffset < sublen) sublen = (int) (fileLength - fileOffset); if (sublen <= 0) return -1; if (fileLength <= INLINE_MAX) { System.arraycopy(inode, inodeOffset + 8 + (int) fileOffset, buffer, bufferOffset, sublen); return sublen; } else if (fileLength <= MINI_FRAG_MAX) { long fragAddr = readMiniFragAddr(inode, inodeOffset, store, fileOffset); int fragOffset = (int) (fileOffset % MINI_FRAG_SIZE); if (MINI_FRAG_SIZE - fragOffset < sublen) sublen = MINI_FRAG_SIZE - fragOffset; store.readMiniFragment(fragAddr, fragOffset, buffer, bufferOffset, sublen); return sublen; } else if (fileLength <= FRAGMENT_MAX) { long fragAddr = readFragmentAddr(inode, inodeOffset, store, fileOffset); int fragOffset = (int) (fileOffset % FRAGMENT_SIZE); if (FRAGMENT_SIZE - fragOffset < sublen) sublen = FRAGMENT_SIZE - fragOffset; store.readFragment(fragAddr, fragOffset, buffer, bufferOffset, sublen); return sublen; } else { long addr = readBlockAddr(inode, inodeOffset, store, fileOffset); int offset = (int) ((fileOffset - FRAGMENT_MAX) % BLOCK_SIZE); if (BLOCK_SIZE - offset < sublen) sublen = BLOCK_SIZE - offset; store.readBlock(addr, offset, buffer, bufferOffset, sublen); return sublen; } } /** * Updates the buffer. Called only from the blob classes. */ static void append(byte []inode, int inodeOffset, Store store, StoreTransaction xa, byte []buffer, int offset, int length) throws IOException { long currentLength = readLong(inode, inodeOffset); long newLength = currentLength + length; writeLong(inode, inodeOffset, newLength); if (newLength <= INLINE_MAX) { System.arraycopy(buffer, offset, inode, (int) (inodeOffset + 8 + currentLength), length); } else if (newLength <= MINI_FRAG_MAX) { while (length > 0) { int sublen = length; if (MINI_FRAG_SIZE < sublen) sublen = MINI_FRAG_SIZE; long miniFragAddr = store.allocateMiniFragment(xa); if (miniFragAddr == 0) { store.setCorrupted(true); throw new IllegalStateException(L.l("{0} illegal mini fragment", store)); } writeMiniFragAddr(inode, inodeOffset, store, xa, currentLength, miniFragAddr); store.writeMiniFragment(xa, miniFragAddr, 0, buffer, offset, sublen); offset += sublen; length -= sublen; currentLength += sublen; } } else { if (currentLength < FRAGMENT_MAX) { int sublen = length; if (FRAGMENT_MAX - currentLength < sublen) sublen = (int) (FRAGMENT_MAX - currentLength); appendFragment(inode, inodeOffset, store, xa, buffer, offset, length, currentLength); offset += sublen; length -= sublen; currentLength += sublen; } if (length > 0) { appendBlock(inode, inodeOffset, store, xa, buffer, offset, length, currentLength); } } } private static void appendFragment(byte []inode, int inodeOffset, Store store, StoreTransaction xa, byte []buffer, int offset, int length, long currentLength) throws IOException { // XXX: theoretically deal with case of appending to inline, although // the blobs are the only writers and will avoid that case. while (length > 0 && currentLength < FRAGMENT_MAX) { if (currentLength % FRAGMENT_SIZE != 0) { long fragAddr = readFragmentAddr(inode, inodeOffset, store, currentLength); if (fragAddr == 0) { store.setCorrupted(true); throw new IllegalStateException(store + " inode: illegal fragment at " + currentLength);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?