fuse.okuyamafs.OkuyamaFilesystem.java Source code

Java tutorial

Introduction

Here is the source code for fuse.okuyamafs.OkuyamaFilesystem.java

Source

package fuse.okuyamafs;

import java.io.*;
import java.nio.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import fuse.*;

import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;

/**
 * OkuyamaFuse.<br>
 * FUSE-J?<br>
 *
 * @author T.Okuyama
 * @license GPL(Lv3)
 */
public class OkuyamaFilesystem implements Filesystem3, XattrSupport {

    private static final Log log = LogFactory.getLog(OkuyamaFilesystem.class);

    public volatile static int blockSizeAssist = 50;

    public volatile static int blockSize = 1024 * 16 + 5;//5200; // Block
    //public volatile static int blockSize = 5632; // Block

    public volatile static int writeBufferSize = 1024 * 1024 * 5 + 1024;

    public static final int maxSingleModeCacheSize = 200000;

    public static int storageType = -1;

    private FuseStatfs statfs;

    private String masterNodeStr = null;

    OkuyamaClientWrapper client = null;

    private Map openStatusMap = new Hashtable();

    private Map appendWriteDataBuf = new HashMap(10);
    private GroupingKeyMap writeBufFpMap = new GroupingKeyMap();

    private Object[] parallelDataAccessSync = new Object[100];

    public volatile static boolean jvmShutdownStatus = false;
    public static List allChildThreadList = null;

    public long startTimeAAA = 0L;

    public OkuyamaFilesystem(String okuyamaMasterNode, boolean singleMode) throws IOException {
        log.info("okuyama file system init start...");

        int files = 0;
        int dirs = 0;
        int blocks = 0;

        this.masterNodeStr = masterNodeStr;

        statfs = new FuseStatfs();
        statfs.blocks = Integer.MAX_VALUE;
        statfs.blockSize = blockSize;
        statfs.blocksFree = Integer.MAX_VALUE;
        statfs.files = files + dirs;
        statfs.filesFree = Integer.MAX_VALUE;
        statfs.namelen = 2048;
        try {
            for (int idx = 0; idx < 100; idx++) {
                this.parallelDataAccessSync[idx] = new Object();
            }
            client = new OkuyamaClientWrapper(singleMode);
        } catch (Exception e) {
            throw new IOException(e);
        }
        log.info("okuyama file system init end...");
    }

    public int chmod(String path, int mode) throws FuseException {
        log.info("chmod " + path + " " + mode);
        String[] pathInfo = null;
        StringBuilder newPathInfo = new StringBuilder();
        try {

            String pathInfoStr = client.getPathDetail(path.trim());
            if (pathInfoStr == null || pathInfoStr.trim().equals(""))
                return Errno.ENOENT;

            pathInfo = pathInfoStr.split("\t");

            pathInfo[7] = new Integer((new Integer(pathInfo[7]).intValue() & FuseStatConstants.TYPE_MASK)
                    | (mode & FuseStatConstants.MODE_MASK)).toString();

            String sep = "";
            for (int i = 0; i < pathInfo.length; i++) {
                newPathInfo.append(sep);
                newPathInfo.append(pathInfo[i]);
                sep = "\t";
            }
            client.setPathDetail(path.trim(), newPathInfo.toString());
        } catch (FuseException fe) {
            throw fe;
        } catch (Exception e) {
            new FuseException(e).initErrno(FuseException.EACCES);
        }
        return 0;
    }

    public int chown(String path, int uid, int gid) throws FuseException {
        log.info("chown " + path + " " + uid + " " + gid);
        try {

            String pathInfoStr = client.getPathDetail(path.trim());
            if (pathInfoStr == null)
                return Errno.ENOENT;

            String[] pathInfo = pathInfoStr.split("\t");

            pathInfo[2] = new Integer(uid).toString(); // 
            pathInfo[3] = new Integer(gid).toString(); // 

            StringBuilder strBuf = new StringBuilder(100);

            String sep = "";
            for (int i = 0; i < pathInfo.length; i++) {

                strBuf.append(sep);
                strBuf.append(pathInfo[i]);
                sep = "\t";
            }

            client.setPathDetail(path.trim(), strBuf.toString());
        } catch (FuseException fe) {
            throw fe;
        } catch (Exception e) {
            new FuseException(e).initErrno(FuseException.EACCES);
        }
        return 0;
        //throw new FuseException("Read Only").initErrno(FuseException.EACCES);
    }

