private void rewriteDirectoryRecordWithInlineAttrContent(final @NotNull BufferExposingByteArrayOutputStream newAttributeInlinableValue)
      throws IOException {

      assert newAttributeInlinableValue.size() < INLINE_ATTRIBUTE_SMALLER_THAN : "Only small values could be stored in directory record";
      assert inlineAttributes : "Attributes could be stored in directory record only if 'inline small attributes' is enabled";

      int recordId = fileAttributeRecordId(connection, fileId);
      int encodedAttrId = connection.getAttributeId(attribute.getId());

      BufferExposingByteArrayOutputStream unchangedPreviousDirectoryStream = null;

      //if this is a new attr record -> it should be directory record
      boolean createDirectoryRecord = false;

      if (recordId == 0) {
        recordId = attributesBlobStorage.createNewRecord();
        updateFileAttributeRecordId(connection, fileId, recordId);
        createDirectoryRecord = true;
      }
      else {
        try (DataInputStream attrRefs = attributesBlobStorage.readStream(recordId)) {

          DataOutputStream dataStream = null;

          try {
            final int remainingAtStart = attrRefs.available();
            if (bulkAttrReadSupport) {
              unchangedPreviousDirectoryStream = new BufferExposingByteArrayOutputStream();
              dataStream = new DataOutputStream(unchangedPreviousDirectoryStream);
              int attId = DataInputOutputUtil.readINT(attrRefs);
              assert attId == PersistentFSConnection.RESERVED_ATTR_ID;
              int fileId = DataInputOutputUtil.readINT(attrRefs);
              assert this.fileId == fileId;

              writeRecordHeader(attId, fileId, dataStream);
            }
            //Read attribute entries (encodedAttrId, address | size, ...), and copy them back to unchangedPreviousDirectoryStream
            // except for given attribute(encodedAttrId) -- which value we try to overwrite, but only if
            // size(new value) == size(old value). i.e. if given attribute is 'big' attribute, then it always fits
            // in, since only a reference (address) to the actual value record is stored in directory record.
            // But if attribute to rewrite is a 'small' attribute, its value is written inline, right in the
            // directory record, if it is of the same size, as was the value previously written.
            while (attrRefs.available() > 0) {
              final int attIdOnPage = DataInputOutputUtil.readINT(attrRefs);
              final int attrAddressOrSize = DataInputOutputUtil.readINT(attrRefs);

              if (attIdOnPage != encodedAttrId) {
                //copy all other attributes as-is:
                if (dataStream == null) {
                  unchangedPreviousDirectoryStream = new BufferExposingByteArrayOutputStream();
                  dataStream = new DataOutputStream(unchangedPreviousDirectoryStream);
                }
                DataInputOutputUtil.writeINT(dataStream, attIdOnPage);
                DataInputOutputUtil.writeINT(dataStream, attrAddressOrSize);

                if (attrAddressOrSize < INLINE_ATTRIBUTE_SMALLER_THAN) {
                  byte[] b = ArrayUtil.newByteArray(attrAddressOrSize);
                  attrRefs.readFully(b);
                  dataStream.write(b);
                }
              }
              else {
                //if( attIdOnPage == encodedAttrId ) and attribute was written inline -> overwrite it inline
                // _only if its size is unchanged_, so entries after the current one -- remain in place.
                if (attrAddressOrSize < INLINE_ATTRIBUTE_SMALLER_THAN) {
                  if (newAttributeInlinableValue.size() == attrAddressOrSize) {
                    // update inplace when new attr has the same size
                    int remaining = attrRefs.available();
                    attributesBlobStorage.replaceBytes(recordId, remainingAtStart - remaining,
                                                       newAttributeInlinableValue.toByteArraySequence());
                    return;
                  }
                  //if size was changed -> do not copy current entry into dataStream at all,
                  //  (will add it after all other entries)
                  attrRefs.skipBytes(attrAddressOrSize);
                }
                //... and continue to copy remaining attr entries
              }
            }
          }
          finally {
            if (dataStream != null) dataStream.close();
          }
        }
      }
      //If new attribute wasn't fit inline into the old value place/space, then we need to re-write
      // directory record: first write unchanged content of directory record (all attributes but the
      // current one), and after that write entry for the current attribute and its new value. If new
      // directory record becomes larger than current one, and doesn't fit into its current place in
      // file -> storage.writeStream() deals with it, by re-allocating record in the new place, and
      // write its new content there (and old record probably marked for reclaiming later)
      try (AbstractStorage.StorageDataOutput directoryStream = attributesBlobStorage.writeStream(recordId)) {
        if (createDirectoryRecord) {
          if (bulkAttrReadSupport) writeRecordHeader(PersistentFSConnection.RESERVED_ATTR_ID, fileId, directoryStream);
        }
        if (unchangedPreviousDirectoryStream != null) {
          directoryStream.write(unchangedPreviousDirectoryStream.getInternalBuffer(), 0, unchangedPreviousDirectoryStream.size());
        }
        if (newAttributeInlinableValue.size() > 0) {
          DataInputOutputUtil.writeINT(directoryStream, encodedAttrId);
          DataInputOutputUtil.writeINT(directoryStream, newAttributeInlinableValue.size());
          directoryStream.write(newAttributeInlinableValue.getInternalBuffer(), 0, newAttributeInlinableValue.size());
        }
      }
    }
private void rewriteDirectoryRecordWithInlineAttrContent(final @NotNull BufferExposingByteArrayOutputStream newAttributeInlinableValue)