Index: comment.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project_issue/comment.inc,v
retrieving revision 1.102
diff -u -p -r1.102 comment.inc
--- comment.inc	12 Oct 2007 23:41:25 -0000	1.102
+++ comment.inc	13 Oct 2007 00:57:49 -0000
@@ -70,8 +70,42 @@ function project_issue_comment(&$arg, $o
       unset($form['page'], $form['issue_details'], $form['project_help']);
       return $form;
     case 'insert':
-      db_query("INSERT INTO {project_issue_comments} (nid, cid, pid, rid, component, category, priority, assigned, sid, title, timestamp) VALUES (%d, %d, %d, %d, '%s', '%s', %d, %d, %d, '%s', %d)", $arg['nid'], $arg['cid'], $arg['project_info']['pid'], $arg['project_info']['rid'], $arg['project_info']['component'], $arg['category'], $arg['priority'], $arg['assigned'], $arg['sid'], $arg['title'], $arg['timestamp']);
-      project_issue_update_by_comment($arg, 'insert');
+      // Get a lock on the issue in order to generate the next comment ID.
+      $tries = 20;
+      $sleep_increment = 0;
+      while ($tries) {
+        $lock = db_query("UPDATE {project_issues} SET db_lock = 1 WHERE nid = %d AND db_lock = 0", $arg['nid']);
+        if (db_affected_rows()) {
+          $id = db_result(db_query("SELECT last_comment_id FROM {project_issues} WHERE nid = %d", $arg['nid'])) + 1;
+          db_query("UPDATE {project_issues} SET last_comment_id = %d, db_lock = 0 WHERE nid = %d", $id, $arg['nid']);
+          break;
+        }
+
+        // Wait a random and increasing amount of time before the next attempt.
+        $sleep = rand(10000, 1000000) + $sleep_increment;
+        usleep($sleep);
+        $sleep_increment += 50000;
+        $tries--;
+      }
+
+      if (isset($id)) {
+        db_query("INSERT INTO {project_issue_comments} (nid, cid, pid, rid, component, category, priority, assigned, sid, title, timestamp) VALUES (%d, %d, %d, %d, '%s', '%s', %d, %d, %d, '%s', %d)", $arg['nid'], $arg['cid'], $arg['project_info']['pid'], $arg['project_info']['rid'], $arg['project_info']['component'], $arg['category'], $arg['priority'], $arg['assigned'], $arg['sid'], $arg['title'], $arg['timestamp']);
+        db_query("UPDATE {comments} SET subject = '%s' WHERE cid = %d", "#$id", $arg['nid']);
+        project_issue_update_by_comment($arg, 'insert');
+
+      }
+      else {
+        drupal_set_message(t('There was an error submitting your comment -- please try again. If the problem persists, contact the system administrator.'), 'error');
+        watchdog('project_issue', t('Error obtaining lock for project issue %nid', array('%nid' => $arg['nid'])), WATCHDOG_ERROR, 'node/'. $arg['nid']);
+        // This is a bit extreme, but we have to clean up the failed comment,
+        // or it will appear on the issue.
+        _comment_delete_thread((object) $arg);
+        _comment_update_node_statistics($arg['nid']);
+        cache_clear_all();
+        // The hard redirect prevents any bogus data from being inserted for the failed comment.
+        drupal_goto('node/'. $arg['nid']);
+      }
+
       break;
     case 'update':
       project_issue_update_by_comment($arg, 'update');
Index: issue.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project_issue/issue.inc,v
retrieving revision 1.264
diff -u -p -r1.264 issue.inc
--- issue.inc	12 Oct 2007 20:29:10 -0000	1.264
+++ issue.inc	13 Oct 2007 00:57:51 -0000
@@ -936,7 +936,7 @@ function project_issue_insert($node) {
     $original_issue_data->$field = $node->$field;
   }
 
-  db_query("INSERT INTO {project_issues} (nid, pid, category, component, priority, rid, assigned, sid, file_path, file_mime, file_size, original_issue_data) VALUES (%d, %d, '%s', '%s', %d, %d, %d, %d, '%s', '%s', %d, '%s')", $node->nid, $node->pid, $node->category, $node->component, $node->priority, $node->rid, $node->assigned, $node->sid, $file->filepath, $file->filemime, $file->filesize, serialize($original_issue_data));
+  db_query("INSERT INTO {project_issues} (nid, pid, category, component, priority, rid, assigned, sid, file_path, file_mime, file_size, original_issue_data, last_comment_id, db_lock) VALUES (%d, %d, '%s', '%s', %d, %d, %d, %d, '%s', '%s', %d, '%s', %d, %d)", $node->nid, $node->pid, $node->category, $node->component, $node->priority, $node->rid, $node->assigned, $node->sid, $file->filepath, $file->filemime, $file->filesize, serialize($original_issue_data), 0, 0);
   project_mail_notify($node);
 }
 