    public int getattr(String path, FuseGetattrSetter getattrSetter) throws FuseException {
        log.info("getattr " + path);
        String[] pathInfo = null;

        try {
            String[] setInfo = new String[11];

            synchronized (this.parallelDataAccessSync[((path.hashCode() << 1) >>> 1) % 100]) {

                // ???????????flush?
                List bufferedDataFhList = writeBufFpMap.removeGroupingData(path);
                if (bufferedDataFhList != null) {
                    for (int idx = 0; idx < bufferedDataFhList.size(); idx++) {
                        Object bFh = bufferedDataFhList.get(idx);
                        this.fixNoCommitData(bFh);
                    }
                }
            }

            if (path.trim().equals("/")) {

                setInfo[1] = new Integer(FuseFtypeConstants.TYPE_DIR | 0777).toString();
                pathInfo = new String[9];
                pathInfo[1] = "0";
                pathInfo[2] = "0";
                pathInfo[3] = "0";
                pathInfo[4] = "0";
                pathInfo[5] = "0";
                pathInfo[6] = "0";
                pathInfo[8] = "0";
            } else {
                String pathInfoStr = client.getPathDetail(path.trim());

                if (pathInfoStr == null || pathInfoStr.trim().equals("")) {

                    return Errno.ENOENT;
                }

                pathInfo = pathInfoStr.split("\t");
                if (pathInfo[0].equals("file")) {
                    setInfo[1] = new Integer(FuseFtypeConstants.TYPE_FILE | new Integer(pathInfo[7]).intValue())
                            .toString();
                } else if (pathInfo[0].equals("dir")) {
                    setInfo[1] = new Integer(FuseFtypeConstants.TYPE_DIR | new Integer(pathInfo[7]).intValue())
                            .toString();
                } else {

                    // ?
                    client.removePathDetail(path.trim());
                    return Errno.ENOENT;
                    //throw new FuseException("No such entry entry name =[" + pathInfoStr + "]").initErrno(FuseException.ENOENT);
                }
            }
            /*
                stat.nlink = 1;
                stat.uid = 0;
                stat.gid = 0;
                stat.size = 1000;
                stat.atime = 0;
                stat.blocks = 2;
            */
            setInfo[0] = new Integer(path.hashCode()).toString(); // inode

            setInfo[2] = pathInfo[1];
            //stat.nlink = Integer.parseInt(pathInfo[1]);

            setInfo[3] = pathInfo[2];
            ///stat.uid = Integer.parseInt(pathInfo[2]);

            setInfo[4] = pathInfo[3];
            //stat.gid = Integer.parseInt(pathInfo[3]);

            setInfo[5] = pathInfo[8]; // rdev

            setInfo[6] = pathInfo[4];
            //stat.size = Integer.parseInt(pathInfo[4]);

            long blockCnt = Long.parseLong(setInfo[6]) / 512;
            if (Long.parseLong(setInfo[6]) % 512 > 0)
                blockCnt++;
            //setInfo[7] = Long.parseLong(setInfo[6]) % 512;

            //stat.blocks = Integer.parseInt(pathInfo[6]);

            setInfo[8] = pathInfo[5];
            //stat.atime = Integer.parseInt(pathInfo[5]);

            setInfo[9] = pathInfo[5]; // mtime

            setInfo[10] = pathInfo[5]; // ctime

            getattrSetter.set(new Long(setInfo[0]).longValue(), new Integer(setInfo[1]).intValue(),
                    new Integer(setInfo[2]).intValue(), new Integer(setInfo[3]).intValue(),
                    new Integer(setInfo[4]).intValue(), new Integer(setInfo[5]).intValue(),
                    new Long(setInfo[6]).longValue(), blockCnt, new Integer(setInfo[8]).intValue(),
                    new Integer(setInfo[9]).intValue(), new Integer(setInfo[10]).intValue());

        } catch (FuseException fe) {
            fe.printStackTrace();
            throw fe;
        } catch (Exception e) {
            e.printStackTrace();
            new FuseException(e).initErrno(FuseException.EACCES);
        }
        return 0;
    }

