<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="339824" data-post-id="339824">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="zachdaniel" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/zachdaniel/120/31980_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  zachdaniel
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Ash</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Ah, yeah you’re right <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"> Wasn’t thinking. I don’t think there is a good way to just apply field policies TBH. They are implemented as calculations.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="339824" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ashgraphql-filter-for-atom-attribute-stopped-working-in-ash-3/66058/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-339824" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="339824"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #11"></div>
  </section>
</div>
    <div class="postbit" id="339827" data-post-id="339827">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sezaru" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sezaru/120/36113_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sezaru
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I’m gonna try using the ets datalayer since I think that one would be more consistent on timing.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="339827" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ashgraphql-filter-for-atom-attribute-stopped-working-in-ash-3/66058/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-339827" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="339827"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #12"></div>
  </section>
</div>
    <div class="postbit" id="340006" data-post-id="340006">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sezaru" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sezaru/120/36113_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sezaru
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>So, <a class="mention" href="/u/zachdaniel" rel="nofollow">@zachdaniel</a> , I did some benchmark testing here and I think I got some interesting numbers.</p>
<p>The test consists of a resource that contains around 255 attributes. I used the ETS data-layer and added one record to it.</p>
<p>Then, I run a read action to fetch it applying my field policies and another run not applying it.</p>
<p>The benchmark code is as follows:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Benchmark do
  alias Core.Pacman.Markets.Record
  
  def run() do
    actor = %{roles: [:blibs]}

    Benchee.run(
      %{
        "run" =&gt; fn -&gt;
          Record
          |&gt; Ash.Query.for_read(:read, %{}, actor: actor)
          |&gt; Ash.read!()
        end,
      },
      time: 100,
      memory_time: 2
    )
  end
end
</code></pre>
<p>For the field policies, I added one per attribute, all of them have the same check, I did two types of checks to see if the check itself would be a bottleneck.</p>
<p>Using a check that search for a atom in the <code>:roles</code> field of an agent (based on the HasRole check from ash rbac):</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">      field_policy :external_id do
        authorize_if {HasRole, role: [:support, :admin, {:agent, :organization_roles}]}
      end
</code></pre>
<p>Using a always authorize check:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">      field_policy :external_id do
        authorize_if always()
      end
</code></pre>
<p>Here are the results:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">Name               ips        average  deviation         median         99th %
disabled       4885.16        0.20 ms    ±16.71%       0.197 ms        0.34 ms
always           50.60       19.76 ms    ±19.98%       19.15 ms       30.24 ms
roles            36.92       27.09 ms    ±11.88%       26.44 ms       38.14 ms

Comparison: 
disabled       4885.16
always           50.60 - 96.55x slower +19.56 ms
roles            36.92 - 132.33x slower +26.88 ms

Memory usage statistics:

Name             average  deviation         median         99th %
disabled       0.0254 MB     ±0.01%      0.0254 MB      0.0254 MB
always           5.22 MB     ±0.06%        5.22 MB        5.23 MB
roles           15.31 MB     ±0.06%       15.31 MB       15.34 MB

Comparison: 
disabled       0.0254 MB
always           5.22 MB - 205.84x memory usage +5.20 MB
roles           15.31 MB - 603.57x memory usage +15.29 MB
</code></pre>
<p>Seems like there is a very big overhead of creating field policies per field</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="340006" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ashgraphql-filter-for-atom-attribute-stopped-working-in-ash-3/66058/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-340006" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="340006"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #13"></div>
  </section>
</div>
    <div class="postbit" id="340012" data-post-id="340012">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sezaru" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sezaru/120/36113_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sezaru
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I just added some more benchmark numbers:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">Name                       ips        average  deviation         median         99th %
disabled               4885.16        0.20 ms    ±16.71%       0.197 ms        0.34 ms
catch_all_always       1227.80        0.81 ms    ±22.45%        0.75 ms        1.61 ms
catch_all_roles         964.08        1.04 ms    ±13.55%        1.00 ms        1.57 ms
always                   50.60       19.76 ms    ±19.98%       19.15 ms       30.24 ms
bypass_roles             37.81       26.45 ms    ±13.31%       26.03 ms       35.65 ms
roles                    36.92       27.09 ms    ±11.88%       26.44 ms       38.14 ms