Index: project_issue.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project_issue/project_issue.install,v
retrieving revision 1.24
diff -u -p -r1.24 project_issue.install
--- project_issue.install	7 Oct 2007 21:42:53 -0000	1.24
+++ project_issue.install	13 Oct 2007 00:57:51 -0000
@@ -34,6 +34,8 @@ function project_issue_install() {
           file_mime varchar(255) NOT NULL default '',
           file_size int NOT NULL default 0,
           original_issue_data text NOT NULL default '',
+          last_comment_id int NOT NULL default 0,
+          db_lock tinyint NOT NULL default 0,
           PRIMARY KEY (nid),
           KEY project_issues_pid (pid),
           KEY project_issues_sid (sid),
@@ -100,6 +102,8 @@ function project_issue_install() {
             file_mime varchar(255) default '' NOT NULL,
             file_size int default 0 NOT NULL,
             original_issue_data text NOT NULL default '',
+            last_comment_id int NOT NULL default 0,
+            db_lock smallint NOT NULL default 0,
             PRIMARY KEY (nid)
           );");
         db_query("CREATE INDEX {project_issues}_pid_idx ON {project_issues}(pid)");
@@ -416,6 +420,8 @@ function project_issue_update_5200() {
           INDEX nid_timestamp (nid, timestamp)
         ) /*!40100 DEFAULT CHARACTER SET utf8 */");
       $ret[] = update_sql("ALTER TABLE {project_issues} ADD COLUMN original_issue_data text NOT NULL DEFAULT ''");
+      $ret[] = update_sql("ALTER TABLE {project_issues} ADD COLUMN last_comment_id int NOT NULL default 0");
+      $ret[] = update_sql("ALTER TABLE {project_issues} ADD COLUMN db_lock tinyint NOT NULL default 0");
       break;
 
     case 'pgsql':
@@ -437,6 +443,8 @@ function project_issue_update_5200() {
         $ret[] = update_sql('CREATE INDEX {project_issue_comments}_nid_timestamp_idx ON {project_issue_comments} (nid, timestamp)');
       }
       db_add_column(&$ret, 'project_issues', 'original_issue_data', 'text', array('not null' => TRUE, 'default' => "''"));
+      db_add_column(&$ret, 'project_issues', 'last_comment_id', 'int', array('not null' => TRUE, 'default' => 0));
+      db_add_column(&$ret, 'project_issues', 'db_lock', 'smallint', array('not null' => TRUE, 'default' => 0));
     break;
   }
   $ret[] = update_sql("UPDATE {node} SET comment = ". COMMENT_NODE_READ_WRITE ." WHERE type = 'project_issue';");
@@ -546,6 +554,7 @@ function project_issue_update_5201() {
         db_query("INSERT INTO {comment_upload_files} (fid, nid, cid, filename, filepath, filemime, filesize, description, list) VALUES (%d, %d, %d, '%s', '%s', '%s', %d, '%s', %d)", $fid, $nid, $cid, basename($comment->file_path), $comment->file_path, $comment->file_mime, $comment->file_size, '', 1);
       }
     }
+    db_query("UPDATE {project_issues} SET last_comment_id = %d WHERE nid = %d", $subject, $nid);
     _comment_update_node_statistics($nid);
     $_SESSION['project_issue_update_6000']++;
   }
Index: project_issue.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/project_issue/project_issue.module,v
retrieving revision 1.57
diff -u -p -r1.57 project_issue.module
--- project_issue.module	12 Oct 2007 23:41:25 -0000	1.57
+++ project_issue.module	13 Oct 2007 00:57:52 -0000
@@ -68,7 +68,7 @@ function project_issue_form_alter($form_
         // This is only for show, the number will be generated when the comment
         // is posted.
         else {
-          $next_id = db_result(db_query('SELECT COUNT(cid) FROM {project_issue_comments} WHERE nid = %d', $form['nid']['#value'])) + 1;
+          $next_id = db_result(db_query('SELECT last_comment_id FROM {project_issues} WHERE nid = %d', $form['nid']['#value'])) + 1;
           $subject = "#$next_id";
         }
         $form['subject'] = array(