    public int getdir(String path, FuseDirFiller dirFiller) throws FuseException {
        log.info("getdir " + path);

        try {
            Map dirChildMap = client.getDirChild(path.trim());

            if (dirChildMap == null)
                return Errno.ENOTDIR;

            int i = 0;
            Set entrySet = dirChildMap.entrySet();
            Iterator entryIte = entrySet.iterator();
            while (entryIte.hasNext()) {

                Map.Entry obj = (Map.Entry) entryIte.next();

                String name = (String) obj.getKey();

                Map metaInfo = client.getDataMetaInfo(name);
                boolean deleteFlg = true;
                if (metaInfo.size() > 1) {

                    if (metaInfo.get("pathdetail") != null && metaInfo.get("attribute") != null) {

                        deleteFlg = false;
                        String[] nameCnv = name.split("/");

                        try {
                            String pathInfoStrCheck = (String) metaInfo.get("pathdetail");

                            if (((String) obj.getValue()).equals("dir")) {
                                dirFiller.add(nameCnv[nameCnv.length - 1], 0L, FuseFtype.TYPE_DIR);
                            } else {
                                dirFiller.add(nameCnv[nameCnv.length - 1], 0L, FuseFtype.TYPE_FILE);
                            }

                            i++;
                        } catch (Exception ee) {
                            deleteFlg = true;
                        }
                    }
                }

                if (deleteFlg) {
                    // ???
                    // ??
                    synchronized (this.parallelDataAccessSync[((name.hashCode() << 1) >>> 1) % 100]) {
                        try {
                            client.removePathDetail(name);
                            client.removeAttribute(name);

                            String pathInfoStr = (String) metaInfo.get("pathdetail");
                            if (pathInfoStr != null) {

                                String[] pathInfo = pathInfoStr.split("\t");
                                client.deleteValue(name, pathInfo[pathInfo.length - 2]);
                            }
                            client.removeDir(name);

                        } catch (Exception innerE) {
                        }
                        log.fatal("broken file remove filename=[" + name + "]");
                    }
                }
            }
        } catch (FuseException fe) {
            throw fe;
        } catch (Exception e) {
            throw new FuseException(e);
        }
        return 0;
    }

    public int link(String from, String to) throws FuseException {
        log.info("link " + from + " " + to);
        return Errno.EACCES;
    }

    public int mkdir(String path, int mode) throws FuseException {
        log.info("mkdir " + path + " " + mode);
        try {
            if (client.addDir(path.trim()) == false)
                return Errno.EEXIST;
            if (client.setDirAttribute(path.trim(), "dir") == false)
                return Errno.EEXIST;

            // setPathDetail
            String pathType = "dir";

            String pathInfoStr = "";
            pathInfoStr = pathInfoStr + pathType;
            pathInfoStr = pathInfoStr + "\t" + "1";
            pathInfoStr = pathInfoStr + "\t" + "0";
            pathInfoStr = pathInfoStr + "\t" + "0";
            pathInfoStr = pathInfoStr + "\t" + "0";
            pathInfoStr = pathInfoStr + "\t" + (System.currentTimeMillis() / 1000L);
            pathInfoStr = pathInfoStr + "\t" + "0";
            pathInfoStr = pathInfoStr + "\t" + mode;
            pathInfoStr = pathInfoStr + "\t" + "0"; //rdev
            pathInfoStr = pathInfoStr + "\t" + System.nanoTime(); // realKeyNodeNo

            if (!client.addPathDetail(path.trim(), pathInfoStr)) {
                return Errno.EEXIST;
            }
        } catch (FuseException fe) {
            throw fe;
        } catch (Exception e) {
            throw new FuseException(e);
        }
        return 0;
    }

