transactd 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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);