tiny_ds 0.0.2 → 0.0.3.pre
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.
- data/README.rdoc +18 -15
- data/Rakefile +1 -1
- data/lib/tiny_ds/base.rb +28 -25
- data/lib/tiny_ds/base_tx.rb +4 -4
- data/lib/tiny_ds/low_ds.rb +14 -4
- data/lib/tiny_ds/property_definition.rb +14 -0
- data/lib/tiny_ds/query.rb +23 -1
- data/lib/tiny_ds/transaction.rb +37 -0
- data/lib/tiny_ds/version.rb +1 -1
- data/lib/tiny_ds.rb +25 -3
- data/spec/basic_spec.rb +212 -13
- data/spec/gae_spec.rb +86 -0
- data/spec/tx_spec.rb +82 -0
- metadata +7 -13
- data/lib/tiny_ds/base.rb~ +0 -115
- data/lib/tiny_ds/base_tx.rb~ +0 -180
- data/lib/tiny_ds/low_ds.rb~ +0 -80
- data/lib/tiny_ds/property_definition.rb~ +0 -54
- data/lib/tiny_ds/query.rb~ +0 -68
- data/lib/tiny_ds/validations.rb~ +0 -9
- data/lib/tiny_ds.rb~ +0 -2
- data/lib/tinyds.rb~ +0 -2
- data/spec/spec_helper.rb~ +0 -0
data/spec/gae_spec.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe "transaction" do
|
5
|
+
it "should push/pop tx" do
|
6
|
+
ds = AppEngine::Datastore.service
|
7
|
+
proc{ ds.getCurrentTransaction }.should raise_error(NativeException, "java.lang.IllegalStateException: java.util.NoSuchElementException")
|
8
|
+
ds.getActiveTransactions.to_a.size.should == 0
|
9
|
+
|
10
|
+
tx1 = ds.beginTransaction
|
11
|
+
# [tx1]
|
12
|
+
tx1.should be_kind_of(com.google.appengine.api.datastore.Transaction)
|
13
|
+
tx1.should == ds.getCurrentTransaction
|
14
|
+
ds.getActiveTransactions.to_a.size.should == 1
|
15
|
+
|
16
|
+
tx2 = ds.beginTransaction
|
17
|
+
# [tx2, tx1]
|
18
|
+
tx2.should be_kind_of(com.google.appengine.api.datastore.Transaction)
|
19
|
+
tx2.should == ds.getCurrentTransaction
|
20
|
+
ds.getActiveTransactions.to_a.size.should == 2
|
21
|
+
ds.getActiveTransactions.to_a[0].should == tx2
|
22
|
+
ds.getActiveTransactions.to_a[1].should == tx1
|
23
|
+
|
24
|
+
tx3 = ds.beginTransaction
|
25
|
+
# [tx3, tx2, tx1]
|
26
|
+
tx3.should be_kind_of(com.google.appengine.api.datastore.Transaction)
|
27
|
+
tx3.should == ds.getCurrentTransaction
|
28
|
+
ds.getActiveTransactions.to_a.size.should == 3
|
29
|
+
ds.getActiveTransactions.to_a[0].should == tx3
|
30
|
+
ds.getActiveTransactions.to_a[1].should == tx2
|
31
|
+
ds.getActiveTransactions.to_a[2].should == tx1
|
32
|
+
|
33
|
+
tx3.commit
|
34
|
+
# [tx2, tx1]
|
35
|
+
tx2.should == ds.getCurrentTransaction
|
36
|
+
ds.getActiveTransactions.to_a.size.should == 2
|
37
|
+
ds.getActiveTransactions.to_a[0].should == tx2
|
38
|
+
ds.getActiveTransactions.to_a[1].should == tx1
|
39
|
+
|
40
|
+
tx4 = ds.beginTransaction
|
41
|
+
# [tx4, tx2, tx1]
|
42
|
+
tx4.should be_kind_of(com.google.appengine.api.datastore.Transaction)
|
43
|
+
tx4.should == ds.getCurrentTransaction
|
44
|
+
ds.getActiveTransactions.to_a.size.should == 3
|
45
|
+
ds.getActiveTransactions.to_a[0].should == tx4
|
46
|
+
ds.getActiveTransactions.to_a[1].should == tx2
|
47
|
+
ds.getActiveTransactions.to_a[2].should == tx1
|
48
|
+
|
49
|
+
tx2.commit
|
50
|
+
# [tx4, tx1]
|
51
|
+
tx4.should == ds.getCurrentTransaction
|
52
|
+
ds.getActiveTransactions.to_a.size.should == 2
|
53
|
+
ds.getActiveTransactions.to_a[0].should == tx4
|
54
|
+
ds.getActiveTransactions.to_a[1].should == tx1
|
55
|
+
|
56
|
+
tx1.rollback
|
57
|
+
# [tx4]
|
58
|
+
tx4.should == ds.getCurrentTransaction
|
59
|
+
ds.getActiveTransactions.to_a.size.should == 1
|
60
|
+
ds.getActiveTransactions.to_a[0].should == tx4
|
61
|
+
|
62
|
+
tx4.rollback
|
63
|
+
# []
|
64
|
+
ds.getCurrentTransaction(nil).should be_nil
|
65
|
+
ds.getActiveTransactions.to_a.size.should == 0
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should be default is NONE" do
|
69
|
+
dsf = com.google.appengine.api.datastore.DatastoreServiceFactory
|
70
|
+
dsc = dsf.getDefaultDatastoreConfig
|
71
|
+
dsc.should == com.google.appengine.api.datastore.DatastoreConfig::DEFAULT
|
72
|
+
dsc.getImplicitTransactionManagementPolicy.should == com.google.appengine.api.datastore.ImplicitTransactionManagementPolicy::NONE
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should be work tx many settings."
|
76
|
+
=begin
|
77
|
+
Policy : AUTO or NONE
|
78
|
+
currentTx : nil or exist
|
79
|
+
method : put(ent) or put(tx, ent) or put(nil, ent)
|
80
|
+
12 patterns.
|
81
|
+
put([e1,e2])
|
82
|
+
=end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
|
data/spec/tx_spec.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
# http://www.slideshare.net/ashigeru/ajn4
|
4
|
+
# 1. EGでのACIDトランザクションの仕組み
|
5
|
+
# 2. パターン「read-modify-write」1エンティティの書き換え
|
6
|
+
# 3. パターン「トランザクションの合成」同一EG複数エンティティの書き換え
|
7
|
+
# 4. パターン「ユニーク制約」id/name指定を用いたユニーク制約の実現
|
8
|
+
# 5. パターン「べき等な処理」1回以上複数回実行されても結果は1回だけ実行された状態になる処理
|
9
|
+
# 6. パターン「exactly-once」確実に1回だけ実行される処理。2回以上実行されない処理
|
10
|
+
# 7. パターン「BASE Transaction」過渡的な状態があるトランザクション
|
11
|
+
|
12
|
+
=begin
|
13
|
+
describe "TinyDS::Transaction" do
|
14
|
+
describe "(1) EG transaction" do
|
15
|
+
it "should work" do
|
16
|
+
Tx.atomic{
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
describe "(2) read_modify_write" do
|
21
|
+
end
|
22
|
+
describe "(3) 2 entities read_modify_write" do
|
23
|
+
end
|
24
|
+
describe "(4) unique value" do
|
25
|
+
it "should work" do
|
26
|
+
User.create(props, {:name=>"hoge@example.com", :check_unique=>true})
|
27
|
+
end
|
28
|
+
# name/id が指定された場合ユニークチェックをする
|
29
|
+
# デフォルトでする / しない?
|
30
|
+
# transaction内の場合 => ...
|
31
|
+
# transaction外の場合 => ...
|
32
|
+
end
|
33
|
+
describe "(5) idempotent" do
|
34
|
+
idempotent_key = TxFlag.generate_key(@parent.key, unique_value)
|
35
|
+
args = {:amount=>5000}
|
36
|
+
Tx.idempotent(idempotent_key, args) do |args|
|
37
|
+
# Tx.atomic{
|
38
|
+
# flag = get(idempotent_key)
|
39
|
+
# raise :not_unique if flag
|
40
|
+
# yield(args){
|
41
|
+
@user.money += args[:amount]
|
42
|
+
# }
|
43
|
+
# }
|
44
|
+
end
|
45
|
+
# @parentの子としてIdempotentFlagが作成される
|
46
|
+
# @parentと(IdempotentFlagと)処理内で使うすべてのentityは同一EGである必要がある
|
47
|
+
end
|
48
|
+
describe "(6) exactly_once" do
|
49
|
+
exactly_once_key = TxFlag.generate_key(@parent.key, unique_value)
|
50
|
+
Tx.exactly_once(exactly_once_key, args) do |args|
|
51
|
+
# idempotent_key = exactly_once_key
|
52
|
+
# TQ.enqueue(idempotent_key, args, proc{|idempotent_key,args|
|
53
|
+
# Tx.idempotent(idempotent_key, args) do |args|
|
54
|
+
user = User.get(args[:user_id])
|
55
|
+
user.money += 5000
|
56
|
+
user.save
|
57
|
+
# end
|
58
|
+
# }.serialize)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
describe "(7) base_transaction" do
|
62
|
+
base_tx_key = TxFlag.generate_key(@parent.key, unique_value)
|
63
|
+
Tx.base_transaction(args, procA, procB) do
|
64
|
+
# Tx.atomic{|tx1|
|
65
|
+
# yield(args){
|
66
|
+
# (procA)
|
67
|
+
a = get(args[:userA_key])
|
68
|
+
a.money -= args[:ampunt]
|
69
|
+
a.save
|
70
|
+
# }
|
71
|
+
# exactly_once_key = ...
|
72
|
+
# Tx.exactly_once_key(exactly_once_key, args){
|
73
|
+
# (procB)
|
74
|
+
b = get(args[:userB_key])
|
75
|
+
b.money += args[:ampunt]
|
76
|
+
b.save
|
77
|
+
# }
|
78
|
+
# }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
=end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tiny_ds
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Takeru Sasaki
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-30 00:00:00 +09:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -36,24 +36,18 @@ files:
|
|
36
36
|
- README.rdoc
|
37
37
|
- Rakefile
|
38
38
|
- spec/basic_spec.rb
|
39
|
+
- spec/gae_spec.rb
|
39
40
|
- spec/spec_helper.rb
|
40
|
-
- spec/
|
41
|
+
- spec/tx_spec.rb
|
41
42
|
- lib/tiny_ds/base.rb
|
42
|
-
- lib/tiny_ds/base.rb~
|
43
43
|
- lib/tiny_ds/base_tx.rb
|
44
|
-
- lib/tiny_ds/base_tx.rb~
|
45
44
|
- lib/tiny_ds/low_ds.rb
|
46
|
-
- lib/tiny_ds/low_ds.rb~
|
47
45
|
- lib/tiny_ds/property_definition.rb
|
48
|
-
- lib/tiny_ds/property_definition.rb~
|
49
46
|
- lib/tiny_ds/query.rb
|
50
|
-
- lib/tiny_ds/
|
47
|
+
- lib/tiny_ds/transaction.rb
|
51
48
|
- lib/tiny_ds/validations.rb
|
52
|
-
- lib/tiny_ds/validations.rb~
|
53
49
|
- lib/tiny_ds/version.rb
|
54
50
|
- lib/tiny_ds.rb
|
55
|
-
- lib/tiny_ds.rb~
|
56
|
-
- lib/tinyds.rb~
|
57
51
|
has_rdoc: true
|
58
52
|
homepage: http://github.com/takeru/tiny_ds
|
59
53
|
licenses: []
|
@@ -71,9 +65,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
71
65
|
version:
|
72
66
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
67
|
requirements:
|
74
|
-
- - "
|
68
|
+
- - ">"
|
75
69
|
- !ruby/object:Gem::Version
|
76
|
-
version:
|
70
|
+
version: 1.3.1
|
77
71
|
version:
|
78
72
|
requirements: []
|
79
73
|
|
data/lib/tiny_ds/base.rb~
DELETED
@@ -1,115 +0,0 @@
|
|
1
|
-
=begin
|
2
|
-
special pname
|
3
|
-
- key
|
4
|
-
- parent
|
5
|
-
- id
|
6
|
-
- name
|
7
|
-
=end
|
8
|
-
|
9
|
-
|
10
|
-
class ModelBase
|
11
|
-
@@properties = {}
|
12
|
-
def self.property(pname, ptype, opts={})
|
13
|
-
pname = pname.to_sym
|
14
|
-
if @@properties[pname]
|
15
|
-
raise "duplicated pname=#{pname}"
|
16
|
-
end
|
17
|
-
@@properties[pname] = Property.new(pname, ptype, opts)
|
18
|
-
end
|
19
|
-
|
20
|
-
# kind-string of entity
|
21
|
-
def self.kind
|
22
|
-
name
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.tx(retries=0, &block)
|
26
|
-
transaction{
|
27
|
-
yield(block)
|
28
|
-
}
|
29
|
-
end
|
30
|
-
|
31
|
-
# Foo.create(attrs
|
32
|
-
def self.create(attrs={})
|
33
|
-
m = new(attrs)
|
34
|
-
m.save
|
35
|
-
m
|
36
|
-
end
|
37
|
-
|
38
|
-
# Foo.new
|
39
|
-
def initialize(attrs={})
|
40
|
-
attributes = attrs
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.new_from_entity(entity)
|
44
|
-
m = new()
|
45
|
-
end
|
46
|
-
|
47
|
-
# foo.save
|
48
|
-
def save
|
49
|
-
_save
|
50
|
-
end
|
51
|
-
|
52
|
-
def _save
|
53
|
-
end
|
54
|
-
|
55
|
-
# Foo.get(key)
|
56
|
-
def self.get(key)
|
57
|
-
if key.kind_of?(String)
|
58
|
-
key = LowDS::KeyFactory.stringToKey(key)
|
59
|
-
end
|
60
|
-
raise "invalid key=#{key}" unless key.kind_of?(AppEngine::Datastore::Key)
|
61
|
-
self.new_from_entity(LowDS.get(key, :kind=>self.kind))
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.find(*args)
|
65
|
-
|
66
|
-
end
|
67
|
-
|
68
|
-
# foo.destroy
|
69
|
-
def destroy
|
70
|
-
end
|
71
|
-
|
72
|
-
def attributes=(attrs)
|
73
|
-
# TODO key, parent, id, name
|
74
|
-
|
75
|
-
attrs.each do |k,v|
|
76
|
-
prop = @@properties[k.to_sym]
|
77
|
-
prop.value = v
|
78
|
-
end
|
79
|
-
nil
|
80
|
-
end
|
81
|
-
|
82
|
-
def method_missing(m, *args)
|
83
|
-
prop, is_set = if m =~ /(.+)=$/
|
84
|
-
[@@properties[$1.to_sym], true]
|
85
|
-
else
|
86
|
-
[@@properties[m.to_sym], false]
|
87
|
-
end
|
88
|
-
if prop
|
89
|
-
# TODO define method.
|
90
|
-
if is_set
|
91
|
-
raise if args.size!=1
|
92
|
-
prop.value = args.first
|
93
|
-
else
|
94
|
-
raise if args.size!=0
|
95
|
-
prop.value
|
96
|
-
end
|
97
|
-
else
|
98
|
-
super(m, *args)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
class Property
|
103
|
-
def initialize(pname, ptype, opts)
|
104
|
-
@pname = pname
|
105
|
-
@ptype = ptype
|
106
|
-
@opts = opts
|
107
|
-
end
|
108
|
-
def value=(v)
|
109
|
-
# check_type or cast
|
110
|
-
@value = v
|
111
|
-
end
|
112
|
-
attr_reader :value
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
data/lib/tiny_ds/base_tx.rb~
DELETED
@@ -1,180 +0,0 @@
|
|
1
|
-
=begin
|
2
|
-
使い方
|
3
|
-
class TxMoveUserPoint < BaseTx
|
4
|
-
def src_phase(src, args)
|
5
|
-
src[:point] -= args[:amount]
|
6
|
-
end
|
7
|
-
def dest_phase(dest, args)
|
8
|
-
dest[:point] += args[:amount]
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
u1 = User.create(:point=>1000)
|
13
|
-
=> #<User @sid=21 @name=nil @message=nil @point=1000 @created_at=Thu, 17 Dec 2009 21:14:29 +0900 @updated_at=Thu, 17 Dec 2009 21:14:29 +0900>
|
14
|
-
|
15
|
-
u2 = User.create(:point=>1000)
|
16
|
-
=> #<User @sid=22 @name=nil @message=nil @point=1000 @created_at=Thu, 17 Dec 2009 21:14:33 +0900 @updated_at=Thu, 17 Dec 2009 21:14:33 +0900>
|
17
|
-
|
18
|
-
TxMoveUserPoint.exec(u1.__entity__, u2.__entity__, :amount=>200)
|
19
|
-
=> true
|
20
|
-
|
21
|
-
u1.reload
|
22
|
-
=> #<User @sid=21 @name=nil @message=nil @point=800 @created_at=Thu, 17 Dec 2009 21:14:29 +0900 @updated_at=Thu, 17 Dec 2009 21:14:29 +0900>
|
23
|
-
|
24
|
-
u2.reload
|
25
|
-
=> #<User @sid=22 @name=nil @message=nil @point=1200 @created_at=Thu, 17 Dec 2009 21:14:33 +0900 @updated_at=Thu, 17 Dec 2009 21:14:33 +0900>
|
26
|
-
|
27
|
-
TxMoveUserPoint.roll_forward_all
|
28
|
-
=end
|
29
|
-
# memo デプロイ時に未完了のトランザクションがあってトランザクション定義がかわったら?version???
|
30
|
-
|
31
|
-
class BaseTx
|
32
|
-
LowDS = TinyDS::LowDS
|
33
|
-
|
34
|
-
def src_phase(src, args)
|
35
|
-
raise "no impl."
|
36
|
-
end
|
37
|
-
def dest_phase(dest, args)
|
38
|
-
raise "no impl."
|
39
|
-
end
|
40
|
-
def self.tx_kind
|
41
|
-
name
|
42
|
-
end
|
43
|
-
def roll_forward_retries_limit
|
44
|
-
100
|
45
|
-
end
|
46
|
-
attr_reader :tx_key
|
47
|
-
|
48
|
-
# トランザクション実行
|
49
|
-
# : src_phase dest_phase
|
50
|
-
# raised : failed ----
|
51
|
-
# false : OK failed
|
52
|
-
# true : OK OK
|
53
|
-
def self.exec(src, dest, args={})
|
54
|
-
tx = new
|
55
|
-
tx.create_tx(src, dest, args)
|
56
|
-
begin
|
57
|
-
tx.roll_forward
|
58
|
-
rescue AppEngine::Datastore::TransactionFailed => e
|
59
|
-
return false
|
60
|
-
end
|
61
|
-
return true
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.roll_forward_all(limit=50)
|
65
|
-
pending_tx_query.each(:limit=>limit) do |tx_ent|
|
66
|
-
tx = new
|
67
|
-
tx.restore_tx(tx_ent)
|
68
|
-
begin
|
69
|
-
tx.roll_forward
|
70
|
-
rescue => e
|
71
|
-
# logger.warn("roll_forward failed. tx=[#{tx.tx_key}] e=[#{e.inspect}]")
|
72
|
-
end
|
73
|
-
end
|
74
|
-
nil
|
75
|
-
end
|
76
|
-
|
77
|
-
def self.pending_tx_query(status="pending", dire=:asc) # pending/done/failed
|
78
|
-
direction = dire==:desc ? AppEngine::Datastore::Query::DESCENDING : AppEngine::Datastore::Query::ASCENDING
|
79
|
-
AppEngine::Datastore::Query.new("TxSrc").
|
80
|
-
filter(:tx_kind, AppEngine::Datastore::Query::EQUAL, tx_kind).
|
81
|
-
filter(:status, AppEngine::Datastore::Query::EQUAL, status).
|
82
|
-
sort(:created_at, direction)
|
83
|
-
end
|
84
|
-
|
85
|
-
# doneなTxSrcと対応するTxDoneを削除する
|
86
|
-
# def self.delete_done_tx
|
87
|
-
# end
|
88
|
-
|
89
|
-
require "benchmark"
|
90
|
-
def create_tx(src, dest, args)
|
91
|
-
#RAILS_DEFAULT_LOGGER.info ["create_tx", Benchmark.measure{
|
92
|
-
_create_tx(src, dest, args)
|
93
|
-
#}].inspect
|
94
|
-
end
|
95
|
-
def roll_forward
|
96
|
-
#RAILS_DEFAULT_LOGGER.info ["roll_forward", Benchmark.measure{
|
97
|
-
_roll_forward
|
98
|
-
#}].inspect
|
99
|
-
end
|
100
|
-
|
101
|
-
# トランザクション前半
|
102
|
-
# TODO TxIDを指定できるようにする。TxSrc#key.nameにTxIDを指定して重複実行防止
|
103
|
-
def _create_tx(src, dest, args)
|
104
|
-
tx_ent = nil
|
105
|
-
ds_transaction{
|
106
|
-
src = src.class.get(src.key)
|
107
|
-
src_phase(src, args)
|
108
|
-
src.save
|
109
|
-
|
110
|
-
attrs = {
|
111
|
-
:tx_kind => self.class.tx_kind,
|
112
|
-
:dest_key => dest.key.to_s,
|
113
|
-
:status => "pending",
|
114
|
-
:roll_forward_failed_count => 0,
|
115
|
-
:args => args.to_yaml,
|
116
|
-
:created_at => Time.now
|
117
|
-
}
|
118
|
-
tx_ent = LowDS.create("TxSrc", attrs, :parent=>src.entity) # srcがparent, tx_entがchild
|
119
|
-
# COMMIT:「srcの処理(=src_phase)、TxSrc作成」
|
120
|
-
}
|
121
|
-
@tx_key = tx_ent.key.to_s
|
122
|
-
nil
|
123
|
-
end
|
124
|
-
|
125
|
-
def restore_tx(tx_ent)
|
126
|
-
@tx_key = tx_ent.key.to_s
|
127
|
-
nil
|
128
|
-
end
|
129
|
-
|
130
|
-
# トランザクション後半
|
131
|
-
def _roll_forward
|
132
|
-
tx_ent = LowDS.get(@tx_key, :kind=>"TxSrc")
|
133
|
-
|
134
|
-
ds_transaction{
|
135
|
-
dest_key = LowDS::KeyFactory.stringToKey(tx_ent[:dest_key])
|
136
|
-
dest = dest_key.kind.constantize.get(dest_key)
|
137
|
-
done_name = "TxDone_#{@tx_key}"
|
138
|
-
done_key = LowDS::KeyFactory.createKey(dest.key, "TxDone", done_name)
|
139
|
-
begin
|
140
|
-
LowDS.get(done_key, "TxDone")
|
141
|
-
# なにもしない : TxDoneが存在しているということはdest_phaseは処理済み
|
142
|
-
rescue AppEngine::Datastore::EntityNotFound => e
|
143
|
-
# TxDoneが無い→dest_phaseが未実行
|
144
|
-
attrs = {:done_at=>Time.now}
|
145
|
-
done_ent = LowDS.create("TxDone", attrs, :parent=>dest.entity, :name=>done_name)
|
146
|
-
dest_phase(dest, YAML.load(tx_ent[:args])) # destの処理を実行
|
147
|
-
dest.save
|
148
|
-
end
|
149
|
-
# memo: done_keyが同じTxDoneをcommitしようとするとTransactionFailedになるはず→dest_phaseもキャンセル
|
150
|
-
# COMMIT:「destの処理(=dest_phase)、TxDone作成」
|
151
|
-
}
|
152
|
-
|
153
|
-
# TxSrc#statusをdoneに
|
154
|
-
ds_transaction{
|
155
|
-
tx_ent = LowDS.get(@tx_key, :kind=>"TxSrc")
|
156
|
-
if tx_ent[:status]=="pending"
|
157
|
-
tx_ent[:status] = "done"
|
158
|
-
tx_ent[:done_at] = Time.now
|
159
|
-
LowDS.save(tx_ent)
|
160
|
-
end
|
161
|
-
}
|
162
|
-
return true
|
163
|
-
rescue
|
164
|
-
ds_transaction{
|
165
|
-
tx_ent = LowDS.get(@tx_key, :kind=>"TxSrc")
|
166
|
-
tx_ent[:roll_forward_failed_count] += 1
|
167
|
-
if roll_forward_retries_limit < tx_ent[:roll_forward_failed_count]
|
168
|
-
tx_ent[:status] = "failed"
|
169
|
-
end
|
170
|
-
LowDS.save(tx_ent)
|
171
|
-
}
|
172
|
-
return false
|
173
|
-
end
|
174
|
-
|
175
|
-
# EntityGroup単位のtransaction
|
176
|
-
def ds_transaction(&block)
|
177
|
-
retries = 3
|
178
|
-
AppEngine::Datastore.transaction(retries, &block)
|
179
|
-
end
|
180
|
-
end
|
data/lib/tiny_ds/low_ds.rb~
DELETED
@@ -1,80 +0,0 @@
|
|
1
|
-
module LowDS
|
2
|
-
KeyFactory = com.google.appengine.api.datastore.KeyFactory
|
3
|
-
|
4
|
-
# create
|
5
|
-
def self.build(kind, attrs, opts={})
|
6
|
-
raise "invalid opts=#{opts.inspect}" if [:id, :name, :key].collect{|k| opts[k] }.compact.size >= 2
|
7
|
-
raise ":id must be Integer" if opts[:id] && !opts[:id].kind_of?(Integer)
|
8
|
-
raise ":name must be String" if opts[:name] && !opts[:name].kind_of?(String)
|
9
|
-
raise ":key must be Key or String" if opts[:key] && !(opts[:key].kind_of?(String) || opts[:key].kind_of?(AppEngine::Datastore::Key))
|
10
|
-
name_or_id = opts[:name] || opts[:id] # name(String) or id(Integer)
|
11
|
-
key = opts[:key].kind_of?(String) ? KeyFactory.stringToKey(parent) : opts[:key]
|
12
|
-
parent = opts[:parent]
|
13
|
-
ent = if key
|
14
|
-
AppEngine::Datastore::Entity.new(key)
|
15
|
-
elsif parent
|
16
|
-
parent_key = case parent
|
17
|
-
when AppEngine::Datastore::Entity; parent.key
|
18
|
-
when AppEngine::Datastore::Key; parent
|
19
|
-
when String; KeyFactory.stringToKey(parent)
|
20
|
-
else raise "invalid parent type parent=[#{parent.inspect}]"
|
21
|
-
end
|
22
|
-
if name_or_id
|
23
|
-
new_key = KeyFactory.createKey(parent_key, kind, name_or_id)
|
24
|
-
AppEngine::Datastore::Entity.new(new_key)
|
25
|
-
else
|
26
|
-
AppEngine::Datastore::Entity.new(kind, parent_key)
|
27
|
-
end
|
28
|
-
else
|
29
|
-
if name_or_id
|
30
|
-
new_key = KeyFactory.createKey(kind, name_or_id)
|
31
|
-
AppEngine::Datastore::Entity.new(new_key)
|
32
|
-
else
|
33
|
-
AppEngine::Datastore::Entity.new(kind)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
attrs.each do |k,v|
|
37
|
-
ent[k] = v
|
38
|
-
end
|
39
|
-
ent
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.create(kind, attrs, opts={})
|
43
|
-
ent = build(kind, attrs, opts)
|
44
|
-
AppEngine::Datastore.put(ent)
|
45
|
-
ent
|
46
|
-
end
|
47
|
-
|
48
|
-
# get by key
|
49
|
-
def self.get(key, opts={})
|
50
|
-
key = case key
|
51
|
-
when AppEngine::Datastore::Key; key
|
52
|
-
when String; KeyFactory.stringToKey(key)
|
53
|
-
else raise "invalid key type key.class=[#{key.class}] key.inspect=[#{key.inspect}]"
|
54
|
-
end
|
55
|
-
ent = AppEngine::Datastore.get(key)
|
56
|
-
if opts[:kind]
|
57
|
-
raise "kind missmatch. #{ent.kind}!=#{opts[:kind]}" if ent.kind!=opts[:kind]
|
58
|
-
end
|
59
|
-
ent
|
60
|
-
end
|
61
|
-
|
62
|
-
# search
|
63
|
-
def self.search
|
64
|
-
# TODO
|
65
|
-
end
|
66
|
-
|
67
|
-
# update
|
68
|
-
def self.save(ent)
|
69
|
-
AppEngine::Datastore.put(ent)
|
70
|
-
end
|
71
|
-
|
72
|
-
# delete
|
73
|
-
def self.delete(ent)
|
74
|
-
AppEngine::Datastore.delete(ent.key)
|
75
|
-
end
|
76
|
-
|
77
|
-
def self.tx(retries=0, &block)
|
78
|
-
AppEngine::Datastore.transaction(retries, &block)
|
79
|
-
end
|
80
|
-
end
|
@@ -1,54 +0,0 @@
|
|
1
|
-
module TinyDS
|
2
|
-
class PropertyDefinition
|
3
|
-
def initialize(pname, ptype, opts)
|
4
|
-
@pname = pname
|
5
|
-
@ptype = ptype
|
6
|
-
@opts = opts
|
7
|
-
end
|
8
|
-
def default_value
|
9
|
-
if @opts.has_key?(:default)
|
10
|
-
default = @opts[:default]
|
11
|
-
case default
|
12
|
-
when Proc
|
13
|
-
default.call
|
14
|
-
else
|
15
|
-
default
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
def to_ds_value(v)
|
20
|
-
return nil if v.nil?
|
21
|
-
case @ptype
|
22
|
-
when :string
|
23
|
-
v.to_s
|
24
|
-
when :integer
|
25
|
-
v.to_i
|
26
|
-
when :text
|
27
|
-
com.google.appengine.api.datastore::Text.new(java.lang.String.new(v))
|
28
|
-
when :time
|
29
|
-
Time.parse(v.to_s)
|
30
|
-
#when :list
|
31
|
-
# raise "todo"
|
32
|
-
else
|
33
|
-
raise "unknown type @ptype=#{@ptype}"
|
34
|
-
end
|
35
|
-
end
|
36
|
-
def to_ruby_value(ds_v)
|
37
|
-
return nil if ds_v.nil?
|
38
|
-
case @ptype
|
39
|
-
when :string
|
40
|
-
ds_v.to_s
|
41
|
-
when :integer
|
42
|
-
ds_v.to_i
|
43
|
-
when :text
|
44
|
-
ds_v.to_s
|
45
|
-
when :time
|
46
|
-
Time.parse(ds_v.to_s)
|
47
|
-
#when :list
|
48
|
-
# raise "todo"
|
49
|
-
else
|
50
|
-
raise "unknown type @ptype=#{@ptype}"
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|