    public int mknod(String path, int mode, int rdev) throws FuseException {
        log.info("mknod " + path + " " + mode + " " + rdev);
        // mode?8??3???????http://sourceforge.net/apps/mediawiki/fuse/index.php?title=Stat
        // 3??=>755??644??
        String modeStr = Integer.toOctalString(mode);
        String pathType = "";
        String fileBlockIdx = null;
        if (modeStr.indexOf("100") == 0) {

            // Regular File
            pathType = "file";
            fileBlockIdx = "-1";
        } else if (modeStr.indexOf("40") == 0) {

            // Directory
            pathType = "dir";
        } else {
            return Errno.EINVAL;
        }

        String pathInfoStr = "";
        pathInfoStr = pathInfoStr + pathType;
        pathInfoStr = pathInfoStr + "\t" + "1";
        pathInfoStr = pathInfoStr + "\t" + "0";
        pathInfoStr = pathInfoStr + "\t" + "0";
        pathInfoStr = pathInfoStr + "\t" + "0";
        pathInfoStr = pathInfoStr + "\t" + (System.currentTimeMillis() / 1000L);
        pathInfoStr = pathInfoStr + "\t" + "0";
        pathInfoStr = pathInfoStr + "\t" + mode;
        pathInfoStr = pathInfoStr + "\t" + rdev;
        pathInfoStr = pathInfoStr + "\t" + System.nanoTime(); // realKeyNodeNo
        if (fileBlockIdx != null) {
            pathInfoStr = pathInfoStr + "\t" + fileBlockIdx;
        }

        try {
            if (!client.addPathDetail(path.trim(), pathInfoStr)) {
                return Errno.EEXIST;
            }
            if (!client.setDirAttribute(path.trim(), pathType)) {
                return Errno.EEXIST;
            }
        } catch (FuseException fe) {
            throw fe;
        } catch (Exception e) {
            new FuseException(e);
        }
        return 0;
    }

    public int open(String path, int flags, FuseOpenSetter openSetter) throws FuseException {

        log.info("open " + path + " " + flags);
        long fileDp = System.nanoTime();
        try {
            String pathInfoStr = client.getPathDetail(path.trim());
            if (pathInfoStr == null || pathInfoStr.trim().equals(""))
                return Errno.ENOENT;
            Map openDt = new HashMap();
            openDt.put("filedp", fileDp); // open??Long(File)
            openDt.put("pathInfoStr", pathInfoStr);
            openStatusMap.put(path.trim(), openDt);
            openSetter.setFh(openDt);
        } catch (FuseException fe) {
            throw fe;
        } catch (Exception e) {
            e.printStackTrace();
            new FuseException(e);
        }
        return 0;
    }

    public int rename(String from, String to) throws FuseException {
        log.info("rename " + from + " " + to);
        String[] pathInfo = null;
        StringBuilder newPathInfo = new StringBuilder();
        try {

            synchronized (this.parallelDataAccessSync[((from.hashCode() << 1) >>> 1) % 100]) {

                // ???????????flush?
                List bufferedDataFhList = writeBufFpMap.removeGroupingData(from);
                if (bufferedDataFhList != null) {
                    for (int idx = 0; idx < bufferedDataFhList.size(); idx++) {
                        Object bFh = bufferedDataFhList.get(idx);
                        this.fixNoCommitData(bFh);
                    }
                }

                String pathInfoStr = client.getPathDetail(from.trim());
                if (pathInfoStr == null || pathInfoStr.trim().equals(""))
                    return Errno.ENOENT;

                pathInfo = pathInfoStr.split("\t");

                if (!client.addPathDetail(to.trim(), pathInfoStr)) {
                    return Errno.EEXIST;
                }
                if (!client.setDirAttribute(to.trim(), pathInfo[0])) {
                    return Errno.EEXIST;
                }

                if (client.removePathDetail(from.trim()) == false)
                    return Errno.EIO;
                if (client.removeAttribute(from.trim()) == false)
                    return Errno.EIO;
            }
        } catch (FuseException fe) {
            throw fe;
        } catch (Exception e) {
            new FuseException(e).initErrno(FuseException.EACCES);
        }
        return 0;
    }

    public int rmdir(String path) throws FuseException {
        log.info("rmdir " + path);
        try {

            String pathInfoStr = client.getPathDetail(path.trim());
            if (pathInfoStr == null)
                return Errno.ENOTDIR;

            Map dirChildMap = client.getDirChild(path.trim());
            if (dirChildMap != null && dirChildMap.size() > 0) {
                return Errno.ENOTEMPTY;
            }

            if (client.removePathDetail(path.trim()) == false)
                return Errno.EBUSY;
            if (client.removeDir(path.trim()) == false)
                return Errno.EBUSY;
        } catch (Exception e) {
            new FuseException(e).initErrno(FuseException.EACCES);
        }
        return 0;
    }

