Search Results

Search found 17303 results on 693 pages for 'nested array'.

Page 278/693 | < Previous Page | 274 275 276 277 278 279 280 281 282 283 284 285  | Next Page >

  • strange doctrine update problem

    - by larryzhao
    Hi, guys, I have a simple table like following: class SnookerCurrentInfo extends Doctrine_Record { public function setTableDefinition() { $this->hasColumn('current_frame_id', 'integer', 4, array('notnull' => 'false')); $this->hasColumn('current_player_id', 'integer', 4, array('notnull' => 'false')); $this->hasColumn('current_score1', 'integer', 4, array('notnull' => 'false')); $this->hasColumn('current_score2', 'integer', 4, array('notnull' => 'false')); } public function setUp(){ $this->setTableName('snooker_current_info'); } } and I would like to keep only one entry in this table. So every time the value is changed I read the entry with id = 1 out and change the object and execute save. like the following: $info = Doctrine::getTable('SnookerCurrentInfo')->find(1); $info->current_frame_id = $jsonInfo['current_frame_id']; $info->current_player_id = $jsonInfo['current_player_id']; $info->current_score1 = $jsonInfo['current_score1']; $info->current_score2 = $jsonInfo['current_score2']; $info->save(); but the strange thing is, I try to make it clear. Let's say at first, the entry is (30, 1, 1, 0) and I switch player, so update the entry to (30, 2, 1, 0). and I switch the player back again, so the entry should be updated to (30, 1, 1, 0), but this is not affected to the database!! In the database, the entry still remains as (30, 2, 1, 0)!!!! But if after (30, 2, 1, 0), I update the score to (30, 2, 1, 1) and then switch the player back (30, 1, 1, 1) then this is ok. What's that? How should I deal with it? Thanks for a lot helping, really urgent!!

    Read the article

  • MySQLi Wrapper -- will this slow down performance?

    - by Kerry
    I found the following code on php.net. I'm trying to write a wrapper for the MySQLi library to make things incredibly simple. If this is going to slow down performance, I'll skip it and find another way, if this works, then I'll do that. I have a single query function, if someone passes in more than one variable, I assume the function has to be prepared. The function that I would use to pass in an array to mysqli_stmt_bind_param is call_user_func_array, I have a feeling that is going to slow things down. Am I right? <?php /* just explaining how to call mysqli_stmt_bind_param with a parameter array */ $sql_link = mysqli_connect('localhost', 'my_user', 'my_password', 'world'); $type = "isssi"; $param = array("5", "File Description", "File Title", "Original Name", time()); $sql = "INSERT INTO file_detail (file_id, file_description, file_title, file_original_name, file_upload_date) VALUES (?, ?, ?, ?, ?)"; $sql_stmt = mysqli_prepare ($sql_link, $sql); call_user_func_array('mysqli_stmt_bind_param', array_merge (array($sql_stmt, $type), $param); mysqli_stmt_execute($sql_stmt); ?>

    Read the article

  • CakePHP pagination with HABTM models

    - by nickf
    I'm having some problems with creating pagination with a HABTM relationship. First, the tables and relationships: requests (id, to_location_id, from_location_id) locations (id, name) items_locations (id, item_id, location_id) items (id, name) So, a Request has a Location the request is coming from and a Location the Request is going to. For this question, I'm only concerned about the "to" location. Request --belongsTo--> Location* --hasAndBelongsToMany--> Item (* as "ToLocation") In my RequestController, I want to paginate all the Items in a Request's ToLocation. // RequestsController var $paginate = array( 'Item' => array( 'limit' => 5, 'contain' => array( "Location" ) ) ); // RequestController::add() $locationId = 21; $items = $this->paginate('Item', array( "Location.id" => $locationId )); And this is failing, because it is generating this SQL: SELECT COUNT(*) AS count FROM items Item WHERE Location.id = 21 I can't figure out how to make it actually use the "contain" argument of $paginate... Any ideas?

    Read the article

  • Approach to Selecting top item matching a criteria

    - by jkelley
    I have a SQL problem that I've come up against routinely, and normally just solved w/ a nested query. I'm hoping someone can suggest a more elegant solution. It often happens that I need to select a result set for a user, conditioned upon it being the most recent, or the most sizeable or whatever. For example: Their complete list of pages created, but I only want the most recent name they applied to a page. It so happens that the database contains many entries for each page, and only the most recent one is desired. I've been using a nested select like: SELECT pg.customName, pg.id FROM ( select id, max(createdAt) as mostRecent from pages where userId = @UserId GROUP BY id ) as MostRecentPages JOIN pages pg ON pg.id = MostRecentPages.id AND pg.createdAt = MostRecentPages.mostRecent Is there a better syntax to perform this selection?

    Read the article

  • PHP and use of the Num_Of_Rows() function?

    - by Michael Smith
    Below is some PHP code that i have written, the problem occurs when it gets to the use of the num_of_rows(), it just does not seem to work and i cant figure out why? <?php try { $divMon_ID = array(); $divMon_Position = array(); $divMon_Width = array(); $divMon_Div = array(); $db = new PDO('sqlite:db/EVENTS.sqlite'); $result_mon = $db->query('SELECT * FROM Monday'); $totalRows = mysql_num_rows($result_mon); //for($counter=1; $counter<=10; $counter+=1) //{ //<div id="event_1" style="position:absolute; left: 0px; top:-39px; width:100px; font-family:Arial, Helvetica, sans-serif; font-size:small; border:2px blue solid; height:93px"> //$divMon_ID[]=$row['Id']; //$divMon_Position[]=$row['Origin']; //$divMon_P[]=$row['Position']; //} } catch(PDOException $e) { print 'Exception : '.$e->getMessage(); } ? I know that it is the "$totalRows = mysql_num_rows($result_mon);" statement because when i then comment it out, the page can load. Am i using the function in the wrong way? Thanks.

    Read the article

  • SPARC T4-4 Beats 8-CPU IBM POWER7 on TPC-H @3000GB Benchmark

    - by Brian
    Oracle's SPARC T4-4 server delivered a world record TPC-H @3000GB benchmark result for systems with four processors. This result beats eight processor results from IBM (POWER7) and HP (x86). The SPARC T4-4 server also delivered better performance per core than these eight processor systems from IBM and HP. Comparisons below are based upon system to system comparisons, highlighting Oracle's complete software and hardware solution. This database world record result used Oracle's Sun Storage 2540-M2 arrays (rotating disk) connected to a SPARC T4-4 server running Oracle Solaris 11 and Oracle Database 11g Release 2 demonstrating the power of Oracle's integrated hardware and software solution. The SPARC T4-4 server based configuration achieved a TPC-H scale factor 3000 world record for four processor systems of 205,792 QphH@3000GB with price/performance of $4.10/QphH@3000GB. The SPARC T4-4 server with four SPARC T4 processors (total of 32 cores) is 7% faster than the IBM Power 780 server with eight POWER7 processors (total of 32 cores) on the TPC-H @3000GB benchmark. The SPARC T4-4 server is 36% better in price performance compared to the IBM Power 780 server on the TPC-H @3000GB Benchmark. The SPARC T4-4 server is 29% faster than the IBM Power 780 for data loading. The SPARC T4-4 server is up to 3.4 times faster than the IBM Power 780 server for the Refresh Function. The SPARC T4-4 server with four SPARC T4 processors is 27% faster than the HP ProLiant DL980 G7 server with eight x86 processors on the TPC-H @3000GB benchmark. The SPARC T4-4 server is 52% faster than the HP ProLiant DL980 G7 server for data loading. The SPARC T4-4 server is up to 3.2 times faster than the HP ProLiant DL980 G7 for the Refresh Function. The SPARC T4-4 server achieved a peak IO rate from the Oracle database of 17 GB/sec. This rate was independent of the storage used, as demonstrated by the TPC-H @3000TB benchmark which used twelve Sun Storage 2540-M2 arrays (rotating disk) and the TPC-H @1000TB benchmark which used four Sun Storage F5100 Flash Array devices (flash storage). [*] The SPARC T4-4 server showed linear scaling from TPC-H @1000GB to TPC-H @3000GB. This demonstrates that the SPARC T4-4 server can handle the increasingly larger databases required of DSS systems. [*] The SPARC T4-4 server benchmark results demonstrate a complete solution of building Decision Support Systems including data loading, business questions and refreshing data. Each phase usually has a time constraint and the SPARC T4-4 server shows superior performance during each phase. [*] The TPC believes that comparisons of results published with different scale factors are misleading and discourages such comparisons. Performance Landscape The table lists the leading TPC-H @3000GB results for non-clustered systems. TPC-H @3000GB, Non-Clustered Systems System Processor P/C/T – Memory Composite(QphH) $/perf($/QphH) Power(QppH) Throughput(QthH) Database Available SPARC Enterprise M9000 3.0 GHz SPARC64 VII+ 64/256/256 – 1024 GB 386,478.3 $18.19 316,835.8 471,428.6 Oracle 11g R2 09/22/11 SPARC T4-4 3.0 GHz SPARC T4 4/32/256 – 1024 GB 205,792.0 $4.10 190,325.1 222,515.9 Oracle 11g R2 05/31/12 SPARC Enterprise M9000 2.88 GHz SPARC64 VII 32/128/256 – 512 GB 198,907.5 $15.27 182,350.7 216,967.7 Oracle 11g R2 12/09/10 IBM Power 780 4.1 GHz POWER7 8/32/128 – 1024 GB 192,001.1 $6.37 210,368.4 175,237.4 Sybase 15.4 11/30/11 HP ProLiant DL980 G7 2.27 GHz Intel Xeon X7560 8/64/128 – 512 GB 162,601.7 $2.68 185,297.7 142,685.6 SQL Server 2008 10/13/10 P/C/T = Processors, Cores, Threads QphH = the Composite Metric (bigger is better) $/QphH = the Price/Performance metric in USD (smaller is better) QppH = the Power Numerical Quantity QthH = the Throughput Numerical Quantity The following table lists data load times and refresh function times during the power run. TPC-H @3000GB, Non-Clustered Systems Database Load & Database Refresh System Processor Data Loading(h:m:s) T4Advan RF1(sec) T4Advan RF2(sec) T4Advan SPARC T4-4 3.0 GHz SPARC T4 04:08:29 1.0x 67.1 1.0x 39.5 1.0x IBM Power 780 4.1 GHz POWER7 05:51:50 1.5x 147.3 2.2x 133.2 3.4x HP ProLiant DL980 G7 2.27 GHz Intel Xeon X7560 08:35:17 2.1x 173.0 2.6x 126.3 3.2x Data Loading = database load time RF1 = power test first refresh transaction RF2 = power test second refresh transaction T4 Advan = the ratio of time to T4 time Complete benchmark results found at the TPC benchmark website http://www.tpc.org. Configuration Summary and Results Hardware Configuration: SPARC T4-4 server 4 x SPARC T4 3.0 GHz processors (total of 32 cores, 128 threads) 1024 GB memory 8 x internal SAS (8 x 300 GB) disk drives External Storage: 12 x Sun Storage 2540-M2 array storage, each with 12 x 15K RPM 300 GB drives, 2 controllers, 2 GB cache Software Configuration: Oracle Solaris 11 11/11 Oracle Database 11g Release 2 Enterprise Edition Audited Results: Database Size: 3000 GB (Scale Factor 3000) TPC-H Composite: 205,792.0 QphH@3000GB Price/performance: $4.10/QphH@3000GB Available: 05/31/2012 Total 3 year Cost: $843,656 TPC-H Power: 190,325.1 TPC-H Throughput: 222,515.9 Database Load Time: 4:08:29 Benchmark Description The TPC-H benchmark is a performance benchmark established by the Transaction Processing Council (TPC) to demonstrate Data Warehousing/Decision Support Systems (DSS). TPC-H measurements are produced for customers to evaluate the performance of various DSS systems. These queries and updates are executed against a standard database under controlled conditions. Performance projections and comparisons between different TPC-H Database sizes (100GB, 300GB, 1000GB, 3000GB, 10000GB, 30000GB and 100000GB) are not allowed by the TPC. TPC-H is a data warehousing-oriented, non-industry-specific benchmark that consists of a large number of complex queries typical of decision support applications. It also includes some insert and delete activity that is intended to simulate loading and purging data from a warehouse. TPC-H measures the combined performance of a particular database manager on a specific computer system. The main performance metric reported by TPC-H is called the TPC-H Composite Query-per-Hour Performance Metric (QphH@SF, where SF is the number of GB of raw data, referred to as the scale factor). QphH@SF is intended to summarize the ability of the system to process queries in both single and multiple user modes. The benchmark requires reporting of price/performance, which is the ratio of the total HW/SW cost plus 3 years maintenance to the QphH. A secondary metric is the storage efficiency, which is the ratio of total configured disk space in GB to the scale factor. Key Points and Best Practices Twelve Sun Storage 2540-M2 arrays were used for the benchmark. Each Sun Storage 2540-M2 array contains 12 15K RPM drives and is connected to a single dual port 8Gb FC HBA using 2 ports. Each Sun Storage 2540-M2 array showed 1.5 GB/sec for sequential read operations and showed linear scaling, achieving 18 GB/sec with twelve Sun Storage 2540-M2 arrays. These were stand alone IO tests. The peak IO rate measured from the Oracle database was 17 GB/sec. Oracle Solaris 11 11/11 required very little system tuning. Some vendors try to make the point that storage ratios are of customer concern. However, storage ratio size has more to do with disk layout and the increasing capacities of disks – so this is not an important metric in which to compare systems. The SPARC T4-4 server and Oracle Solaris efficiently managed the system load of over one thousand Oracle Database parallel processes. Six Sun Storage 2540-M2 arrays were mirrored to another six Sun Storage 2540-M2 arrays on which all of the Oracle database files were placed. IO performance was high and balanced across all the arrays. The TPC-H Refresh Function (RF) simulates periodical refresh portion of Data Warehouse by adding new sales and deleting old sales data. Parallel DML (parallel insert and delete in this case) and database log performance are a key for this function and the SPARC T4-4 server outperformed both the IBM POWER7 server and HP ProLiant DL980 G7 server. (See the RF columns above.) See Also Transaction Processing Performance Council (TPC) Home Page Ideas International Benchmark Page SPARC T4-4 Server oracle.com OTN Oracle Solaris oracle.com OTN Oracle Database 11g Release 2 Enterprise Edition oracle.com OTN Sun Storage 2540-M2 Array oracle.com OTN Disclosure Statement TPC-H, QphH, $/QphH are trademarks of Transaction Processing Performance Council (TPC). For more information, see www.tpc.org. SPARC T4-4 205,792.0 QphH@3000GB, $4.10/QphH@3000GB, available 5/31/12, 4 processors, 32 cores, 256 threads; IBM Power 780 QphH@3000GB, 192,001.1 QphH@3000GB, $6.37/QphH@3000GB, available 11/30/11, 8 processors, 32 cores, 128 threads; HP ProLiant DL980 G7 162,601.7 QphH@3000GB, $2.68/QphH@3000GB available 10/13/10, 8 processors, 64 cores, 128 threads.

    Read the article

  • Magento - edit form in custom module grid

    - by Shani1351
    I have a custom module and I have a working grid to menage the module items in the admin. My module file structore is : app\code\local\G4R\GroupSales\Block\Adminhtml\Groupsale\ I want to add an edit form so I can view and edit each item in the grid. I followed this tutorial : http://www.magentocommerce.com/wiki/5_-_modules_and_development/0_-_module_development_in_magento/custom_module_with_custom_database_table#part_2_-_backend_administration but when the edit page loads, instead of the tab content I get an error : Fatal error: Call to a member function setData() on a non-object in C:\xampp\htdocs\mystore\app\code\core\Mage\Adminhtml\Block\Widget\Form\Container.php on line 129 This is my code : /app/code/local/G4R/GroupSales/Block/Adminhtml/Groupsale/Edit.php <?php class G4R_GroupSales_Block_Adminhtml_Groupsale_Edit extends Mage_Adminhtml_Block_Widget_Form_Container { public function __construct() { parent::__construct(); $this->_objectId = 'id'; $this->_blockGroup = 'groupsale'; $this->_controller = 'adminhtml_groupsales'; $this->_updateButton('save', 'label', Mage::helper('groupsales')->__('Save Item')); $this->_updateButton('delete', 'label', Mage::helper('groupsales')->__('Delete Item')); } public function getHeaderText() { if( Mage::registry('groupsale_data') && Mage::registry('groupsale_data')->getId() ) { return Mage::helper('groupsales')->__("Edit Item '%s'", $this->htmlEscape(Mage::registry('groupsale_data')->getTitle())); } else { return Mage::helper('groupsales')->__('Add Item'); } } } /app/code/local/G4R/GroupSales/Block/Adminhtml/Groupsale/Edit/Form.php : <?php class G4R_GroupSales_Block_Adminhtml_Groupsale_Edit_Form extends Mage_Adminhtml_Block_Widget_Form { protected function _prepareForm() { $form = new Varien_Data_Form(array( 'id' => 'edit_form', 'action' => $this->getUrl('*/*/save', array('id' => $this->getRequest()->getParam('id'))), 'method' => 'post', ) ); $form->setUseContainer(true); $this->setForm($form); return parent::_prepareForm(); } } /app/code/local/G4R/GroupSales/Block/Adminhtml/Groupsale/Edit/Tabs.php: <?php class G4R_GroupSales_Block_Adminhtml_Groupsale_Edit_Tabs extends Mage_Adminhtml_Block_Widget_Tabs { public function __construct() { parent::__construct(); $this->setId('groupsales_groupsale_tabs'); $this->setDestElementId('edit_form'); $this->setTitle(Mage::helper('groupsales')->__('Groupsale Information')); } protected function _beforeToHtml() { $this->addTab('form_section', array( 'label' => Mage::helper('groupsales')->__('Item Information 1'), 'title' => Mage::helper('groupsales')->__('Item Information 2'), 'content' => $this->getLayout()->createBlock('groupsales/adminhtml_groupsale_edit_tab_form')->toHtml(), )); return parent::_beforeToHtml(); } } /app/code/local/G4R/GroupSales/Block/Adminhtml/Groupsale/Edit/Tab/Form.php : <?php class G4R_GroupSales_Block_Adminhtml_Groupsale_Edit_Tab_Form extends Mage_Adminhtml_Block_Widget_Form { protected function _prepareForm() { $form = new Varien_Data_Form(); $this->setForm($form); $fieldset = $form->addFieldset('groupsales_form', array('legend'=>Mage::helper('groupsales')->__('Item information 3'))); // $fieldset->addField('title', 'text', array( // 'label' => Mage::helper('groupsales')->__('Title'), // 'class' => 'required-entry', // 'required' => true, // 'name' => 'title', // )); // if ( Mage::getSingleton('adminhtml/session')->getGroupsaleData() ) { $form->setValues(Mage::getSingleton('adminhtml/session')->getGroupsaleData()); Mage::getSingleton('adminhtml/session')->setGroupsaleData(null); } elseif ( Mage::registry('groupsale_data') ) { $form->setValues(Mage::registry('groupsale_data')->getData()); } return parent::_prepareForm(); } } /app/code/local/G4R/GroupSales/controllers/Adminhtml/GroupsaleController.php : <?php class G4R_GroupSales_Adminhtml_GroupsaleController extends Mage_Adminhtml_Controller_Action { protected function _initAction() { $this->loadLayout() ->_setActiveMenu('groupsale/items') ->_addBreadcrumb(Mage::helper('adminhtml')->__('Items Manager'), Mage::helper('adminhtml')->__('Item Manager')); return $this; } public function indexAction() { $this->_initAction(); $this->_addContent($this->getLayout()->createBlock('groupsales/adminhtml_groupsale')); $this->renderLayout(); } public function editAction() { $groupsaleId = $this->getRequest()->getParam('id'); $groupsaleModel = Mage::getModel('groupsales/groupsale')->load($groupsaleId); if ($groupsaleModel->getId() || $groupsaleId == 0) { Mage::register('groupsale_data', $groupsaleModel); $this->loadLayout(); $this->_setActiveMenu('groupsale/items'); $this->_addBreadcrumb(Mage::helper('adminhtml')->__('Item Manager'), Mage::helper('adminhtml')->__('Item Manager')); $this->_addBreadcrumb(Mage::helper('adminhtml')->__('Item News'), Mage::helper('adminhtml')->__('Item News')); $this->getLayout()->getBlock('head')->setCanLoadExtJs(true); $this->_addContent($this->getLayout()->createBlock('groupsales/adminhtml_groupsale_edit')) ->_addLeft($this->getLayout()->createBlock('groupsales/adminhtml_groupsale_edit_tabs')); $this->renderLayout(); } else { Mage::getSingleton('adminhtml/session')->addError(Mage::helper('groupsales')->__('Item does not exist')); $this->_redirect('*/*/'); } } public function newAction() { $this->_forward('edit'); } public function saveAction() { if ( $this->getRequest()->getPost() ) { try { $postData = $this->getRequest()->getPost(); $groupsaleModel = Mage::getModel('groupsales/groupsale'); $groupsaleModel->setId($this->getRequest()->getParam('id')) ->setTitle($postData['title']) ->setContent($postData['content']) ->setStatus($postData['status']) ->save(); Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('adminhtml')->__('Item was successfully saved')); Mage::getSingleton('adminhtml/session')->setGroupsaleData(false); $this->_redirect('*/*/'); return; } catch (Exception $e) { Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); Mage::getSingleton('adminhtml/session')->setGroupsaleData($this->getRequest()->getPost()); $this->_redirect('*/*/edit', array('id' => $this->getRequest()->getParam('id'))); return; } } $this->_redirect('*/*/'); } public function deleteAction() { if( $this->getRequest()->getParam('id') > 0 ) { try { $groupsaleModel = Mage::getModel('groupsales/groupsale'); $groupsaleModel->setId($this->getRequest()->getParam('id')) ->delete(); Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('adminhtml')->__('Item was successfully deleted')); $this->_redirect('*/*/'); } catch (Exception $e) { Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); $this->_redirect('*/*/edit', array('id' => $this->getRequest()->getParam('id'))); } } $this->_redirect('*/*/'); } /** * Product grid for AJAX request. * Sort and filter result for example. */ public function gridAction() { $this->loadLayout(); $this->getResponse()->setBody( $this->getLayout()->createBlock('importedit/adminhtml_groupsales_grid')->toHtml() ); } } Any ideas what is the cause for the error?

    Read the article

  • Beginning Java (Working with Arrays; Class Assignment)

    - by Jason
    I am to the point where I feel as if I correctly wrote the code for this homework assignment. We were given a skeleton and 2 classes that we had to import (FileIOHelper and Student). /* * Created: *** put the date here *** * * Author: *** put your name here *** * * The program will read information about students and their * scores from a file, and output the name of each student with * all his/her scores and the total score, plus the average score * of the class, and the name and total score of the students with * the highest and lowest total score. */ // import java.util.Scanner; import java.io.*; // C:\Users\Adam\info.txt public class Lab6 { public static void main(String[] args) throws IOException { // Fill in the body according to the following comments Scanner key boardFile = new Scanner(System.in); // Input file name String filename = getFileName(keyboardFile); //Open the file // Input number of students int numStudents = FileIOHelper.getNumberOfStudents(filename); Student students[] = new Student[numStudents]; // Input all student records and create Student array and // integer array for total scores int totalScore[] = new int[students.length]; for (int i = 0; i < students.length; i++){ for(int j = 1; j < 4; j++){ totalScore[i] = totalScore[i] + students[i].getScore(j); } } // Compute total scores and find students with lowest and // highest total score int maxScore = 0; int minScore = 0; for(int i = 0; i < students.length; i++){ if(totalScore[i] >= totalScore[maxScore]){ maxScore = i; } else if(totalScore[i] <= totalScore[minScore]){ minScore = i; } } // Compute average total score int allScores = 0; int average = 0; for (int i = 0; i < totalScore.length; i++){ allScores = allScores + totalScore[i]; } average = allScores / totalScore.length; // Output results outputResults(students, totalScore, maxScore, minScore, average); } // Given a Scanner in, this method prompts the user to enter // a file name, inputs it, and returns it. private static String getFileName(Scanner in) { // Fill in the body System.out.print("Enter the name of a file: "); String filename = in.next(); return filename; // Do not declare the Scanner variable in this method. // You must use the value this method receives in the // argument (in). } // Given the number of students records n to input, this // method creates an array of Student of the appropriate size, // reads n student records using the FileIOHelper, and stores // them in the array, and finally returns the Student array. private static Student[] getStudents(int n) { Student[] myStudents = new Student[n]; for(int i = 0; i <= n; i++){ myStudents[i] = FileIOHelper.getNextStudent(); } return myStudents; } // Given an array of Student records, an array with the total scores, // the indices in the arrays of the students with the highest and // lowest total scores, and the average total score for the class, // this method outputs a table of all the students appropriately // formatted, plus the total number of students, the average score // of the class, and the name and total score of the students with // the highest and lowest total score. private static void outputResults( Student[] students, int[] totalScores, int maxIndex, int minIndex, int average ) { // Fill in the body System.out.println("\nName \t\tScore1 \tScore2 \tScore3 \tTotal"); System.out.println("--------------------------------------------------------"); for(int i = 0; i < students.length; i++){ outputStudent(students[i], totalScores[i], average); System.out.println(); } System.out.println("--------------------------------------------------------"); outputNumberOfStudents(students.length); outputAverage(average); outputMaxStudent(students[maxIndex], totalScores[maxIndex]); outputMinStudent(students[minIndex], totalScores[minIndex]); System.out.println("--------------------------------------------------------"); } // Given a Student record, the total score for the student, // and the average total score for all the students, this method // outputs one line in the result table appropriately formatted. private static void outputStudent(Student s, int total, int avg) { System.out.print(s.getName() + "\t"); for(int i = 1; i < 4; i++){ System.out.print(s.getScore(i) + "\t"); } System.out.print(total + "\t"); if(total < avg){ System.out.print("-"); }else if(total > avg){ System.out.print("+"); }else{ System.out.print("="); } } // Given the number of students, this method outputs a message // stating what the total number of students in the class is. private static void outputNumberOfStudents(int n) { System.out.println("The total number of students in this class is: \t" + n); } // Given the average total score of all students, this method // outputs a message stating what the average total score of // the class is. private static void outputAverage(int average) { System.out.println("The average total score of the class is: \t" + average); } // Given the Student with highest total score and the student's // total score, this method outputs a message stating the name // of the student and the highest score. private static void outputMaxStudent( Student student, int score ) { System.out.println(student.getName() + " got the maximum total score of: \t" + score); } // Given the Student with lowest total score and the student's // total score, this method outputs a message stating the name // of the student and the lowest score. private static void outputMinStudent( Student student, int score ) { System.out.println(student.getName() + " got the minimum total score of: \t" + score); } } But now I get an error at the line totalScore[i] = totalScore[i] + students[i].getScore(j); Exception in thread "main" java.lang.NullPointerException at Lab6.main(Lab6.java:42)

    Read the article

  • storing session data in mysql using php is not retrieving the data properly from the tables.

    - by Ronedog
    I have a problem retrieving some data from the $_SESSION using php and mysql. I've commented out the line in php.ini that tells the server to use the "file" to store the session info so my database will be used. I have a class that I use to write the information to the database and its working fine. When the user passes their credentials the class gets instantiated and the $_SESSION vars get set, then the user gets redirected to the index page. The index.php page includes the file where the db session class is, which when instantiated calles session_start() and the session variables should be in $_SESSION, but when I do var_dump($_SESSION) there is nothing in the array. However, when I look at the data in mysql, all the session information is in there. Its acting like session_start() has not been called, but by instantiating the class it is. Any idea what could be wrong? Here's the HTML: <?php include_once "classes/phpsessions_db/class.dbsession.php"; //used for sessions var_dump($_SESSION); ?> <html> . . . </html> Here's the dbsession class: <?php error_reporting(E_ALL); class dbSession { function dbSession($gc_maxlifetime = "", $gc_probability = "", $gc_divisor = "") { // if $gc_maxlifetime is specified and is an integer number if ($gc_maxlifetime != "" && is_integer($gc_maxlifetime)) { // set the new value @ini_set('session.gc_maxlifetime', $gc_maxlifetime); } // if $gc_probability is specified and is an integer number if ($gc_probability != "" && is_integer($gc_probability)) { // set the new value @ini_set('session.gc_probability', $gc_probability); } // if $gc_divisor is specified and is an integer number if ($gc_divisor != "" && is_integer($gc_divisor)) { // set the new value @ini_set('session.gc_divisor', $gc_divisor); } // get session lifetime $this->sessionLifetime = ini_get("session.gc_maxlifetime"); //Added by AARON. cancel the session's auto start,important, without this the session var's don't show up on next pg. session_write_close(); // register the new handler session_set_save_handler( array(&$this, 'open'), array(&$this, 'close'), array(&$this, 'read'), array(&$this, 'write'), array(&$this, 'destroy'), array(&$this, 'gc') ); register_shutdown_function('session_write_close'); // start the session @session_start(); } function stop() { $new_sess_id = $this->regenerate_id(true); session_unset(); session_destroy(); return $new_sess_id; } function regenerate_id($return_val=false) { // saves the old session's id $oldSessionID = session_id(); // regenerates the id // this function will create a new session, with a new id and containing the data from the old session // but will not delete the old session session_regenerate_id(); // because the session_regenerate_id() function does not delete the old session, // we have to delete it manually //$this->destroy($oldSessionID); //ADDED by aaron // returns the new session id if($return_val) { return session_id(); } } function open($save_path, $session_name) { // global $gf; // $gf->debug_this($gf, "GF: Opening Session"); // change the next values to match the setting of your mySQL database $mySQLHost = "localhost"; $mySQLUsername = "user"; $mySQLPassword = "pass"; $mySQLDatabase = "sessions"; $link = mysql_connect($mySQLHost, $mySQLUsername, $mySQLPassword); if (!$link) { die ("Could not connect to database!"); } $dbc = mysql_select_db($mySQLDatabase, $link); if (!$dbc) { die ("Could not select database!"); } return true; } function close() { mysql_close(); return true; } function read($session_id) { $result = @mysql_query(" SELECT session_data FROM session_data WHERE session_id = '".$session_id."' AND http_user_agent = '".$_SERVER["HTTP_USER_AGENT"]."' AND session_expire > '".time()."' "); // if anything was found if (is_resource($result) && @mysql_num_rows($result) > 0) { // return found data $fields = @mysql_fetch_assoc($result); // don't bother with the unserialization - PHP handles this automatically return unserialize($fields["session_data"]); } // if there was an error return an empty string - this HAS to be an empty string return ""; } function write($session_id, $session_data) { // global $gf; // first checks if there is a session with this id $result = @mysql_query(" SELECT * FROM session_data WHERE session_id = '".$session_id."' "); // if there is if (@mysql_num_rows($result) > 0) { // update the existing session's data // and set new expiry time $result = @mysql_query(" UPDATE session_data SET session_data = '".serialize($session_data)."', session_expire = '".(time() + $this->sessionLifetime)."' WHERE session_id = '".$session_id."' "); // if anything happened if (@mysql_affected_rows()) { // return true return true; } } else // if this session id is not in the database { // $gf->debug_this($gf, "inside dbSession, trying to write to db because session id was NOT in db"); $sql = " INSERT INTO session_data ( session_id, http_user_agent, session_data, session_expire ) VALUES ( '".serialize($session_id)."', '".$_SERVER["HTTP_USER_AGENT"]."', '".$session_data."', '".(time() + $this->sessionLifetime)."' ) "; // insert a new record $result = @mysql_query($sql); // if anything happened if (@mysql_affected_rows()) { // return an empty string return ""; } } // if something went wrong, return false return false; } function destroy($session_id) { // deletes the current session id from the database $result = @mysql_query(" DELETE FROM session_data WHERE session_id = '".$session_id."' "); // if anything happened if (@mysql_affected_rows()) { // return true return true; } // if something went wrong, return false return false; } function gc($maxlifetime) { // it deletes expired sessions from database $result = @mysql_query(" DELETE FROM session_data WHERE session_expire < '".(time() - $maxlifetime)."' "); } } //End of Class $session = new dbsession(); ?>

    Read the article

  • Criticize my code, please

    - by Micky
    Hey, I was applying for a position, and they asked me to complete a coding problem for them. I did so and submitted it, but I later found out I was rejected from the position. Anyways, I have an eclectic programming background so I'm not sure if my code is grossly wrong or if I just didn't have the best solution out there. I would like to post my code and get some feedback about it. Before I do, here's a description of a problem: You are given a sorted array of integers, say, {1, 2, 4, 4, 5, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 11, 13 }. Now you are supposed to write a program (in C or C++, but I chose C) that prompts the user for an element to search for. The program will then search for the element. If it is found, then it should return the first index the entry was found at and the number of instances of that element. If the element is not found, then it should return "not found" or something similar. Here's a simple run of it (with the array I just put up): Enter a number to search for: 4 4 was found at index 2. There are 2 instances for 4 in the array. Enter a number to search for: -4. -4 is not in the array. They made a comment that my code should scale well with large arrays (so I wrote up a binary search). Anyways, my code basically runs as follows: Prompts user for input. Then it checks if it is within bounds (bigger than a[0] in the array and smaller than the largest element of the array). If so, then I perform a binary search. If the element is found, then I wrote two while loops. One while loop will count to the left of the element found, and the second while loop will count to the right of the element found. The loops terminate when the adjacent elements do not match with the desired value. EX: 4, 4, 4, 4, 4 The bold 4 is the value the binary search landed on. One loop will check to the left of it, and another loop will check to the right of it. Their sum will be the total number of instances of the the number four. Anyways, I don't know if there are any advanced techniques that I am missing or if I just don't have the CS background and made a big error. Any constructive critiques would be appreciated! #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stddef.h> /* function prototype */ int get_num_of_ints( const int* arr, size_t r, int N, size_t* first, size_t* count ); int main() { int N; /* input variable */ int arr[]={1,1,2,3,3,4,4,4,4,5,5,7,7,7,7,8,8,8,9,11,12,12}; /* array of sorted integers */ size_t r = sizeof(arr)/sizeof(arr[0]); /* right bound */ size_t first; /* first match index */ size_t count; /* total number of matches */ /* prompts the user to enter input */ printf( "\nPlease input the integer you would like to find.\n" ); scanf( "%d", &N ); int a = get_num_of_ints( arr, r, N, &first, &count ); /* If the function returns -1 then the value is not found. Else it is returned */ if( a == -1) printf( "%d has not been found.\n", N ); else if(a >= 0){ printf( "The first matching index is %d.\n", first ); printf( "The total number of instances is %d.\n", count ); } return 0; } /* function definition */ int get_num_of_ints( const int* arr, size_t r, int N, size_t* first, size_t* count ) { int lo=0; /* lower bound for search */ int m=0; /* middle value obtained */ int hi=r-1; /* upper bound for search */ int w=r-1; /* used as a fixed upper bound to calculate the number of right instances of a particular value. */ /* binary search to find if a value exists */ /* first check if the element is out of bounds */ if( N < arr[0] || arr[hi] < N ){ m = -1; } else{ /* binary search to find a value, if it exists, within given parameters */ while(lo <= hi){ m = (hi + lo)/2; if(arr[m] < N) lo = m+1; else if(arr[m] > N) hi = m-1; else if(arr[m]==N){ m=m; break; } } if (lo > hi) /* if it doesn't we assign it -1 */ m = -1; } /* If the value is found, then we compute the left and right instances of it */ if( m >= 0 ){ int j = m-1; /* starting with the first term to the left */ int L = 0; /* total number of left instances */ /* while loop computes total number of left instances */ while( j >= 0 && arr[j] == arr[m] ){ L++; j--; } /* There are six possible outcomes of this. Depending on the outcome, we must assign the first index variable accordingly */ if( j > 0 && L > 0 ) *first=j+1; else if( j==0 && L==0) *first=m; else if( j > 0 && L==0 ) *first=m; else if(j < 0 && L==0 ) *first=m; else if( j < 0 && L > 0 ) *first=0; else if( j=0 && L > 0 ) *first=j+1; int h = m + 1; /* starting with the first term to the right */ int R = 0; /* total number of right instances */ /* while loop computes total number of right instances */ /* we fixed w earlier so that it's value does not change */ while( arr[h]==arr[m] && h <= w ){ R++; h++; } *count = (R + L + 1); /* total number of instances stored as value of count */ return *first; /* first instance index stored here */ } /* if value does not exist, then we return a negative value */ else if( m==-1) return -1; }

    Read the article

  • Strange (Undefined?) Behavior of Free in C

    - by Chris Cirefice
    This is really strange... and I can't debug it (tried for about two hours, debugger starts going haywire after a while...). Anyway, I'm trying to do something really simple: Free an array of strings. The array is in the form: char **myStrings. The array elements are initialized as: myString[index] = malloc(strlen(word)); myString[index] = word; and I'm calling a function like this: free_memory(myStrings, size); where size is the length of the array (I know this is not the problem, I tested it extensively and everything except this function is working). free_memory looks like this: void free_memory(char **list, int size) { for (int i = 0; i < size; i ++) { free(list[i]); } free(list); } Now here comes the weird part. if (size> strlen(list[i])) then the program crashes. For example, imagine that I have a list of strings that looks something like this: myStrings[0] = "Some"; myStrings[1] = "random"; myStrings[2] = "strings"; And thus the length of this array is 3. If I pass this to my free_memory function, strlen(myStrings[0]) > 3 (4 3), and the program crashes. However, if I change myStrings[0] to be "So" instead, then strlen(myStrings[0]) < 3 (2 < 3) and the program does not crash. So it seems to me that free(list[i]) is actually going through the char[] that is at that location and trying to free each character, which I imagine is undefined behavior. The only reason I say this is because I can play around with the size of the first element of myStrings and make the program crash whenever I feel like it, so I'm assuming that this is the problem area. Note: I did try to debug this by stepping through the function that calls free_memory, noting any weird values and such, but the moment I step into the free_memory function, the debugger crashes, so I'm not really sure what is going on. Nothing is out of the ordinary until I enter the function, then the world explodes. Another note: I also posted the shortened version of the source for this program (not too long; Pastebin) here. I am compiling on MinGW with the c99 flag on. PS - I just thought of this. I am indeed passing numUniqueWords to the free function, and I know that this does not actually free the entire piece of memory that I allocated. I've called it both ways, that's not the issue. And I left it how I did because that is the way that I will be calling it after I get it to work in the first place, I need to revise some of my logic in that function. Source, as per request (on-site): #include <stdio.h> #include <string.h> #include <ctype.h> #include <stdlib.h> #include "words.h" int getNumUniqueWords(char text[], int size); int main(int argc, char* argv[]) { setvbuf(stdout, NULL, 4, _IONBF); // For Eclipse... stupid bug. --> does NOT affect the program, just the output to console! int nbr_words; char text[] = "Some - \"text, a stdin\". We'll have! also repeat? We'll also have a repeat!"; int length = sizeof(text); nbr_words = getNumUniqueWords(text, length); return 0; } void free_memory(char **list, int size) { for (int i = 0; i < size; i ++) { // You can see that printing the values is fine, as long as free is not called. // When free is called, the program will crash if (size > strlen(list[i])) //printf("Wanna free value %d w/len of %d: %s\n", i, strlen(list[i]), list[i]); free(list[i]); } free(list); } int getNumUniqueWords(char text[], int length) { int numTotalWords = 0; char *word; printf("Length: %d characters\n", length); char totalWords[length]; strcpy(totalWords, text); word = strtok(totalWords, " ,.-!?()\"0123456789"); while (word != NULL) { numTotalWords ++; printf("%s\n", word); word = strtok(NULL, " ,.-!?()\"0123456789"); } printf("Looks like we counted %d total words\n\n", numTotalWords); char *uniqueWords[numTotalWords]; char *tempWord; int wordAlreadyExists = 0; int numUniqueWords = 0; char totalWordsCopy[length]; strcpy(totalWordsCopy, text); for (int i = 0; i < numTotalWords; i++) { uniqueWords[i] = NULL; } // Tokenize until all the text is consumed. word = strtok(totalWordsCopy, " ,.-!?()\"0123456789"); while (word != NULL) { // Look through the word list for the current token. for (int j = 0; j < numTotalWords; j ++) { // Just for clarity, no real meaning. tempWord = uniqueWords[j]; // The word list is either empty or the current token is not in the list. if (tempWord == NULL) { break; } //printf("Comparing (%s) with (%s)\n", tempWord, word); // If the current token is the same as the current element in the word list, mark and break if (strcmp(tempWord, word) == 0) { printf("\nDuplicate: (%s)\n\n", word); wordAlreadyExists = 1; break; } } // Word does not exist, add it to the array. if (!wordAlreadyExists) { uniqueWords[numUniqueWords] = malloc(strlen(word)); uniqueWords[numUniqueWords] = word; numUniqueWords ++; printf("Unique: %s\n", word); } // Reset flags and continue. wordAlreadyExists = 0; word = strtok(NULL, " ,.-!?()\"0123456789"); } // Print out the array just for funsies - make sure it's working properly. for (int x = 0; x <numUniqueWords; x++) { printf("Unique list %d: %s\n", x, uniqueWords[x]); } printf("\nNumber of unique words: %d\n\n", numUniqueWords); // Right below is where things start to suck. free_memory(uniqueWords, numUniqueWords); return numUniqueWords; }

    Read the article

  • HW RAID 1 different disk sizes?

    - by jacka
    I was told by an HP support guy that I should not replace a failed drive in a mirror with a bigger size drive, since it could crash my array. I am puzzled why is this so and how to hell am I suppose to support this array once the specific hdd model is not available any more?

    Read the article

  • mdadm: Win7-install created a boot partition on one of my RAID6 drives. How to rebuild?

    - by EXIT_FAILURE
    My problem happened when I attempted to install Windows 7 on it's own SSD. The Linux OS I used which has knowledge of the software RAID system is on a SSD that I disconnected prior to the install. This was so that windows (or I) wouldn't inadvertently mess it up. However, and in retrospect, foolishly, I left the RAID disks connected, thinking that windows wouldn't be so ridiculous as to mess with a HDD that it sees as just unallocated space. Boy was I wrong! After copying over the installation files to the SSD (as expected and desired), it also created an ntfs partition on one of the RAID disks. Both unexpected and totally undesired! . I changed out the SSDs again, and booted up in linux. mdadm didn't seem to have any problem assembling the array as before, but if I tried to mount the array, I got the error message: mount: wrong fs type, bad option, bad superblock on /dev/md0, missing codepage or helper program, or other error In some cases useful info is found in syslog - try dmesg | tail or so dmesg: EXT4-fs (md0): ext4_check_descriptors: Block bitmap for group 0 not in group (block 1318081259)! EXT4-fs (md0): group descriptors corrupted! I then used qparted to delete the newly created ntfs partition on /dev/sdd so that it matched the other three /dev/sd{b,c,e}, and requested a resync of my array with echo repair > /sys/block/md0/md/sync_action This took around 4 hours, and upon completion, dmesg reports: md: md0: requested-resync done. A bit brief after a 4-hour task, though I'm unsure as to where other log files exist (I also seem to have messed up my sendmail configuration). In any case: No change reported according to mdadm, everything checks out. mdadm -D /dev/md0 still reports: Version : 1.2 Creation Time : Wed May 23 22:18:45 2012 Raid Level : raid6 Array Size : 3907026848 (3726.03 GiB 4000.80 GB) Used Dev Size : 1953513424 (1863.02 GiB 2000.40 GB) Raid Devices : 4 Total Devices : 4 Persistence : Superblock is persistent Update Time : Mon May 26 12:41:58 2014 State : clean Active Devices : 4 Working Devices : 4 Failed Devices : 0 Spare Devices : 0 Layout : left-symmetric Chunk Size : 4K Name : okamilinkun:0 UUID : 0c97ebf3:098864d8:126f44e3:e4337102 Events : 423 Number Major Minor RaidDevice State 0 8 16 0 active sync /dev/sdb 1 8 32 1 active sync /dev/sdc 2 8 48 2 active sync /dev/sdd 3 8 64 3 active sync /dev/sde Trying to mount it still reports: mount: wrong fs type, bad option, bad superblock on /dev/md0, missing codepage or helper program, or other error In some cases useful info is found in syslog - try dmesg | tail or so and dmesg: EXT4-fs (md0): ext4_check_descriptors: Block bitmap for group 0 not in group (block 1318081259)! EXT4-fs (md0): group descriptors corrupted! I'm a bit unsure where to proceed from here, and trying stuff "to see if it works" is a bit too risky for me. This is what I suggest I should attempt to do: Tell mdadm that /dev/sdd (the one that windows wrote into) isn't reliable anymore, pretend it is newly re-introduced to the array, and reconstruct its content based on the other three drives. I also could be totally wrong in my assumptions, that the creation of the ntfs partition on /dev/sdd and subsequent deletion has changed something that cannot be fixed this way. My question: Help, what should I do? If I should do what I suggested , how do I do that? From reading documentation, etc, I would think maybe: mdadm --manage /dev/md0 --set-faulty /dev/sdd mdadm --manage /dev/md0 --remove /dev/sdd mdadm --manage /dev/md0 --re-add /dev/sdd However, the documentation examples suggest /dev/sdd1, which seems strange to me, as there is no partition there as far as linux is concerned, just unallocated space. Maybe these commands won't work without. Maybe it makes sense to mirror the partition table of one of the other raid devices that weren't touched, before --re-add. Something like: sfdisk -d /dev/sdb | sfdisk /dev/sdd Bonus question: Why would the Windows 7 installation do something so st...potentially dangerous? Update I went ahead and marked /dev/sdd as faulty, and removed it (not physically) from the array: # mdadm --manage /dev/md0 --set-faulty /dev/sdd # mdadm --manage /dev/md0 --remove /dev/sdd However, attempting to --re-add was disallowed: # mdadm --manage /dev/md0 --re-add /dev/sdd mdadm: --re-add for /dev/sdd to /dev/md0 is not possible --add, was fine. # mdadm --manage /dev/md0 --add /dev/sdd mdadm -D /dev/md0 now reports the state as clean, degraded, recovering, and /dev/sdd as spare rebuilding. /proc/mdstat shows the recovery progress: md0 : active raid6 sdd[4] sdc[1] sde[3] sdb[0] 3907026848 blocks super 1.2 level 6, 4k chunk, algorithm 2 [4/3] [UU_U] [>....................] recovery = 2.1% (42887780/1953513424) finish=348.7min speed=91297K/sec nmon also shows expected output: ¦sdb 0% 87.3 0.0| > |¦ ¦sdc 71% 109.1 0.0|RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR > |¦ ¦sdd 40% 0.0 87.3|WWWWWWWWWWWWWWWWWWWW > |¦ ¦sde 0% 87.3 0.0|> || It looks good so far. Crossing my fingers for another five+ hours :) Update 2 The recovery of /dev/sdd finished, with dmesg output: [44972.599552] md: md0: recovery done. [44972.682811] RAID conf printout: [44972.682815] --- level:6 rd:4 wd:4 [44972.682817] disk 0, o:1, dev:sdb [44972.682819] disk 1, o:1, dev:sdc [44972.682820] disk 2, o:1, dev:sdd [44972.682821] disk 3, o:1, dev:sde Attempting mount /dev/md0 reports: mount: wrong fs type, bad option, bad superblock on /dev/md0, missing codepage or helper program, or other error In some cases useful info is found in syslog - try dmesg | tail or so And on dmesg: [44984.159908] EXT4-fs (md0): ext4_check_descriptors: Block bitmap for group 0 not in group (block 1318081259)! [44984.159912] EXT4-fs (md0): group descriptors corrupted! I'm not sure what do do now. Suggestions? Output of dumpe2fs /dev/md0: dumpe2fs 1.42.8 (20-Jun-2013) Filesystem volume name: Atlas Last mounted on: /mnt/atlas Filesystem UUID: e7bfb6a4-c907-4aa0-9b55-9528817bfd70 Filesystem magic number: 0xEF53 Filesystem revision #: 1 (dynamic) Filesystem features: has_journal ext_attr resize_inode dir_index filetype extent flex_bg sparse_super large_file huge_file uninit_bg dir_nlink extra_isize Filesystem flags: signed_directory_hash Default mount options: user_xattr acl Filesystem state: clean Errors behavior: Continue Filesystem OS type: Linux Inode count: 244195328 Block count: 976756712 Reserved block count: 48837835 Free blocks: 92000180 Free inodes: 243414877 First block: 0 Block size: 4096 Fragment size: 4096 Reserved GDT blocks: 791 Blocks per group: 32768 Fragments per group: 32768 Inodes per group: 8192 Inode blocks per group: 512 RAID stripe width: 2 Flex block group size: 16 Filesystem created: Thu May 24 07:22:41 2012 Last mount time: Sun May 25 23:44:38 2014 Last write time: Sun May 25 23:46:42 2014 Mount count: 341 Maximum mount count: -1 Last checked: Thu May 24 07:22:41 2012 Check interval: 0 (<none>) Lifetime writes: 4357 GB Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root) First inode: 11 Inode size: 256 Required extra isize: 28 Desired extra isize: 28 Journal inode: 8 Default directory hash: half_md4 Directory Hash Seed: e177a374-0b90-4eaa-b78f-d734aae13051 Journal backup: inode blocks dumpe2fs: Corrupt extent header while reading journal super block

    Read the article

  • Simple mdadm RAID 1 not activating spare

    - by Nick Liu
    I had created two 2TB HDD partitions (/dev/sdb1 and /dev/sdc1) in a RAID 1 array called /dev/md0 using mdadm on Ubuntu 12.04 LTS Precise Pangolin. The command sudo mdadm --detail /dev/md0 used to indicate both drives as active sync. Then, for testing, I failed /dev/sdb1, removed it, then added it again with the command sudo mdadm /dev/md0 --add /dev/sdb1 watch cat /proc/mdstat showed a progress bar of the array rebuilding, but I wouldn't spend hours watching it, so I assumed that the software knew what it was doing. After the progress bar was no longer showing, cat /proc/mdstat displays: md0 : active raid1 sdb1[2](S) sdc1[1] 1953511288 blocks super 1.2 [2/1] [U_] And sudo mdadm --detail /dev/md0 shows: /dev/md0: Version : 1.2 Creation Time : Sun May 27 11:26:05 2012 Raid Level : raid1 Array Size : 1953511288 (1863.01 GiB 2000.40 GB) Used Dev Size : 1953511288 (1863.01 GiB 2000.40 GB) Raid Devices : 2 Total Devices : 2 Persistence : Superblock is persistent Update Time : Mon May 28 11:16:49 2012 State : clean, degraded Active Devices : 1 Working Devices : 2 Failed Devices : 0 Spare Devices : 1 Name : Deltique:0 (local to host Deltique) UUID : 49733c26:dd5f67b5:13741fb7:c568bd04 Events : 32365 Number Major Minor RaidDevice State 1 8 33 0 active sync /dev/sdc1 1 0 0 1 removed 2 8 17 - spare /dev/sdb1 I've been told that mdadm automatically replaces removed drives with spares, but /dev/sdb1 isn't being moved into the expected position, RaidDevice 1. UPDATE (30 May 2012): A badblocks destructive read-write test of the entire /dev/sdb yielded no errors as expected; both HDDs are new. As of the latest edit, I assembled the array with this command: sudo mdadm --assemble --force --no-degraded /dev/md0 /dev/sdb1 /dev/sdc1 The output was: mdadm: /dev/md0 has been started with 1 drive (out of 2) and 1 rebuilding. Rebuilding looks like it's progressing normally: md0 : active raid1 sdc1[1] sdb1[2] 1953511288 blocks super 1.2 [2/1] [U_] [>....................] recovery = 0.6% (13261504/1953511288) finish=2299.7min speed=14060K/sec unused devices: <none> I'm now waiting on this rebuild, but I'm expecting /dev/sdb1 to become a spare just like the five or six times that I've tried rebuilding before. UPDATE (31 May 2012): Yeah, it's still a spare. Ugh! UPDATE (01 June 2012): I'm trying Adrian Kelly's suggested command: sudo mdadm --assemble --update=resync /dev/md0 /dev/sdb1 /dev/sdc1 Waiting on the rebuild now... My questions are: Why isn't the spare drive becoming active sync? How can I make the spare drive become active?

    Read the article

  • Should I worry about the integrity of my linux software RAID5 after a crash or kernel panic?

    - by Josh
    I have a dual core Intel i5 Ubuntu Server 10.04 LTS system running kernel 2.6.32-22-server #33-Ubuntu SMP with three 1TB SATA hard drives set up in a RAID5 array using linux md devices. I have read about the RAID5 write hole and am concerned: if my linux system locks up or kernel panics, should I be assume that the integrety of my data has been compromised and restore from backup? How can I know if the data on the RAID5 array is "safe"?

    Read the article

  • mdadm software RAID doesn't load at boot

    - by martinald
    Hi there, I'm using mdadm to create a raid1 mirror across two disks. I can create my /dev/md5 array perfectly using the tools, but it does not automatically reload my /dev/md5 when I restart, I need to manually recreate the array. Am I missing something obvious here?

    Read the article

  • Is memcache impacting my performence negatively?

    - by iTech
    I am using pressflow 6 and NewRelic seems to suggest that memcache is infact hurting performance as shown below : My settings.php file : # Varnish reverse proxy on localhost $conf['reverse_proxy'] = TRUE; $conf['reverse_proxy_addresses'] = array('127.0.0.1'); # Memcached configuration $conf['cache_inc'] = './sites/all/modules/memcache/memcache.inc'; $conf['memcache_servers'] = array( '127.0.0.1:11211' => 'default', ); ### END Mercury settings written on 2011-11-01T07:12:49-04:00

    Read the article

  • What the best way to recover from when your RAID H/W incorrectly thinks a disk is missing

    - by Software Monkey
    I have a Windows 7 system with an MSI motherboard (running the latest AMD BIOS) and two of my four disks (not the system boot disk) configured via the Mobo as RAID-1. After a normal system restart today, the RAID BIOS reports that one of the two drives has been disconnected or has failed. It's not really failed; via recovery tools I can verify that if I take the BIOS out of RAID mode. But I can find no way to re-add the second hard disk to the array and rebuild via the BIOS - the only option seems be to delete the array and recreate it, but I've done that once before and it blows away the disk. It's done this once before, however on a subsequent reboot after double-checking the drive cabling (but not changing anything) and it boot up fine. So I think the mobo RAID is a little bit flaky. At this point I would like to remove the RAID drivers, change to AHCI mode and switch over to using a Windows 7 dynamic mirror disk. But the RAID drivers seem somehow deeply bound into the Windows startup - I can't find anything like the good ol' safe-mode in Windows 7. If I boot from the Win 7 install disk in ACHI mode I can use recovery tools to log in to the Windows 7 installation, so the boot drive it seems fine with ACHI mode. Additionally, I can see all my other disks, run chkdsk on them and they seem to be fine. If I try to boot from the HDD in AHCI mode, it just reboots part way through, presumably because the RAID drivers load and conflict with the BIOS being set to AHCI. So: How do I strip the RAID drivers from my Win 7 installation? If I delete the RAID logical disk, will it really delete partitioning information, or is that just a poorly worded message when it says the data on the disk will be deleted? If I disconnect the 2 disks in a RAID array, then delete the logical disk array, and then reconnect and reboot still in RAID mode, will the disks simply revert to RAID single-disks like my other 2 and then maybe I can leave windows with RAID drivers by operate the disks as singles with 2 of them in a Windows dynamic disk mirrored setup? Does Windows 7 have anything like the Windows XP Repair Install, where it will reinstall the O/S binaries from CD, but leave apps and setup alone. I am really hoping I don't have to do a complete reinstall of Windows 7 - the last one, when I upgraded from XP, took me two days to get everything set up and installed.

    Read the article

  • Nginx - basic http authentication on PHP-script

    - by half_bit
    I added a PHP-Script that serves as "cgi-bin", Configuration: location ~^/cgi-bin/.*\.(cgi|pl|py|rb) { gzip off; fastcgi_pass 127.0.0.1:9000; fastcgi_index cgi-bin.php; fastcgi_param SCRIPT_FILENAME /etc/nginx/cgi-bin.php; fastcgi_param SCRIPT_NAME /cgi-bin/cgi-bin.php; fastcgi_param X_SCRIPT_FILENAME /usr/lib/$fastcgi_script_name; fastcgi_param X_SCRIPT_NAME $fastcgi_script_name; fastcgi_param QUERY_STRING $query_string; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param REMOTE_USER $remote_user; } PHP-Script: <?php $descriptorspec = array( 0 => array("pipe", "r"), // stdin is a pipe that the child will read from 1 => array("pipe", "w"), // stdout is a pipe that the child will write to 2 => array("pipe", "w") // stderr is a file to write to ); $newenv = $_SERVER; $newenv["SCRIPT_FILENAME"] = $_SERVER["X_SCRIPT_FILENAME"]; $newenv["SCRIPT_NAME"] = $_SERVER["X_SCRIPT_NAME"]; if (is_executable($_SERVER["X_SCRIPT_FILENAME"])) { $process = proc_open($_SERVER["X_SCRIPT_FILENAME"], $descriptorspec, $pipes, NULL, $newenv); if (is_resource($process)) { fclose($pipes[0]); $head = fgets($pipes[1]); while (strcmp($head, "\n")) { header($head); $head = fgets($pipes[1]); } fpassthru($pipes[1]); fclose($pipes[1]); fclose($pipes[2]); $return_value = proc_close($process); } else { header("Status: 500 Internal Server Error"); echo("Internal Server Error"); } } else { header("Status: 404 Page Not Found"); echo("Page Not Found"); } ?> The problem with it thought is that I cannot add basic authentication. As soon as I enable it for location ~/cgi-bin it gives me a 404 error when I try to look it up. How can I solve this? I thought about restricting access to only my second server where I then add basic authentication over a proxy, but there must be a simpler solution. Sorry for the bad title, I couldn't think of a better one.

    Read the article

  • Server with 3 Disk, what's the best HD Configuration?

    - by aleroot
    I Have an HP Server with a quad core Opteron and 3 Disk 250Gb S-ATA Disk, i'm thinking about what's the best configuration of the disk for performance and reliability. There is mainly 2 scenario : -RAID 5 with these 3 HD (on the the array 100GB Partition for OS, Other Space for Data Partition) -RAID 1 + 1 Disk for OS (one single Disk OS Installation, RAID 1 Array for a Data Partition) What's the best configuration ? In the Server Run MySQL and Small Document File server, the OS to be installed is Windows Server 2008 ...

    Read the article

  • Removing raid 1 (mirroring) and leaving data on both drives

    - by ajma
    Hello, I have two drives in a raid 1 (mirroring) array. Hardware raid using whatever is built into an Intel motherboard. (asus P5BE) I'd like to remove one drive but keep the data in both (I want to put one of the drives into another machine). Can I go into the raid configuration and remove the array and have the data remain?

    Read the article

  • android listview set dynamically background color of views

    - by Sephy
    Hi everybody, I know that there have quite a lot of answers to similar questions but I couldn't find any solution to my question, so new topic : I'm creating a listview, with one basic view per row, my try is to change the background color of the view by .setbackgroundcolor, but nothing's doing the trick... I define an array of color at the beginning of my resources and i'm trying to display it, I also tried to put the array in the class, write the color like #00FF00, int, and I wanted to try 0x...... but as my colors are in an array, I can't do 0x+myColorsArray[i] because Eclipse tells me that it's not a proper hex color... I'm getting a bit desperate... thanks for any help

    Read the article

  • "Could not authenticate you." -error when using Twitter OAuth.

    - by Martti Laine
    Hello I'm building my first system using Twitters OAuth and have some issues. First, I'm using Abraham's Twitter-class for this and I have followed this tutorial. However, I get these lines on my callback.php: Warning: array_merge() [function.array-merge]: Argument #2 is not an array in C:\xampp\htdocs\twitter\twitterOAuth\OAuth.php on line 301 Warning: strtoupper() expects parameter 1 to be string, array given in C:\xampp\htdocs\twitter\twitterOAuth\OAuth.php on line 373 Oops - an error has occurred. SimpleXMLElement Object ( [request] => /account/verify_credentials.xml [error] => Could not authenticate you. ) Is this problem by Twitter-class, or am I doing something wrong? I have my Consumer Key and Consumer Secret in config.php as tutorial says, but should I store something else? Martti Laine

    Read the article

  • Creating blob properties with Entity Framework 4?

    - by David Veeneman
    I am creating an EF4 model-first application with a WPF UI. One of the controls on my UI is a RichTextDocument, which outputs a WPF FlowDocument. I can either serialize the FlowDocument to a byte array, or extract its XAML markup as a string. I would prefer to use binary serialization, if I can. Here are my questions: If I serialize to a byte array, how do I specify an entity property as a byte array in the EDM Designer? If I extract a XAML markup string, can I specify that the EDM Designer create the corresponding database column as a nvarchar(max) column? As to the second question, I assume I could always manually edit the MyModel.edmx.sql file to change the data type from nvarchar(4000) to nvarchar(max) before executing it, but I would like to know if it can be done in the Designer. Thanks for your help.

    Read the article

  • Improving Partitioned Table Join Performance

    - by Paul White
    The query optimizer does not always choose an optimal strategy when joining partitioned tables. This post looks at an example, showing how a manual rewrite of the query can almost double performance, while reducing the memory grant to almost nothing. Test Data The two tables in this example use a common partitioning partition scheme. The partition function uses 41 equal-size partitions: CREATE PARTITION FUNCTION PFT (integer) AS RANGE RIGHT FOR VALUES ( 125000, 250000, 375000, 500000, 625000, 750000, 875000, 1000000, 1125000, 1250000, 1375000, 1500000, 1625000, 1750000, 1875000, 2000000, 2125000, 2250000, 2375000, 2500000, 2625000, 2750000, 2875000, 3000000, 3125000, 3250000, 3375000, 3500000, 3625000, 3750000, 3875000, 4000000, 4125000, 4250000, 4375000, 4500000, 4625000, 4750000, 4875000, 5000000 ); GO CREATE PARTITION SCHEME PST AS PARTITION PFT ALL TO ([PRIMARY]); There two tables are: CREATE TABLE dbo.T1 ( TID integer NOT NULL IDENTITY(0,1), Column1 integer NOT NULL, Padding binary(100) NOT NULL DEFAULT 0x,   CONSTRAINT PK_T1 PRIMARY KEY CLUSTERED (TID) ON PST (TID) );   CREATE TABLE dbo.T2 ( TID integer NOT NULL, Column1 integer NOT NULL, Padding binary(100) NOT NULL DEFAULT 0x,   CONSTRAINT PK_T2 PRIMARY KEY CLUSTERED (TID, Column1) ON PST (TID) ); The next script loads 5 million rows into T1 with a pseudo-random value between 1 and 5 for Column1. The table is partitioned on the IDENTITY column TID: INSERT dbo.T1 WITH (TABLOCKX) (Column1) SELECT (ABS(CHECKSUM(NEWID())) % 5) + 1 FROM dbo.Numbers AS N WHERE n BETWEEN 1 AND 5000000; In case you don’t already have an auxiliary table of numbers lying around, here’s a script to create one with 10 million rows: CREATE TABLE dbo.Numbers (n bigint PRIMARY KEY);   WITH L0 AS(SELECT 1 AS c UNION ALL SELECT 1), L1 AS(SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B), L2 AS(SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B), L3 AS(SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B), L4 AS(SELECT 1 AS c FROM L3 AS A CROSS JOIN L3 AS B), L5 AS(SELECT 1 AS c FROM L4 AS A CROSS JOIN L4 AS B), Nums AS(SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS n FROM L5) INSERT dbo.Numbers WITH (TABLOCKX) SELECT TOP (10000000) n FROM Nums ORDER BY n OPTION (MAXDOP 1); Table T1 contains data like this: Next we load data into table T2. The relationship between the two tables is that table 2 contains ‘n’ rows for each row in table 1, where ‘n’ is determined by the value in Column1 of table T1. There is nothing particularly special about the data or distribution, by the way. INSERT dbo.T2 WITH (TABLOCKX) (TID, Column1) SELECT T.TID, N.n FROM dbo.T1 AS T JOIN dbo.Numbers AS N ON N.n >= 1 AND N.n <= T.Column1; Table T2 ends up containing about 15 million rows: The primary key for table T2 is a combination of TID and Column1. The data is partitioned according to the value in column TID alone. Partition Distribution The following query shows the number of rows in each partition of table T1: SELECT PartitionID = CA1.P, NumRows = COUNT_BIG(*) FROM dbo.T1 AS T CROSS APPLY (VALUES ($PARTITION.PFT(TID))) AS CA1 (P) GROUP BY CA1.P ORDER BY CA1.P; There are 40 partitions containing 125,000 rows (40 * 125k = 5m rows). The rightmost partition remains empty. The next query shows the distribution for table 2: SELECT PartitionID = CA1.P, NumRows = COUNT_BIG(*) FROM dbo.T2 AS T CROSS APPLY (VALUES ($PARTITION.PFT(TID))) AS CA1 (P) GROUP BY CA1.P ORDER BY CA1.P; There are roughly 375,000 rows in each partition (the rightmost partition is also empty): Ok, that’s the test data done. Test Query and Execution Plan The task is to count the rows resulting from joining tables 1 and 2 on the TID column: SET STATISTICS IO ON; DECLARE @s datetime2 = SYSUTCDATETIME();   SELECT COUNT_BIG(*) FROM dbo.T1 AS T1 JOIN dbo.T2 AS T2 ON T2.TID = T1.TID;   SELECT DATEDIFF(Millisecond, @s, SYSUTCDATETIME()); SET STATISTICS IO OFF; The optimizer chooses a plan using parallel hash join, and partial aggregation: The Plan Explorer plan tree view shows accurate cardinality estimates and an even distribution of rows across threads (click to enlarge the image): With a warm data cache, the STATISTICS IO output shows that no physical I/O was needed, and all 41 partitions were touched: Running the query without actual execution plan or STATISTICS IO information for maximum performance, the query returns in around 2600ms. Execution Plan Analysis The first step toward improving on the execution plan produced by the query optimizer is to understand how it works, at least in outline. The two parallel Clustered Index Scans use multiple threads to read rows from tables T1 and T2. Parallel scan uses a demand-based scheme where threads are given page(s) to scan from the table as needed. This arrangement has certain important advantages, but does result in an unpredictable distribution of rows amongst threads. The point is that multiple threads cooperate to scan the whole table, but it is impossible to predict which rows end up on which threads. For correct results from the parallel hash join, the execution plan has to ensure that rows from T1 and T2 that might join are processed on the same thread. For example, if a row from T1 with join key value ‘1234’ is placed in thread 5’s hash table, the execution plan must guarantee that any rows from T2 that also have join key value ‘1234’ probe thread 5’s hash table for matches. The way this guarantee is enforced in this parallel hash join plan is by repartitioning rows to threads after each parallel scan. The two repartitioning exchanges route rows to threads using a hash function over the hash join keys. The two repartitioning exchanges use the same hash function so rows from T1 and T2 with the same join key must end up on the same hash join thread. Expensive Exchanges This business of repartitioning rows between threads can be very expensive, especially if a large number of rows is involved. The execution plan selected by the optimizer moves 5 million rows through one repartitioning exchange and around 15 million across the other. As a first step toward removing these exchanges, consider the execution plan selected by the optimizer if we join just one partition from each table, disallowing parallelism: SELECT COUNT_BIG(*) FROM dbo.T1 AS T1 JOIN dbo.T2 AS T2 ON T2.TID = T1.TID WHERE $PARTITION.PFT(T1.TID) = 1 AND $PARTITION.PFT(T2.TID) = 1 OPTION (MAXDOP 1); The optimizer has chosen a (one-to-many) merge join instead of a hash join. The single-partition query completes in around 100ms. If everything scaled linearly, we would expect that extending this strategy to all 40 populated partitions would result in an execution time around 4000ms. Using parallelism could reduce that further, perhaps to be competitive with the parallel hash join chosen by the optimizer. This raises a question. If the most efficient way to join one partition from each of the tables is to use a merge join, why does the optimizer not choose a merge join for the full query? Forcing a Merge Join Let’s force the optimizer to use a merge join on the test query using a hint: SELECT COUNT_BIG(*) FROM dbo.T1 AS T1 JOIN dbo.T2 AS T2 ON T2.TID = T1.TID OPTION (MERGE JOIN); This is the execution plan selected by the optimizer: This plan results in the same number of logical reads reported previously, but instead of 2600ms the query takes 5000ms. The natural explanation for this drop in performance is that the merge join plan is only using a single thread, whereas the parallel hash join plan could use multiple threads. Parallel Merge Join We can get a parallel merge join plan using the same query hint as before, and adding trace flag 8649: SELECT COUNT_BIG(*) FROM dbo.T1 AS T1 JOIN dbo.T2 AS T2 ON T2.TID = T1.TID OPTION (MERGE JOIN, QUERYTRACEON 8649); The execution plan is: This looks promising. It uses a similar strategy to distribute work across threads as seen for the parallel hash join. In practice though, performance is disappointing. On a typical run, the parallel merge plan runs for around 8400ms; slower than the single-threaded merge join plan (5000ms) and much worse than the 2600ms for the parallel hash join. We seem to be going backwards! The logical reads for the parallel merge are still exactly the same as before, with no physical IOs. The cardinality estimates and thread distribution are also still very good (click to enlarge): A big clue to the reason for the poor performance is shown in the wait statistics (captured by Plan Explorer Pro): CXPACKET waits require careful interpretation, and are most often benign, but in this case excessive waiting occurs at the repartitioning exchanges. Unlike the parallel hash join, the repartitioning exchanges in this plan are order-preserving ‘merging’ exchanges (because merge join requires ordered inputs): Parallelism works best when threads can just grab any available unit of work and get on with processing it. Preserving order introduces inter-thread dependencies that can easily lead to significant waits occurring. In extreme cases, these dependencies can result in an intra-query deadlock, though the details of that will have to wait for another time to explore in detail. The potential for waits and deadlocks leads the query optimizer to cost parallel merge join relatively highly, especially as the degree of parallelism (DOP) increases. This high costing resulted in the optimizer choosing a serial merge join rather than parallel in this case. The test results certainly confirm its reasoning. Collocated Joins In SQL Server 2008 and later, the optimizer has another available strategy when joining tables that share a common partition scheme. This strategy is a collocated join, also known as as a per-partition join. It can be applied in both serial and parallel execution plans, though it is limited to 2-way joins in the current optimizer. Whether the optimizer chooses a collocated join or not depends on cost estimation. The primary benefits of a collocated join are that it eliminates an exchange and requires less memory, as we will see next. Costing and Plan Selection The query optimizer did consider a collocated join for our original query, but it was rejected on cost grounds. The parallel hash join with repartitioning exchanges appeared to be a cheaper option. There is no query hint to force a collocated join, so we have to mess with the costing framework to produce one for our test query. Pretending that IOs cost 50 times more than usual is enough to convince the optimizer to use collocated join with our test query: -- Pretend IOs are 50x cost temporarily DBCC SETIOWEIGHT(50);   -- Co-located hash join SELECT COUNT_BIG(*) FROM dbo.T1 AS T1 JOIN dbo.T2 AS T2 ON T2.TID = T1.TID OPTION (RECOMPILE);   -- Reset IO costing DBCC SETIOWEIGHT(1); Collocated Join Plan The estimated execution plan for the collocated join is: The Constant Scan contains one row for each partition of the shared partitioning scheme, from 1 to 41. The hash repartitioning exchanges seen previously are replaced by a single Distribute Streams exchange using Demand partitioning. Demand partitioning means that the next partition id is given to the next parallel thread that asks for one. My test machine has eight logical processors, and all are available for SQL Server to use. As a result, there are eight threads in the single parallel branch in this plan, each processing one partition from each table at a time. Once a thread finishes processing a partition, it grabs a new partition number from the Distribute Streams exchange…and so on until all partitions have been processed. It is important to understand that the parallel scans in this plan are different from the parallel hash join plan. Although the scans have the same parallelism icon, tables T1 and T2 are not being co-operatively scanned by multiple threads in the same way. Each thread reads a single partition of T1 and performs a hash match join with the same partition from table T2. The properties of the two Clustered Index Scans show a Seek Predicate (unusual for a scan!) limiting the rows to a single partition: The crucial point is that the join between T1 and T2 is on TID, and TID is the partitioning column for both tables. A thread that processes partition ‘n’ is guaranteed to see all rows that can possibly join on TID for that partition. In addition, no other thread will see rows from that partition, so this removes the need for repartitioning exchanges. CPU and Memory Efficiency Improvements The collocated join has removed two expensive repartitioning exchanges and added a single exchange processing 41 rows (one for each partition id). Remember, the parallel hash join plan exchanges had to process 5 million and 15 million rows. The amount of processor time spent on exchanges will be much lower in the collocated join plan. In addition, the collocated join plan has a maximum of 8 threads processing single partitions at any one time. The 41 partitions will all be processed eventually, but a new partition is not started until a thread asks for it. Threads can reuse hash table memory for the new partition. The parallel hash join plan also had 8 hash tables, but with all 5,000,000 build rows loaded at the same time. The collocated plan needs memory for only 8 * 125,000 = 1,000,000 rows at any one time. Collocated Hash Join Performance The collated join plan has disappointing performance in this case. The query runs for around 25,300ms despite the same IO statistics as usual. This is much the worst result so far, so what went wrong? It turns out that cardinality estimation for the single partition scans of table T1 is slightly low. The properties of the Clustered Index Scan of T1 (graphic immediately above) show the estimation was for 121,951 rows. This is a small shortfall compared with the 125,000 rows actually encountered, but it was enough to cause the hash join to spill to physical tempdb: A level 1 spill doesn’t sound too bad, until you realize that the spill to tempdb probably occurs for each of the 41 partitions. As a side note, the cardinality estimation error is a little surprising because the system tables accurately show there are 125,000 rows in every partition of T1. Unfortunately, the optimizer uses regular column and index statistics to derive cardinality estimates here rather than system table information (e.g. sys.partitions). Collocated Merge Join We will never know how well the collocated parallel hash join plan might have worked without the cardinality estimation error (and the resulting 41 spills to tempdb) but we do know: Merge join does not require a memory grant; and Merge join was the optimizer’s preferred join option for a single partition join Putting this all together, what we would really like to see is the same collocated join strategy, but using merge join instead of hash join. Unfortunately, the current query optimizer cannot produce a collocated merge join; it only knows how to do collocated hash join. So where does this leave us? CROSS APPLY sys.partitions We can try to write our own collocated join query. We can use sys.partitions to find the partition numbers, and CROSS APPLY to get a count per partition, with a final step to sum the partial counts. The following query implements this idea: SELECT row_count = SUM(Subtotals.cnt) FROM ( -- Partition numbers SELECT p.partition_number FROM sys.partitions AS p WHERE p.[object_id] = OBJECT_ID(N'T1', N'U') AND p.index_id = 1 ) AS P CROSS APPLY ( -- Count per collocated join SELECT cnt = COUNT_BIG(*) FROM dbo.T1 AS T1 JOIN dbo.T2 AS T2 ON T2.TID = T1.TID WHERE $PARTITION.PFT(T1.TID) = p.partition_number AND $PARTITION.PFT(T2.TID) = p.partition_number ) AS SubTotals; The estimated plan is: The cardinality estimates aren’t all that good here, especially the estimate for the scan of the system table underlying the sys.partitions view. Nevertheless, the plan shape is heading toward where we would like to be. Each partition number from the system table results in a per-partition scan of T1 and T2, a one-to-many Merge Join, and a Stream Aggregate to compute the partial counts. The final Stream Aggregate just sums the partial counts. Execution time for this query is around 3,500ms, with the same IO statistics as always. This compares favourably with 5,000ms for the serial plan produced by the optimizer with the OPTION (MERGE JOIN) hint. This is another case of the sum of the parts being less than the whole – summing 41 partial counts from 41 single-partition merge joins is faster than a single merge join and count over all partitions. Even so, this single-threaded collocated merge join is not as quick as the original parallel hash join plan, which executed in 2,600ms. On the positive side, our collocated merge join uses only one logical processor and requires no memory grant. The parallel hash join plan used 16 threads and reserved 569 MB of memory:   Using a Temporary Table Our collocated merge join plan should benefit from parallelism. The reason parallelism is not being used is that the query references a system table. We can work around that by writing the partition numbers to a temporary table (or table variable): SET STATISTICS IO ON; DECLARE @s datetime2 = SYSUTCDATETIME();   CREATE TABLE #P ( partition_number integer PRIMARY KEY);   INSERT #P (partition_number) SELECT p.partition_number FROM sys.partitions AS p WHERE p.[object_id] = OBJECT_ID(N'T1', N'U') AND p.index_id = 1;   SELECT row_count = SUM(Subtotals.cnt) FROM #P AS p CROSS APPLY ( SELECT cnt = COUNT_BIG(*) FROM dbo.T1 AS T1 JOIN dbo.T2 AS T2 ON T2.TID = T1.TID WHERE $PARTITION.PFT(T1.TID) = p.partition_number AND $PARTITION.PFT(T2.TID) = p.partition_number ) AS SubTotals;   DROP TABLE #P;   SELECT DATEDIFF(Millisecond, @s, SYSUTCDATETIME()); SET STATISTICS IO OFF; Using the temporary table adds a few logical reads, but the overall execution time is still around 3500ms, indistinguishable from the same query without the temporary table. The problem is that the query optimizer still doesn’t choose a parallel plan for this query, though the removal of the system table reference means that it could if it chose to: In fact the optimizer did enter the parallel plan phase of query optimization (running search 1 for a second time): Unfortunately, the parallel plan found seemed to be more expensive than the serial plan. This is a crazy result, caused by the optimizer’s cost model not reducing operator CPU costs on the inner side of a nested loops join. Don’t get me started on that, we’ll be here all night. In this plan, everything expensive happens on the inner side of a nested loops join. Without a CPU cost reduction to compensate for the added cost of exchange operators, candidate parallel plans always look more expensive to the optimizer than the equivalent serial plan. Parallel Collocated Merge Join We can produce the desired parallel plan using trace flag 8649 again: SELECT row_count = SUM(Subtotals.cnt) FROM #P AS p CROSS APPLY ( SELECT cnt = COUNT_BIG(*) FROM dbo.T1 AS T1 JOIN dbo.T2 AS T2 ON T2.TID = T1.TID WHERE $PARTITION.PFT(T1.TID) = p.partition_number AND $PARTITION.PFT(T2.TID) = p.partition_number ) AS SubTotals OPTION (QUERYTRACEON 8649); The actual execution plan is: One difference between this plan and the collocated hash join plan is that a Repartition Streams exchange operator is used instead of Distribute Streams. The effect is similar, though not quite identical. The Repartition uses round-robin partitioning, meaning the next partition id is pushed to the next thread in sequence. The Distribute Streams exchange seen earlier used Demand partitioning, meaning the next partition id is pulled across the exchange by the next thread that is ready for more work. There are subtle performance implications for each partitioning option, but going into that would again take us too far off the main point of this post. Performance The important thing is the performance of this parallel collocated merge join – just 1350ms on a typical run. The list below shows all the alternatives from this post (all timings include creation, population, and deletion of the temporary table where appropriate) from quickest to slowest: Collocated parallel merge join: 1350ms Parallel hash join: 2600ms Collocated serial merge join: 3500ms Serial merge join: 5000ms Parallel merge join: 8400ms Collated parallel hash join: 25,300ms (hash spill per partition) The parallel collocated merge join requires no memory grant (aside from a paltry 1.2MB used for exchange buffers). This plan uses 16 threads at DOP 8; but 8 of those are (rather pointlessly) allocated to the parallel scan of the temporary table. These are minor concerns, but it turns out there is a way to address them if it bothers you. Parallel Collocated Merge Join with Demand Partitioning This final tweak replaces the temporary table with a hard-coded list of partition ids (dynamic SQL could be used to generate this query from sys.partitions): SELECT row_count = SUM(Subtotals.cnt) FROM ( VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10), (11),(12),(13),(14),(15),(16),(17),(18),(19),(20), (21),(22),(23),(24),(25),(26),(27),(28),(29),(30), (31),(32),(33),(34),(35),(36),(37),(38),(39),(40),(41) ) AS P (partition_number) CROSS APPLY ( SELECT cnt = COUNT_BIG(*) FROM dbo.T1 AS T1 JOIN dbo.T2 AS T2 ON T2.TID = T1.TID WHERE $PARTITION.PFT(T1.TID) = p.partition_number AND $PARTITION.PFT(T2.TID) = p.partition_number ) AS SubTotals OPTION (QUERYTRACEON 8649); The actual execution plan is: The parallel collocated hash join plan is reproduced below for comparison: The manual rewrite has another advantage that has not been mentioned so far: the partial counts (per partition) can be computed earlier than the partial counts (per thread) in the optimizer’s collocated join plan. The earlier aggregation is performed by the extra Stream Aggregate under the nested loops join. The performance of the parallel collocated merge join is unchanged at around 1350ms. Final Words It is a shame that the current query optimizer does not consider a collocated merge join (Connect item closed as Won’t Fix). The example used in this post showed an improvement in execution time from 2600ms to 1350ms using a modestly-sized data set and limited parallelism. In addition, the memory requirement for the query was almost completely eliminated  – down from 569MB to 1.2MB. The problem with the parallel hash join selected by the optimizer is that it attempts to process the full data set all at once (albeit using eight threads). It requires a large memory grant to hold all 5 million rows from table T1 across the eight hash tables, and does not take advantage of the divide-and-conquer opportunity offered by the common partitioning. The great thing about the collocated join strategies is that each parallel thread works on a single partition from both tables, reading rows, performing the join, and computing a per-partition subtotal, before moving on to a new partition. From a thread’s point of view… If you have trouble visualizing what is happening from just looking at the parallel collocated merge join execution plan, let’s look at it again, but from the point of view of just one thread operating between the two Parallelism (exchange) operators. Our thread picks up a single partition id from the Distribute Streams exchange, and starts a merge join using ordered rows from partition 1 of table T1 and partition 1 of table T2. By definition, this is all happening on a single thread. As rows join, they are added to a (per-partition) count in the Stream Aggregate immediately above the Merge Join. Eventually, either T1 (partition 1) or T2 (partition 1) runs out of rows and the merge join stops. The per-partition count from the aggregate passes on through the Nested Loops join to another Stream Aggregate, which is maintaining a per-thread subtotal. Our same thread now picks up a new partition id from the exchange (say it gets id 9 this time). The count in the per-partition aggregate is reset to zero, and the processing of partition 9 of both tables proceeds just as it did for partition 1, and on the same thread. Each thread picks up a single partition id and processes all the data for that partition, completely independently from other threads working on other partitions. One thread might eventually process partitions (1, 9, 17, 25, 33, 41) while another is concurrently processing partitions (2, 10, 18, 26, 34) and so on for the other six threads at DOP 8. The point is that all 8 threads can execute independently and concurrently, continuing to process new partitions until the wider job (of which the thread has no knowledge!) is done. This divide-and-conquer technique can be much more efficient than simply splitting the entire workload across eight threads all at once. Related Reading Understanding and Using Parallelism in SQL Server Parallel Execution Plans Suck © 2013 Paul White – All Rights Reserved Twitter: @SQL_Kiwi

    Read the article

< Previous Page | 274 275 276 277 278 279 280 281 282 283 284 285  | Next Page >