001// 002// Name 003// $RCSfile: Partition.java,v $ 004// 005// Copyright 006// Copyright 2010-2015 Cloud Software Group, Inc. ALL RIGHTS RESERVED. 007// Cloud Software Group, Inc. Confidential Information 008// 009// History 010// $Revision: 1.1.2.30.2.1 $ $Date: 2015/08/05 20:33:21 $ 011// 012package com.kabira.platform.highavailability; 013 014import com.kabira.platform.ResourceUnavailableException; 015import com.kabira.platform.disteng.DEPartitionManager; 016import com.kabira.platform.disteng.DENodeMismatch; 017import com.kabira.platform.disteng.DEReplicationType; 018import com.kabira.platform.disteng.DEProperties; 019import com.kabira.platform.disteng.DEPartitionStats; 020import com.kabira.platform.disteng.DESparsePartitionAudit; 021import com.kabira.platform.disteng.DEReplicaAudit; 022import com.kabira.platform.disteng.DERemoteEnableAction; 023import com.kabira.platform.disteng.DEPartitionBroadcast; 024import java.util.Date; 025 026/** 027 * The Partition class. This non-managed class contains a snapshot of a 028 * shared memory partition. Direct access to the Partition instance in 029 * shared memory is not allowed to avoid transaction locking issues. 030 * <p> 031 * Note that partitions are only visible on their active and replica 032 * nodes, not all nodes in the cluster. 033 */ 034public final class Partition 035{ 036 /** 037 * The Partition states 038 */ 039 public enum State 040 { 041 /** The partition has been defined, but not enabled */ 042 INITIAL, 043 /** The partition is active */ 044 ACTIVE, 045 /** 046 * The partition definition is being updated. Entered when 047 * partition membership (i.e. the objects associated with the 048 * partition) is being updated to split or merge partitions. 049 */ 050 UPDATING, 051 /** 052 * The partition owner is being updated. Each object in the 053 * partition is sent to the new owner and the location definition 054 * of all instances are updated. 055 */ 056 MIGRATING, 057 /** 058 * The partition replicas are being updated. Each object in the 059 * partition is sent to the new replica list. 060 */ 061 REPLICATING, 062 /** 063 * The partition is not active because all associated nodes have 064 * failed, the node was taken off-line because it is in a 065 * non-quorum state, or the node was restarted. 066 */ 067 UNAVAILABLE 068 } 069 070 /** 071 * The Partition status 072 */ 073 public enum Status 074 { 075 /** The partition has been disabled */ 076 LOCAL_DISABLED, 077 /** The partition has been defined, but not enabled */ 078 LOCAL_DEFINED, 079 /** The partition has been defined and enabled. */ 080 LOCAL_ENABLED, 081 /** The partition has been defined remotely. */ 082 REMOTE_DEFINED, 083 /** 084 * The partition has been defined and enabled on a remote node 085 * but not defined on this node. 086 */ 087 REMOTE_ENABLED 088 } 089 090 /** 091 * The Partition properties used when defining a partition 092 */ 093 public final static class Properties 094 { 095 /** 096 * An enumeration of the possible audits that can be taken when 097 * enabling a sparse Partition. 098 * <p> 099 * A sparse Partition is a partition that doesn't have the local 100 * node as the active node, or in the replica node list. When 101 * enabled, no data migration takes place; instead the node list 102 * is verified against the node list that is present on the 103 * active node to verify they match. 104 * <p> 105 * When restoring multiple nodes, it may be necessary to disable 106 * the auditing of node lists, since the active node may have a 107 * node list that is the result of a previous failover. 108 * <p> 109 * The default audit is defined by {@link #DefaultSparseAudit}, 110 */ 111 public enum SparseAudit 112 { 113 /** 114 * Verify that the defined node list matches the active node's 115 * node list. 116 */ 117 VERIFY_NODE_LIST, 118 /** 119 * Do not perform any verification of node lists. 120 */ 121 IGNORE_NODE_LIST 122 } 123 124 /** 125 * An enumeration of the possible audits done for each replica when 126 * enabling a Partition. 127 * <p> 128 * The default audit is defined by {@link #DefaultReplicaAudit}, 129 */ 130 public enum ReplicaAudit 131 { 132 /** 133 * Block until all replica nodes are active. The runtime will 134 * wait until each replica node is active before enabling the 135 * partition. If the wait times out, a ResourceUnavailableException 136 * exception is thrown. 137 */ 138 WAIT_ACTIVE, 139 /** 140 * Discard the replica if not active. If the replica node state 141 * is not Active, the replica node is removed from the node list, 142 * and a log message is generated. 143 */ 144 DISCARD_REPLICA, 145 /** 146 * The replica node state is ignored. 147 */ 148 @Deprecated 149 IGNORE_REPLICA 150 } 151 152 /** 153 * An enumeration of the possible actions to be taken when a remote 154 * node enables a Partition. 155 * <p> 156 * When a remote node enables a partition, it will enable the 157 * partition on all nodes in the node list, and update the partition 158 * status and state. This is done even on nodes that have explicitly 159 * disabled the partition. This behaviour can be changed by setting 160 * the RemoteEnableAction to LEAVE_DISABLED. Note that this only 161 * controls the behaviour on the local node, it does not affect 162 * partitions defined on remote nodes. 163 * <p> 164 * The default action is defined by {@link #DefaultRemoteEnableAction}, 165 */ 166 public enum RemoteEnableAction 167 { 168 /** 169 * Allow remote nodes to enable the partition on the local node. 170 */ 171 ENABLE_PARTITION, 172 /** 173 * Do not allow remote nodes to enable the partition on the 174 * local node if it has been explicitly disabled. 175 */ 176 LEAVE_DISABLED 177 } 178 179 /** 180 * Default constructor. 181 */ 182 public Properties() 183 { 184 m_restoreFromNode = null; 185 m_forceReplication = false; 186 m_objectsLockedPerTransaction = DefaultObjectsLockedPerTransaction; 187 m_numberOfThreads = DefaultNumberOfThreads; 188 m_sparseAudit = DefaultSparseAudit; 189 m_replicaAudit = DefaultReplicaAudit; 190 m_remoteEnableAction = DefaultRemoteEnableAction; 191 m_broadcastUpdates = DEPartitionBroadcast.BroadcastDefault; 192 } 193 194 /** 195 * Define the node that the partition should be restored from. 196 * <p> 197 * When this property is set, the partition defined on the given 198 * remote node is loaded to the local node. This should be done 199 * when restoring a node from a split-brain situation, where 200 * <b>nodeName</b> is the node in the cluster where all objects 201 * should be preserved, and the local node is the node being 202 * restored. Any conflicts during restore will preserve the 203 * objects on <b>nodeName</b>, and remove the conflicting objects 204 * on the local node. 205 * <p> 206 * A restore is needed when multiple nodes are currently the active 207 * node for a partition in a cluster due to a split-brain scenario. 208 * In this case, the application needs to decide which active node 209 * will be the node where the objects are preserved during a 210 * restore. Note that the <b>nodeName</b> does not necessarily have 211 * to be the node which becomes the partition's active node after the 212 * restore completes. 213 * <p> 214 * The actual restore of the partition is done in the 215 * enable() or enablePartitions() method when the JOIN_CLUSTER_RESTORE 216 * EnableAction is used. If any other EnableAction is used, 217 * object data isn't preserved, and no restoration of partition 218 * objects is done. 219 * <p> 220 * If restoreFromNode isn't set after a split-brain scenario, the 221 * runtime will perform a cluster wide broadcast to find the 222 * current active node, and use that node to restore instances in 223 * the partition. If multiple active nodes are found, the first 224 * responder is chosen. 225 * <p> 226 * @param nodeName The remote node to use when restoring the 227 * partition's objects. 228 * 229 * @exception IllegalArgumentException 230 * The nodeName was empty. 231 * @see PartitionManager#definePartition(String, 232 * Partition.Properties, String, ReplicaNode []) 233 * @see PartitionManager.EnableAction 234 */ 235 public void restoreFromNode(String nodeName) 236 throws IllegalArgumentException 237 { 238 if (nodeName.isEmpty()) 239 { 240 throw new IllegalArgumentException( 241 "nodeName cannot be empty"); 242 } 243 m_restoreFromNode = nodeName; 244 } 245 246 /** 247 * Get the current restoreFromNode property value. 248 * @return String containing value. 249 */ 250 public final String getRestoreFromNode() 251 { 252 return m_restoreFromNode; 253 } 254 255 /** 256 * Determine how objects are replicated during a migrate of 257 * an object partition. 258 * <p> 259 * When set to true, a migrate() or 260 * definePartition()/enablePartitions() will force the copy of 261 * partitioned objects to all pre-existing replica nodes. The 262 * default value for this property is false, objects are only 263 * copied to new replicas as they are added since the objects 264 * should already exist on the pre-existing replica nodes. 265 * <p> 266 * Normally, a migrate will skip the replication of objects to 267 * pre-existing nodes in the partition's replica node list. This 268 * allows applications to incrementally add replica nodes without 269 * having to copy the objects to replicas that already exist in 270 * the partition. However, if one or more replicas have gone 271 * offline, or were not discovered when the partition was first 272 * enabled, this property can be set to insure that objects are 273 * pushed to all replicas in the cluster. 274 * <p> 275 * Warning: This is performance hostile, and should only be done 276 * if the replica can't be manually taken offline and restored. 277 * <p> 278 * The value passed into definePartition() is stored and used in 279 * failover. The value passed to migrate() overrides 280 * the value passed to definePartition(). 281 * 282 * @param enabled If true, force the copy of objects to all replicas 283 * when a migrate() or enablePartition() is executed. 284 * 285 */ 286 public void forceReplication(boolean enabled) 287 { 288 m_forceReplication = enabled; 289 } 290 291 /** 292 * Get the current forceReplication property value. 293 * @return boolean containing value. 294 */ 295 public final boolean getForceReplication() 296 { 297 return m_forceReplication; 298 } 299 300 /** 301 * Define the number of objects locked in a transaction when performing 302 * a migrate() or update(). 303 * <p> 304 * When distribution performs a migrate() or update(), or when it 305 * performs a migrate() as part of failover, the work is done in 306 * units of work defined by objectsLockedPerTransaction. This 307 * allows applications to concurrently run while the work is in 308 * progress, otherwise all partitioned instances would be locked 309 * in the calling transaction, preventing application code from 310 * establishing a write lock on instances on the active node, or 311 * establishing a read lock on instances on replica nodes. 312 * <p> 313 * The default is defined by {@link #DefaultObjectsLockedPerTransaction} 314 * <p> 315 * If objectsLockedPerTransaction is set to zero, all instances will 316 * be processed in the caller's transaction. 317 * <p> 318 * If the calling transaction has one or more partitioned 319 * instances locked in the transaction, 320 * objectsLockedPerTransaction is ignored, and all work is done 321 * in the caller's transaction. To insure that migrate() or update() 322 * minimizes the number of locks taken, they should be run in separate 323 * transactions that have no partitioned instances locked. 324 * <p> 325 * The value passed into definePartition() is stored and used in 326 * failover. The value passed to migrate() and update() override 327 * the value passed to definePartition(). 328 * 329 * @param objectsLockedPerTransaction Number of objects locked 330 * per transaction when sending data to remote nodes. 331 * @exception IllegalArgumentException The objectsLockedPerTransaction 332 * value was negative. 333 */ 334 public void setObjectsLockedPerTransaction( 335 long objectsLockedPerTransaction) 336 { 337 if (objectsLockedPerTransaction < 0) 338 { 339 throw new IllegalArgumentException( 340 "invalid objectsLockedPerTransaction: " + 341 objectsLockedPerTransaction); 342 } 343 m_objectsLockedPerTransaction = objectsLockedPerTransaction; 344 } 345 346 /** 347 * Get the current objectsLockedPerTransaction property value. 348 * @return long containing value. 349 */ 350 public final long getObjectsLockedPerTransaction() 351 { 352 return m_objectsLockedPerTransaction; 353 } 354 355 /** 356 * Define the number of threads used when performing a migrate(). 357 * <p> 358 * When distribution performs a migrate(), either explicitly or 359 * as part of the enablePartitions() call, the work is done in 360 * multiple threads in order to scale to the number of CPUs 361 * available in the system. 362 * <p> 363 * The default is defined by {@link #DefaultNumberOfThreads} 364 * <p> 365 * If the number of partitioned instances is less that 366 * objectsLockedPerTransaction, only one thread will be used. 367 * <p> 368 * If objectsLockedPerTransaction is zero, or the calling 369 * transaction has one or more partitioned instances locked in 370 * the transaction, numberOfThreads is ignored, and all work is 371 * done in the caller's transaction. 372 * <p> 373 * @param numberOfThreads Number of threads to use 374 * when sending data to remote nodes. 375 * @exception IllegalArgumentException The numberOfThreads 376 * value was less than one. 377 */ 378 public void setNumberOfThreads(long numberOfThreads) 379 { 380 if (numberOfThreads < 1) 381 { 382 throw new IllegalArgumentException( 383 "invalid numberOfThreads: " + numberOfThreads); 384 } 385 m_numberOfThreads = numberOfThreads; 386 } 387 388 /** 389 * Get the current numberOfThreads property value. 390 * @return long containing value. 391 */ 392 public final long getNumberOfThreads() 393 { 394 return m_numberOfThreads; 395 } 396 397 /** 398 * Set the sparseAudit property value. 399 * <p> 400 * The default is defined by {@link #DefaultSparseAudit} 401 * 402 * @param sparseAudit What auditing should be done. 403 * 404 */ 405 public void setSparseAudit(final SparseAudit sparseAudit) 406 { 407 m_sparseAudit = sparseAudit; 408 } 409 410 /** 411 * Get the current sparseAudit property value. 412 * @return SparseAudit enum. 413 */ 414 public final SparseAudit getSparseAudit() 415 { 416 return m_sparseAudit; 417 } 418 419 /** 420 * Set the replicaAudit property value. 421 * <p> 422 * The default is defined by {@link #DefaultReplicaAudit} 423 * 424 * @param replicaAudit What auditing should be done. 425 * 426 */ 427 public void setReplicaAudit(final ReplicaAudit replicaAudit) 428 { 429 m_replicaAudit = replicaAudit; 430 } 431 432 /** 433 * Get the current replicaAudit property value. 434 * @return ReplicaAudit enum. 435 */ 436 public final ReplicaAudit getReplicaAudit() 437 { 438 return m_replicaAudit; 439 } 440 441 /** 442 * Set the remoteEnableAction property value. 443 * <p> 444 * The default is defined by {@link #DefaultRemoteEnableAction} 445 * 446 * @param remoteEnableAction The action to take when remote nodes enable 447 * a partition. 448 * 449 */ 450 public void setRemoteEnableAction(final RemoteEnableAction remoteEnableAction) 451 { 452 m_remoteEnableAction = remoteEnableAction; 453 } 454 455 /** 456 * Get the current remoteEnableAction property value. 457 * @return RemoteEnableAction enum. 458 */ 459 public final RemoteEnableAction getRemoteEnableAction() 460 { 461 return m_remoteEnableAction; 462 } 463 464 /** 465 * Set the broadcastUpdates property value. 466 * <p> 467 * By default, this property is enabled. Updates to the partition's 468 * definition are broadcast to all nodes in the cluster so that 469 * the partition definition is consistent across the cluster. 470 * <p> 471 * Warning: The ability to disable this property is only provided 472 * to support the testing of multi-master scenarios. 473 * Disabling this property for any other reason is not recommended. 474 * 475 * @param enabled If true, broadcast partition definition updates 476 * to all nodes in the cluster. 477 */ 478 public void broadcastUpdates(boolean enabled) 479 { 480 m_broadcastUpdates = (enabled == true) 481 ? DEPartitionBroadcast.BroadcastEnabled 482 : DEPartitionBroadcast.BroadcastDisabled; 483 } 484 485 /** 486 * Get the current broadcastUpdates property value. 487 * @return boolean containing value. 488 */ 489 public final boolean getBroadcastUpdates() 490 { 491 // Map both BroadcastDefault and BroadcastEnabled to true. 492 return (m_broadcastUpdates == DEPartitionBroadcast.BroadcastDisabled) 493 ? false : true; 494 } 495 496 // 497 // package private constructor 498 // 499 Properties( 500 boolean forceReplication, 501 long objectChunks, 502 long numThreads, 503 SparseAudit sparseAudit, 504 ReplicaAudit replicaAudit, 505 RemoteEnableAction remoteEnableAction, 506 DEPartitionBroadcast broadcastUpdates) 507 { 508 m_restoreFromNode = null; 509 m_forceReplication = forceReplication; 510 m_objectsLockedPerTransaction = objectChunks; 511 m_numberOfThreads = numThreads; 512 m_sparseAudit = sparseAudit; 513 m_replicaAudit = replicaAudit; 514 m_remoteEnableAction = remoteEnableAction; 515 m_broadcastUpdates = broadcastUpdates; 516 } 517 518 String m_restoreFromNode; 519 boolean m_forceReplication; 520 long m_objectsLockedPerTransaction; 521 long m_numberOfThreads; 522 SparseAudit m_sparseAudit; 523 ReplicaAudit m_replicaAudit; 524 RemoteEnableAction m_remoteEnableAction; 525 DEPartitionBroadcast m_broadcastUpdates; 526 } 527 528 /** 529 * Partition statistics 530 * <p> 531 * Partition statistics are captured for the local node only, any 532 * operations done on remote nodes are not reflected in the stats. As 533 * an example, if the local node is a replica, and the node executes 534 * 10 object creates, the createCount will be set to 10. If objects 535 * are created on the active node, or on other replica nodes, the 536 * createCount will not be updated. 537 * <p> 538 * All partition statistics are reset each time an engine containing 539 * the highavailability component is restarted. They do not persist 540 * across engine restarts. 541 */ 542 public final static class Statistics 543 { 544 /** 545 * The number of instances created in this partition. 546 */ 547 public long createCount; 548 /** 549 * The number of updates that have been applied to instance in this 550 * partition. 551 */ 552 public long updateCount; 553 /** 554 * The number of instances deleted in this partition. 555 */ 556 public long deleteCount; 557 /** 558 * The number of synchronous create failures that occurred in 559 * this partition. 560 */ 561 public long createFailures; 562 /** 563 * The number of synchronous update failures that occurred in 564 * this partition. 565 */ 566 public long updateFailures; 567 /** 568 * The number of synchronous delete failures that occurred in 569 * this partition. 570 */ 571 public long deleteFailures; 572 /** 573 * The number of asynchronous create failures that occurred in 574 * this partition. 575 */ 576 public long asyncCreateFailures; 577 /** 578 * The number of asynchronous update failures that occurred in 579 * this partition. 580 */ 581 public long asyncUpdateFailures; 582 /** 583 * The number of asynchronous delete failures that occurred in 584 * this partition. 585 */ 586 public long asyncDeleteFailures; 587 588 // package private constructor 589 Statistics(DEPartitionStats stats) 590 { 591 this.createCount = stats.createCount; 592 this.updateCount = stats.updateCount; 593 this.deleteCount = stats.deleteCount; 594 this.createFailures = stats.createFailures; 595 this.updateFailures = stats.updateFailures; 596 this.deleteFailures = stats.deleteFailures; 597 this.asyncCreateFailures = stats.asyncCreateFailures; 598 this.asyncUpdateFailures = stats.asyncUpdateFailures; 599 this.asyncDeleteFailures = stats.asyncDeleteFailures; 600 } 601 // private constructor 602 private Statistics() { } 603 } 604 605 /** Index to the active node in the nodes array */ 606 public final static int ActiveNodeIndex = 0; 607 608 /** 609 * The default number of objects locked per transaction when 610 * performing a migrate or update. 611 */ 612 public final static long DefaultObjectsLockedPerTransaction = 1000; 613 614 /** 615 * The default number of threads to use when performing a migrate. 616 */ 617 public final static long DefaultNumberOfThreads = 1; 618 619 /** 620 * The default audit used for sparse partitions. 621 * The value is {@link Properties.SparseAudit#VERIFY_NODE_LIST} 622 */ 623 public final static Properties.SparseAudit DefaultSparseAudit = 624 Properties.SparseAudit.VERIFY_NODE_LIST; 625 626 /** 627 * The default audit used for replicas. 628 * The value is {@link Properties.ReplicaAudit#WAIT_ACTIVE} 629 */ 630 public final static Properties.ReplicaAudit DefaultReplicaAudit = 631 Properties.ReplicaAudit.WAIT_ACTIVE; 632 633 /** 634 * The default action used for remote partition enables. 635 * The value is {@link Properties.RemoteEnableAction#ENABLE_PARTITION} 636 */ 637 public final static Properties.RemoteEnableAction DefaultRemoteEnableAction = 638 Properties.RemoteEnableAction.ENABLE_PARTITION; 639 640 /** 641 * Get the partition name. 642 * @return Partition name. 643 */ 644 public final String getName() 645 { 646 return m_name; 647 } 648 649 /** 650 * Get the active node for the partition. 651 * @return Active node name. 652 */ 653 public final String getActiveNode() 654 { 655 assert( m_nodes.length >= 1 ); 656 return m_nodes[ActiveNodeIndex]; 657 } 658 659 /** 660 * Get the replica node list for the partition. 661 * @return Array of replica node names. 662 */ 663 public final String [] getReplicaNodes() 664 { 665 assert( m_nodes.length >= 1 ); 666 String [] replicas = new String[m_nodes.length - 1]; 667 for (int i = 0; i < m_nodes.length - 1; i++) 668 { 669 replicas[i] = m_nodes[i + 1]; 670 } 671 return replicas; 672 } 673 674 /** 675 * Get the complete node list for the partition. 676 * <p> 677 * The node list is a String array of node names, with the active 678 * node being at ActiveNodeIndex, followed by a prioritized list of 679 * replica nodes. 680 * @return Array of node names. 681 */ 682 public final String [] getNodeList() 683 { 684 return m_nodes; 685 } 686 687 /** 688 * Get the current state for the partition. 689 * @return Current state of partition. 690 */ 691 public final State getCurrentState() 692 { 693 return m_currentState; 694 } 695 696 /** 697 * Get the current status for the partition. 698 * @return Current status of partition. 699 */ 700 public final Status getCurrentStatus() 701 { 702 return m_currentStatus; 703 } 704 705 /** 706 * Get the ReplicaNode instance for the given replica node index. 707 * @param idx Index into the ReplicaNode array. 708 * @return ReplicaNode instance. 709 * @exception IndexOutOfBoundsException 710 * The idx isn't valid. 711 */ 712 public final ReplicaNode getReplicaNode(int idx) 713 throws IndexOutOfBoundsException 714 { 715 // m_nodes[0] is active node, so we need to disallow -1 716 if (idx < 0) throw new IndexOutOfBoundsException(Integer.toString(idx)); 717 return new ReplicaNode(m_nodes[idx + 1], 718 PartitionManager.mapDEReplicationType( 719 m_replicationTypes[idx + 1])); 720 } 721 722 /** 723 * Get the ReplicaNode instance for the given replica node name. 724 * @param nodeName Name of replica node. 725 * @return ReplicaNode instance, or null if not found. 726 * @exception IllegalArgumentException The nodeName was invalid. 727 */ 728 public final ReplicaNode getReplicaNode(final String nodeName) 729 throws IllegalArgumentException 730 { 731 if (nodeName.isEmpty()) 732 { 733 throw new IllegalArgumentException("nodeName cannot be empty"); 734 } 735 for (int idx = 1; idx < m_nodes.length; idx++) 736 { 737 if (m_nodes[idx].equals(nodeName)) 738 { 739 return getReplicaNode(idx - 1); 740 } 741 } 742 return null; 743 } 744 745 /** 746 * Get the last time the state for the partition was updated 747 * @return Date of last state change for partition. 748 */ 749 public final Date getLastStateChangeTime() 750 { 751 return m_lastUpdated; 752 } 753 754 /** 755 * Get the properties currently defined for the partition. 756 * <p> 757 * The restoreFromNode property is not stored in the runtime since it 758 * has no meaning outside of the initial definePartition(). So this method 759 * will return a Properties instance with a null restoreFromNode value. 760 * 761 * @return Properties instance for partition. 762 */ 763 public final Properties getProperties() 764 { 765 return new Properties(m_forceReplication, m_objectChunks, 766 m_numThreads, m_sparseAudit, m_replicaAudit, 767 m_remoteEnableAction, m_broadcastUpdates); 768 } 769 770 /** 771 * Get the statistics for the partition. 772 * 773 * @return A Statistics instance for the partition. 774 */ 775 public final Statistics getStatistics() 776 { 777 DEPartitionManager pm = new DEPartitionManager(); 778 return new Statistics(pm.getPartitionStats(m_name)); 779 } 780 781 /** 782 * Clear the statistics for the partition. 783 */ 784 public final void clearStatistics() 785 { 786 DEPartitionManager pm = new DEPartitionManager(); 787 pm.clearPartitionStats(m_name); 788 } 789 790 /** 791 * Use {@link #update(Properties)} instead. 792 */ 793 @Deprecated 794 public final void update() throws NodeMismatch, NotActiveNode 795 { 796 update(null); 797 } 798 799 /** 800 * Update the partition. 801 * <p> 802 * This method is used to re-partition all instances that exist in a 803 * partition. For each instance in the partition, the {@link 804 * PartitionMapper} defined for that type is accessed, and the 805 * instance re-assigned to the partition that the {@link 806 * PartitionMapper#getPartition} method returns. The update() method 807 * must be called on the current active node for the partition. 808 * <p> 809 * To split a partition, the applications should create the new 810 * partition, install a new PartitionMapper for all types managed by 811 * the partition, and call the update() method for the existing 812 * partition. 813 * <p> 814 * To merge two or more partitions, the applications should install a 815 * new PartitionMapper for all types managed by the partition(s), and 816 * call the update() method for all the partitions that need to 817 * be merged. 818 * <p> 819 * It is important that all partitions returned when executing the 820 * PartitionMapper's getPartition() call for a type all contain 821 * identical node lists. If the partition returned contains a 822 * different node list than this partition, a NodeMismatch exception 823 * is thrown, and the update() terminates. To fix this, perform a 824 * migrate() on all partitions that will be split or merged to insure 825 * that they have identical node lists before performing an update(). 826 * 827 * @param partitionProperties Optional properties for the partition. 828 * If null, the default property values are used. 829 * 830 * @exception NodeMismatch 831 * The re-partitioning of instances was done using partitions that 832 * have different node lists. 833 * @exception NotActiveNode 834 * The current node is not the active node for the partition. 835 */ 836 public final void update(final Properties partitionProperties) 837 throws NodeMismatch, NotActiveNode 838 { 839 DEProperties props = copyDEProperties(partitionProperties); 840 841 PartitionManager.updatePartition(m_name, props); 842 } 843 844 /** 845 * Use {@link #migrate(Properties, String, ReplicaNode [])} instead. 846 * @param nodes An ordered list of nodes for the partition. 847 */ 848 @Deprecated 849 public final void migrate(String [] nodes) 850 throws NotActiveNode, IllegalArgumentException 851 { 852 PartitionManager.validateNodeList(nodes); 853 DEReplicationType [] drl = new DEReplicationType[nodes.length]; 854 for (int i = 0; i < drl.length; i++) 855 { 856 drl[i] = DEReplicationType.DataSynchronous; 857 } 858 859 DEProperties props = defaultDEProperties(); 860 861 PartitionManager.migratePartition(m_name, props, nodes, drl); 862 } 863 864 /** 865 * Migrate the partition. 866 * <p> 867 * This method is used to migrate all instances that exist in a 868 * partition. For each instance in the partition, the object is 869 * migrated as needed to all nodes in the replicas array, and to the 870 * new activeNode if it is different from the current active node. This 871 * method must be called on the currently active node for the partition. 872 * <p> 873 * Any properties passed in only apply to the current migrate() command, 874 * properties passed into definePartition() are saved and used during 875 * failover. 876 * 877 * @param partitionProperties Optional properties for the partition. 878 * If null, the default property values are used. 879 * @param activeNode Active node after migrate completes. 880 * @param replicas An ordered list of replica nodes for the partition. 881 * Should be passed in as a null instance or a zero length array if 882 * no replicas exists. 883 * 884 * @exception NotActiveNode 885 * The current node is not the active node for the partition. 886 * @exception IllegalArgumentException 887 * The activeNode or replica array was invalid. 888 */ 889 public final void migrate( 890 final Properties partitionProperties, 891 String activeNode, 892 ReplicaNode [] replicas) 893 throws NotActiveNode, IllegalArgumentException 894 { 895 PartitionManager.validateReplicaList(replicas); 896 897 int nodeLength = (replicas == null) ? 1 : replicas.length + 1; 898 String [] nodes = new String[nodeLength]; 899 900 nodes[0] = activeNode; 901 if (replicas != null ) 902 { 903 for (int i = 0; i < replicas.length; i++) 904 { 905 assert( i + 1 < nodes.length ); 906 nodes[i + 1] = replicas[i].nodeName; 907 } 908 } 909 PartitionManager.validateNodeList(nodes); 910 911 DEReplicationType [] drl = new DEReplicationType[nodes.length]; 912 drl[0] = DEReplicationType.DataSynchronous; 913 if (replicas != null) 914 { 915 for (int i = 0; i < replicas.length; i++) 916 { 917 assert( i + 1 < nodes.length ); 918 drl[i + 1] = PartitionManager.mapReplicationType( 919 replicas[i].replicationType); 920 } 921 } 922 boolean forceReplication = (partitionProperties != null) 923 ? partitionProperties.m_forceReplication : false; 924 925 DEProperties props = copyDEProperties(partitionProperties); 926 927 PartitionManager.migratePartition(m_name, props, nodes, drl); 928 } 929 930 /** 931 * Enable high availability for this partition. 932 * <p> 933 * This method is used to enable this partition. If the partition is 934 * already in the <b>ACTIVE</b> state, no action is taken. 935 * This method blocks until all required object migration 936 * is complete. 937 * 938 * @param enableAction The action to take when enabling partitions. 939 * 940 * @exception ResourceUnavailableException 941 * The minimum number of nodes needed to establish a quorum has not been 942 * seen, or the partition has not been defined. 943 * @exception NodeMismatch 944 * The partition does not have the local node in the node list, and the 945 * active node for the partition has a different node list. 946 * @see PartitionManager#enablePartitions(PartitionManager.EnableAction) 947 */ 948 public final void enable( 949 final PartitionManager.EnableAction enableAction) 950 throws NodeMismatch, ResourceUnavailableException 951 { 952 DEPartitionManager pm = new DEPartitionManager(); 953 try 954 { 955 pm.enablePartition(m_name, 956 PartitionManager.mapEnable(enableAction)); 957 } 958 catch (DENodeMismatch ex) 959 { 960 throw new NodeMismatch(ex.errMsg); 961 } 962 } 963 964 /** 965 * Disable high availability for this partition. 966 * <p> 967 * This method is used to remove the local node from the node list 968 * of this partition, and move the partition state to <b>UNAVAILABLE</b>. 969 * If called multiple times, the additional calls have no effect. 970 * <p> 971 * If the local node does not exist in the partition, no action is taken. 972 * 973 * @param disableAction The action to take when disabling partitions. 974 * 975 * @exception ResourceUnavailableException 976 * The partition would be in the <b>UNAVAILABLE</b> state after the 977 * disable executes, not thrown if <b>LEAVE_CLUSTER_FORCE</b> is used. 978 * @see PartitionManager#disablePartitions(PartitionManager.DisableAction) 979 */ 980 public final void disable( 981 final PartitionManager.DisableAction disableAction) 982 throws ResourceUnavailableException 983 { 984 DEPartitionManager pm = new DEPartitionManager(); 985 pm.disablePartition(m_name, PartitionManager.mapDisable(disableAction)); 986 } 987 988 /** 989 * Associated a notifier with the partition. 990 * <p> 991 * This method is used to associate a user defined {@link PartitionNotifier} 992 * instance with a partition. 993 * <p> 994 * PartitionNotifier instances are local to a node, this method 995 * should be executed on all nodes which need to determine if a 996 * partition state change occurs. 997 * <p> 998 * The same PartitionNotifier instance can be associated with multiple 999 * partitions. Multiple PartitionNotifier instances can be installed for 1000 * a given Partition. When a state change occurs, all instances are 1001 * executed, no order is guaranteed when executing the notifiers. 1002 * To remove a notifier, the PartitionNotifier instance should be deleted. 1003 * 1004 * @param partitionNotifier User defined notifier instance. 1005 * 1006 */ 1007 public final void setNotifier(PartitionNotifier partitionNotifier) 1008 { 1009 PartitionManager.setNotifier(m_name, partitionNotifier); 1010 } 1011 1012 /** 1013 * Returns the number of instances in this partition. 1014 * <p> 1015 * This method does not establish transaction locks on the 1016 * partition or any of the individual objects in the partition. 1017 * This means the number returned by cardinality() may 1018 * change even as observed within a single transaction. 1019 * <p> 1020 * Warning: This method requires a scan of all objects for each class in 1021 * the partition to determine the count, which is computationally 1022 * expensive. 1023 * 1024 * @return Number of instances found. 1025 */ 1026 public final long cardinality() 1027 { 1028 DEPartitionManager pm = new DEPartitionManager(); 1029 return pm.getCardinality(m_name); 1030 } 1031 1032 /** The name of the partition */ 1033 private final String m_name; 1034 1035 /** The list of nodes for a partition */ 1036 private final String [] m_nodes; 1037 1038 /** The list of nodes for a partition */ 1039 private final DEReplicationType [] m_replicationTypes; 1040 1041 /** The current state of the partition */ 1042 private final State m_currentState; 1043 1044 /** The current status of the partition */ 1045 private final Status m_currentStatus; 1046 1047 /** The time it was updated */ 1048 private final Date m_lastUpdated; 1049 1050 /** stored property */ 1051 private final boolean m_forceReplication; 1052 1053 /** stored property */ 1054 private final long m_objectChunks; 1055 1056 /** stored property */ 1057 private final long m_numThreads; 1058 1059 /** stored property */ 1060 private final Properties.SparseAudit m_sparseAudit; 1061 1062 /** stored property */ 1063 private final Properties.ReplicaAudit m_replicaAudit; 1064 1065 /** stored property */ 1066 private final Properties.RemoteEnableAction m_remoteEnableAction; 1067 1068 /** stored property */ 1069 private final DEPartitionBroadcast m_broadcastUpdates; 1070 1071 // 1072 // FIX THIS: Add stats attributes... 1073 // 1074 1075 // 1076 // Package private constructor 1077 // 1078 Partition( 1079 String name, 1080 String [] nodes, 1081 DEReplicationType [] replicationTypes, 1082 State currentState, 1083 Status currentStatus, 1084 Date lastUpdated, 1085 boolean forceReplication, 1086 long objectChunks, 1087 long numThreads, 1088 Properties.SparseAudit sparseAudit, 1089 Properties.ReplicaAudit replicaAudit, 1090 Properties.RemoteEnableAction remoteEnableAction, 1091 DEPartitionBroadcast broadcastUpdates) 1092 { 1093 this.m_name = name; 1094 this.m_nodes = nodes; 1095 this.m_replicationTypes = replicationTypes; 1096 this.m_currentState = currentState; 1097 this.m_currentStatus = currentStatus; 1098 this.m_lastUpdated = lastUpdated; 1099 this.m_forceReplication = forceReplication; 1100 this.m_objectChunks = objectChunks; 1101 this.m_numThreads = numThreads; 1102 this.m_sparseAudit = sparseAudit; 1103 this.m_replicaAudit = replicaAudit; 1104 this.m_remoteEnableAction = remoteEnableAction; 1105 this.m_broadcastUpdates = broadcastUpdates; 1106 } 1107 // 1108 // Never should be called 1109 // 1110 private Partition() 1111 { 1112 this.m_name = null; 1113 this.m_nodes = null; 1114 this.m_replicationTypes = null; 1115 this.m_currentState = null; 1116 this.m_currentStatus = null; 1117 this.m_lastUpdated = null; 1118 this.m_forceReplication = false; 1119 this.m_objectChunks = 0; 1120 this.m_numThreads = 0; 1121 this.m_sparseAudit = null; 1122 this.m_replicaAudit = null; 1123 this.m_remoteEnableAction = null; 1124 this.m_broadcastUpdates = DEPartitionBroadcast.BroadcastDefault; 1125 } 1126 1127 // 1128 // Copy properties to DEProperties. 1129 // 1130 static DEProperties copyDEProperties(Properties partitionProperties) 1131 { 1132 if (partitionProperties == null) 1133 { 1134 return defaultDEProperties(); 1135 } 1136 1137 DEProperties props = new DEProperties(); 1138 1139 props.forceReplication = partitionProperties.m_forceReplication; 1140 props.objectChunks = 1141 partitionProperties.m_objectsLockedPerTransaction; 1142 props.numThreads = partitionProperties.m_numberOfThreads; 1143 props.sparseAudit = 1144 PartitionManager.mapSparseAudit(partitionProperties.m_sparseAudit); 1145 props.replicaAudit = 1146 PartitionManager.mapReplicaAudit(partitionProperties.m_replicaAudit); 1147 props.remoteEnableAction = 1148 PartitionManager.mapRemoteEnableAction(partitionProperties.m_remoteEnableAction); 1149 props.restoreFromNode = partitionProperties.m_restoreFromNode; 1150 props.broadcastUpdates = partitionProperties.m_broadcastUpdates; 1151 1152 return props; 1153 } 1154 1155 // 1156 // Allocate and initialize default DEProperties. 1157 // 1158 static DEProperties defaultDEProperties() 1159 { 1160 DEProperties props = new DEProperties(); 1161 1162 // 1163 // Note: This needs to match the Properties() constructor. 1164 // 1165 props.forceReplication = false; 1166 props.objectChunks = DefaultObjectsLockedPerTransaction; 1167 props.numThreads = DefaultNumberOfThreads; 1168 props.sparseAudit = DESparsePartitionAudit.VerifyNodeList; 1169 props.replicaAudit = DEReplicaAudit.ReplicaIgnore; 1170 props.remoteEnableAction = DERemoteEnableAction.EnablePartition; 1171 props.restoreFromNode = null; 1172 props.broadcastUpdates = DEPartitionBroadcast.BroadcastDefault; 1173 1174 return props; 1175 } 1176}