/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hdfs.server.namenode;
import io.hops.exception.StorageException;
import io.hops.exception.TransactionContextException;
import io.hops.transaction.EntityManager;
import org.apache.hadoop.fs.permission.PermissionStatus;
import org.apache.hadoop.hdfs.protocol.DSQuotaExceededException;
import org.apache.hadoop.hdfs.protocol.NSQuotaExceededException;
import org.apache.hadoop.hdfs.protocol.QuotaExceededException;
import java.io.IOException;
/**
* Directory INode class that has a quota restriction
*/
public class INodeDirectoryWithQuota extends INodeDirectory {
/**
* Convert an existing directory inode to one with the given quota
*
* @param nsQuota
* Namespace quota to be assigned to this inode
* @param dsQuota
* Diskspace quota to be assigned to this indoe
* @param other
* The other inode from which all other properties are copied
*/
INodeDirectoryWithQuota(Long nsQuota, Long dsQuota, INodeDirectory other)
throws IOException {
super(other);
INode.DirCounts counts = new INode.DirCounts();
other.spaceConsumedInTree(counts);
createINodeAttributes(nsQuota, counts.getNsCount(), dsQuota,
counts.getDsCount());
setQuota(nsQuota, dsQuota);
}
INodeDirectoryWithQuota(Long nsQuota, Long dsQuota, Long nsCount,
Long dsCount, INodeDirectory other)
throws IOException {
super(other);
createINodeAttributes(nsQuota, nsCount, dsQuota, dsCount);
setQuota(nsQuota, dsQuota);
}
/**
* constructor with no quota verification
*/
public INodeDirectoryWithQuota(String name, PermissionStatus permissions)
throws IOException {
super(name, permissions);
}
/**
* Get this directory's namespace quota
*
* @return this directory's namespace quota
*/
@Override
public long getNsQuota()
throws StorageException, TransactionContextException {
return getINodeAttributes().getNsQuota();
}
/**
* Get this directory's diskspace quota
*
* @return this directory's diskspace quota
*/
@Override
public long getDsQuota()
throws StorageException, TransactionContextException {
return getINodeAttributes().getDsQuota();
}
/**
* Set this directory's quota
*
* @param newNsQuota
* Namespace quota to be set
* @param newDsQuota
* diskspace quota to be set
*/
void setQuota(Long newNsQuota, Long newDsQuota)
throws StorageException, TransactionContextException {
getINodeAttributes().setNsQuota(newNsQuota);
getINodeAttributes().setDsQuota(newDsQuota);
}
@Override
DirCounts spaceConsumedInTree(DirCounts counts)
throws StorageException, TransactionContextException {
counts.nsCount += getINodeAttributes().getNsCount();
counts.dsCount += getINodeAttributes().getDiskspace();
return counts;
}
/**
* Get the number of names in the subtree rooted at this directory
*
* @return the size of the subtree rooted at this directory
*/
public Long numItemsInTree()
throws StorageException, TransactionContextException {
return getINodeAttributes().getNsCount();
}
public Long diskspaceConsumed()
throws StorageException, TransactionContextException {
return getINodeAttributes().getDiskspace();
}
/**
* Update the size of the tree
*
* @param nsDelta
* the change of the tree size
* @param dsDelta
* change to disk space occupied
*/
void updateNumItemsInTree(Long nsDelta, Long dsDelta)
throws StorageException, TransactionContextException {
getINodeAttributes()
.setNsCount(getINodeAttributes().getNsCount() + nsDelta);
getINodeAttributes()
.setDiskspace(getINodeAttributes().getDiskspace() + dsDelta);
}
/**
* Update the size of the tree
*
* @param nsDelta
* the change of the tree size
* @param dsDelta
* change to disk space occupied
*/
void unprotectedUpdateNumItemsInTree(Long nsDelta, Long dsDelta)
throws StorageException, TransactionContextException {
getINodeAttributes()
.setNsCount(getINodeAttributes().getNsCount() + nsDelta);
getINodeAttributes()
.setDiskspace(getINodeAttributes().getDiskspace() + dsDelta);
}
/**
* Sets namespace and diskspace take by the directory rooted
* at this INode. This should be used carefully. It does not check
* for quota violations.
*
* @param namespace
* size of the directory to be set
* @param diskspace
* disk space take by all the nodes under this directory
*/
public void setSpaceConsumed(Long namespace, Long diskspace)
throws StorageException, TransactionContextException {
getINodeAttributes().setNsCount(namespace);
getINodeAttributes().setDiskspace(diskspace);
}
public void setSpaceConsumedNoPersistance(Long namespace, Long diskspace)
throws StorageException, TransactionContextException {
getINodeAttributes().setNsCountNoPersistance(namespace);
getINodeAttributes().setDiskspaceNoPersistance(diskspace);
}
/**
* Verify if the namespace count disk space satisfies the quota restriction
*
* @throws QuotaExceededException
* if the given quota is less than the count
*/
void verifyQuota(Long nsDelta, Long dsDelta)
throws QuotaExceededException, StorageException,
TransactionContextException {
Long newCount = getINodeAttributes().getNsCount() + nsDelta;
Long newDiskspace = getINodeAttributes().getDiskspace() + dsDelta;
if (nsDelta > 0 || dsDelta > 0) {
if (getINodeAttributes().getNsQuota() >= 0 &&
getINodeAttributes().getNsQuota() < newCount) {
throw new NSQuotaExceededException(getINodeAttributes().getNsQuota(),
newCount);
}
if (getINodeAttributes().getDsQuota() >= 0 &&
getINodeAttributes().getDsQuota() < newDiskspace) {
throw new DSQuotaExceededException(getINodeAttributes().getDsQuota(),
newDiskspace);
}
}
}
public static INodeDirectoryWithQuota createRootDir(
PermissionStatus permissions) throws IOException {
INodeDirectoryWithQuota newRootINode =
new INodeDirectoryWithQuota(ROOT_NAME, permissions);
newRootINode.setIdNoPersistance(ROOT_ID);
newRootINode.setParentIdNoPersistance(ROOT_PARENT_ID);
newRootINode.setPartitionIdNoPersistance(getRootDirPartitionKey());
return newRootINode;
}
public static INodeDirectoryWithQuota getRootDir()
throws StorageException, TransactionContextException {
INode inode = EntityManager
.find(INode.Finder.ByINodeIdFTIS, ROOT_ID);
return (INodeDirectoryWithQuota) inode;
}
public INodeAttributes getINodeAttributes()
throws StorageException, TransactionContextException {
return EntityManager.find(INodeAttributes.Finder.ByINodeId, id);
}
private void createINodeAttributes(Long nsQuota, Long nsCount, Long dsQuota,
Long diskspace) throws StorageException, TransactionContextException {
INodeAttributes attr =
new INodeAttributes(id, nsQuota, nsCount, dsQuota, diskspace);
EntityManager.add(attr);
}
protected void persistAttributes()
throws StorageException, TransactionContextException {
getINodeAttributes().saveAttributes();
}
protected void removeAttributes()
throws StorageException, TransactionContextException {
INodeAttributes attributes = getINodeAttributes();
if(attributes!=null){
attributes.removeAttributes();
}
}
protected void changeAttributesPkNoPersistance(Integer id)
throws StorageException, TransactionContextException {
getINodeAttributes().setInodeIdNoPersistance(id);
}
}