transactd 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/bin/common/tdclc_32_2_2.dll +0 -0
  3. data/bin/common/tdclc_64_2_2.dll +0 -0
  4. data/build/swig/ruby/generate.cmd +45 -0
  5. data/build/swig/ruby/generate.sh +40 -0
  6. data/build/swig/ruby/tdclrb_wrap.cpp +406 -969
  7. data/build/swig/tdcl.i +88 -0
  8. data/build/tdclc/CMakeLists.txt +5 -1
  9. data/build/tdclc/tdclc.cbproj +1 -1
  10. data/build/tdclc/tdclc.rc +4 -4
  11. data/build/tdclcpp/tdclcpp.rc +4 -4
  12. data/build/tdclcpp/tdclcpp_bc.cbproj +1 -1
  13. data/build/tdclrb/tdclrb.rc +4 -4
  14. data/source/bzs/db/engine/mysql/database.cpp +165 -74
  15. data/source/bzs/db/engine/mysql/database.h +19 -5
  16. data/source/bzs/db/engine/mysql/dbManager.cpp +33 -11
  17. data/source/bzs/db/engine/mysql/dbManager.h +6 -1
  18. data/source/bzs/db/engine/mysql/mydebuglog.h +12 -0
  19. data/source/bzs/db/engine/mysql/mysqlInternal.h +10 -3
  20. data/source/bzs/db/engine/mysql/mysqlThd.cpp +20 -8
  21. data/source/bzs/db/protocol/hs/hsCommandExecuter.cpp +12 -7
  22. data/source/bzs/db/protocol/hs/hsCommandExecuter.h +1 -1
  23. data/source/bzs/db/protocol/tdap/client/activeTableImple.h +1 -0
  24. data/source/bzs/db/protocol/tdap/client/client.cpp +17 -15
  25. data/source/bzs/db/protocol/tdap/client/client.h +102 -30
  26. data/source/bzs/db/protocol/tdap/client/connectionPool.cpp +1 -1
  27. data/source/bzs/db/protocol/tdap/client/database.cpp +32 -10
  28. data/source/bzs/db/protocol/tdap/client/database.h +1 -0
  29. data/source/bzs/db/protocol/tdap/client/databaseFactory.cpp +0 -2
  30. data/source/bzs/db/protocol/tdap/client/dbDef.cpp +2 -0
  31. data/source/bzs/db/protocol/tdap/client/dllmain.cpp +47 -42
  32. data/source/bzs/db/protocol/tdap/client/fields.h +3 -1
  33. data/source/bzs/db/protocol/tdap/client/filter.h +3 -3
  34. data/source/bzs/db/protocol/tdap/client/nsDatabase.cpp +18 -2
  35. data/source/bzs/db/protocol/tdap/client/nsDatabase.h +3 -2
  36. data/source/bzs/db/protocol/tdap/client/nsTable.cpp +14 -6
  37. data/source/bzs/db/protocol/tdap/client/nsTable.h +12 -12
  38. data/source/bzs/db/protocol/tdap/client/recordsetImple.h +6 -3
  39. data/source/bzs/db/protocol/tdap/client/request.h +1 -0
  40. data/source/bzs/db/protocol/tdap/client/sqlBuilder.cpp +101 -64
  41. data/source/bzs/db/protocol/tdap/client/sqlBuilder.h +3 -0
  42. data/source/bzs/db/protocol/tdap/client/stringConverter.h +9 -13
  43. data/source/bzs/db/protocol/tdap/client/table.cpp +73 -56
  44. data/source/bzs/db/protocol/tdap/client/table.h +8 -8
  45. data/source/bzs/db/protocol/tdap/client/trdboostapi.h +52 -100
  46. data/source/bzs/db/protocol/tdap/mysql/databaseSchema.cpp +8 -1
  47. data/source/bzs/db/protocol/tdap/mysql/request.h +6 -0
  48. data/source/bzs/db/protocol/tdap/mysql/tdapCommandExecuter.cpp +349 -189
  49. data/source/bzs/db/protocol/tdap/mysql/tdapCommandExecuter.h +28 -12
  50. data/source/bzs/db/protocol/tdap/tdapRequest.h +5 -4
  51. data/source/bzs/db/protocol/tdap/tdapSchema.h +6 -1
  52. data/source/bzs/db/protocol/tdap/tdapcapi.h +29 -4
  53. data/source/bzs/db/protocol/tdap/uri.h +297 -0
  54. data/source/bzs/db/transactd/appModule.cpp +41 -16
  55. data/source/bzs/db/transactd/appModule.h +1 -2
  56. data/source/bzs/db/transactd/transactd.cpp +37 -14
  57. data/source/bzs/env/crosscompile.h +1 -3
  58. data/source/bzs/example/queryData.cpp +2 -2
  59. data/source/bzs/netsvc/client/iconnection.h +3 -1
  60. data/source/bzs/netsvc/client/tcpClient.cpp +75 -28
  61. data/source/bzs/netsvc/client/tcpClient.h +94 -62
  62. data/source/bzs/netsvc/server/IAppModule.h +2 -2
  63. data/source/bzs/netsvc/server/serverCpt.cpp +17 -10
  64. data/source/bzs/netsvc/server/serverPipe.cpp +26 -19
  65. data/source/bzs/netsvc/server/serverTpool.cpp +8 -2
  66. data/source/bzs/rtl/debuglog.cpp +21 -5
  67. data/source/bzs/rtl/debuglog.h +1 -1
  68. data/source/bzs/test/tdclphp/transactd_Test.php +183 -37
  69. data/source/bzs/test/tdclphp/transactd_pool_Test.php +1 -2
  70. data/source/bzs/test/tdclrb/transactd_spec.rb +183 -39
  71. data/source/bzs/test/transactdBench/scaling_bench.cpp +3 -3
  72. data/source/bzs/test/trdclengn/test_trdclengn.cpp +172 -57
  73. data/source/global/boost/sha1.hpp +223 -0
  74. data/source/global/tdclatl/ConnectParams.cpp +2 -2
  75. data/source/global/tdclatl/ConnectParams.h +1 -1
  76. data/source/global/tdclatl/Database.cpp +18 -0
  77. data/source/global/tdclatl/Database.h +5 -0
  78. data/source/global/tdclatl/tdclatl.idl +23 -1
  79. data/source/linux/linuxTypes.h +2 -0
  80. metadata +8 -6
  81. data/bin/common/tdclc_32_2_1.dll +0 -0
  82. data/bin/common/tdclc_64_2_1.dll +0 -0
  83. data/source/bzs/db/protocol/tdap/client/memRecordset.cpp +0 -448
  84. data/source/bzs/db/protocol/tdap/client/memRecordset.h +0 -159
