HDFS-11336: [SPS]: Remove xAttrs when movements done or SPS disabled. Contributed by Yuanbo Liu.
This commit is contained in:
parent
9b15f5418d
commit
c00be44463
|
@ -19,6 +19,7 @@ package org.apache.hadoop.hdfs.server.namenode;
|
||||||
|
|
||||||
import static org.apache.hadoop.util.Time.monotonicNow;
|
import static org.apache.hadoop.util.Time.monotonicNow;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -54,6 +55,7 @@ public class BlockStorageMovementAttemptedItems {
|
||||||
private final List<BlocksStorageMovementResult> storageMovementAttemptedResults;
|
private final List<BlocksStorageMovementResult> storageMovementAttemptedResults;
|
||||||
private volatile boolean monitorRunning = true;
|
private volatile boolean monitorRunning = true;
|
||||||
private Daemon timerThread = null;
|
private Daemon timerThread = null;
|
||||||
|
private final StoragePolicySatisfier sps;
|
||||||
//
|
//
|
||||||
// It might take anywhere between 30 to 60 minutes before
|
// It might take anywhere between 30 to 60 minutes before
|
||||||
// a request is timed out.
|
// a request is timed out.
|
||||||
|
@ -69,7 +71,8 @@ public class BlockStorageMovementAttemptedItems {
|
||||||
|
|
||||||
public BlockStorageMovementAttemptedItems(long recheckTimeout,
|
public BlockStorageMovementAttemptedItems(long recheckTimeout,
|
||||||
long selfRetryTimeout,
|
long selfRetryTimeout,
|
||||||
BlockStorageMovementNeeded unsatisfiedStorageMovementFiles) {
|
BlockStorageMovementNeeded unsatisfiedStorageMovementFiles,
|
||||||
|
StoragePolicySatisfier sps) {
|
||||||
if (recheckTimeout > 0) {
|
if (recheckTimeout > 0) {
|
||||||
this.minCheckTimeout = Math.min(minCheckTimeout, recheckTimeout);
|
this.minCheckTimeout = Math.min(minCheckTimeout, recheckTimeout);
|
||||||
}
|
}
|
||||||
|
@ -78,6 +81,7 @@ public class BlockStorageMovementAttemptedItems {
|
||||||
this.blockStorageMovementNeeded = unsatisfiedStorageMovementFiles;
|
this.blockStorageMovementNeeded = unsatisfiedStorageMovementFiles;
|
||||||
storageMovementAttemptedItems = new HashMap<>();
|
storageMovementAttemptedItems = new HashMap<>();
|
||||||
storageMovementAttemptedResults = new ArrayList<>();
|
storageMovementAttemptedResults = new ArrayList<>();
|
||||||
|
this.sps = sps;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -200,6 +204,9 @@ public class BlockStorageMovementAttemptedItems {
|
||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie) {
|
||||||
LOG.info("BlocksStorageMovementAttemptResultMonitor thread "
|
LOG.info("BlocksStorageMovementAttemptResultMonitor thread "
|
||||||
+ "is interrupted.", ie);
|
+ "is interrupted.", ie);
|
||||||
|
} catch (IOException ie) {
|
||||||
|
LOG.warn("BlocksStorageMovementAttemptResultMonitor thread "
|
||||||
|
+ "received exception and exiting.", ie);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,7 +255,7 @@ public class BlockStorageMovementAttemptedItems {
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void blockStorageMovementResultCheck() {
|
void blockStorageMovementResultCheck() throws IOException {
|
||||||
synchronized (storageMovementAttemptedResults) {
|
synchronized (storageMovementAttemptedResults) {
|
||||||
Iterator<BlocksStorageMovementResult> resultsIter =
|
Iterator<BlocksStorageMovementResult> resultsIter =
|
||||||
storageMovementAttemptedResults.iterator();
|
storageMovementAttemptedResults.iterator();
|
||||||
|
@ -296,6 +303,9 @@ public class BlockStorageMovementAttemptedItems {
|
||||||
+ " reported from co-ordinating datanode. But the trackID "
|
+ " reported from co-ordinating datanode. But the trackID "
|
||||||
+ "doesn't exists in storageMovementAttemptedItems list",
|
+ "doesn't exists in storageMovementAttemptedItems list",
|
||||||
storageMovementAttemptedResult.getTrackId());
|
storageMovementAttemptedResult.getTrackId());
|
||||||
|
// Remove xattr for the track id.
|
||||||
|
this.sps.notifyBlkStorageMovementFinished(
|
||||||
|
storageMovementAttemptedResult.getTrackId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Remove trackID from the attempted list, if any.
|
// Remove trackID from the attempted list, if any.
|
||||||
|
|
|
@ -534,6 +534,14 @@ public class FSDirAttrOp {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void unprotectedRemoveSPSXAttr(INode inode, XAttr spsXAttr)
|
||||||
|
throws IOException{
|
||||||
|
List<XAttr> existingXAttrs = XAttrStorage.readINodeXAttrs(inode);
|
||||||
|
existingXAttrs.remove(spsXAttr);
|
||||||
|
XAttrStorage.updateINodeXAttrs(inode, existingXAttrs,
|
||||||
|
INodesInPath.fromINode(inode).getLatestSnapshotId());
|
||||||
|
}
|
||||||
|
|
||||||
private static void setDirStoragePolicy(
|
private static void setDirStoragePolicy(
|
||||||
FSDirectory fsd, INodesInPath iip, byte policyId) throws IOException {
|
FSDirectory fsd, INodesInPath iip, byte policyId) throws IOException {
|
||||||
INode inode = FSDirectory.resolveLastINode(iip);
|
INode inode = FSDirectory.resolveLastINode(iip);
|
||||||
|
|
|
@ -1418,6 +1418,22 @@ public class FSDirectory implements Closeable {
|
||||||
getBlockManager().satisfyStoragePolicy(inode.getId());
|
getBlockManager().satisfyStoragePolicy(inode.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the SPS xattr from the inode, retrieve the inode from the
|
||||||
|
* block collection id.
|
||||||
|
* @param id
|
||||||
|
* - file block collection id.
|
||||||
|
*/
|
||||||
|
public void removeSPSXattr(long id) throws IOException {
|
||||||
|
final INode inode = getInode(id);
|
||||||
|
final XAttrFeature xaf = inode.getXAttrFeature();
|
||||||
|
final XAttr spsXAttr = xaf.getXAttr(XATTR_SATISFY_STORAGE_POLICY);
|
||||||
|
|
||||||
|
if (spsXAttr != null) {
|
||||||
|
FSDirAttrOp.unprotectedRemoveSPSXAttr(inode, spsXAttr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void addEncryptionZone(INodeWithAdditionalFields inode,
|
private void addEncryptionZone(INodeWithAdditionalFields inode,
|
||||||
XAttrFeature xaf) {
|
XAttrFeature xaf) {
|
||||||
if (xaf == null) {
|
if (xaf == null) {
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hadoop.hdfs.server.namenode;
|
package org.apache.hadoop.hdfs.server.namenode;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -91,7 +92,8 @@ public class StoragePolicySatisfier implements Runnable {
|
||||||
conf.getLong(
|
conf.getLong(
|
||||||
DFSConfigKeys.DFS_STORAGE_POLICY_SATISFIER_SELF_RETRY_TIMEOUT_MILLIS_KEY,
|
DFSConfigKeys.DFS_STORAGE_POLICY_SATISFIER_SELF_RETRY_TIMEOUT_MILLIS_KEY,
|
||||||
DFSConfigKeys.DFS_STORAGE_POLICY_SATISFIER_SELF_RETRY_TIMEOUT_MILLIS_DEFAULT),
|
DFSConfigKeys.DFS_STORAGE_POLICY_SATISFIER_SELF_RETRY_TIMEOUT_MILLIS_DEFAULT),
|
||||||
storageMovementNeeded);
|
storageMovementNeeded,
|
||||||
|
this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -119,12 +121,6 @@ public class StoragePolicySatisfier implements Runnable {
|
||||||
*/
|
*/
|
||||||
public synchronized void stop(boolean reconfigStop) {
|
public synchronized void stop(boolean reconfigStop) {
|
||||||
isRunning = false;
|
isRunning = false;
|
||||||
if (reconfigStop) {
|
|
||||||
LOG.info("Stopping StoragePolicySatisfier, as admin requested to "
|
|
||||||
+ "deactivate it.");
|
|
||||||
} else {
|
|
||||||
LOG.info("Stopping StoragePolicySatisfier.");
|
|
||||||
}
|
|
||||||
if (storagePolicySatisfierThread == null) {
|
if (storagePolicySatisfierThread == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -135,8 +131,12 @@ public class StoragePolicySatisfier implements Runnable {
|
||||||
}
|
}
|
||||||
this.storageMovementsMonitor.stop();
|
this.storageMovementsMonitor.stop();
|
||||||
if (reconfigStop) {
|
if (reconfigStop) {
|
||||||
this.clearQueues();
|
LOG.info("Stopping StoragePolicySatisfier, as admin requested to "
|
||||||
|
+ "deactivate it.");
|
||||||
|
this.clearQueuesWithNotification();
|
||||||
this.blockManager.getDatanodeManager().addDropSPSWorkCommandsToAllDNs();
|
this.blockManager.getDatanodeManager().addDropSPSWorkCommandsToAllDNs();
|
||||||
|
} else {
|
||||||
|
LOG.info("Stopping StoragePolicySatisfier.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -717,4 +717,33 @@ public class StoragePolicySatisfier implements Runnable {
|
||||||
+ "user requests on satisfying block storages would be discarded.");
|
+ "user requests on satisfying block storages would be discarded.");
|
||||||
storageMovementNeeded.clearAll();
|
storageMovementNeeded.clearAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean all the movements in storageMovementNeeded and notify
|
||||||
|
* to clean up required resources.
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private void clearQueuesWithNotification() {
|
||||||
|
Long id;
|
||||||
|
while ((id = storageMovementNeeded.get()) != null) {
|
||||||
|
try {
|
||||||
|
notifyBlkStorageMovementFinished(id);
|
||||||
|
} catch (IOException ie) {
|
||||||
|
LOG.warn("Failed to remove SPS "
|
||||||
|
+ "xattr for collection id " + id, ie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When block movement has been finished successfully, some additional
|
||||||
|
* operations should be notified, for example, SPS xattr should be
|
||||||
|
* removed.
|
||||||
|
* @param trackId track id i.e., block collection id.
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void notifyBlkStorageMovementFinished(long trackId)
|
||||||
|
throws IOException {
|
||||||
|
this.namesystem.getFSDirectory().removeSPSXattr(trackId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2454,6 +2454,6 @@ public class DFSTestUtil {
|
||||||
+ expectedStorageCount + " and actual=" + actualStorageCount);
|
+ expectedStorageCount + " and actual=" + actualStorageCount);
|
||||||
return expectedStorageCount == actualStorageCount;
|
return expectedStorageCount == actualStorageCount;
|
||||||
}
|
}
|
||||||
}, 1000, timeout);
|
}, 500, timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.apache.hadoop.hdfs.server.protocol.BlocksStorageMovementResult;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that block storage movement attempt failures are reported from DN and
|
* Tests that block storage movement attempt failures are reported from DN and
|
||||||
|
@ -36,10 +37,11 @@ public class TestBlockStorageMovementAttemptedItems {
|
||||||
private final int selfRetryTimeout = 500;
|
private final int selfRetryTimeout = 500;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() throws Exception {
|
||||||
unsatisfiedStorageMovementFiles = new BlockStorageMovementNeeded();
|
unsatisfiedStorageMovementFiles = new BlockStorageMovementNeeded();
|
||||||
|
StoragePolicySatisfier sps = Mockito.mock(StoragePolicySatisfier.class);
|
||||||
bsmAttemptedItems = new BlockStorageMovementAttemptedItems(100,
|
bsmAttemptedItems = new BlockStorageMovementAttemptedItems(100,
|
||||||
selfRetryTimeout, unsatisfiedStorageMovementFiles);
|
selfRetryTimeout, unsatisfiedStorageMovementFiles, sps);
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
|
@ -20,16 +20,22 @@ package org.apache.hadoop.hdfs.server.namenode;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.Path;
|
import org.apache.hadoop.fs.Path;
|
||||||
import org.apache.hadoop.fs.StorageType;
|
import org.apache.hadoop.fs.StorageType;
|
||||||
|
import org.apache.hadoop.fs.XAttr;
|
||||||
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
||||||
import org.apache.hadoop.hdfs.DFSTestUtil;
|
import org.apache.hadoop.hdfs.DFSTestUtil;
|
||||||
import org.apache.hadoop.hdfs.DistributedFileSystem;
|
import org.apache.hadoop.hdfs.DistributedFileSystem;
|
||||||
import org.apache.hadoop.hdfs.HdfsConfiguration;
|
import org.apache.hadoop.hdfs.HdfsConfiguration;
|
||||||
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
||||||
import org.apache.hadoop.hdfs.MiniDFSNNTopology;
|
import org.apache.hadoop.hdfs.MiniDFSNNTopology;
|
||||||
|
import org.apache.hadoop.hdfs.XAttrHelper;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.ha.HATestUtil;
|
import org.apache.hadoop.hdfs.server.namenode.ha.HATestUtil;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.apache.hadoop.hdfs.server.common.HdfsServerConstants.XATTR_SATISFY_STORAGE_POLICY;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test persistence of satisfying files/directories.
|
* Test persistence of satisfying files/directories.
|
||||||
|
@ -72,7 +78,16 @@ public class TestPersistentStoragePolicySatisfier {
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public void clusterSetUp() throws Exception {
|
public void clusterSetUp() throws Exception {
|
||||||
clusterSetUp(false);
|
clusterSetUp(false, new HdfsConfiguration());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup environment for every test case.
|
||||||
|
* @param hdfsConf hdfs conf.
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public void clusterSetUp(Configuration hdfsConf) throws Exception {
|
||||||
|
clusterSetUp(false, hdfsConf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,8 +95,9 @@ public class TestPersistentStoragePolicySatisfier {
|
||||||
* @param isHAEnabled if true, enable simple HA.
|
* @param isHAEnabled if true, enable simple HA.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private void clusterSetUp(boolean isHAEnabled) throws Exception {
|
private void clusterSetUp(boolean isHAEnabled, Configuration newConf)
|
||||||
conf = new HdfsConfiguration();
|
throws Exception {
|
||||||
|
conf = newConf;
|
||||||
final int dnNumber = storageTypes.length;
|
final int dnNumber = storageTypes.length;
|
||||||
final short replication = 3;
|
final short replication = 3;
|
||||||
MiniDFSCluster.Builder clusterBuilder = new MiniDFSCluster.Builder(conf)
|
MiniDFSCluster.Builder clusterBuilder = new MiniDFSCluster.Builder(conf)
|
||||||
|
@ -188,7 +204,7 @@ public class TestPersistentStoragePolicySatisfier {
|
||||||
public void testWithHA() throws Exception {
|
public void testWithHA() throws Exception {
|
||||||
try {
|
try {
|
||||||
// Enable HA env for testing.
|
// Enable HA env for testing.
|
||||||
clusterSetUp(true);
|
clusterSetUp(true, new HdfsConfiguration());
|
||||||
|
|
||||||
fs.setStoragePolicy(testFile, ALL_SSD);
|
fs.setStoragePolicy(testFile, ALL_SSD);
|
||||||
fs.satisfyStoragePolicy(testFile);
|
fs.satisfyStoragePolicy(testFile);
|
||||||
|
@ -297,6 +313,94 @@ public class TestPersistentStoragePolicySatisfier {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests to verify SPS xattr will be removed if the satisfy work has
|
||||||
|
* been finished, expect that the method satisfyStoragePolicy can be
|
||||||
|
* invoked on the same file again after the block movement has been
|
||||||
|
* finished:
|
||||||
|
* 1. satisfy storage policy of file1.
|
||||||
|
* 2. wait until storage policy is satisfied.
|
||||||
|
* 3. satisfy storage policy of file1 again
|
||||||
|
* 4. make sure step 3 works as expected.
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Test(timeout = 300000)
|
||||||
|
public void testMultipleSatisfyStoragePolicy() throws Exception {
|
||||||
|
try {
|
||||||
|
// Lower block movement check for testing.
|
||||||
|
conf = new HdfsConfiguration();
|
||||||
|
final long minCheckTimeout = 500; // minimum value
|
||||||
|
conf.setLong(
|
||||||
|
DFSConfigKeys.DFS_STORAGE_POLICY_SATISFIER_RECHECK_TIMEOUT_MILLIS_KEY,
|
||||||
|
minCheckTimeout);
|
||||||
|
clusterSetUp(conf);
|
||||||
|
fs.setStoragePolicy(testFile, ONE_SSD);
|
||||||
|
fs.satisfyStoragePolicy(testFile);
|
||||||
|
DFSTestUtil.waitExpectedStorageType(
|
||||||
|
testFileName, StorageType.SSD, 1, timeout, fs);
|
||||||
|
DFSTestUtil.waitExpectedStorageType(
|
||||||
|
testFileName, StorageType.DISK, 2, timeout, fs);
|
||||||
|
|
||||||
|
// Make sure that SPS xattr has been removed.
|
||||||
|
int retryTime = 0;
|
||||||
|
while (retryTime < 30) {
|
||||||
|
if (!fileContainsSPSXAttr(testFile)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Thread.sleep(minCheckTimeout);
|
||||||
|
retryTime += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.setStoragePolicy(testFile, COLD);
|
||||||
|
fs.satisfyStoragePolicy(testFile);
|
||||||
|
DFSTestUtil.waitExpectedStorageType(
|
||||||
|
testFileName, StorageType.ARCHIVE, 3, timeout, fs);
|
||||||
|
} finally {
|
||||||
|
clusterShutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests to verify SPS xattr is removed after SPS is dropped,
|
||||||
|
* expect that if the SPS is disabled/dropped, the SPS
|
||||||
|
* xattr should be removed accordingly:
|
||||||
|
* 1. satisfy storage policy of file1.
|
||||||
|
* 2. drop SPS thread in block manager.
|
||||||
|
* 3. make sure sps xattr is removed.
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Test(timeout = 300000)
|
||||||
|
public void testDropSPS() throws Exception {
|
||||||
|
try {
|
||||||
|
clusterSetUp();
|
||||||
|
fs.setStoragePolicy(testFile, ONE_SSD);
|
||||||
|
fs.satisfyStoragePolicy(testFile);
|
||||||
|
|
||||||
|
cluster.getNamesystem().getBlockManager().deactivateSPS();
|
||||||
|
|
||||||
|
// Make sure satisfy xattr has been removed.
|
||||||
|
assertFalse(fileContainsSPSXAttr(testFile));
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
clusterShutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether file contains SPS xattr.
|
||||||
|
* @param fileName file name.
|
||||||
|
* @return true if file contains SPS xattr.
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private boolean fileContainsSPSXAttr(Path fileName) throws IOException {
|
||||||
|
final INode inode = cluster.getNamesystem()
|
||||||
|
.getFSDirectory().getINode(fileName.toString());
|
||||||
|
final XAttr satisfyXAttr =
|
||||||
|
XAttrHelper.buildXAttr(XATTR_SATISFY_STORAGE_POLICY);
|
||||||
|
List<XAttr> existingXAttrs = XAttrStorage.readINodeXAttrs(inode);
|
||||||
|
return existingXAttrs.contains(satisfyXAttr);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Restart the hole env and trigger the DataNode's heart beats.
|
* Restart the hole env and trigger the DataNode's heart beats.
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
|
|
Loading…
Reference in New Issue