Comparison: 
disabled               4885.16
catch_all_always       1227.80 - 3.98x slower +0.61 ms
catch_all_roles         964.08 - 5.07x slower +0.83 ms
always                   50.60 - 96.55x slower +19.56 ms
bypass_roles             37.81 - 129.19x slower +26.24 ms
roles                    36.92 - 132.33x slower +26.88 ms

Memory usage statistics:

Name                     average  deviation         median         99th %
disabled               0.0254 MB     ±0.01%      0.0254 MB      0.0254 MB
catch_all_always        0.142 MB     ±0.00%       0.142 MB       0.142 MB
catch_all_roles          0.29 MB     ±0.01%        0.29 MB        0.29 MB
always                   5.22 MB     ±0.06%        5.22 MB        5.23 MB
bypass_roles            15.10 MB     ±0.13%       15.10 MB       15.15 MB
roles                   15.31 MB     ±0.06%       15.31 MB       15.34 MB

Comparison: 
disabled               0.0254 MB
catch_all_always        0.142 MB - 5.62x memory usage +0.117 MB
catch_all_roles          0.29 MB - 11.45x memory usage +0.27 MB
always                   5.22 MB - 205.84x memory usage +5.20 MB
bypass_roles            15.10 MB - 595.18x memory usage +15.07 MB
roles                   15.31 MB - 603.57x memory usage +15.29 MB
</code></pre>
<p>Legend:<br>
<strong>disabled</strong>: field_policies are fully disabled<br>
<strong>catch_all_always</strong>: there is only one field_policy with a catch_all that always authorize<br>
<strong>catch_all_roles</strong>: there is only one field_policy with a catch_all that checks for the role<br>
<strong>always</strong>: have a field_policy per attribute that always authorize<br>
<strong>bypass_roles</strong>: have a field_policy_bypass per attribute that will check for the role<br>
<strong>roles</strong>: have a field_policy per attribute that will check for the role</p>
<p>It is interesting to see that even having just one field_policy already makes the query 4x slower than not having any check at all</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="340012" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ashgraphql-filter-for-atom-attribute-stopped-working-in-ash-3/66058/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-340012" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="340012"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #14"></div>
  </section>
</div>
    <div class="postbit" id="340018" data-post-id="340018">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="zachdaniel" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/zachdaniel/120/31980_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  zachdaniel
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Ash</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Yeah, I’d imagine this area is rife for optimizations <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<p>Ultimately, I think having fewer field policies is better than one policy per field from a conceptual standpoint, and we should come up with a way for you to write either a deny-list or an allow-list.</p>
<p>I’d be willing to bet that we could eliminate most if not all of that additional processing time via optimizing those code paths. If you could open an issue on Ash showing this info that would be great. I won’t have the time to optimize this in the near future, unfortunately, but perhaps an adventurous soul can investigate.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="340018" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ashgraphql-filter-for-atom-attribute-stopped-working-in-ash-3/66058/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-340018" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="340018"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #15"></div>
  </section>
</div>
    <div class="postbit" id="340019" data-post-id="340019">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sezaru" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sezaru/120/36113_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sezaru
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Would you mind giving me some hints which files/functions the field policies code path is run? I can take a look into it when I have some free time in my hands.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="340019" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ashgraphql-filter-for-atom-attribute-stopped-working-in-ash-3/66058/17">Post #16</a>
	                </div>
	            </div>
              <div id="likers-container-340019" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="340019"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #16"></div>
  </section>
</div>
    <div class="postbit" id="340022" data-post-id="340022">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="zachdaniel" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/zachdaniel/120/31980_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  zachdaniel
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Ash</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>The <code>add_calculations</code> callback is where we determine the calculations, and then in <code>add_field_level_auth</code> function in the read action logic.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="340022" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ashgraphql-filter-for-atom-attribute-stopped-working-in-ash-3/66058/18">Post #17</a>
	                </div>
	            </div>
              <div id="likers-container-340022" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="340022"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-last-post cat-last-post" title="Last post!"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <span class="all-loaded">— All posts loaded —</span>
</div></template></turbo-stream>