public static void checkSanity() {
    long t = System.currentTimeMillis();

    try {
      r.lock();
      final int fileLength = (int) getRecords().length();
      assert fileLength % RECORD_SIZE == 0;
      int recordCount = fileLength / RECORD_SIZE;

      IntArrayList usedAttributeRecordIds = new IntArrayList();
      IntArrayList validAttributeIds = new IntArrayList();
      for (int id = 2; id < recordCount; id++) {
        int flags = getFlags(id);
        LOG.assertTrue(
            (flags & ~ALL_VALID_FLAGS) == 0,
            "Invalid flags: 0x" + Integer.toHexString(flags) + ", id: " + id);
        if ((flags & FREE_RECORD_FLAG) != 0) {
          LOG.assertTrue(
              DbConnection.myFreeRecords.contains(id),
              "Record, marked free, not in free list: " + id);
        } else {
          LOG.assertTrue(
              !DbConnection.myFreeRecords.contains(id),
              "Record, not marked free, in free list: " + id);
          checkRecordSanity(id, recordCount, usedAttributeRecordIds, validAttributeIds);
        }
      }
    } finally {
      r.unlock();
    }

    t = System.currentTimeMillis() - t;
    LOG.info("Sanity check took " + t + " ms");
  }
  public static Pair<String[], int[]> listAll(int parentId) {
    try {
      r.lock();
      try {
        final DataInputStream input = readAttribute(parentId, CHILDREN_ATT);
        if (input == null)
          return Pair.create(ArrayUtil.EMPTY_STRING_ARRAY, ArrayUtil.EMPTY_INT_ARRAY);

        final int count = DataInputOutputUtil.readINT(input);
        final int[] ids = ArrayUtil.newIntArray(count);
        final String[] names = ArrayUtil.newStringArray(count);
        for (int i = 0; i < count; i++) {
          int id = DataInputOutputUtil.readINT(input);
          id = id >= 0 ? id + parentId : -id;
          ids[i] = id;
          names[i] = getName(id);
        }
        input.close();
        return Pair.create(names, ids);
      } finally {
        r.unlock();
      }
    } catch (Throwable e) {
      throw DbConnection.handleError(e);
    }
  }
 public static long getCreationTimestamp() {
   try {
     r.lock();
     return DbConnection.getTimestamp();
   } finally {
     r.unlock();
   }
 }
 public static int getModCount() {
   try {
     r.lock();
     return getRecords().getInt(HEADER_GLOBAL_MOD_COUNT_OFFSET);
   } finally {
     r.unlock();
   }
 }
 public static int getFlags(int id) {
   try {
     r.lock();
     return getRecordInt(id, FLAGS_OFFSET);
   } finally {
     r.unlock();
   }
 }
 public static long getLength(int id) {
   try {
     r.lock();
     return getRecords().getLong(getOffset(id, LENGTH_OFFSET));
   } finally {
     r.unlock();
   }
 }
 public static long getTimestamp(int id) {
   try {
     r.lock();
     return getRecords().getLong(getOffset(id, TIMESTAMP_OFFSET));
   } finally {
     r.unlock();
   }
 }
 public static int getModCount(int id) {
   try {
     r.lock();
     return getRecordInt(id, MOD_COUNT_OFFSET);
   } finally {
     r.unlock();
   }
 }
 public static void setTimestamp(int id, long value) {
   try {
     w.lock();
     incModCount(id);
     getRecords().putLong(getOffset(id, TIMESTAMP_OFFSET), value);
   } catch (Throwable e) {
     throw DbConnection.handleError(e);
   } finally {
     w.unlock();
   }
 }
 public static void setLength(int id, long len) {
   try {
     w.lock();
     incModCount(id);
     getRecords().putLong(getOffset(id, LENGTH_OFFSET), len);
   } catch (Throwable e) {
     throw DbConnection.handleError(e);
   } finally {
     w.unlock();
   }
 }
 public static void setName(int id, String name) {
   try {
     w.lock();
     incModCount(id);
     putRecordInt(id, NAME_OFFSET, getNames().enumerate(name));
   } catch (Throwable e) {
     throw DbConnection.handleError(e);
   } finally {
     w.unlock();
   }
 }
 public static void deleteRecordRecursively(int id) {
   try {
     w.lock();
     incModCount(id);
     doDeleteRecursively(id);
   } catch (Throwable e) {
     throw DbConnection.handleError(e);
   } finally {
     w.unlock();
   }
 }
 public static int acquireFileContent(int fileId) {
   try {
     w.lock();
     int record = getContentRecordId(fileId);
     if (record > 0) getContentStorage().acquireRecord(record);
     return record;
   } catch (Throwable e) {
     throw DbConnection.handleError(e);
   } finally {
     w.unlock();
   }
 }
 public static boolean wereChildrenAccessed(int id) {
   try {
     r.lock();
     try {
       return findAttributePage(id, CHILDREN_ATT, false) != 0;
     } finally {
       r.unlock();
     }
   } catch (Throwable e) {
     throw DbConnection.handleError(e);
   }
 }
    public void writeBytes(ByteSequence bytes, int fileId) throws IOException {
      final int page;
      try {
        w.lock();
        incModCount(fileId);
        page = findOrCreatePage();
      } finally {
        w.unlock();
      }

      getStorage().writeBytes(page, bytes, myFixedSize);
    }
 public static void dispose() {
   try {
     w.lock();
     DbConnection.force();
     DbConnection.closeFiles();
   } catch (Throwable e) {
     throw DbConnection.handleError(e);
   } finally {
     ourIsDisposed = true;
     w.unlock();
   }
 }
 public static int getContentId(int fileId) {
   try {
     r.lock();
     try {
       return getContentRecordId(fileId);
     } finally {
       r.unlock();
     }
   } catch (Throwable e) {
     throw DbConnection.handleError(e);
   }
 }
 public static void connect() {
   try {
     w.lock();
     if (!ourInitialized) {
       init();
       setupFlushing();
       ourInitialized = true;
     }
   } finally {
     w.unlock();
   }
 }
 public static String getName(int id) {
   try {
     r.lock();
     try {
       final int nameId = getRecordInt(id, NAME_OFFSET);
       return nameId != 0 ? getNames().valueOf(nameId) : "";
     } finally {
       r.unlock();
     }
   } catch (Throwable e) {
     throw DbConnection.handleError(e);
   }
 }
 public static void setFlags(int id, int flags, final boolean markAsChange) {
   try {
     w.lock();
     if (markAsChange) {
       incModCount(id);
     }
     putRecordInt(id, FLAGS_OFFSET, flags);
   } catch (Throwable e) {
     throw DbConnection.handleError(e);
   } finally {
     w.unlock();
   }
 }
  public static int findRootRecord(String rootUrl) throws IOException {
    try {
      w.lock();
      DbConnection.markDirty();
      final int root = getNames().enumerate(rootUrl);

      final DataInputStream input = readAttribute(1, CHILDREN_ATT);
      int[] names = ArrayUtil.EMPTY_INT_ARRAY;
      int[] ids = ArrayUtil.EMPTY_INT_ARRAY;

      if (input != null) {
        try {
          final int count = DataInputOutputUtil.readINT(input);
          names = ArrayUtil.newIntArray(count);
          ids = ArrayUtil.newIntArray(count);
          for (int i = 0; i < count; i++) {
            final int name = DataInputOutputUtil.readINT(input);
            final int id = DataInputOutputUtil.readINT(input);
            if (name == root) {
              return id;
            }

            names[i] = name;
            ids[i] = id;
          }
        } finally {
          input.close();
        }
      }

      final DataOutputStream output = writeAttribute(1, CHILDREN_ATT, false);
      int id;
      try {
        id = createRecord();
        DataInputOutputUtil.writeINT(output, names.length + 1);
        for (int i = 0; i < names.length; i++) {
          DataInputOutputUtil.writeINT(output, names[i]);
          DataInputOutputUtil.writeINT(output, ids[i]);
        }
        DataInputOutputUtil.writeINT(output, root);
        DataInputOutputUtil.writeINT(output, id);
      } finally {
        output.close();
      }

      return id;
    } finally {
      w.unlock();
    }
  }
  private static void deleteRecord(final int id) {
    try {
      w.lock();
      DbConnection.markDirty();
      deleteContentAndAttributes(id);

      DbConnection.cleanRecord(id);
      addToFreeRecordsList(id);
    } catch (Throwable e) {
      throw DbConnection.handleError(e);
    } finally {
      w.unlock();
    }
  }
  public static void setParent(int id, int parent) {
    if (id == parent) {
      LOG.error("Cyclic parent/child relations");
      return;
    }

    try {
      w.lock();
      incModCount(id);
      putRecordInt(id, PARENT_OFFSET, parent);
    } catch (Throwable e) {
      throw DbConnection.handleError(e);
    } finally {
      w.unlock();
    }
  }
 @Nullable
 public static DataInputStream readContent(int fileId) {
   try {
     int page;
     try {
       r.lock();
       page = findContentPage(fileId, false);
       if (page == 0) return null;
     } finally {
       r.unlock();
     }
     return getContentStorage().readStream(page);
   } catch (Throwable e) {
     throw DbConnection.handleError(e);
   }
 }
 public static void force() {
   try {
     w.lock();
     if (myRecords != null) {
       markClean();
     }
     if (myNames != null) {
       myNames.force();
       myAttributes.force();
       myContents.force();
       myRecords.force();
     }
   } finally {
     w.unlock();
   }
 }
 @Nullable
 public static DataInputStream readAttribute(int fileId, String attId) {
   try {
     synchronized (attId) {
       int page;
       try {
         r.lock();
         page = findAttributePage(fileId, attId, false);
         if (page == 0) return null;
       } finally {
         r.unlock();
       }
       return getAttributesStorage().readStream(page);
     }
   } catch (Throwable e) {
     throw DbConnection.handleError(e);
   }
 }
  public static int getParent(int id) {
    try {
      r.lock();
      try {
        final int parentId = getRecordInt(id, PARENT_OFFSET);
        if (parentId == id) {
          LOG.error("Cyclic parent child relations in the database. id = " + id);
          return 0;
        }

        return parentId;
      } finally {
        r.unlock();
      }
    } catch (Throwable e) {
      throw DbConnection.handleError(e);
    }
  }
  public static void deleteRootRecord(int id) throws IOException {
    try {
      w.lock();
      DbConnection.markDirty();
      final DataInputStream input = readAttribute(1, CHILDREN_ATT);
      assert input != null;
      int count;
      int[] names;
      int[] ids;
      try {
        count = DataInputOutputUtil.readINT(input);

        names = ArrayUtil.newIntArray(count);
        ids = ArrayUtil.newIntArray(count);
        for (int i = 0; i < count; i++) {
          names[i] = DataInputOutputUtil.readINT(input);
          ids[i] = DataInputOutputUtil.readINT(input);
        }
      } finally {
        input.close();
      }

      final int index = ArrayUtil.find(ids, id);
      assert index >= 0;

      names = ArrayUtil.remove(names, index);
      ids = ArrayUtil.remove(ids, index);

      final DataOutputStream output = writeAttribute(1, CHILDREN_ATT, false);
      try {
        DataInputOutputUtil.writeINT(output, count - 1);
        for (int i = 0; i < names.length; i++) {
          DataInputOutputUtil.writeINT(output, names[i]);
          DataInputOutputUtil.writeINT(output, ids[i]);
        }
      } finally {
        output.close();
      }
    } finally {
      w.unlock();
    }
  }
    public static void flushSome() {
      if (!isDirty() || HeavyProcessLatch.INSTANCE.isRunning()) return;

      try {
        w.lock();
        if (myFlushingFuture == null) {
          return; // avoid NPE when close has already taken place
        }
        myNames.force();

        final boolean attribsFlushed = myAttributes.flushSome();
        final boolean contentsFlushed = myContents.flushSome();
        if (attribsFlushed && contentsFlushed) {
          markClean();
          myRecords.force();
        }
      } finally {
        w.unlock();
      }
    }
 public static void updateList(int id, @NotNull int[] children) {
   try {
     w.lock();
     DbConnection.markDirty();
     final DataOutputStream record = writeAttribute(id, CHILDREN_ATT, false);
     DataInputOutputUtil.writeINT(record, children.length);
     for (int child : children) {
       if (child == id) {
         LOG.error("Cyclic parent child relations");
       } else {
         child = child > id ? child - id : -child;
         DataInputOutputUtil.writeINT(record, child);
       }
     }
     record.close();
   } catch (Throwable e) {
     throw DbConnection.handleError(e);
   } finally {
     w.unlock();
   }
 }