    public int statfs(FuseStatfsSetter statfsSetter) throws FuseException {
        log.info("statfs " + statfsSetter);
        statfsSetter.set(blockSize, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, 0, Integer.MAX_VALUE,
                2000);
        return 0;
    }

    public int symlink(String from, String to) throws FuseException {
        log.info("symlink " + from + " " + to);
        return Errno.EACCES;
    }

    public int truncate(String path, long size) throws FuseException {
        log.info("truncate " + path + " " + size);
        try {
            synchronized (this.parallelDataAccessSync[((path.hashCode() << 1) >>> 1) % 100]) {

                // ???????????flush?
                List bufferedDataFhList = writeBufFpMap.removeGroupingData(path);
                if (bufferedDataFhList != null) {
                    for (int idx = 0; idx < bufferedDataFhList.size(); idx++) {
                        Object bFh = bufferedDataFhList.get(idx);
                        this.fixNoCommitData(bFh);
                    }
                }

                String pathInfoStr = client.getPathDetail(path.trim());
                if (pathInfoStr == null)
                    return Errno.ENOENT;
                String[] pathInfo = pathInfoStr.split("\t");

                if (new Long(pathInfo[4].trim()).longValue() > size) {

                    client.removeValue(path.trim(), size, (Long.parseLong(pathInfo[4]) - size),
                            pathInfo[pathInfo.length - 2]);
                } else {

                    client.appendingNullData(path.trim(), size, pathInfo[pathInfo.length - 2]);
                }

                pathInfo[4] = new Long(size).toString();
                pathInfo[5] = new Long(System.currentTimeMillis() / 1000L).toString();
                int assistBlockSize = 0;
                if ((size % blockSize) > 0) {
                    assistBlockSize = 1;
                }
                pathInfo[6] = new Long((size / blockSize) + assistBlockSize).toString();
                StringBuilder strBuf = new StringBuilder(64);
                strBuf.append(pathInfo[0]).append("\t").append(pathInfo[1]).append("\t").append(pathInfo[2])
                        .append("\t").append(pathInfo[3]).append("\t").append(pathInfo[4]).append("\t")
                        .append(pathInfo[5]).append("\t").append(pathInfo[6]).append("\t").append(pathInfo[7])
                        .append("\t").append(pathInfo[8]).append("\t").append(pathInfo[9]).append("\t")
                        .append("-1");

                if (!client.setPathDetail(path.trim(), strBuf.toString()))
                    return Errno.EIO;
            }
        } catch (FuseException fe) {
            throw fe;
        } catch (Exception e) {
            throw new FuseException(e).initErrno(FuseException.EACCES);
        }
        return 0;
    }

    /*    public int unlink(String path) throws FuseException {
    return 0;
        }
    */
    public int unlink(String path) throws FuseException {
        log.info("unlink " + path);

        try {
            synchronized (this.parallelDataAccessSync[((path.hashCode() << 1) >>> 1) % 100]) {

                // ???????????flush?
                List bufferedDataFhList = writeBufFpMap.removeGroupingData(path);
                if (bufferedDataFhList != null) {
                    for (int idx = 0; idx < bufferedDataFhList.size(); idx++) {
                        Object bFh = bufferedDataFhList.get(idx);
                        this.fixNoCommitData(bFh);
                    }
                }

                Map metaInfo = client.getDataMetaInfo(path);
                boolean deleteFlg = true;
                if (metaInfo.size() > 1) {

                    if (metaInfo.get("pathdetail") != null && metaInfo.get("attribute") != null) {

                        deleteFlg = false;

                        String pathInfoStr = client.getPathDetail(path.trim());
                        if (pathInfoStr == null)
                            return Errno.ENOENT;
                        String[] pathInfo = pathInfoStr.split("\t");

                        if (client.removePathDetail(path.trim()) == false)
                            return Errno.EIO;
                        if (client.removeAttribute(path.trim()) == false)
                            return Errno.EIO;
                        client.deleteValue(path.trim(), pathInfo[pathInfo.length - 2]);
                    }
                }

                if (deleteFlg) {
                    try {
                        client.removePathDetail(path);
                        client.removeAttribute(path);

                        String pathInfoStr = (String) metaInfo.get("pathdetail");
                        if (pathInfoStr != null) {

                            String[] pathInfo = pathInfoStr.split("\t");
                            client.deleteValue(path, pathInfo[pathInfo.length - 2]);
                        }
                    } catch (Exception innerE) {
                    }
                    log.fatal("broken file remove filename=[" + path + "]");
                }
            }
        } catch (Exception e) {
            throw new FuseException(e).initErrno(FuseException.EIO);
        }
        return 0;
    }

