You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by br...@apache.org on 2011/10/04 23:20:41 UTC
svn commit: r1178957 - in /cassandra/branches: cassandra-0.8/CHANGES.txt
cassandra-0.8/src/java/org/apache/cassandra/tools/NodeCmd.java
cassandra-1.0.0/CHANGES.txt
cassandra-1.0.0/src/java/org/apache/cassandra/tools/NodeCmd.java
Author: brandonwilliams
Date: Tue Oct 4 21:20:41 2011
New Revision: 1178957
URL: http://svn.apache.org/viewvc?rev=1178957&view=rev
Log:
Nodetool closes JMX connections to avoid leaking timer threads.
Patch by vijay, reviewed by brandonwilliams for CASSANDRA-3309
Modified:
cassandra/branches/cassandra-0.8/CHANGES.txt
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/tools/NodeCmd.java
cassandra/branches/cassandra-1.0.0/CHANGES.txt
cassandra/branches/cassandra-1.0.0/src/java/org/apache/cassandra/tools/NodeCmd.java
Modified: cassandra/branches/cassandra-0.8/CHANGES.txt
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/CHANGES.txt?rev=1178957&r1=1178956&r2=1178957&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/CHANGES.txt (original)
+++ cassandra/branches/cassandra-0.8/CHANGES.txt Tue Oct 4 21:20:41 2011
@@ -21,6 +21,7 @@
* Fix bug where the failure detector can take too long to mark a host
down (CASSANDRA-3273)
* Fix stress COUNTER_GET option (CASSANDRA-3301)
+ * Nodetool no longer leaks threads and closes JMX connections (CASSANDRA-3309)
0.8.6
Modified: cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/tools/NodeCmd.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/tools/NodeCmd.java?rev=1178957&r1=1178956&r2=1178957&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/tools/NodeCmd.java (original)
+++ cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/tools/NodeCmd.java Tue Oct 4 21:20:41 2011
@@ -585,132 +585,145 @@ public class NodeCmd
{
err(ioe, "Error connection to remote JMX agent!");
}
-
- NodeCommand command = null;
-
try
{
- command = cmd.getCommand();
- }
- catch (IllegalArgumentException e)
- {
- badUse(e.getMessage());
- }
-
+ NodeCommand command = null;
- NodeCmd nodeCmd = new NodeCmd(probe);
-
- // Execute the requested command.
- String[] arguments = cmd.getCommandArguments();
+ try
+ {
+ command = cmd.getCommand();
+ }
+ catch (IllegalArgumentException e)
+ {
+ badUse(e.getMessage());
+ }
- switch (command)
- {
- case RING : nodeCmd.printRing(System.out); break;
- case INFO : nodeCmd.printInfo(System.out); break;
- case CFSTATS : nodeCmd.printColumnFamilyStats(System.out); break;
- case DECOMMISSION : probe.decommission(); break;
- case TPSTATS : nodeCmd.printThreadPoolStats(System.out); break;
- case VERSION : nodeCmd.printReleaseVersion(System.out); break;
- case COMPACTIONSTATS : nodeCmd.printCompactionStats(System.out); break;
- case DISABLEGOSSIP : probe.stopGossiping(); break;
- case ENABLEGOSSIP : probe.startGossiping(); break;
- case DISABLETHRIFT : probe.stopThriftServer(); break;
- case ENABLETHRIFT : probe.startThriftServer(); break;
- case STATUSTHRIFT : nodeCmd.printIsThriftServerRunning(System.out); break;
- case DRAIN :
- try { probe.drain(); }
- catch (ExecutionException ee) { err(ee, "Error occured during flushing"); }
- break;
+ NodeCmd nodeCmd = new NodeCmd(probe);
- case NETSTATS :
- if (arguments.length > 0) { nodeCmd.printNetworkStats(InetAddress.getByName(arguments[0]), System.out); }
- else { nodeCmd.printNetworkStats(null, System.out); }
- break;
+ // Execute the requested command.
+ String[] arguments = cmd.getCommandArguments();
- case SNAPSHOT :
- case CLEARSNAPSHOT :
- String tag = cmd.getOptionValue(TAG_OPT.left);
- handleSnapshots(command, tag, arguments, probe);
- break;
+ switch (command)
+ {
+ case RING : nodeCmd.printRing(System.out); break;
+ case INFO : nodeCmd.printInfo(System.out); break;
+ case CFSTATS : nodeCmd.printColumnFamilyStats(System.out); break;
+ case DECOMMISSION : probe.decommission(); break;
+ case TPSTATS : nodeCmd.printThreadPoolStats(System.out); break;
+ case VERSION : nodeCmd.printReleaseVersion(System.out); break;
+ case COMPACTIONSTATS : nodeCmd.printCompactionStats(System.out); break;
+ case DISABLEGOSSIP : probe.stopGossiping(); break;
+ case ENABLEGOSSIP : probe.startGossiping(); break;
+ case DISABLETHRIFT : probe.stopThriftServer(); break;
+ case ENABLETHRIFT : probe.startThriftServer(); break;
+ case STATUSTHRIFT : nodeCmd.printIsThriftServerRunning(System.out); break;
+
+ case DRAIN :
+ try { probe.drain(); }
+ catch (ExecutionException ee) { err(ee, "Error occured during flushing"); }
+ break;
- case MOVE :
- if (arguments.length != 1) { badUse("Missing token argument for move."); }
- probe.move(arguments[0]);
- break;
+ case NETSTATS :
+ if (arguments.length > 0) { nodeCmd.printNetworkStats(InetAddress.getByName(arguments[0]), System.out); }
+ else { nodeCmd.printNetworkStats(null, System.out); }
+ break;
- case JOIN:
- if (probe.isJoined())
- {
- System.err.println("This node has already joined the ring.");
- System.exit(1);
- }
+ case SNAPSHOT :
+ case CLEARSNAPSHOT :
+ String tag = cmd.getOptionValue(TAG_OPT.left);
+ handleSnapshots(command, tag, arguments, probe);
+ break;
- probe.joinRing();
- break;
+ case MOVE :
+ if (arguments.length != 1) { badUse("Missing token argument for move."); }
+ probe.move(arguments[0]);
+ break;
- case SETCOMPACTIONTHROUGHPUT :
- if (arguments.length != 1) { badUse("Missing value argument."); }
- probe.setCompactionThroughput(Integer.valueOf(arguments[0]));
- break;
+ case JOIN:
+ if (probe.isJoined())
+ {
+ System.err.println("This node has already joined the ring.");
+ System.exit(1);
+ }
- case REMOVETOKEN :
- if (arguments.length != 1) { badUse("Missing an argument for removetoken (either status, force, or a token)"); }
- else if (arguments[0].equals("status")) { nodeCmd.printRemovalStatus(System.out); }
- else if (arguments[0].equals("force")) { nodeCmd.printRemovalStatus(System.out); probe.forceRemoveCompletion(); }
- else { probe.removeToken(arguments[0]); }
- break;
+ probe.joinRing();
+ break;
- case CLEANUP :
- case COMPACT :
- case REPAIR :
- case FLUSH :
- case SCRUB :
- case INVALIDATEKEYCACHE :
- case INVALIDATEROWCACHE :
- optionalKSandCFs(command, arguments, probe);
- break;
+ case SETCOMPACTIONTHROUGHPUT :
+ if (arguments.length != 1) { badUse("Missing value argument."); }
+ probe.setCompactionThroughput(Integer.valueOf(arguments[0]));
+ break;
- case GETCOMPACTIONTHRESHOLD :
- if (arguments.length != 2) { badUse("getcompactionthreshold requires ks and cf args."); }
- probe.getCompactionThreshold(System.out, arguments[0], arguments[1]);
- break;
+ case REMOVETOKEN :
+ if (arguments.length != 1) { badUse("Missing an argument for removetoken (either status, force, or a token)"); }
+ else if (arguments[0].equals("status")) { nodeCmd.printRemovalStatus(System.out); }
+ else if (arguments[0].equals("force")) { nodeCmd.printRemovalStatus(System.out); probe.forceRemoveCompletion(); }
+ else { probe.removeToken(arguments[0]); }
+ break;
- case CFHISTOGRAMS :
- if (arguments.length != 2) { badUse("cfhistograms requires ks and cf args"); }
- nodeCmd.printCfHistograms(arguments[0], arguments[1], System.out);
- break;
+ case CLEANUP :
+ case COMPACT :
+ case REPAIR :
+ case FLUSH :
+ case SCRUB :
+ case INVALIDATEKEYCACHE :
+ case INVALIDATEROWCACHE :
+ optionalKSandCFs(command, arguments, probe);
+ break;
- case SETCACHECAPACITY :
- if (arguments.length != 4) { badUse("setcachecapacity requires ks, cf, keycachecap, and rowcachecap args."); }
- probe.setCacheCapacities(arguments[0], arguments[1], Integer.parseInt(arguments[2]), Integer.parseInt(arguments[3]));
- break;
+ case GETCOMPACTIONTHRESHOLD :
+ if (arguments.length != 2) { badUse("getcompactionthreshold requires ks and cf args."); }
+ probe.getCompactionThreshold(System.out, arguments[0], arguments[1]);
+ break;
- case SETCOMPACTIONTHRESHOLD :
- if (arguments.length != 4) { badUse("setcompactionthreshold requires ks, cf, min, and max threshold args."); }
- int minthreshold = Integer.parseInt(arguments[2]);
- int maxthreshold = Integer.parseInt(arguments[3]);
- if ((minthreshold < 0) || (maxthreshold < 0)) { badUse("Thresholds must be positive integers"); }
- if (minthreshold > maxthreshold) { badUse("Min threshold cannot be greater than max."); }
- if (minthreshold < 2 && maxthreshold != 0) { badUse("Min threshold must be at least 2"); }
- probe.setCompactionThreshold(arguments[0], arguments[1], minthreshold, maxthreshold);
- break;
+ case CFHISTOGRAMS :
+ if (arguments.length != 2) { badUse("cfhistograms requires ks and cf args"); }
+ nodeCmd.printCfHistograms(arguments[0], arguments[1], System.out);
+ break;
- case GETENDPOINTS :
- if (arguments.length != 3) { badUse("getendpoints requires ks, cf and key args"); }
- nodeCmd.printEndPoints(arguments[0], arguments[1], arguments[2], System.out);
- break;
+ case SETCACHECAPACITY :
+ if (arguments.length != 4) { badUse("setcachecapacity requires ks, cf, keycachecap, and rowcachecap args."); }
+ probe.setCacheCapacities(arguments[0], arguments[1], Integer.parseInt(arguments[2]), Integer.parseInt(arguments[3]));
+ break;
- case REFRESH:
- if (arguments.length != 2) { badUse("load_new_sstables requires ks and cf args"); }
- probe.loadNewSSTables(arguments[0], arguments[1]);
- break;
+ case SETCOMPACTIONTHRESHOLD :
+ if (arguments.length != 4) { badUse("setcompactionthreshold requires ks, cf, min, and max threshold args."); }
+ int minthreshold = Integer.parseInt(arguments[2]);
+ int maxthreshold = Integer.parseInt(arguments[3]);
+ if ((minthreshold < 0) || (maxthreshold < 0)) { badUse("Thresholds must be positive integers"); }
+ if (minthreshold > maxthreshold) { badUse("Min threshold cannot be greater than max."); }
+ if (minthreshold < 2 && maxthreshold != 0) { badUse("Min threshold must be at least 2"); }
+ probe.setCompactionThreshold(arguments[0], arguments[1], minthreshold, maxthreshold);
+ break;
- default :
- throw new RuntimeException("Unreachable code.");
+ case GETENDPOINTS :
+ if (arguments.length != 3) { badUse("getendpoints requires ks, cf and key args"); }
+ nodeCmd.printEndPoints(arguments[0], arguments[1], arguments[2], System.out);
+ break;
+ case REFRESH:
+ if (arguments.length != 2) { badUse("load_new_sstables requires ks and cf args"); }
+ probe.loadNewSSTables(arguments[0], arguments[1]);
+ break;
+ default :
+ throw new RuntimeException("Unreachable code.");
+ }
+ }
+ finally
+ {
+ if (probe != null)
+ {
+ try
+ {
+ probe.close();
+ }
+ catch (IOException ex)
+ {
+ // swallow the exception so the user will see the real one.
+ }
+ }
}
-
System.exit(0);
}
Modified: cassandra/branches/cassandra-1.0.0/CHANGES.txt
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-1.0.0/CHANGES.txt?rev=1178957&r1=1178956&r2=1178957&view=diff
==============================================================================
--- cassandra/branches/cassandra-1.0.0/CHANGES.txt (original)
+++ cassandra/branches/cassandra-1.0.0/CHANGES.txt Tue Oct 4 21:20:41 2011
@@ -15,6 +15,7 @@
(CASSANDRA-3295)
* Fix missing fields in CLI `show schema` output (CASSANDRA-3304)
* Fix broken CompressedRandomAccessReaderTest (CASSANDRA-3298)
+ * Nodetool no longer leaks threads and closes JMX connections (CASSANDRA-3309)
1.0.0-rc2
* Log a meaningful warning when a node receives a message for a repair session
Modified: cassandra/branches/cassandra-1.0.0/src/java/org/apache/cassandra/tools/NodeCmd.java
URL: http://svn.apache.org/viewvc/cassandra/branches/cassandra-1.0.0/src/java/org/apache/cassandra/tools/NodeCmd.java?rev=1178957&r1=1178956&r2=1178957&view=diff
==============================================================================
--- cassandra/branches/cassandra-1.0.0/src/java/org/apache/cassandra/tools/NodeCmd.java (original)
+++ cassandra/branches/cassandra-1.0.0/src/java/org/apache/cassandra/tools/NodeCmd.java Tue Oct 4 21:20:41 2011
@@ -588,134 +588,148 @@ public class NodeCmd
{
err(ioe, "Error connection to remote JMX agent!");
}
-
- NodeCommand command = null;
-
try
{
- command = cmd.getCommand();
- }
- catch (IllegalArgumentException e)
- {
- badUse(e.getMessage());
- }
-
+ NodeCommand command = null;
- NodeCmd nodeCmd = new NodeCmd(probe);
+ try
+ {
+ command = cmd.getCommand();
+ }
+ catch (IllegalArgumentException e)
+ {
+ badUse(e.getMessage());
+ }
- // Execute the requested command.
- String[] arguments = cmd.getCommandArguments();
- switch (command)
- {
- case RING : nodeCmd.printRing(System.out); break;
- case INFO : nodeCmd.printInfo(System.out); break;
- case CFSTATS : nodeCmd.printColumnFamilyStats(System.out); break;
- case DECOMMISSION : probe.decommission(); break;
- case TPSTATS : nodeCmd.printThreadPoolStats(System.out); break;
- case VERSION : nodeCmd.printReleaseVersion(System.out); break;
- case COMPACTIONSTATS : nodeCmd.printCompactionStats(System.out); break;
- case DISABLEGOSSIP : probe.stopGossiping(); break;
- case ENABLEGOSSIP : probe.startGossiping(); break;
- case DISABLETHRIFT : probe.stopThriftServer(); break;
- case ENABLETHRIFT : probe.startThriftServer(); break;
- case STATUSTHRIFT : nodeCmd.printIsThriftServerRunning(System.out); break;
+ NodeCmd nodeCmd = new NodeCmd(probe);
- case DRAIN :
- try { probe.drain(); }
- catch (ExecutionException ee) { err(ee, "Error occured during flushing"); }
- break;
+ // Execute the requested command.
+ String[] arguments = cmd.getCommandArguments();
- case NETSTATS :
- if (arguments.length > 0) { nodeCmd.printNetworkStats(InetAddress.getByName(arguments[0]), System.out); }
- else { nodeCmd.printNetworkStats(null, System.out); }
- break;
+ switch (command)
+ {
+ case RING : nodeCmd.printRing(System.out); break;
+ case INFO : nodeCmd.printInfo(System.out); break;
+ case CFSTATS : nodeCmd.printColumnFamilyStats(System.out); break;
+ case DECOMMISSION : probe.decommission(); break;
+ case TPSTATS : nodeCmd.printThreadPoolStats(System.out); break;
+ case VERSION : nodeCmd.printReleaseVersion(System.out); break;
+ case COMPACTIONSTATS : nodeCmd.printCompactionStats(System.out); break;
+ case DISABLEGOSSIP : probe.stopGossiping(); break;
+ case ENABLEGOSSIP : probe.startGossiping(); break;
+ case DISABLETHRIFT : probe.stopThriftServer(); break;
+ case ENABLETHRIFT : probe.startThriftServer(); break;
+ case STATUSTHRIFT : nodeCmd.printIsThriftServerRunning(System.out); break;
+
+ case DRAIN :
+ try { probe.drain(); }
+ catch (ExecutionException ee) { err(ee, "Error occured during flushing"); }
+ break;
- case SNAPSHOT :
- case CLEARSNAPSHOT :
- String tag = cmd.getOptionValue(TAG_OPT.left);
- handleSnapshots(command, tag, arguments, probe);
- break;
+ case NETSTATS :
+ if (arguments.length > 0) { nodeCmd.printNetworkStats(InetAddress.getByName(arguments[0]), System.out); }
+ else { nodeCmd.printNetworkStats(null, System.out); }
+ break;
- case MOVE :
- if (arguments.length != 1) { badUse("Missing token argument for move."); }
- probe.move(arguments[0]);
- break;
+ case SNAPSHOT :
+ case CLEARSNAPSHOT :
+ String tag = cmd.getOptionValue(TAG_OPT.left);
+ handleSnapshots(command, tag, arguments, probe);
+ break;
- case JOIN:
- if (probe.isJoined())
- {
- System.err.println("This node has already joined the ring.");
- System.exit(1);
- }
+ case MOVE :
+ if (arguments.length != 1) { badUse("Missing token argument for move."); }
+ probe.move(arguments[0]);
+ break;
- probe.joinRing();
- break;
+ case JOIN:
+ if (probe.isJoined())
+ {
+ System.err.println("This node has already joined the ring.");
+ System.exit(1);
+ }
- case SETCOMPACTIONTHROUGHPUT :
- if (arguments.length != 1) { badUse("Missing value argument."); }
- probe.setCompactionThroughput(Integer.valueOf(arguments[0]));
- break;
+ probe.joinRing();
+ break;
- case REMOVETOKEN :
- if (arguments.length != 1) { badUse("Missing an argument for removetoken (either status, force, or a token)"); }
- else if (arguments[0].equals("status")) { nodeCmd.printRemovalStatus(System.out); }
- else if (arguments[0].equals("force")) { nodeCmd.printRemovalStatus(System.out); probe.forceRemoveCompletion(); }
- else { probe.removeToken(arguments[0]); }
- break;
+ case SETCOMPACTIONTHROUGHPUT :
+ if (arguments.length != 1) { badUse("Missing value argument."); }
+ probe.setCompactionThroughput(Integer.valueOf(arguments[0]));
+ break;
- case CLEANUP :
- case COMPACT :
- case REPAIR :
- case FLUSH :
- case SCRUB :
- case INVALIDATEKEYCACHE :
- case INVALIDATEROWCACHE :
- optionalKSandCFs(command, cmd, arguments, probe);
- break;
+ case REMOVETOKEN :
+ if (arguments.length != 1) { badUse("Missing an argument for removetoken (either status, force, or a token)"); }
+ else if (arguments[0].equals("status")) { nodeCmd.printRemovalStatus(System.out); }
+ else if (arguments[0].equals("force")) { nodeCmd.printRemovalStatus(System.out); probe.forceRemoveCompletion(); }
+ else { probe.removeToken(arguments[0]); }
+ break;
- case GETCOMPACTIONTHRESHOLD :
- if (arguments.length != 2) { badUse("getcompactionthreshold requires ks and cf args."); }
- probe.getCompactionThreshold(System.out, arguments[0], arguments[1]);
- break;
+ case CLEANUP :
+ case COMPACT :
+ case REPAIR :
+ case FLUSH :
+ case SCRUB :
+ case INVALIDATEKEYCACHE :
+ case INVALIDATEROWCACHE :
+ optionalKSandCFs(command, cmd, arguments, probe);
+ break;
- case CFHISTOGRAMS :
- if (arguments.length != 2) { badUse("cfhistograms requires ks and cf args"); }
- nodeCmd.printCfHistograms(arguments[0], arguments[1], System.out);
- break;
+ case GETCOMPACTIONTHRESHOLD :
+ if (arguments.length != 2) { badUse("getcompactionthreshold requires ks and cf args."); }
+ probe.getCompactionThreshold(System.out, arguments[0], arguments[1]);
+ break;
- case SETCACHECAPACITY :
- if (arguments.length != 4) { badUse("setcachecapacity requires ks, cf, keycachecap, and rowcachecap args."); }
- probe.setCacheCapacities(arguments[0], arguments[1], Integer.parseInt(arguments[2]), Integer.parseInt(arguments[3]));
- break;
+ case CFHISTOGRAMS :
+ if (arguments.length != 2) { badUse("cfhistograms requires ks and cf args"); }
+ nodeCmd.printCfHistograms(arguments[0], arguments[1], System.out);
+ break;
- case SETCOMPACTIONTHRESHOLD :
- if (arguments.length != 4) { badUse("setcompactionthreshold requires ks, cf, min, and max threshold args."); }
- int minthreshold = Integer.parseInt(arguments[2]);
- int maxthreshold = Integer.parseInt(arguments[3]);
- if ((minthreshold < 0) || (maxthreshold < 0)) { badUse("Thresholds must be positive integers"); }
- if (minthreshold > maxthreshold) { badUse("Min threshold cannot be greater than max."); }
- if (minthreshold < 2 && maxthreshold != 0) { badUse("Min threshold must be at least 2"); }
- probe.setCompactionThreshold(arguments[0], arguments[1], minthreshold, maxthreshold);
- break;
+ case SETCACHECAPACITY :
+ if (arguments.length != 4) { badUse("setcachecapacity requires ks, cf, keycachecap, and rowcachecap args."); }
+ probe.setCacheCapacities(arguments[0], arguments[1], Integer.parseInt(arguments[2]), Integer.parseInt(arguments[3]));
+ break;
- case GETENDPOINTS :
- if (arguments.length != 3) { badUse("getendpoints requires ks, cf and key args"); }
- nodeCmd.printEndPoints(arguments[0], arguments[1], arguments[2], System.out);
- break;
+ case SETCOMPACTIONTHRESHOLD :
+ if (arguments.length != 4) { badUse("setcompactionthreshold requires ks, cf, min, and max threshold args."); }
+ int minthreshold = Integer.parseInt(arguments[2]);
+ int maxthreshold = Integer.parseInt(arguments[3]);
+ if ((minthreshold < 0) || (maxthreshold < 0)) { badUse("Thresholds must be positive integers"); }
+ if (minthreshold > maxthreshold) { badUse("Min threshold cannot be greater than max."); }
+ if (minthreshold < 2 && maxthreshold != 0) { badUse("Min threshold must be at least 2"); }
+ probe.setCompactionThreshold(arguments[0], arguments[1], minthreshold, maxthreshold);
+ break;
- case REFRESH:
- if (arguments.length != 2) { badUse("load_new_sstables requires ks and cf args"); }
- probe.loadNewSSTables(arguments[0], arguments[1]);
- break;
+ case GETENDPOINTS :
+ if (arguments.length != 3) { badUse("getendpoints requires ks, cf and key args"); }
+ nodeCmd.printEndPoints(arguments[0], arguments[1], arguments[2], System.out);
+ break;
- case GOSSIPINFO : nodeCmd.printGossipInfo(System.out); break;
+ case REFRESH:
+ if (arguments.length != 2) { badUse("load_new_sstables requires ks and cf args"); }
+ probe.loadNewSSTables(arguments[0], arguments[1]);
+ break;
- default :
- throw new RuntimeException("Unreachable code.");
+ case GOSSIPINFO : nodeCmd.printGossipInfo(System.out); break;
+ default :
+ throw new RuntimeException("Unreachable code.");
+ }
+ }
+ finally
+ {
+ if (probe != null)
+ {
+ try
+ {
+ probe.close();
+ }
+ catch (IOException ex)
+ {
+ // swallow the exception so the user will see the real one.
+ }
+ }
}
-
System.exit(0);
}