InfiniSQL  v0.1.2-alpha
Massive Scale Transaction Processing
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Table.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Mark Travis <mtravis15432+src@gmail.com>
3  * All rights reserved. No warranty, explicit or implicit, provided.
4  *
5  * This file is part of InfiniSQL(tm).
6 
7  * InfiniSQL is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 3
9  * as published by the Free Software Foundation.
10  *
11  * InfiniSQL is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with InfiniSQL. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
28 #include "Table.h"
29 #line 30 "Table.cc"
30 
31 Table::Table(int64_t idarg) : id(idarg)
32 {
33  if (id) // if a real table, create a shadow table with id 0
34  {
35  shadowTable = new class Table(0);
36  }
37 
38  name = "";
39  rowsize = 0;
40 }
41 
42 void Table::setname(string namearg)
43 {
44  name = namearg;
45 }
46 
47 string *Table::getname()
48 {
49  return &name;
50 }
51 
52 int64_t Table::addfield(fieldtype_e type, int64_t length, string name,
53  indextype_e indextype)
54 {
55  class Field newfield(type, length, indextype, name);
56 
57  fields.push_back(newfield);
58  columnaNameToFieldMap[name] = fields.size() - 1;
59 
60  if (rowsize != -1)
61  {
62  rowsize += sizeof(bool);
63 
64  switch (type)
65  {
66  case INT:
67  rowsize += sizeof(int64_t);
68  break;
69 
70  case UINT:
71  rowsize += sizeof(uint64_t);
72  break;
73 
74  case BOOL:
75  rowsize += sizeof(bool);
76  break;
77 
78  case FLOAT:
79  rowsize += sizeof(long double);
80 
81  case CHAR:
82  rowsize += sizeof(char);
83  break;
84 
85  case CHARX:
86  rowsize += length;
87  break;
88 
89  case VARCHAR:
90  rowsize = -1;
91  break;
92 
93  default:
94  fprintf(logfile, "anomaly: %i %s %i\n", type, __FILE__, __LINE__);
95  }
96  }
97 
98  return fields.size() - 1;
99 }
100 
101 bool Table::makerow(vector<fieldValue_s> *fieldVal, string *res)
102 {
103  vector<fieldValue_s> &fieldValRef = *fieldVal;
104 
105  if (fieldValRef.size() != fields.size())
106  {
107  fprintf(logfile, "%s %i anomaly fieldValRef.size() %lu fields.size() %lu\n", __FILE__, __LINE__, (unsigned long)fieldValRef.size(),
108  (unsigned long)fields.size());
109  return false;
110  }
111 
112  if (rowsize != -1)
113  {
114  res->assign(rowsize, 0);
115  }
116  else
117  {
118  int64_t rsize = 0;
119  bool hasvarchar=false;
120 
121  for (size_t n=0; n<fieldValRef.size(); n++)
122  {
123  rsize += sizeof(bool);
124  rowsize += sizeof(bool);
125 
126  switch (fields[n].type)
127  {
128  case INT:
129  rsize += sizeof(int64_t);
130  break;
131 
132  case UINT:
133  rsize += sizeof(uint64_t);
134  break;
135 
136  case BOOL:
137  rsize += sizeof(bool);
138  break;
139 
140  case FLOAT:
141  rsize += sizeof(long double);
142  break;
143 
144  case CHAR:
145  rsize += sizeof(char);
146  break;
147 
148  case CHARX:
149  rsize += fields[n].length;
150  break;
151 
152  case VARCHAR:
153  rsize += sizeof(int64_t);
154  rsize += fieldValRef[n].str.length();
155  hasvarchar=true;
156  break;
157 
158  default:
159  fprintf(logfile, "anomaly: %i %s %i\n", fields[n].type, __FILE__,
160  __LINE__);
161  }
162 
163  }
164 
165  if (hasvarchar==true)
166  {
167  rowsize=-1;
168  }
169 
170  res->assign(rsize, 0);
171  }
172 
173  int64_t pos = 0;
174 
175  for (size_t n=0; n<fields.size(); n++)
176  {
177  if (fieldValRef[n].isnull==false)
178  {
179  res->operator [](pos++)=0;
180  }
181  else
182  {
183  res->operator[](pos++)=1;
184  continue;
185  }
186 
187  switch (fields[n].type)
188  {
189  case INT:
190  memcpy(&res->operator [](pos), &fieldValRef[n].value.integer,
191  sizeof(fieldValRef[n].value.integer));
192  pos += sizeof(fieldValRef[n].value.integer);
193  break;
194 
195  case UINT:
196  memcpy(&res->operator [](pos), &fieldValRef[n].value.uinteger,
197  sizeof(fieldValRef[n].value.uinteger));
198  pos += sizeof(fieldValRef[n].value.uinteger);
199  break;
200 
201  case BOOL:
202  memcpy(&res->operator [](pos), &fieldValRef[n].value.boolean,
203  sizeof(fieldValRef[n].value.boolean));
204  pos += sizeof(fieldValRef[n].value.boolean);
205  break;
206 
207  case FLOAT:
208  memcpy(&res->operator [](pos), &fieldValRef[n].value.floating,
209  sizeof(fieldValRef[n].value.floating));
210  pos += sizeof(fieldValRef[n].value.floating);
211  break;
212 
213  case CHAR:
214  memcpy(&res->operator [](pos), &fieldValRef[n].value.character,
215  sizeof(fieldValRef[n].value.character));
216  pos += sizeof(fieldValRef[n].value.character);
217  break;
218 
219  case CHARX:
220 
221  // pad if necessary
222  if (fieldValRef[n].str.length() < (size_t)fields[n].length)
223  {
224  fieldValRef[n].str.append(fields[n].length-
225  fieldValRef[n].str.length(), ' ');
226  }
227 
228  fieldValRef[n].str.copy(&res->operator [](pos), fields[n].length, 0);
229  pos += fields[n].length;
230  break;
231 
232  case VARCHAR:
233  {
234  int64_t varcharlength = fieldValRef[n].str.length();
235  memcpy(&res->operator [](pos),
236  &varcharlength, sizeof(varcharlength));
237  pos += sizeof(varcharlength);
238  memcpy(&res->operator [](pos), fieldValRef[n].str.c_str(),
239  varcharlength);
240  pos += varcharlength;
241  }
242  break;
243 
244  default:
245  fprintf(logfile, "anomaly: %i %s %i\n", fields[n].type, __FILE__,
246  __LINE__);
247  }
248  }
249 
250  return true;
251 }
252 
253 void Table::getrows(vector<int64_t> rowids, locktype_e locktype,
254  int64_t subtransactionid, int64_t pendingcmdid,
255  vector<returnRow_s> *returnRows,
256  vector<int64_t> *lockPendingRowids,
257  int64_t tacmdentrypoint)
258 {
259  if (locktype != NOLOCK)
260  {
261  lockPendingRowids->clear();
262  }
263 
264  rowdata_s *currentRowPtr;
265 
266  for (size_t n=0; n < rowids.size(); n++)
267  {
268  int64_t rid = rowids[n];
269 
270  if (rows.count(rid))
271  {
272  currentRowPtr = rows[rid];
273 
274  switch (locktype)
275  {
276  case NOLOCK:
277  {
278  if (getinsertflag(currentRowPtr->flags)==false)
279  {
280  returnRow_s r = {};
281  r.rowid = rid;
282  r.row = currentRowPtr->row;
283  returnRows->push_back(r);
284  }
285  }
286  break;
287 
288  case READLOCK:
289  {
290  switch (getlocktype(currentRowPtr->flags))
291  {
292  case NOLOCK: // lock it and add create readlockHolders
293  {
294  returnRow_s r = {};
295  r.rowid = rid;
296  r.row = currentRowPtr->row;
297  returnRows->push_back(r);
298  setreadlock(&currentRowPtr->flags);
299  currentRowPtr->readlockHolders =
300  new boost::unordered_set<int64_t>;
301  printf("%s %i ROWID %li READLOCKHOLDERS->insert %li\n",
302  __FILE__, __LINE__, rid, subtransactionid);
303  currentRowPtr->readlockHolders->insert(subtransactionid);
304  }
305  break;
306 
307  case READLOCK:
308  {
309  printf("%s %i ROWID %li READLOCKHOLDERS->insert %li\n",
310  __FILE__, __LINE__, rid, subtransactionid);
311  currentRowPtr->readlockHolders->insert(subtransactionid);
312  returnRow_s r = {};
313  r.rowid = rid;
314  r.row = currentRowPtr->row;
315  returnRows->push_back(r);
316  }
317  break;
318 
319  case WRITELOCK:
320  {
321  // make it pending
322  lockQueueRowEntry qEntry = {};
323  // populate qEntry, d'accord
324  qEntry.pendingcmdid = pendingcmdid;
325  qEntry.tacmdentrypoint = tacmdentrypoint;
326  qEntry.subtransactionid = subtransactionid;
327  qEntry.locktype = READLOCK;
328  lockQueue[rid].push(qEntry);
329  lockPendingRowids->push_back(rid);
330  }
331  break;
332 
333  default:
334  fprintf(logfile, "anomaly: %i %s %i\n",
335  getlocktype(currentRowPtr->flags), __FILE__,
336  __LINE__);
337  }
338  }
339  break;
340 
341  case WRITELOCK:
342  {
343  switch (getlocktype(currentRowPtr->flags))
344  {
345  case NOLOCK:
346  {
347  // lock it & return
348  setwritelock(&currentRowPtr->flags);
349  currentRowPtr->writelockHolder = subtransactionid;
350  returnRow_s r = {};
351  r.rowid = rid;
352  r.row = currentRowPtr->row;
353  returnRows->push_back(r);
354  }
355  break;
356 
357  case READLOCK:
358  {
359  // lock pending
360  lockQueueRowEntry qEntry = {};
361  // populate qEntry, d'accord
362  qEntry.pendingcmdid = pendingcmdid;
363  qEntry.tacmdentrypoint = tacmdentrypoint;
364  qEntry.subtransactionid = subtransactionid;
365  qEntry.locktype = WRITELOCK;
366  lockQueue[rid].push(qEntry);
367  lockPendingRowids->push_back(rid);
368  }
369  break;
370 
371  case WRITELOCK:
372  {
373  // lock pending
374  lockQueueRowEntry qEntry = {};
375  // populate qEntry, d'accord
376  qEntry.pendingcmdid = pendingcmdid;
377  qEntry.tacmdentrypoint = tacmdentrypoint;
378  qEntry.subtransactionid = subtransactionid;
379  qEntry.locktype = WRITELOCK;
380  lockQueue[rid].push(qEntry);
381  lockPendingRowids->push_back(rid);
382  }
383  break;
384 
385  default:
386  fprintf(logfile, "anomaly: %i %s %i\n",
387  getlocktype(currentRowPtr->flags), __FILE__,
388  __LINE__);
389  }
390  }
391  break;
392 
393  default:
394  fprintf(logfile, "anomaly: %i %s %i\n", locktype, __FILE__,
395  __LINE__);
396  }
397  }
398  }
399 }
400 
401 int64_t Table::updaterow(int64_t rowid, int64_t subtransactionid, string *row)
402 {
403  if (!rows.count(rowid))
404  {
405  return STATUS_NOTOK;
406  }
407 
408  rowdata_s &currentRowRef = *rows[rowid];
409 
410  if ((getlocktype(currentRowRef.flags) != WRITELOCK) ||
411  (currentRowRef.writelockHolder != subtransactionid))
412  {
413  fprintf(logfile, "anomaly %i %li %s %i\n", currentRowRef.flags,
414  currentRowRef.writelockHolder, __FILE__, __LINE__);
415  return STATUS_NOTOK;
416  }
417 
418  // should probably validate the row is not garbage, but o well
419  rowdata_s *nrow=new rowdata_s();
420  nrow->row=*row;
421  shadowTable->rows[rowid]=nrow;
422 
423  return STATUS_OK;
424 }
425 
426 // this means there's a replacement row, so index hits that refer here
427 // need to be forwarded on
428 int64_t Table::deleterow(int64_t rowid, int64_t subtransactionid,
429  int64_t forward_rowid, int64_t forward_engineid)
430 {
431  int64_t status = deleterow(rowid, subtransactionid);
432 
433  if (status)
434  {
435  return status;
436  }
437 
438  rowdata_s &currentRowRef = *rows[rowid];
439 
440  setreplacedeleteflag(&currentRowRef.flags);
441  forwarderEntry forwarder;
442  forwarder.rowid = forward_rowid;
443  forwarder.engineid = forward_engineid;
444  forwarderMap[rowid] = forwarder;
445  return STATUS_OK;
446 }
447 
448 void Table::selectrows(vector<int64_t> *rowids, locktype_e locktype,
449  int64_t subtransactionid, int64_t pendingcmdid,
450  vector<returnRow_s> *returnRows, int64_t tacmdentrypoint)
451 {
452  vector<returnRow_s> &returnRowsRef = *returnRows;
453  size_t numrowids = rowids->size();
454  returnRowsRef.reserve(numrowids);
455  returnRow_s workrow;
456  int64_t rowid;
457 
458  switch (locktype)
459  {
460  case NOLOCK:
461  {
462  for (size_t n=0; n<numrowids; n++)
463  {
464  rowid = rowids->at(n);
465  workrow.rowid = rowid;
466 
467  if (!rows.count(rowid))
468  {
469  workrow.row.clear();
470  workrow.locktype = NOTFOUNDLOCK;
471  }
472  else
473  {
474  switch (getlocktype(rows[rowid]->flags))
475  {
476  case NOLOCK:
477  break;
478 
479  case READLOCK:
480  if (rows[rowid]->readlockHolders->count(subtransactionid))
481  {
482  continue;
483  }
484 
485  break;
486 
487  case WRITELOCK:
488  if (rows[rowid]->writelockHolder==subtransactionid)
489  {
490  continue;
491  }
492 
493  break;
494 
495  default:
496  printf("%s %i anomaly %i\n", __FILE__, __LINE__,
497  getlocktype(rows[rowid]->flags));
498  continue;
499  }
500 
501  workrow.row = rows[rowid]->row;
502  workrow.locktype = NOLOCK;
503  }
504 
505  returnRowsRef.push_back(workrow);
506  }
507  }
508  break;
509 
510  case READLOCK:
511  {
512  for (size_t n=0; n<numrowids; n++)
513  {
514  rowid = rowids->at(n);
515  workrow.rowid = rowid;
516 
517  if (!rows.count(rowid))
518  {
519  workrow.row.clear();
520  workrow.locktype = NOTFOUNDLOCK;
521  }
522  else
523  {
524  switch (getlocktype(rows[rowid]->flags))
525  {
526  case NOLOCK: // lock it & return row
527  setreadlock(&rows[rowid]->flags);
528  rows[rowid]->readlockHolders =
529  new boost::unordered_set<int64_t>;
530  rows[rowid]->readlockHolders->insert(subtransactionid);
531  workrow.row = rows[rowid]->row;
532  workrow.locktype = READLOCK;
533  break;
534 
535  case READLOCK:
536  if (rows[rowid]->readlockHolders->count(subtransactionid))
537  {
538  continue;
539  }
540  else
541  {
542  rows[rowid]->readlockHolders->insert(subtransactionid);
543  workrow.row = rows[rowid]->row;
544  workrow.locktype = READLOCK;
545  }
546 
547  break;
548 
549  case WRITELOCK: // pending
550  {
551  if (rows[rowid]->writelockHolder==subtransactionid)
552  {
553  continue;
554  }
555 
556  if (assignToLockQueue(rowid, READLOCK, subtransactionid,
557  pendingcmdid,
558  tacmdentrypoint)==NOTFOUNDLOCK)
559  {
560  continue;
561  }
562 
563  workrow.row.clear();
564  workrow.locktype = PENDINGLOCK;
565  }
566  break;
567 
568  default:
569  fprintf(logfile, "anomaly: %i %s %i\n",
570  getlocktype(rows[rowid]->flags), __FILE__, __LINE__);
571  }
572  }
573 
574  returnRowsRef.push_back(workrow);
575  }
576  }
577  break;
578 
579  case WRITELOCK:
580  {
581  for (size_t n=0; n<numrowids; n++)
582  {
583  rowid = rowids->at(n);
584  workrow.rowid = rowid;
585 
586  if (!rows.count(rowid))
587  {
588  workrow.row.clear();
589  workrow.locktype = NOTFOUNDLOCK;
590  }
591  else
592  {
593  switch (getlocktype(rows[rowid]->flags))
594  {
595  case NOLOCK: // lock it & return row
596  setwritelock(&rows[rowid]->flags);
597  rows[rowid]->writelockHolder = subtransactionid;
598  workrow.row = rows[rowid]->row;
599  workrow.locktype = WRITELOCK;
600  break;
601 
602  case READLOCK: // pending
603  if (assignToLockQueue(rowid, WRITELOCK, subtransactionid,
604  pendingcmdid,
605  tacmdentrypoint)==NOTFOUNDLOCK)
606  {
607  continue;
608  }
609 
610  workrow.row.clear();
611  workrow.locktype = PENDINGLOCK;
612  break;
613 
614  case WRITELOCK: // pending
615  if (subtransactionid == rows[rowid]->writelockHolder)
616  {
617  workrow.row = rows[rowid]->row;
618  workrow.locktype = WRITELOCK;
619  }
620  else
621  {
622  if (assignToLockQueue(rowid, WRITELOCK, subtransactionid,
623  pendingcmdid,
624  tacmdentrypoint)==NOTFOUNDLOCK)
625  {
626  continue;
627  }
628 
629  workrow.row.clear();
630  workrow.locktype = PENDINGLOCK;
631  }
632 
633  break;
634 
635  default:
636  fprintf(logfile, "anomaly: %i %s %i\n",
637  getlocktype(rows[rowid]->flags), __FILE__, __LINE__);
638  }
639  }
640 
641  returnRowsRef.push_back(workrow);
642  }
643  }
644  break;
645 
646  default:
647  fprintf(logfile, "anomaly: %i %s %i\n", locktype, __FILE__, __LINE__);
648  }
649 }
650 
651 void Table::commitRollbackUnlock(int64_t rowid, int64_t subtransactionid,
652  enginecmd_e cmd)
653 {
654  switch (cmd)
655  {
656  case COMMITCMD:
657  {
658  rowdata_s &currentRowRef = *rows[rowid];
659 
660  if (getlocktype(currentRowRef.flags)==READLOCK) // just unlock
661  {
662  if (!currentRowRef.readlockHolders->count(subtransactionid))
663  {
664  printf("%s %i anomaly subtransactionid %li\n", __FILE__,
665  __LINE__, subtransactionid);
666  return; // bogus request
667  }
668 
669  currentRowRef.readlockHolders->erase(subtransactionid);
670 
671  if (currentRowRef.readlockHolders->empty()==true)
672  {
673  clearlockedflag(&currentRowRef.flags);
674  delete currentRowRef.readlockHolders;
675  currentRowRef.readlockHolders = NULL;
676  }
677 
678  return;
679  }
680 
681  if ((getlocktype(currentRowRef.flags) != WRITELOCK) ||
682  (currentRowRef.writelockHolder != subtransactionid))
683  {
684  printf("%s %i anomaly flags %i subtransactionid %li writelockHolder %li rowid %li cmd %i flags %i\n", __FILE__, __LINE__, (int)currentRowRef.flags,
685  subtransactionid, currentRowRef.writelockHolder, rowid, cmd,
686  (int)currentRowRef.flags);
687  return; // bogus request
688  }
689 
690  if (getdeleteflag(currentRowRef.flags)==true)
691  {
692  if (getreplacedeleteflag(currentRowRef.flags)==true)
693  {
694  forwarderMap.erase(rowid);
695  }
696 
697  delete &currentRowRef;
698  rows.erase(rowid);
699 
700  if (shadowTable->rows.count(rowid))
701  {
702  delete shadowTable->rows[rowid];
703  shadowTable->rows.erase(rowid);
704  }
705 
706  return;
707  }
708 
709  if (currentRowRef.readlockHolders != NULL)
710  {
711  printf("%s %i anomaly: readlockHolders\n", __FILE__, __LINE__);
712  boost::unordered_set<int64_t>::const_iterator it;
713 
714  for (it = currentRowRef.readlockHolders->begin();
715  it != currentRowRef.readlockHolders->end(); ++it)
716  {
717  printf("%s %i readlockHolder %li\n", __FILE__, __LINE__, *it);
718  }
719 
720  delete currentRowRef.readlockHolders;
721  currentRowRef.readlockHolders=NULL;
722  }
723 
724  // only change the row if changes have been made, this covers in case a
725  // locked row didn't get modified, but still part of a commit
726  if (shadowTable->rows.count(rowid))
727  {
728  rowdata_s &shadowRowRef = *shadowTable->rows[rowid];
729  shadowRowRef.previoussubtransactionid=currentRowRef.writelockHolder;
730  shadowRowRef.flags=0;
731  shadowRowRef.writelockHolder=0;
732  shadowRowRef.readlockHolders=NULL;
733 
734  if (rows[rowid]==shadowTable->rows[rowid]) // insert
735  {
736  shadowTable->rows.erase(rowid);
737  }
738  else // update
739  {
740  delete &currentRowRef;
741  rows[rowid]=&shadowRowRef;
742  shadowTable->rows.erase(rowid);
743  }
744  }
745  else
746  {
747  printf("%s %i anomaly\n", __FILE__, __LINE__);
748  currentRowRef.flags=0;
749  currentRowRef.writelockHolder=0;
750  }
751 
752  /*
753  if (shadowTable->rows.count(rowid))
754  {
755  if (currentRowRef.previoussubtransactionid==0)
756  {
757  currentRowRef.previoussubtransactionid = currentRowRef.writelockHolder;
758  currentRowRef.row = shadowTable->rows[rowid].row;
759  }
760  else
761  { // if update row uses string::copy() then the container's memory will be consumed
762  currentRowRef.previoussubtransactionid = currentRowRef.writelockHolder;
763  memcpy(&currentRowRef.row[0], &shadowTable->rows[rowid].row[0],
764  currentRowRef.row.size());
765  }
766  shadowTable->rows.erase(rowid);
767  }
768  currentRowRef.flags = 0;
769  currentRowRef.writelockHolder = 0;
770  */
771  }
772  break;
773 
774  case ROLLBACKCMD:
775  {
776  if (!rows.count(rowid))
777  {
778  return;
779  }
780 
781  rowdata_s &currentRowRef = *rows[rowid];
782 
783  if ((currentRowRef.writelockHolder != subtransactionid) &&
784  (getlocktype(currentRowRef.flags) == WRITELOCK))
785  {
786  fprintf(logfile, "anomaly: %s %i\n", __FILE__, __LINE__);
787  return; // bogus request
788  }
789 
790  if (getinsertflag(currentRowRef.flags)==true)
791  {
792  delete &currentRowRef;
793  rows.erase(rowid);
794  shadowTable->rows.erase(rowid);
795  // drain Q
796  return;
797  }
798 
799  if (getdeleteflag(currentRowRef.flags)==true)
800  {
801  if (getreplacedeleteflag(currentRowRef.flags)==true)
802  {
803  clearreplacedeleteflag(&currentRowRef.flags);
804  forwarderMap.erase(rowid);
805  }
806 
807  cleardeleteflag(&currentRowRef.flags);
808 
809  if (shadowTable->rows.count(rowid))
810  {
811  printf("%s %i anomaly rowid %li\n", __FILE__, __LINE__, rowid);
812  delete shadowTable->rows[rowid];
813  shadowTable->rows.erase(rowid);
814  }
815  }
816 
817  currentRowRef.writelockHolder = 0;
818 
819  if (getlocktype(currentRowRef.flags)==READLOCK)
820  {
821  currentRowRef.readlockHolders->erase(subtransactionid);
822 
823  if (currentRowRef.readlockHolders->empty()==true)
824  {
825  delete currentRowRef.readlockHolders;
826  currentRowRef.readlockHolders = NULL;
827  }
828  }
829 
830  currentRowRef.flags = 0;
831 
832  if (currentRowRef.readlockHolders != NULL)
833  {
834  setreadlock(&currentRowRef.flags);
835  }
836 
837  if (shadowTable->rows.count(rowid))
838  {
839  delete shadowTable->rows[rowid];
840  shadowTable->rows.erase(rowid);
841  }
842 
843  // process Q
844  }
845  break;
846 
847  case UNLOCKCMD:
848  {
849  rowdata_s &currentRowRef = *rows[rowid];
850 
851  if (getlocktype(currentRowRef.flags) != READLOCK)
852  {
853  fprintf(logfile, "anomaly: %s %i\n", __FILE__, __LINE__);
854  return; // bogus request
855  }
856 
857  if (!currentRowRef.readlockHolders->count(subtransactionid))
858  {
859  fprintf(logfile, "anomaly: %s %i\n", __FILE__, __LINE__);
860  return; // bogus request
861  }
862 
863  currentRowRef.readlockHolders->erase(subtransactionid);
864 
865  if (currentRowRef.readlockHolders->empty()==true)
866  {
867  clearlockedflag(&currentRowRef.flags);
868  delete currentRowRef.readlockHolders;
869  currentRowRef.readlockHolders = NULL;
870  }
871  }
872  break;
873 
874  // REVERTCMD likely broken somehow
875  case REVERTCMD:
876  {
877  // do what rollback does, but don't unlock
878  if (!rows.count(rowid))
879  {
880  return;
881  }
882 
883  rowdata_s &currentRowRef = *rows[rowid];
884 
885  if ((currentRowRef.writelockHolder != subtransactionid) ||
886  (getlocktype(currentRowRef.flags) != WRITELOCK))
887  {
888  fprintf(logfile, "anomaly: %s %i\n", __FILE__, __LINE__);
889  return; // bogus request
890  }
891 
892  if (getinsertflag(currentRowRef.flags)==true)
893  {
894  rows.erase(rowid);
895  }
896  else
897  {
898  currentRowRef.flags = 0;
899  }
900 
901  forwarderMap.erase(rowid);
902  shadowTable->rows.erase(rowid);
903  }
904  break;
905 
906  default:
907  fprintf(logfile, "anomaly %i %s %i\n", cmd, __FILE__, __LINE__);
908  }
909 }
910 
911 bool Table::unmakerow(string *rowstring, vector<fieldValue_s> *resultFields)
912 {
913  vector<fieldValue_s> &resultFieldsRef = *resultFields;
914  string &rowstringRef = *rowstring;
915 
916  size_t pos = 0;
917  size_t numfields = fields.size();
918  resultFieldsRef.resize(numfields, fieldValue_s());
919  size_t rowsize = rowstringRef.size();
920 
921  for (size_t n=0; n < numfields; n++)
922  {
923  if (pos >= rowsize-1) // remember the bool for isnull or not
924  {
925  return false;
926  }
927 
928  if (rowstringRef[pos++] == 0)
929  {
930  resultFieldsRef[n].isnull = false;
931  }
932  else
933  {
934  resultFieldsRef[n].isnull = true;
935  continue;
936  }
937 
938  switch (fields[n].type)
939  {
940  case INT:
941  memcpy(&resultFieldsRef[n].value.integer, &rowstringRef[pos],
942  sizeof(resultFieldsRef[n].value.integer));
943  pos += sizeof(resultFieldsRef[n].value.integer);
944  break;
945 
946  case UINT:
947  memcpy(&resultFieldsRef[n].value.uinteger, &rowstringRef[pos],
948  sizeof(resultFieldsRef[n].value.uinteger));
949  pos += sizeof(resultFieldsRef[n].value.uinteger);
950  break;
951 
952  case BOOL:
953  memcpy(&resultFieldsRef[n].value.boolean, &rowstringRef[pos],
954  sizeof(resultFieldsRef[n].value.boolean));
955  pos += sizeof(resultFieldsRef[n].value.boolean);
956  break;
957 
958  case FLOAT:
959  memcpy(&resultFieldsRef[n].value.floating, &rowstringRef[pos],
960  sizeof(resultFieldsRef[n].value.floating));
961  pos += sizeof(resultFieldsRef[n].value.floating);
962  break;
963 
964  case CHAR:
965  memcpy(&resultFieldsRef[n].value.character, &rowstringRef[pos],
966  sizeof(resultFieldsRef[n].value.character));
967  pos += sizeof(resultFieldsRef[n].value.character);
968  break;
969 
970  case CHARX: // makerow() already padded this field to the length of the
971  // char(x)
972  resultFieldsRef[n].str.assign(rowstringRef, pos, fields[n].length);
973 
974  if (resultFieldsRef[n].str.size() < fields[n].length)
975  {
976  // this should not be, but pad it anyway
977  printf("%s %i rowstring.size() %lu field %lu resultFieldsRef[n].str.size() %lu fields[n].length %lu\n", __FILE__, __LINE__,
978  (unsigned long)rowstring->size(), (unsigned long)n,
979  resultFieldsRef[n].str.size(), fields[n].length);
980  resultFieldsRef[n].str.append(fields[n].length -
981  resultFieldsRef[n].str.size(), 0);
982  }
983 
984  pos += fields[n].length;
985  break;
986 
987  case VARCHAR:
988  {
989  int64_t varcharlength;
990  memcpy(&varcharlength, &rowstringRef[pos], sizeof(varcharlength));
991  pos += sizeof(varcharlength);
992  resultFieldsRef[n].str.assign(rowstringRef, pos, varcharlength);
993  pos += varcharlength;
994  }
995  break;
996 
997  default:
998  fprintf(logfile, "anomaly: %i %s %i\n", fields[n].type, __FILE__,
999  __LINE__);
1000  }
1001  }
1002 
1003  return true;
1004 }
1005 
1007 {
1008  return ++nextrowid;
1009 }
1010 
1011 void Table::newrow(int64_t newrowid, int64_t subtransactionid, string &row)
1012 {
1013  rowdata_s *nrow = new rowdata_s();
1014  // nrow->flags = 0;
1015  setwritelock(&nrow->flags);
1016  nrow->writelockHolder = subtransactionid;
1017  setinsertflag(&nrow->flags);
1018  // nrow.previoussubtransactionid = 0;
1019  nrow->row = row;
1020  // nrow.readlockHolders=NULL;
1021 
1022  rows[newrowid] = nrow;
1023  shadowTable->rows[newrowid] = nrow;
1024 }
1025 
1026 int64_t Table::deleterow(int64_t rowid, int64_t subtransactionid)
1027 {
1028  if (!rows.count(rowid))
1029  {
1030  return STATUS_NOTOK;
1031  }
1032 
1033  rowdata_s &currentRowRef = *rows[rowid];
1034 
1035  if ((getlocktype(currentRowRef.flags) != WRITELOCK) ||
1036  (currentRowRef.writelockHolder != subtransactionid))
1037  {
1038  fprintf(logfile, "anomaly %i %li %s %i\n", currentRowRef.flags,
1039  currentRowRef.writelockHolder, __FILE__, __LINE__);
1040  return STATUS_NOTOK;
1041  }
1042 
1043  setdeleteflag(&currentRowRef.flags);
1044  return STATUS_OK;
1045 }
1046 
1048  int64_t subtransactionid, int64_t pendingcmdid, int64_t tacmdentrypoint)
1049 {
1050  if (getinsertflag(rows[rowid]->flags)==true)
1051  {
1052  return NOTFOUNDLOCK;
1053  }
1054 
1055  lockQueueRowEntry entry;
1056  entry.tacmdentrypoint = tacmdentrypoint;
1057  entry.locktype = locktype;
1058  entry.pendingcmdid = pendingcmdid;
1059  entry.subtransactionid = subtransactionid;
1060 
1061  lockQueue[rowid].push(entry);
1062 
1063  return locktype;
1064 }