    public int utime(String path, int atime, int mtime) throws FuseException {
        log.info("utime " + path + " " + atime + " " + mtime);
        return 0;
    }

    public int readlink(String path, CharBuffer link) throws FuseException {
        log.info("readlink " + path);
        link.append(path);
        return 0;
    }

    public int write_bk(String path, Object fh, boolean isWritepage, ByteBuffer buf, long offset)
            throws FuseException {
        byte[] tmpBuf = new byte[buf.limit()];
        buf.get(tmpBuf);

        return 0;
    }

    public int write(String path, Object fh, boolean isWritepage, ByteBuffer buf, long offset)
            throws FuseException {
        log.info("write  path:" + path + " offset:" + offset + " isWritepage:" + isWritepage + " buf.limit:"
                + buf.limit());
        //long startAA = System.nanoTime();
        try {

            if (startTimeAAA == 0L)
                startTimeAAA = System.nanoTime();
            // ??????????????
            if (OkuyamaFilesystem.storageType == 1)
                return realWrite(path, fh, isWritepage, buf, offset);

            if (fh == null)
                return Errno.EBADE;

            synchronized (this.parallelDataAccessSync[((path.hashCode() << 1) >>> 1) % 100]) {

                if (appendWriteDataBuf.containsKey(fh)) {

                    Map appendData = (Map) appendWriteDataBuf.get(fh);
                    ByteArrayOutputStream bBuf = (ByteArrayOutputStream) appendData.get("buf");
                    long bOffset = ((Long) appendData.get("offset")).longValue();

                    if ((bOffset + bBuf.size()) == offset) {

                        byte[] tmpBuf = new byte[buf.limit()];
                        buf.get(tmpBuf);
                        bBuf.write(tmpBuf);

                        // ??????????????????
                        if (bBuf.size() >= writeBufferSize) {

                            // ???????
                            appendWriteDataBuf.remove(fh);
                            String bPath = (String) appendData.get("path");
                            Object bFh = (Object) appendData.get("fh");
                            boolean bIsWritepage = ((Boolean) appendData.get("isWritepage")).booleanValue();

                            int ret = this.realWrite(bPath, bFh, bIsWritepage, bBuf, bOffset);

                            return ret;
                        } else {

                            return 0;
                        }
                    } else {

                        // offset?????????????
                        appendWriteDataBuf.remove(fh);
                        String bPath = (String) appendData.get("path");
                        Object bFh = (Object) appendData.get("fh");
                        boolean bIsWritepage = ((Boolean) appendData.get("isWritepage")).booleanValue();

                        int realWriteRet = this.realWrite(bPath, bFh, bIsWritepage, bBuf, bOffset);

                        if (realWriteRet == 0) {

                            int retI = this.realWrite(path, fh, isWritepage, buf, offset);

                            return retI;
                        } else {
                            return realWriteRet;
                        }
                    }
                } else {

                    Map appendData = new HashMap();
                    appendData.put("path", path);
                    appendData.put("fh", fh);
                    appendData.put("isWritepage", isWritepage);
                    ByteArrayOutputStream baos = new ByteArrayOutputStream(1024 * 1024 * 10 + 8192);
                    byte[] tmpByte = new byte[buf.limit()];
                    buf.get(tmpByte);
                    baos.write(tmpByte);
                    appendData.put("buf", baos);
                    appendData.put("offset", offset);
                    this.appendWriteDataBuf.put(fh, appendData);
                    this.writeBufFpMap.addGroupingData(path, fh);

                    return 0;
                }
            }
        } catch (Exception e) {

            throw new FuseException(e);
        } finally {
        }
    }

    public int realWrite(String path, Object fh, boolean isWritepage, ByteBuffer buf, long offset)
            throws FuseException {
        byte[] writeData = new byte[buf.limit()];
        buf.get(writeData);
        return realWrite(path, fh, isWritepage, writeData, offset);
    }