@@ -47,7 +47,7 @@ namespace cpt // connection per thread
47
47
  unsigned int g_connections = 0;
48
48
  unsigned int g_waitThread = 0;
49
49
  // ---------------------------------------------------------------------------
50
- // connection
50
+ // connection
51
51
  // ---------------------------------------------------------------------------
52
52
  #define READBUF_SIZE 66000
53
53
  #define WRITEBUF_SIZE 66000
@@ -85,9 +85,15 @@ class connection : public iconnection, private boost::noncopyable
85
85
  m_optionalBuffes.clear();
86
86
  vecBuffer vbuf(m_result);
87
87
  bzs::netsvc::server::IResultBuffer& buf = vbuf;
88
- if (m_module->execute(buf, size, &m_optionalBuffes) ==
89
- EXECUTE_RESULT_QUIT)
88
+ int ret = m_module->execute(buf, size, &m_optionalBuffes);
89
+ if (ret == EXECUTE_RESULT_QUIT)
90
90
  return;
91
+ else if(ret == EXECUTE_RESULT_ACCESS_DNIED)
92
+ {
93
+ boost::asio::write(m_socket, buffer(&m_result[0], size),
94
+ boost::asio::transfer_all());
95
+ return;
96
+ }
91
97
  else
92
98
  {
93
99
  m_readLen = 0;
@@ -200,6 +206,7 @@ public:
200
206
  m_socket.set_option(
201
207
  boost::asio::socket_base::send_buffer_size(1024 * 1024 * 10), ec);
202
208
 
209
+ //send handshake packet
203
210
  size_t n = m_module->onAccept(&m_result[0], WRITEBUF_SIZE);
204
211
  if (n)
205
212
  boost::asio::write(m_socket, buffer(&m_result[0], n),
@@ -235,7 +242,7 @@ std::vector<connection*> connection::connections;
235
242
  mutex connection::m_mutex;
236
243
 
237
244
  // ---------------------------------------------------------------------------
238
- // worker
245
+ // worker
239
246
  // ---------------------------------------------------------------------------
240
247
 
241
248
  class worker : private boost::noncopyable
@@ -323,7 +330,7 @@ public:
323
330
  ((IAppModuleBuilder*)app)->createSessionModule(
324
331
  endpoint, m_connection.get(), SERVER_TYPE_CPT));
325
332
  m_connection->setModule(mod);
326
- if (mod->checkHost(hostCheckName))
333
+ if (mod->checkHost(hostCheckName, NULL, 0))
327
334
  {
328
335
  m_connection->sendConnectAccept();
329
336
  m_connection->start(); // It does not return, unless a
@@ -372,7 +379,7 @@ std::vector<boost::shared_ptr<boost::thread> > worker::m_threads;
372
379
  std::vector<worker*> worker::m_workers;
373
380
 
374
381
  // ---------------------------------------------------------------------------
375
- // listener
382
+ // listener
376
383
  // ---------------------------------------------------------------------------
377
384
 
378
385
  class listener
@@ -429,13 +436,13 @@ public:
429
436
  };
430
437
 
431
438
  // ---------------------------------------------------------------------------
432
- // server
439
+ // server
433
440
  // ---------------------------------------------------------------------------
434
441
  inotifyHandler* server::erh = NULL;
435
442
 
436
443
  /** server
437
- * If it starts, a server will create the exclusive thread for accpter
438
- * and will go into an infinite loop.
444
+ * If it starts, a server will create the exclusive thread for accpter
445
+ * and will go into an infinite loop.
439
446
  */
440
447
  server::server(std::size_t max_connections, const char* hostCheckName)
441
448
  : m_timer(m_ios), m_maxConnections(max_connections), m_stopped(false)
@@ -467,7 +474,7 @@ bool server::checkConnections()
467
474
  {
468
475
  while (connection::connections.size() > m_maxConnections)
469
476
  {
470
- Sleep(100 * MCRTOMM);
477
+ Sleep(100);
471
478
  if (m_stopped)
472
479
  return false;
473
480
  }
@@ -92,14 +92,10 @@ void acceptor::accept(platform_stream& pipe)
92
92
  m_fd = CreateNamedPipe(pipeName, // pipe name
93
93
  PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
94
94
  PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
95
- PIPE_UNLIMITED_INSTANCES // max. instances
96
- ,
97
- BUFSIZE // output buffer size
98
- ,
99
- BUFSIZE // input buffer size
100
- ,
101
- 0 // client time-out
102
- ,
95
+ PIPE_UNLIMITED_INSTANCES, // max. instances
96
+ BUFSIZE, // output buffer size
97
+ BUFSIZE, // input buffer size
98
+ 0, // client time-out
103
99
  &sa); // default security attribute
104
100
  if (m_fd == INVALID_HANDLE_VALUE)
105
101
  THROW_BZS_ERROR_WITH_MSG(getWindowsErrMsg(GetLastError()));
@@ -190,9 +186,10 @@ public:
190
186
  return true;
191
187
  DWORD ExitCode;
192
188
  if (m_procHandle && GetExitCodeProcess(m_procHandle, &ExitCode))
193
-
189
+ {
194
190
  if (STILL_ACTIVE != ExitCode)
195
191
  return true;
192
+ }
196
193
  if (m_module && m_module->isShutDown())
197
194
  return true;
198
195
  return false;
@@ -235,11 +232,13 @@ public:
235
232
 
236
233
  bool recv(int checkTimeSpan, IExitCheckHandler* handler)
237
234
  {
238
- DWORD wait;
235
+ DWORD wait = WAIT_TIMEOUT;
239
236
  do
240
237
  {
238
+ if (wait == WAIT_ABANDONED)
239
+ return false;
241
240
  if (m_cancel || (handler && (handler->isExit())))
242
- return 0;
241
+ return false;
243
242
  } while (WAIT_OBJECT_0 !=
244
243
  (wait = WaitForSingleObject(m_recv, checkTimeSpan)));
245
244
  m_sent = false;
@@ -341,19 +340,23 @@ class connection : public iconnection, private noncopyable
341
340
  return;
342
341
  bool complete = false;
343
342
  m_readLen = *((unsigned int*)m_sharedMem->readBuffer());
343
+ //When readLen = 0 , close connection
344
344
  if (m_readLen == 0)
345
345
  return;
346
346
  m_module->onRead(m_sharedMem->readBuffer(), m_readLen, complete);
347
347
  if (complete)
348
348
  {
349
349
  size_t size = 0;
350
- if (m_module->execute(sharedMemBuffer(*m_sharedMem), size,
351
- NULL) == EXECUTE_RESULT_QUIT)
350
+ int ret = m_module->execute(sharedMemBuffer(*m_sharedMem), size, NULL);
351
+ if (ret == EXECUTE_RESULT_QUIT)
352
352
  return;
353
353
  else
354
354
  m_readLen = 0;
355
355
 
356
356
  sentResult = m_comm->send();
357
+ //When named pipe, dissconnect from local client.
358
+ //if (ret == EXECUTE_RESULT_ACCESS_DNIED)
359
+ // return;
357
360
  m_module->cleanup();
358
361
  }
359
362
  }
@@ -434,10 +437,15 @@ public:
434
437
  m_exitHandler.reset(new exitCheckHnadler(clinetProcessID));
435
438
  if (m_module)
436
439
  m_exitHandler->setModule(m_module.get());
437
- m_module->onAccept(tmp, 50);
438
-
439
- strcpy(tmp, "OK");
440
- memcpy(tmp + 3, &m_shareMemSize, 4);
440
+ tmp[0] = 0x00; // signe of handshakable
441
+ memcpy(tmp + 3, &m_shareMemSize, sizeof(unsigned int));// sharemem size
442
+ //asio::write(m_socket, buffer(tmp, 7), e);
443
+ //len = asio::read(m_socket, buffer(buf, 9), e);
444
+ //if (len != 9)
445
+ // THROW_BZS_ERROR_WITH_MSG("handshake error");
446
+ //send handshake packet
447
+ m_module->onAccept(m_sharedMem->writeBuffer(), m_sharedMem->size());
448
+ m_comm->send();
441
449
  asio::write(m_socket, buffer(tmp, 7), e);
442
450
  run();
443
451
  }
@@ -522,7 +530,6 @@ public:
522
530
  */
523
531
  static worker* worker::get(const IAppModuleBuilder* app)
524
532
  {
525
-
526
533
  worker* p = findWaitThread();
527
534
  if (p == NULL)
528
535
  {
@@ -565,7 +572,7 @@ public:
565
572
  ((IAppModuleBuilder*)app)->createSessionModule(
566
573
  endpoint, m_connection.get(), SERVER_TYPE_CPT));
567
574
  m_connection->setModule(mod);
568
- if (mod->checkHost(hostCheckName))
575
+ if (mod->checkHost(hostCheckName, NULL, 0))
569
576
  m_connection->start(); // It does not return, unless a
570
577
  // connection is close.
571
578
  m_connection.reset();
@@ -153,6 +153,12 @@ class connection : public boost::enable_shared_from_this<connection>,
153
153
 
154
154
  if (ret == EXECUTE_RESULT_QUIT)
155
155
  return;
156
+ else if(ret == EXECUTE_RESULT_ACCESS_DNIED)
157
+ {
158
+ boost::asio::write(m_socket, buffer(&m_result[0], size),
159
+ boost::asio::transfer_all());
160
+ return;
161
+ }
156
162
 
157
163
  m_optionalBuffes.insert(m_optionalBuffes.begin(),
158
164
  buffer(&m_result[0], size));
@@ -170,7 +176,6 @@ class connection : public boost::enable_shared_from_this<connection>,
170
176
  boost::bind(&connection::handle_write,
171
177
  shared_from_this(),
172
178
  boost::asio::placeholders::error));
173
-
174
179
  return;
175
180
  }