    public int realWrite(String path, Object fh, boolean isWritepage, ByteArrayOutputStream buf, long offset)
            throws FuseException {
        byte[] data = buf.toByteArray();
        return realWrite(path, fh, isWritepage, data, offset);
    }

    public int realWrite(String path, Object fh, boolean isWritepage, byte[] writeData, long offset)
            throws FuseException {

        //log.info("realWrite  path:" + path + " offset:" + offset + " isWritepage:" + isWritepage + " buf.limit:" + writeData.length);
        if (fh == null)
            return Errno.EBADE;
        //long start = System.nanoTime();
        try {
            /*System.out.println("--------------- start --------------- ");
                        for (int i = 0; i < writeData.length; i++) {
            System.out.println("path=" + path + " offet=" + offset +" writeData[" + i + "]=" + writeData[i]);
                        }
            System.out.println("--------------- end --------------- ");*/
            String pathTrimStr = path.trim();
            String pathInfoStr = (String) client.getPathDetail(pathTrimStr);
            if (pathInfoStr == null)
                return Errno.ENOENT;
            String[] pathInfo = pathInfoStr.split("\t");
            //long end2 = System.nanoTime();
            //System.out.println("Time2=" + (end2 - start));

            long writeLastBlockIdx = -1L;
            if (writeData == null || writeData.length < 1) {
                log.error("write data nothing = realWrite  path:" + path + " offset:" + offset + " isWritepage:"
                        + isWritepage + " buf.limit:" + writeData.length);
            } else {
                int idx = writeData.length;
                writeLastBlockIdx = client.writeValue(pathTrimStr, offset, writeData, writeData.length,
                        pathInfo[pathInfo.length - 2], new Long(pathInfo[10]).longValue());
            }
            //long end3 = System.nanoTime();
            //System.out.println("Time3=" + (end3 - end2));
            if (Long.parseLong(pathInfo[4]) < 1) {
                pathInfo[4] = new Long(writeData.length).toString();
            } else if (Long.parseLong(pathInfo[4]) < new Long(offset + new Long(writeData.length).longValue())
                    .longValue()) {
                pathInfo[4] = new Long(offset + new Long(writeData.length).longValue()).toString();
            }
            pathInfo[5] = new Long(System.currentTimeMillis() / 1000L).toString();
            int assistBlockSize = 0;
            if (((Long.parseLong(pathInfo[4]) + writeData.length) % blockSize) > 0) {
                assistBlockSize = 1;
            }
            pathInfo[6] = new Long(((Long.parseLong(pathInfo[4]) + writeData.length) / blockSize) + assistBlockSize)
                    .toString();
            StringBuilder strBuf = new StringBuilder(64);
            strBuf.append(pathInfo[0]).append("\t").append(pathInfo[1]).append("\t").append(pathInfo[2])
                    .append("\t").append(pathInfo[3]).append("\t").append(pathInfo[4]).append("\t")
                    .append(pathInfo[5]).append("\t").append(pathInfo[6]).append("\t").append(pathInfo[7])
                    .append("\t").append(pathInfo[8]).append("\t").append(pathInfo[9]).append("\t");
            if (new Long(pathInfo[10]).longValue() < writeLastBlockIdx) {
                strBuf.append(writeLastBlockIdx);
            } else {
                strBuf.append(pathInfo[10]);
            }
            client.setPathDetail(pathTrimStr, strBuf.toString());
            //long end4 = System.nanoTime();
            //System.out.println("Time4=" + (end4 - end3));
        } catch (FuseException fe) {
            throw fe;
        } catch (Exception e) {
            new FuseException(e);
        }
        //long end = System.nanoTime();
        //System.out.println("Time=" + (end - start));
        return 0;
    }