176
181
 
@@ -231,6 +236,7 @@ public:
231
236
 
232
237
  void sendConnectAccept()
233
238
  {
239
+ //send handshake packet
234
240
  size_t n = m_module->onAccept(&m_result[0], WRITEBUF_SIZE);
235
241
  if (n)
236
242
  boost::asio::write(m_socket, buffer(&m_result[0], n),
@@ -313,7 +319,7 @@ public:
313
319
  boost::shared_ptr<IAppModule> mod(m_app->createSessionModule(
314
320
  endpoint, m_newConnection.get(), SERVER_TYPE_TPOOL));
315
321
  m_newConnection->setModule(mod);
316
- if (mod->checkHost(m_srv->hostCheckName()))
322
+ if (mod->checkHost(m_srv->hostCheckName(), NULL, 0))
317
323
  {
318
324
  m_newConnection->sendConnectAccept();
319
325
  m_newConnection->start();
@@ -74,12 +74,26 @@ void debuglog::dump(FILE* fp, const char* p, int size, int limit)
74
74
  size = std::min<int>(size, limit);
75
75
  for (int i = 0; i < size; i += 16)
76
76
  {
77
-
78
- for (int j = 0; j < 16; j++)
79
- fprintf(fp, "%02X ", *((unsigned char*)(p + i + j)));
77
+ const char* pp = p + i;
78
+ int max = std::min<int>(size - i, 16);
79
+ for (int j = 0; j < max; j++)
80
+ fprintf(fp, "%02X ", *((unsigned char*)(pp + j)));
81
+
82
+ if (max != 16)
83
+ {
84
+ for (int j = 0; j < 16 - max; j++)
85
+ fprintf(fp, " ");
86
+ }
87
+
80
88
  fprintf(fp, " ");
81
- for (int j = 0; j < 16; j++)
82
- fprintf(fp, "%c", *((unsigned char*)(p + i + j)));
89
+ for (int j = 0; j < max; j++)
90
+ {
91
+ const char* p1 = pp + j;
92
+ if (*p1 >= ' ' && *p1 <= '~')
93
+ fprintf(fp, "%c", *p1);
94
+ else
95
+ fprintf(fp, " ");
96
+ }
83
97
  fprintf(fp, "\n");
84
98
  }
85
99
  fprintf(fp, "\n");
@@ -91,6 +105,8 @@ void debuglog::writeDump(const char* msg, const char* ptr, int size)
91
105
  FILE* fp = fileOpen(logfilename, "a+");
92
106
  if (fp)
93
107
  {
108
+ fputs(dateTime(), fp);
109
+ fputs(" ", fp);
94
110
  fputs(msg, fp);
95
111
  fputs("\n", fp);
96
112
  dump(fp, ptr, size, INT_MAX);
@@ -61,7 +61,7 @@ public:
61
61
  #define DEBUG_WRITELOG(MSG)
62
62
  #endif // DEBUG_LOG
63
63
 
64
- #if defined(DEBUG_PROFILE) || defined(DEBUG_LOG)
64
+ #if defined(DEBUG_PROFILE) || defined(DEBUG_LOG) || defined(DEBUG_LOG_ERR)
65
65
  #define DEBUG_PROFILE_INIT() bzs::rtl::debuglog::get()->init();
66
66
  #define DEBUG_PROFILE_DEINIT() bzs::rtl::debuglog::get()->stop();
67
67
  #else
@@ -42,7 +42,32 @@ define("FDI_NAMEW", 2);
42
42
  define("BULKBUFSIZE", 65535 - 1000);
43
43
  define("TEST_COUNT", 20000);
44
44
  define("FIVE_PERCENT_OF_TEST_COUNT", TEST_COUNT / 20);
45
- define("ALLOWABLE_ERROR_DISTANCE_IN_ESTIMATE_COUNT", TEST_COUNT / 4);
45
+
46
+ // multi thread test if `php_pthreads` exists.
47
+ if(class_exists('Thread')){
48
+ class SeekLessThanWorker extends Thread
49
+ {
50
+ public function __construct()
51
+ {
52
+ $this->value = -1;
53
+ }
54
+ public function run()
55
+ {
56
+ $dbm = new Bz\pooledDbManager(new Bz\connectParams(URL));
57
+ $tb = $dbm->table('user');
58
+ $tb->setFV(FDI_ID, 300000);
59
+ $tb->seekLessThan(false, Bz\transactd::ROW_LOCK_X);
60
+ $this->value = $tb->getFVint(FDI_ID);
61
+ $tb->unlock();
62
+ $tb->close();
63
+ $dbm->unUse();
64
+ }
65
+ public function getResult()
66
+ {
67
+ return $this->value;
68
+ }
69
+ }
70
+ }
46
71
 
47
72
  class transactdTest extends PHPUnit_Framework_TestCase
48
73
  {
@@ -263,8 +288,9 @@ class transactdTest extends PHPUnit_Framework_TestCase
263
288
  $this->assertEquals($client_ver->majorVersion, Bz\transactd::CPP_INTERFACE_VER_MAJOR);
264
289
  $this->assertEquals($client_ver->minorVersion, Bz\transactd::CPP_INTERFACE_VER_MINOR);
265
290
  $this->assertEquals(chr($client_ver->type), 'N');
266
- $this->assertTrue($server_ver->majorVersion >= 5);
267
- $this->assertTrue($server_ver->majorVersion != 5 || $server_ver->minorVersion >= 5);
291
+ $my5x = ($server_ver->majorVersion == 5) && ($server_ver->minorVersion >= 5);
292
+ $maria10 = ($server_ver->majorVersion == 10) && ($server_ver->minorVersion == 0);
293
+ $this->assertTrue($my5x || $maria10);
268
294
  $this->assertEquals(chr($server_ver->type), 'M');
269
295
  $this->assertEquals($engine_ver->majorVersion, Bz\transactd::TRANSACTD_VER_MAJOR);
270
296
  $this->assertEquals($engine_ver->minorVersion, Bz\transactd::TRANSACTD_VER_MINOR);
@@ -756,6 +782,9 @@ class transactdTest extends PHPUnit_Framework_TestCase
756
782
  $this->assertEquals($tb->stat(), Bz\transactd::STATUS_NOT_FOUND_TI);
757
783
 
758
784
  // clean up
785
+ $tb2->setFV(FDI_ID, 29999);
786
+ $tb2->seek();
787
+ $this->assertEquals($tb2->stat(), 0);
759
788
  $tb2->del();
760
789
  $this->assertEquals($tb2->stat(), 0);
761
790
 
@@ -784,6 +813,24 @@ class transactdTest extends PHPUnit_Framework_TestCase
784
813
  $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
785
814
 
786
815
  $db->endSnapshot();
816
+
817
+ // gap lock
818
+ $db->beginSnapshot(Bz\transactd::MULTILOCK_NOGAP_SHARE);
819
+ $tb->seekLast(); // id = 30000
820
+ $this->assertEquals($tb->stat(), 0);
821
+ $tb->seekPrev(); // id = 20002
822
+ $this->assertEquals($tb->stat(), 0);
823
+ $tb->seekPrev(); // id = 20001
824
+ $this->assertEquals($tb->stat(), 0);
825
+
826
+ $tb2->setFV(FDI_ID, 20002);
827
+ $tb2->seek(Bz\transactd::ROW_LOCK_X);
828
+ $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
829
+
830
+ $tb2->seekLast(Bz\transactd::ROW_LOCK_X);
831
+ $this->assertEquals($tb2->stat(), Bz\transactd::STATUS_LOCK_ERROR);
832
+
833
+ $db->endSnapshot();
787
834
  }
788
835
  public function testConflict()
789
836
  {
@@ -954,6 +1001,37 @@ class transactdTest extends PHPUnit_Framework_TestCase
954
1001
  $this->assertEquals($tb->getFVint(FDI_ID), $last2);
955
1002
  $db->endTrn();
956
1003
 
1004
+ // ----------------------------------------------------
1005
+ // Test use shared lock option
1006
+ // ----------------------------------------------------
1007
+ $db->beginTrn(Bz\transactd::MULTILOCK_REPEATABLE_READ);
1008
+ $this->assertEquals(0, $db->stat());
1009
+
1010
+ $db2->beginTrn(Bz\transactd::MULTILOCK_REPEATABLE_READ);
1011
+ $this->assertEquals(0, $db2->stat());
1012
+
1013
+ $tb->seekLast(Bz\transactd::ROW_LOCK_S);
1014
+ $this->assertEquals(0, $tb->stat());
1015
+ $tb2->seekLast(Bz\transactd::ROW_LOCK_S);
1016
+ $this->assertEquals(0, $tb2->stat());
1017
+
1018
+ $tb->seekPrev(); // Lock(X)
1019
+ $this->assertEquals(0, $tb->stat());
1020
+
1021
+ $tb2->seekPrev(Bz\transactd::ROW_LOCK_S);
1022
+ $this->assertEquals(Bz\transactd::STATUS_LOCK_ERROR, $tb2->stat());
1023
+
1024
+ $tb->seekPrev(Bz\transactd::ROW_LOCK_S);
1025
+ $this->assertEquals(0, $tb->stat());
1026
+ $id = $tb->getFVint(FDI_ID);
1027
+
1028
+ $tb2->setFV(FDI_ID, $id);
1029
+ $tb2->seek(Bz\transactd::ROW_LOCK_S);
1030
+ $this->assertEquals(0, $tb2->stat());
1031
+
1032
+ $db2->endTrn();
1033
+ $db->endTrn();
1034
+
957
1035
  // ----------------------------------------------------
958
1036
  // Test Abort
959
1037
  // ----------------------------------------------------
@@ -1255,6 +1333,9 @@ class transactdTest extends PHPUnit_Framework_TestCase
1255
1333
  // No match records are unlocked.
1256
1334
  $tb2->setFV(FDI_ID, 100);
1257
1335
  $tb2->seek(Bz\transactd::ROW_LOCK_X);
1336
+ $this->assertEquals(0, $tb2->stat());
1337
+ $tb2->setFV(FDI_ID, 101);
1338
+ $tb2->seek(Bz\transactd::ROW_LOCK_X);
1258
1339
  $this->assertEquals($tb2->stat(), 0);
1259
1340
  $tb2->unlock();
1260
1341
  $db->endTrn();
@@ -1318,8 +1399,11 @@ class transactdTest extends PHPUnit_Framework_TestCase
1318
1399
  $tb2->seekNext(Bz\transactd::ROW_LOCK_X); // lock(X) third, second lock freed
1319
1400
  $this->assertEquals($tb2->stat(), 0);
1320
1401
 
1321
- $tb->seekNext(); // nobody lock second.
1322
- $this->assertEquals($tb->stat(), 0);
1402
+ $tb->seekNext(); // nobody lock second. But REPEATABLE_READ tb2 lock all(no unlock)
1403
+ if ($db->trxIsolationServer() == Bz\transactd::SRV_ISO_REPEATABLE_READ)
1404
+ $this->assertEquals($tb->stat(), Bz\transactd::STATUS_LOCK_ERROR);
1405
+ else
1406
+ $this->assertEquals($tb->stat(), 0);
1323
1407
  $tb->seekNext(Bz\transactd::ROW_LOCK_X); // Try lock(X) third
1324
1408
  $this->assertEquals($tb->stat(), Bz\transactd::STATUS_LOCK_ERROR);
1325
1409
 
@@ -1345,10 +1429,15 @@ class transactdTest extends PHPUnit_Framework_TestCase
1345
1429
  $tb->setFV(FDI_ID, 21000);
1346
1430
  $tb->insert();
1347
1431
  $this->assertEquals($tb->stat(), 0);
1432
+
1433
+ //cleanup
1434
+ $tb->setFV(FDI_ID, 21000);
1435
+ $tb->seek();
1436
+ $this->assertEquals($tb->stat(), 0);
1348
1437
  $tb->del();
1349
1438
  $this->assertEquals($tb->stat(), 0);
1350
1439
 
1351
- // --------- Unlock test ----------------------------
1440
+ // --------- Unlock test ---------------------------
1352
1441
  // 1 unlock()
1353
1442
  $tb->seekFirst(Bz\transactd::ROW_LOCK_X);
1354
1443
  $this->assertEquals($tb->stat(), 0);
@@ -1404,7 +1493,11 @@ class transactdTest extends PHPUnit_Framework_TestCase
1404
1493
  $tb2->seekFirst(Bz\transactd::ROW_LOCK_X);
1405
1494
  $this->assertEquals($tb2->stat(), 0);
1406
1495
  $tb2->unlock();
1407
- // --------- End Unlock test ----------------------------
1496
+ // --------- End Unlock test -----------------------
1497
+
1498
+ // --------- Invalid lock type test ----------------
1499
+ $tb2->seekFirst(Bz\transactd::ROW_LOCK_S);
1500
+ $this->assertEquals(Bz\transactd::STATUS_INVALID_LOCKTYPE, $tb2->stat());
1408
1501
  }
1409
1502
  public function testExclusive()
1410
1503
  {
@@ -1423,23 +1516,21 @@ class transactdTest extends PHPUnit_Framework_TestCase
1423
1516
  $db2->connect(PROTOCOL . HOSTNAME . DBNAME, true);
1424
1517
  $this->assertEquals($db2->stat(), 0);
1425
1518
  $db2->open(URL, Bz\transactd::TYPE_SCHEMA_BDF);
1519
+ // database open error. Check database::stat()
1426
1520
  $this->assertEquals($db2->stat(), Bz\transactd::STATUS_CANNOT_LOCK_TABLE);
1427
1521
  $tb->close();
1428
1522
  $db->close();
1429
1523
  $db2->close();
1430
1524
 
1431
1525
  // ------------------------------------------------------
1432
- // database WRITE EXCLUSIVE
1526
+ // database READ EXCLUSIVE
1433
1527
  // ------------------------------------------------------
1434
- // table mode exclusive
1435
- $db = new Bz\database();
1436
1528
  $db->open(URL, Bz\transactd::TYPE_SCHEMA_BDF, Bz\transactd::TD_OPEN_READONLY_EXCLUSIVE);
1437
1529
  $this->assertEquals($db->stat(), 0);
1438
1530
  $tb = $db->openTable(TABLENAME, Bz\transactd::TD_OPEN_READONLY_EXCLUSIVE);
1439
1531
  $this->assertEquals($db->stat(), 0);
1440
1532
 
1441
1533
  // Read only open
1442
- $db2 = new Bz\database();
1443
1534
  $db2->open(URL, Bz\transactd::TYPE_SCHEMA_BDF);
1444
1535
  $this->assertEquals($db2->stat(), 0);
1445
1536
  $db2->close();
@@ -1459,6 +1550,7 @@ class transactdTest extends PHPUnit_Framework_TestCase
1459
1550
  $db2->open(URL, Bz\transactd::TYPE_SCHEMA_BDF, Bz\transactd::TD_OPEN_READONLY_EXCLUSIVE);
1460
1551
  $this->assertEquals($db2->stat(), 0);
1461
1552
  $db2->close();
1553
+ $tb->close();
1462
1554
  $db->close();
1463
1555
 
1464
1556
  // ------------------------------------------------------
@@ -1473,10 +1565,10 @@ class transactdTest extends PHPUnit_Framework_TestCase
1473
1565
 
1474
1566
  $tb2 = $db->openTable('group', Bz\transactd::TD_OPEN_EXCLUSIVE);
1475
1567
  $this->assertEquals($db->stat(), 0);
1568
+
1476
1569
  // Check tb2 Exclusive
1477
1570
  $tb3 = $db2->openTable('group', Bz\transactd::TD_OPEN_NORMAL);
1478
1571
  $this->assertEquals($db2->stat(), Bz\transactd::STATUS_CANNOT_LOCK_TABLE);
1479
-
1480
1572
  for ($i = 1; $i < 5; $i++)
1481
1573
  {
1482
1574
  $tb2->setFV(FDI_ID, $i + 1);
@@ -1517,10 +1609,10 @@ class transactdTest extends PHPUnit_Framework_TestCase
1517
1609
  $this->assertEquals($tb->stat(), 0);
1518
1610
 
1519
1611
  // ------------------------------------------------------
1520
- // Normal and Exclusive opend tables mix transaction
1612
+ // Normal and Exclusive open tables mix transaction
1521
1613
  // ------------------------------------------------------
1522
1614
  $tb2 = $db->openTable('group', Bz\transactd::TD_OPEN_EXCLUSIVE);
1523
- $this->assertEquals($tb2->stat(), 0);
1615
+ $this->assertEquals($db->stat(), 0);
1524
1616
  // Check tb2 Exclusive
1525
1617
  $tb3 = $db2->openTable('group', Bz\transactd::TD_OPEN_NORMAL);
1526
1618
  $this->assertEquals($db2->stat(), Bz\transactd::STATUS_CANNOT_LOCK_TABLE);
@@ -1586,6 +1678,70 @@ class transactdTest extends PHPUnit_Framework_TestCase
1586
1678
  $v2 = $tb->getFVstr(FDI_NAME);
1587
1679
  $this->assertEquals($v, $v2);
1588
1680
  }
1681
+ public function testMissingUpdate()
1682
+ {
1683
+ if(! class_exists('Thread'))
1684
+ {
1685
+ echo(' * class Thread not found! * ');
1686
+ return;
1687
+ }
1688
+ $db = new Bz\database();
1689
+ $tb = $this->openTable($db);
1690
+ Bz\pooledDbManager::setMaxConnections(3);
1691
+ // Lock last record and insert to next of it
1692
+ $w = new SeekLessThanWorker();
1693
+ $tb->setFV(FDI_ID, 300000);
1694
+ $tb->seekLessThan(false, Bz\transactd::ROW_LOCK_X);
1695
+ $this->assertEquals($tb->stat(), 0);
1696
+ if ($tb->stat() == 0)
1697
+ {
1698
+ // Get lock(X) same record in parallel.
1699
+ $w->start();
1700
+ usleep(5000);
1701
+ $v = $tb->getFVint(FDI_ID);
1702
+ $tb->setFV(FDI_ID, ++$v);
1703
+ $tb->insert();
1704
+ $this->assertEquals($tb->stat(), 0);
1705
+ $w->join();
1706
+ $v2 = $w->getResult();
1707
+
1708
+ if ($db->trxIsolationServer() == Bz\transactd::SRV_ISO_REPEATABLE_READ)
1709
+ { // $tb can not insert because $tb2 got gap lock with SRV_ISO_REPEATABLE_READ.
1710
+ // It is deadlock!
1711
+ $this->assertEquals($tb->stat(), Bz\transactd::STATUS_LOCK_ERROR);
1712
+ }
1713
+ else
1714
+ { // When SRV_ISO_READ_COMMITED set, $tb2 get lock after $tb->insert.
1715
+ // But this is not READ_COMMITED !
1716
+ $this->assertEquals($tb->stat(), 0);
1717
+ $this->assertEquals($v2, $v - 1);
1718
+ // cleanup
1719
+ $tb->setFV(FDI_ID, $v);
1720
+ $tb->seek();
1721
+ $this->assertEquals($tb->stat(), 0);
1722
+ $tb->del();
1723
+ $this->assertEquals($tb->stat(), 0);
1724
+ }
1725
+ }
1726
+ // Lock last record and delete it
1727
+ $w = new SeekLessThanWorker();
1728
+ $tb->setFV(FDI_ID, 300000);
1729
+ $tb->seekLessThan(false, Bz\transactd::ROW_LOCK_X);
1730
+ $this->assertEquals($tb->stat(), 0);
1731
+ if ($tb->stat() == 0)
1732
+ {
1733
+ // Get lock(X) same record in parallel.
1734
+ $w->start();
1735
+ usleep(5000);
1736
+ $v = $tb->getFVint(FDI_ID);
1737
+ $tb->del();
1738
+ $this->assertEquals($tb->stat(), 0);
1739
+ $w->join();
1740
+ $v2 = $w->getResult();
1741
+ $this->assertNotEquals($v, $v2);
1742
+ }
1743
+ (new Bz\pooledDbManager())->reset(0);
1744
+ }
1589
1745
  public function testInsert2()
1590
1746
  {
1591
1747
  $db = new Bz\database();
@@ -1611,13 +1767,16 @@ class transactdTest extends PHPUnit_Framework_TestCase
1611
1767
  $db = new Bz\database();
1612
1768
  $tb = $this->openTable($db);
1613
1769
  $this->assertNotEquals($tb, NULL);
1770
+ $expected_count = 20003;
1771
+ if(! class_exists('Thread'))
1772
+ $expected_count = $expected_count + 1;
1614
1773
  // estimate count
1615
1774
  $count = $tb->recordCount(true);
1616
- $is_valid_count = (abs($count - TEST_COUNT) < ALLOWABLE_ERROR_DISTANCE_IN_ESTIMATE_COUNT);
1775
+ $is_valid_count = (abs($count - $expected_count) < 5000);
1617
1776
  $this->assertTrue($is_valid_count);
1618
1777
  if (! $is_valid_count)
1619
- print("true record count = " . (TEST_COUNT + 3) . " and estimate recordCount count = " . $count);
1620
- $this->assertEquals($tb->recordCount(false), TEST_COUNT + 3); // true count
1778
+ print("true record count = " . $expected_count . " and estimate recordCount count = " . $count);
1779
+ $this->assertEquals($tb->recordCount(false), $expected_count); // true count
1621
1780
  $vv = TEST_COUNT * 3 / 4 + 1;
1622
1781
  $tb->clearBuffer();
1623
1782
  $tb->setFV(FDI_ID, $vv);
@@ -1684,7 +1843,7 @@ class transactdTest extends PHPUnit_Framework_TestCase
1684
1843
  $db2->connect(PROTOCOL . HOSTNAME, true);
1685
1844
  $this->assertEquals($db2->stat(), 0);
1686
1845
  unset($db2);
1687
- $db->disconnect(PROTOCOL . HOSTNAME);
1846
+ $db->disconnect();
1688
1847
  $this->assertEquals($db->stat(), 0);
1689
1848
  }
1690
1849
  // invalid host name
@@ -1696,24 +1855,24 @@ class transactdTest extends PHPUnit_Framework_TestCase
1696
1855
  print('bad host $db->stat() = ' . $db->stat());
1697
1856
  $this->createDatabase($db);
1698
1857
  $this->createTable($db);
1699
- $db->disconnect(PROTOCOL . HOSTNAME . DBNAME);
1858
+ $db->close();
1700
1859
  $this->assertEquals($db->stat(), 0);
1701
1860
  // true database name
1702
1861
  $db->connect(PROTOCOL . HOSTNAME . DBNAME);
1703
1862
  $this->assertEquals($db->stat(), 0);
1704
1863
  if ($db->stat() == 0)
1705
1864
  {
1706
- $db->disconnect(PROTOCOL . HOSTNAME . DBNAME);
1865
+ $db->disconnect();
1707
1866
  $this->assertEquals($db->stat(), 0);
1708
1867
  }
1709
1868
  // invalid database name
1710
1869
  $this->dropDatabase($db);
1711
- $db->disconnect(PROTOCOL . HOSTNAME . DBNAME);
1870
+ $db->disconnect();
1712
1871
  $this->assertEquals($db->stat(), 0);
1713
1872
  $db->connect(PROTOCOL . HOSTNAME . DBNAME);
1714
- $this->assertEquals($db->stat(), 25000 + 1049);
1715
- $db->disconnect(PROTOCOL . HOSTNAME . DBNAME);
1716
- $this->assertEquals($db->stat(), 0);
1873
+ $this->assertEquals($db->stat(), Bz\transactd::ERROR_NO_DATABASE);
1874
+ $db->disconnect();
1875
+ $this->assertEquals($db->stat(), 1);
1717
1876
  }
1718
1877
 
1719
1878
  /* -----------------------------------------------------
@@ -3242,19 +3401,6 @@ class transactdTest extends PHPUnit_Framework_TestCase
3242
3401
  // $rs[0];
3243
3402
  $this->assertEquals($rs[0]['group_name'], '1 group');
3244
3403
 
3245
- /*
3246
- sortFields orderRv;
3247
- orderRv.add('group_name', false);
3248
- rs.orderBy(orderRv);
3249
-
3250
- sortFields order;
3251
- order.add('group_name', true);
3252
- rs.orderBy(order);
3253
- BOOST_CHECK_MESSAGE(_tstring(rs[(size_t)0]['group_name'].c_str()) ==
3254
- _tstring('1 group'),
3255
- "group_name = 1 group "
3256
- << string(rs[(size_t)0]['group_name'].a_str()));
3257
- */
3258
3404
  // All fields
3259
3405
  $rs->clear();
3260
3406
  $q->reset()->all();
@@ -90,7 +90,6 @@ class transactdPoolTest extends PHPUnit_Framework_TestCase
90
90
  $dbm = new Bz\pooledDbManager($cp);
91
91
  $atu = new Bz\ActiveTable($dbm, 'user');
92
92
  $q = new Bz\query();
93
- $rs = new Bz\RecordSet();
94
93
  $atu->alias('名前', 'name');
95
94
  $q->select('id', 'name', 'group')->where('id', '<=', 15000);
96
95
  $rs = $atu->index(0)->keyValue(1)->read($q);
@@ -105,7 +104,7 @@ class transactdPoolTest extends PHPUnit_Framework_TestCase
105
104
  public function testMultiThreads()
106
105
  {
107
106
  if(! class_exists('Thread')){
108
- echo(' * class Tread not found! * ');
107
+ echo(' * class Thread not found! * ');
109
108
  return;
110
109
  }
111
110
  Bz\pooledDbManager::setMaxConnections(5);