    public int read(String path, Object fh, ByteBuffer buf, long offset) throws FuseException {

        /*long start1 = 0L;
        long start2 = 0L;
        long start3 = 0L;
        long start4 = 0L;
        long start5 = 0L;
            
        long end2 = 0L;
        long end3 = 0L;
        long end4 = 0L;
        long end5 = 0L;
        */
        //start1 = System.nanoTime();
        //start2 = System.nanoTime();

        log.info("read:" + path + " offset:" + offset + " buf.limit:" + buf.limit());
        if (fh == null)
            return Errno.EBADE;
        try {

            String trimToPath = path.trim();
            synchronized (this.parallelDataAccessSync[((path.hashCode() << 1) >>> 1) % 100]) {

                // ???????????flush?
                List bufferedDataFhList = writeBufFpMap.removeGroupingData(path);
                if (bufferedDataFhList != null) {
                    for (int idx = 0; idx < bufferedDataFhList.size(); idx++) {
                        Object bFh = bufferedDataFhList.get(idx);
                        this.fixNoCommitData(bFh);
                    }
                }
                String pathInfoStr = (String) client.getPathDetail(trimToPath);

                String[] pathInfo = pathInfoStr.split("\t");
                long nowSize = Long.parseLong(pathInfo[4]);
                int readLen = client.readValue(trimToPath, offset, buf.limit(), pathInfo[pathInfo.length - 2], buf);

                if (readLen == -1 || readLen < 1) {

                    log.info("read data nothing read=" + "read:" + path + " offset:" + offset + " buf.limit:"
                            + buf.limit());
                }
            }
        } catch (FuseException fe) {
            throw fe;
        } catch (Exception e) {
            new FuseException(e);
        }
        return 0;
    }

    public int release(String path, Object fh, int flags) throws FuseException {
        log.info("release " + path + " " + fh + " " + flags);
        synchronized (this.parallelDataAccessSync[((path.hashCode() << 1) >>> 1) % 100]) {

            List bufferedDataFhList = writeBufFpMap.removeGroupingData(path);

            if (bufferedDataFhList != null) {
                for (int idx = 0; idx < bufferedDataFhList.size(); idx++) {
                    Object bFh = bufferedDataFhList.get(idx);
                    this.fixNoCommitData(bFh);
                }
            }

            openStatusMap.remove(path.trim());
            this.fixNoCommitData(fh);
        }

        return 0;
    }

    public int flush(String path, Object fh) throws FuseException {
        synchronized (this.parallelDataAccessSync[((path.hashCode() << 1) >>> 1) % 100]) {
            log.info("flush " + path + " " + fh);
            List bufferedDataFhList = writeBufFpMap.removeGroupingData(path);

            if (bufferedDataFhList != null) {
                for (int idx = 0; idx < bufferedDataFhList.size(); idx++) {
                    Object bFh = bufferedDataFhList.get(idx);
                    this.fixNoCommitData(bFh);
                }
            }

            this.fixNoCommitData(fh);
        }
        return 0;
    }

    public int fsync(String path, Object fh, boolean isDatasync) throws FuseException {
        synchronized (this.parallelDataAccessSync[((path.hashCode() << 1) >>> 1) % 100]) {
            log.info("fsync " + path + " " + fh + " " + isDatasync);
            List bufferedDataFhList = writeBufFpMap.removeGroupingData(path);

            if (bufferedDataFhList != null) {
                for (int idx = 0; idx < bufferedDataFhList.size(); idx++) {
                    Object bFh = bufferedDataFhList.get(idx);
                    this.fixNoCommitData(bFh);
                }
            }

            this.fixNoCommitData(fh);
        }
        return 0;
    }

    private int fixNoCommitData(Object fh) throws FuseException {

        if (appendWriteDataBuf.containsKey(fh)) {
            Map appendData = (Map) appendWriteDataBuf.remove(fh);
            if (appendData != null) {
                String bPath = (String) appendData.get("path");
                Object bFh = (Object) appendData.get("fh");
                boolean bIsWritepage = ((Boolean) appendData.get("isWritepage")).booleanValue();
                ByteArrayOutputStream bBuf = (ByteArrayOutputStream) appendData.get("buf");
                long bOffset = ((Long) appendData.get("offset")).longValue();

                int realWriteRet = this.realWrite(bPath, bFh, bIsWritepage, bBuf, bOffset);
                return realWriteRet;
            }
        }
        return 0;
    }

    public int getxattr(String path, String name, ByteBuffer dst) throws FuseException, BufferOverflowException {

        return 0;
    }

    public int getxattrsize(String path, String name, FuseSizeSetter sizeSetter) throws FuseException {

        return 0;
    }

    public int listxattr(String path, XattrLister lister) throws FuseException {

        return 0;
    }

    public int removexattr(String path, String name) throws FuseException {
        return 0;
    }

    public int setxattr(String path, String name, ByteBuffer value, int flags) throws FuseException {
        return 0;
    }
}