http://git-wip-us.apache.org/repos/asf/cassandra/blob/72790dc8/lib/licenses/jflex-1.6.0.txt
----------------------------------------------------------------------
diff --git a/lib/licenses/jflex-1.6.0.txt b/lib/licenses/jflex-1.6.0.txt
new file mode 100644
index 0000000..50086f8
--- /dev/null
+++ b/lib/licenses/jflex-1.6.0.txt
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!) The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cassandra/blob/72790dc8/lib/licenses/primitive-1.0.txt
----------------------------------------------------------------------
diff --git a/lib/licenses/primitive-1.0.txt b/lib/licenses/primitive-1.0.txt
new file mode 100644
index 0000000..50086f8
--- /dev/null
+++ b/lib/licenses/primitive-1.0.txt
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!) The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cassandra/blob/72790dc8/lib/licenses/snowball-stemmer-1.3.0.581.1.txt
----------------------------------------------------------------------
diff --git a/lib/licenses/snowball-stemmer-1.3.0.581.1.txt 
b/lib/licenses/snowball-stemmer-1.3.0.581.1.txt
new file mode 100644
index 0000000..50086f8
--- /dev/null
+++ b/lib/licenses/snowball-stemmer-1.3.0.581.1.txt
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!) The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cassandra/blob/72790dc8/lib/primitive-1.0.jar
----------------------------------------------------------------------
diff --git a/lib/primitive-1.0.jar b/lib/primitive-1.0.jar
new file mode 100644
index 0000000..288daa0
Binary files /dev/null and b/lib/primitive-1.0.jar differ

http://git-wip-us.apache.org/repos/asf/cassandra/blob/72790dc8/lib/snowball-stemmer-1.3.0.581.1.jar
----------------------------------------------------------------------
diff --git a/lib/snowball-stemmer-1.3.0.581.1.jar 
b/lib/snowball-stemmer-1.3.0.581.1.jar
new file mode 100644
index 0000000..92189b9
Binary files /dev/null and b/lib/snowball-stemmer-1.3.0.581.1.jar differ

http://git-wip-us.apache.org/repos/asf/cassandra/blob/72790dc8/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java 
b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
index 116d92e..2a2719a 100644
--- a/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
+++ b/src/java/org/apache/cassandra/config/DatabaseDescriptor.java
@@ -1964,5 +1964,10 @@ public class DatabaseDescriptor
     public static void setEncryptionContext(EncryptionContext ec)
     {
         encryptionContext = ec;
-    } 
+    }
+
+    public static int searchConcurrencyFactor()
+    {
+        return 
Integer.valueOf(System.getProperty("cassandra.search_concurrency_factor", "1"));
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/72790dc8/src/java/org/apache/cassandra/db/ColumnIndex.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/ColumnIndex.java 
b/src/java/org/apache/cassandra/db/ColumnIndex.java
index 749c155..930fc05 100644
--- a/src/java/org/apache/cassandra/db/ColumnIndex.java
+++ b/src/java/org/apache/cassandra/db/ColumnIndex.java
@@ -152,9 +152,9 @@ public class ColumnIndex
 
             UnfilteredSerializer.serializer.serialize(unfiltered, header, 
writer, pos - previousRowStart, version);
 
-            // notify observers about each new cell added to the row
-            if (!observers.isEmpty() && unfiltered.isRow())
-                ((Row) unfiltered).stream().forEach(cell -> 
observers.forEach((o) -> o.nextCell(cell)));
+            // notify observers about each new row
+            if (!observers.isEmpty())
+                observers.forEach((o) -> o.nextUnfilteredCluster(unfiltered));
 
             lastClustering = unfiltered.clustering();
             previousRowStart = pos;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/72790dc8/src/java/org/apache/cassandra/db/filter/RowFilter.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/filter/RowFilter.java 
b/src/java/org/apache/cassandra/db/filter/RowFilter.java
index 4cd2f64..c234fc9 100644
--- a/src/java/org/apache/cassandra/db/filter/RowFilter.java
+++ b/src/java/org/apache/cassandra/db/filter/RowFilter.java
@@ -171,6 +171,11 @@ public abstract class RowFilter implements 
Iterable<RowFilter.Expression>
         return withNewExpressions(newExpressions);
     }
 
+    public RowFilter withoutExpressions()
+    {
+        return withNewExpressions(Collections.emptyList());
+    }
+
     protected abstract RowFilter withNewExpressions(List<Expression> 
expressions);
 
     public boolean isEmpty()
@@ -312,7 +317,7 @@ public abstract class RowFilter implements 
Iterable<RowFilter.Expression>
         // Note: the order of this enum matter, it's used for serialization
         protected enum Kind { SIMPLE, MAP_EQUALITY, THRIFT_DYN_EXPR, CUSTOM }
 
-        abstract Kind kind();
+        protected abstract Kind kind();
         protected final ColumnDefinition column;
         protected final Operator operator;
         protected final ByteBuffer value;
@@ -689,7 +694,7 @@ public abstract class RowFilter implements 
Iterable<RowFilter.Expression>
         }
 
         @Override
-        Kind kind()
+        protected Kind kind()
         {
             return Kind.SIMPLE;
         }
@@ -782,7 +787,7 @@ public abstract class RowFilter implements 
Iterable<RowFilter.Expression>
         }
 
         @Override
-        Kind kind()
+        protected Kind kind()
         {
             return Kind.MAP_EQUALITY;
         }
@@ -833,7 +838,7 @@ public abstract class RowFilter implements 
Iterable<RowFilter.Expression>
         }
 
         @Override
-        Kind kind()
+        protected Kind kind()
         {
             return Kind.THRIFT_DYN_EXPR;
         }
@@ -883,7 +888,7 @@ public abstract class RowFilter implements 
Iterable<RowFilter.Expression>
                                          .customExpressionValueType());
         }
 
-        Kind kind()
+        protected Kind kind()
         {
             return Kind.CUSTOM;
         }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/72790dc8/src/java/org/apache/cassandra/index/SecondaryIndexManager.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/index/SecondaryIndexManager.java 
b/src/java/org/apache/cassandra/index/SecondaryIndexManager.java
index 7349167..e4a03de 100644
--- a/src/java/org/apache/cassandra/index/SecondaryIndexManager.java
+++ b/src/java/org/apache/cassandra/index/SecondaryIndexManager.java
@@ -665,6 +665,11 @@ public class SecondaryIndexManager implements IndexRegistry
         return selected;
     }
 
+    public Optional<Index> getBestIndexFor(RowFilter.Expression expression)
+    {
+        return indexes.values().stream().filter((i) -> 
i.supportsExpression(expression.column(), expression.operator())).findFirst();
+    }
+
     /**
      * Called at write time to ensure that values present in the update
      * are valid according to the rules of all registered indexes which
@@ -1040,6 +1045,12 @@ public class SecondaryIndexManager implements 
IndexRegistry
 
     private static void executeAllBlocking(Stream<Index> indexers, 
Function<Index, Callable<?>> function)
     {
+        if (function == null)
+        {
+            logger.error("failed to flush indexes: {} because flush task is 
missing.", indexers);
+            return;
+        }
+
         List<Future<?>> waitFor = new ArrayList<>();
         indexers.forEach(indexer -> {
             Callable<?> task = function.apply(indexer);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/72790dc8/src/java/org/apache/cassandra/index/sasi/SASIIndex.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/index/sasi/SASIIndex.java 
b/src/java/org/apache/cassandra/index/sasi/SASIIndex.java
new file mode 100644
index 0000000..d69b440
--- /dev/null
+++ b/src/java/org/apache/cassandra/index/sasi/SASIIndex.java
@@ -0,0 +1,288 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.index.sasi;
+
+import java.util.*;
+import java.util.concurrent.Callable;
+import java.util.function.BiFunction;
+
+import com.googlecode.concurrenttrees.common.Iterables;
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.config.Schema;
+import org.apache.cassandra.cql3.Operator;
+import org.apache.cassandra.db.*;
+import org.apache.cassandra.db.compaction.OperationType;
+import org.apache.cassandra.db.filter.RowFilter;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.partitions.PartitionIterator;
+import org.apache.cassandra.db.partitions.PartitionUpdate;
+import org.apache.cassandra.db.rows.Row;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.index.Index;
+import org.apache.cassandra.index.IndexRegistry;
+import org.apache.cassandra.index.SecondaryIndexBuilder;
+import org.apache.cassandra.index.internal.CassandraIndex;
+import org.apache.cassandra.index.sasi.conf.ColumnIndex;
+import org.apache.cassandra.index.sasi.disk.PerSSTableIndexWriter;
+import org.apache.cassandra.index.sasi.plan.QueryPlan;
+import org.apache.cassandra.index.transactions.IndexTransaction;
+import org.apache.cassandra.io.sstable.Descriptor;
+import org.apache.cassandra.io.sstable.format.SSTableFlushObserver;
+import org.apache.cassandra.io.sstable.format.SSTableReader;
+import org.apache.cassandra.notifications.*;
+import org.apache.cassandra.schema.IndexMetadata;
+import org.apache.cassandra.utils.FBUtilities;
+import org.apache.cassandra.utils.concurrent.OpOrder;
+
+public class SASIIndex implements Index, INotificationConsumer
+{
+    private static class SASIIndexBuildingSupport implements 
IndexBuildingSupport
+    {
+        public SecondaryIndexBuilder getIndexBuildTask(ColumnFamilyStore cfs,
+                                                       Set<Index> indexes,
+                                                       
Collection<SSTableReader> sstablesToRebuild)
+        {
+            NavigableMap<SSTableReader, Map<ColumnDefinition, ColumnIndex>> 
sstables = new TreeMap<>((a, b) -> {
+                return Integer.compare(a.descriptor.generation, 
b.descriptor.generation);
+            });
+
+            indexes.stream()
+                   .filter((i) -> i instanceof SASIIndex)
+                   .forEach((i) -> {
+                       SASIIndex sasi = (SASIIndex) i;
+                       sstablesToRebuild.stream()
+                                        .filter((sstable) -> 
!sasi.index.hasSSTable(sstable))
+                                        .forEach((sstable) -> {
+                                            Map<ColumnDefinition, ColumnIndex> 
toBuild = sstables.get(sstable);
+                                            if (toBuild == null)
+                                                sstables.put(sstable, (toBuild 
= new HashMap<>()));
+
+                                            
toBuild.put(sasi.index.getDefinition(), sasi.index);
+                                        });
+                   });
+
+            return new SASIIndexBuilder(cfs, sstables);
+        }
+    }
+
+    private static final SASIIndexBuildingSupport INDEX_BUILDER_SUPPORT = new 
SASIIndexBuildingSupport();
+
+    private final ColumnFamilyStore baseCfs;
+    private final IndexMetadata config;
+    private final ColumnIndex index;
+
+    public SASIIndex(ColumnFamilyStore baseCfs, IndexMetadata config)
+    {
+        this.baseCfs = baseCfs;
+        this.config = config;
+
+        ColumnDefinition column = CassandraIndex.parseTarget(baseCfs.metadata, 
config).left;
+        this.index = new ColumnIndex(baseCfs.metadata.getKeyValidator(), 
column, config);
+
+        baseCfs.getTracker().subscribe(this);
+    }
+
+    public static Map<String, String> validateOptions(Map<String, String> 
options)
+    {
+        return Collections.emptyMap();
+    }
+
+    public void register(IndexRegistry registry)
+    {
+        registry.registerIndex(this);
+    }
+
+    public IndexMetadata getIndexMetadata()
+    {
+        return config;
+    }
+
+    public Callable<?> getInitializationTask()
+    {
+        return null;
+    }
+
+    public Callable<?> getMetadataReloadTask(IndexMetadata indexMetadata)
+    {
+        return null;
+    }
+
+    public Callable<?> getBlockingFlushTask()
+    {
+        return null; // SASI indexes are flushed along side memtable
+    }
+
+    public Callable<?> getInvalidateTask()
+    {
+        return getTruncateTask(FBUtilities.timestampMicros());
+    }
+
+    public Callable<?> getTruncateTask(long truncatedAt)
+    {
+        return () -> {
+            index.dropData(truncatedAt);
+            return null;
+        };
+    }
+
+    public boolean shouldBuildBlocking()
+    {
+        return true;
+    }
+
+    public Optional<ColumnFamilyStore> getBackingTable()
+    {
+        return Optional.empty();
+    }
+
+    public boolean indexes(PartitionColumns columns)
+    {
+        return columns.contains(index.getDefinition());
+    }
+
+    public boolean dependsOn(ColumnDefinition column)
+    {
+        return index.getDefinition().compareTo(column) == 0;
+    }
+
+    public boolean supportsExpression(ColumnDefinition column, Operator 
operator)
+    {
+        return dependsOn(column);
+    }
+
+    public AbstractType<?> customExpressionValueType()
+    {
+        return null;
+    }
+
+    public RowFilter getPostIndexQueryFilter(RowFilter filter)
+    {
+        return filter.withoutExpressions();
+    }
+
+    public long getEstimatedResultRows()
+    {
+        // this is temporary (until proper QueryPlan is integrated into 
Cassandra)
+        // and allows us to priority SASI indexes if any in the query since 
they
+        // are going to be more efficient, to query and intersect, than 
built-in indexes.
+        return Long.MIN_VALUE;
+    }
+
+    public void validate(PartitionUpdate update) throws InvalidRequestException
+    {}
+
+    public Indexer indexerFor(DecoratedKey key, PartitionColumns columns, int 
nowInSec, OpOrder.Group opGroup, IndexTransaction.Type transactionType)
+    {
+        return new Indexer()
+        {
+            public void begin()
+            {}
+
+            public void partitionDelete(DeletionTime deletionTime)
+            {}
+
+            public void rangeTombstone(RangeTombstone tombstone)
+            {}
+
+            public void insertRow(Row row)
+            {
+                if (isNewData())
+                    adjustMemtableSize(index.index(key, row), opGroup);
+            }
+
+            public void updateRow(Row oldRow, Row newRow)
+            {
+                insertRow(newRow);
+            }
+
+            public void removeRow(Row row)
+            {}
+
+            public void finish()
+            {}
+
+            // we are only interested in the data from Memtable
+            // everything else is going to be handled by SSTableWriter 
observers
+            private boolean isNewData()
+            {
+                return transactionType == IndexTransaction.Type.UPDATE;
+            }
+
+            public void adjustMemtableSize(long additionalSpace, OpOrder.Group 
opGroup)
+            {
+                
baseCfs.getTracker().getView().getCurrentMemtable().getAllocator().onHeap().allocate(additionalSpace,
 opGroup);
+            }
+        };
+    }
+
+    public Searcher searcherFor(ReadCommand command) throws 
InvalidRequestException
+    {
+        CFMetaData config = command.metadata();
+        ColumnFamilyStore cfs = 
Schema.instance.getColumnFamilyStoreInstance(config.cfId);
+        return controller -> new QueryPlan(cfs, command, 
DatabaseDescriptor.getRangeRpcTimeout()).execute(controller);
+    }
+
+    public SSTableFlushObserver getFlushObserver(Descriptor descriptor, 
OperationType opType)
+    {
+        return newWriter(baseCfs.metadata.getKeyValidator(), descriptor, 
Collections.singletonMap(index.getDefinition(), index), opType);
+    }
+
+    public BiFunction<PartitionIterator, ReadCommand, PartitionIterator> 
postProcessorFor(ReadCommand command)
+    {
+        return (partitionIterator, readCommand) -> partitionIterator;
+    }
+
+    public IndexBuildingSupport getBuildTaskSupport()
+    {
+        return INDEX_BUILDER_SUPPORT;
+    }
+
+    public void handleNotification(INotification notification, Object sender)
+    {
+        // unfortunately, we can only check the type of notification via 
instanceof :(
+        if (notification instanceof SSTableAddedNotification)
+        {
+            SSTableAddedNotification notice = (SSTableAddedNotification) 
notification;
+            index.update(Collections.<SSTableReader>emptyList(), 
Iterables.toList(notice.added));
+        }
+        else if (notification instanceof SSTableListChangedNotification)
+        {
+            SSTableListChangedNotification notice = 
(SSTableListChangedNotification) notification;
+            index.update(notice.removed, notice.added);
+        }
+        else if (notification instanceof MemtableRenewedNotification)
+        {
+            index.switchMemtable();
+        }
+    }
+
+    public ColumnIndex getIndex()
+    {
+        return index;
+    }
+
+    protected static PerSSTableIndexWriter newWriter(AbstractType<?> 
keyValidator,
+                                                     Descriptor descriptor,
+                                                     Map<ColumnDefinition, 
ColumnIndex> indexes,
+                                                     OperationType opType)
+    {
+        return new PerSSTableIndexWriter(keyValidator, descriptor, opType, 
indexes);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/72790dc8/src/java/org/apache/cassandra/index/sasi/SASIIndexBuilder.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/index/sasi/SASIIndexBuilder.java 
b/src/java/org/apache/cassandra/index/sasi/SASIIndexBuilder.java
new file mode 100644
index 0000000..fc5b675
--- /dev/null
+++ b/src/java/org/apache/cassandra/index/sasi/SASIIndexBuilder.java
@@ -0,0 +1,128 @@
+package org.apache.cassandra.index.sasi;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+
+import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.db.ColumnFamilyStore;
+import org.apache.cassandra.db.DecoratedKey;
+import org.apache.cassandra.db.RowIndexEntry;
+import org.apache.cassandra.db.compaction.CompactionInfo;
+import org.apache.cassandra.db.compaction.CompactionInterruptedException;
+import org.apache.cassandra.db.compaction.OperationType;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.index.SecondaryIndexBuilder;
+import org.apache.cassandra.index.sasi.conf.ColumnIndex;
+import org.apache.cassandra.index.sasi.disk.PerSSTableIndexWriter;
+import org.apache.cassandra.io.FSReadError;
+import org.apache.cassandra.io.sstable.KeyIterator;
+import org.apache.cassandra.io.sstable.SSTable;
+import org.apache.cassandra.io.sstable.SSTableIdentityIterator;
+import org.apache.cassandra.io.sstable.format.SSTableReader;
+import org.apache.cassandra.io.util.RandomAccessReader;
+import org.apache.cassandra.utils.ByteBufferUtil;
+import org.apache.cassandra.utils.UUIDGen;
+
+class SASIIndexBuilder extends SecondaryIndexBuilder
+{
+    private final ColumnFamilyStore cfs;
+    private final UUID compactionId = UUIDGen.getTimeUUID();
+
+    private final SortedMap<SSTableReader, Map<ColumnDefinition, ColumnIndex>> 
sstables;
+
+    private long bytesProcessed = 0;
+    private final long totalSizeInBytes;
+
+    public SASIIndexBuilder(ColumnFamilyStore cfs, SortedMap<SSTableReader, 
Map<ColumnDefinition, ColumnIndex>> sstables)
+    {
+        long totalIndexBytes = 0;
+        for (SSTableReader sstable : sstables.keySet())
+            totalIndexBytes += getPrimaryIndexLength(sstable);
+
+        this.cfs = cfs;
+        this.sstables = sstables;
+        this.totalSizeInBytes = totalIndexBytes;
+    }
+
+    public void build()
+    {
+        AbstractType<?> keyValidator = cfs.metadata.getKeyValidator();
+        for (Map.Entry<SSTableReader, Map<ColumnDefinition, ColumnIndex>> e : 
sstables.entrySet())
+        {
+            SSTableReader sstable = e.getKey();
+            Map<ColumnDefinition, ColumnIndex> indexes = e.getValue();
+
+            try (RandomAccessReader dataFile = sstable.openDataReader())
+            {
+                PerSSTableIndexWriter indexWriter = 
SASIIndex.newWriter(keyValidator, sstable.descriptor, indexes, 
OperationType.COMPACTION);
+
+                long previousKeyPosition = 0;
+                try (KeyIterator keys = new KeyIterator(sstable.descriptor, 
cfs.metadata))
+                {
+                    while (keys.hasNext())
+                    {
+                        if (isStopRequested())
+                            throw new 
CompactionInterruptedException(getCompactionInfo());
+
+                        final DecoratedKey key = keys.next();
+                        final long keyPosition = keys.getKeyPosition();
+
+                        indexWriter.startPartition(key, keyPosition);
+
+                        try
+                        {
+                            RowIndexEntry indexEntry = 
sstable.getPosition(key, SSTableReader.Operator.EQ);
+                            dataFile.seek(indexEntry.position + 
indexEntry.headerOffset());
+                            ByteBufferUtil.readWithShortLength(dataFile); // 
key
+
+                            try (SSTableIdentityIterator partition = new 
SSTableIdentityIterator(sstable, dataFile, key))
+                            {
+                                while (partition.hasNext())
+                                    
indexWriter.nextUnfilteredCluster(partition.next());
+                            }
+                        }
+                        catch (IOException ex)
+                        {
+                            throw new FSReadError(ex, sstable.getFilename());
+                        }
+
+                        bytesProcessed += keyPosition - previousKeyPosition;
+                        previousKeyPosition = keyPosition;
+                    }
+
+                    completeSSTable(indexWriter, sstable, indexes.values());
+                }
+            }
+        }
+    }
+
+    public CompactionInfo getCompactionInfo()
+    {
+        return new CompactionInfo(cfs.metadata,
+                                  OperationType.INDEX_BUILD,
+                                  bytesProcessed,
+                                  totalSizeInBytes,
+                                  compactionId);
+    }
+
+    private long getPrimaryIndexLength(SSTable sstable)
+    {
+        File primaryIndex = new File(sstable.getIndexFilename());
+        return primaryIndex.exists() ? primaryIndex.length() : 0;
+    }
+
+    private void completeSSTable(PerSSTableIndexWriter indexWriter, 
SSTableReader sstable, Collection<ColumnIndex> indexes)
+    {
+        indexWriter.complete();
+
+        for (ColumnIndex index : indexes)
+        {
+            File tmpIndex = new 
File(sstable.descriptor.filenameFor(index.getComponent()));
+            if (!tmpIndex.exists()) // no data was inserted into the index for 
given sstable
+                continue;
+
+            index.update(Collections.<SSTableReader>emptyList(), 
Collections.singletonList(sstable));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/72790dc8/src/java/org/apache/cassandra/index/sasi/SSTableIndex.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/index/sasi/SSTableIndex.java 
b/src/java/org/apache/cassandra/index/sasi/SSTableIndex.java
new file mode 100644
index 0000000..7b65232
--- /dev/null
+++ b/src/java/org/apache/cassandra/index/sasi/SSTableIndex.java
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.index.sasi;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.cassandra.db.DecoratedKey;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.index.sasi.conf.ColumnIndex;
+import org.apache.cassandra.index.sasi.disk.OnDiskIndex;
+import org.apache.cassandra.index.sasi.disk.Token;
+import org.apache.cassandra.index.sasi.plan.Expression;
+import org.apache.cassandra.index.sasi.utils.RangeIterator;
+import org.apache.cassandra.io.FSReadError;
+import org.apache.cassandra.io.sstable.format.SSTableReader;
+import org.apache.cassandra.io.util.FileUtils;
+import org.apache.cassandra.utils.concurrent.Ref;
+
+import org.apache.commons.lang3.builder.HashCodeBuilder;
+
+import com.google.common.base.Function;
+
+public class SSTableIndex
+{
+    private final ColumnIndex columnIndex;
+    private final Ref<SSTableReader> sstableRef;
+    private final SSTableReader sstable;
+    private final OnDiskIndex index;
+    private final AtomicInteger references = new AtomicInteger(1);
+    private final AtomicBoolean obsolete = new AtomicBoolean(false);
+
+    public SSTableIndex(ColumnIndex index, File indexFile, SSTableReader 
referent)
+    {
+        this.columnIndex = index;
+        this.sstableRef = referent.tryRef();
+        this.sstable = sstableRef.get();
+
+        if (sstable == null)
+            throw new IllegalStateException("Couldn't acquire reference to the 
sstable: " + referent);
+
+        AbstractType<?> validator = columnIndex.getValidator();
+
+        assert validator != null;
+        assert indexFile.exists() : String.format("SSTable %s should have 
index %s.",
+                sstable.getFilename(),
+                columnIndex.getIndexName());
+
+        this.index = new OnDiskIndex(indexFile, validator, new 
DecoratedKeyFetcher(sstable));
+    }
+
+    public ByteBuffer minTerm()
+    {
+        return index.minTerm();
+    }
+
+    public ByteBuffer maxTerm()
+    {
+        return index.maxTerm();
+    }
+
+    public ByteBuffer minKey()
+    {
+        return index.minKey();
+    }
+
+    public ByteBuffer maxKey()
+    {
+        return index.maxKey();
+    }
+
+    public RangeIterator<Long, Token> search(Expression expression)
+    {
+        return index.search(expression);
+    }
+
+    public SSTableReader getSSTable()
+    {
+        return sstable;
+    }
+
+    public String getPath()
+    {
+        return index.getIndexPath();
+    }
+
+    public boolean reference()
+    {
+        while (true)
+        {
+            int n = references.get();
+            if (n <= 0)
+                return false;
+            if (references.compareAndSet(n, n + 1))
+                return true;
+        }
+    }
+
+    public void release()
+    {
+        int n = references.decrementAndGet();
+        if (n == 0)
+        {
+            FileUtils.closeQuietly(index);
+            sstableRef.release();
+            if (obsolete.get() || sstableRef.globalCount() == 0)
+                FileUtils.delete(index.getIndexPath());
+        }
+    }
+
+    public void markObsolete()
+    {
+        obsolete.getAndSet(true);
+        release();
+    }
+
+    public boolean isObsolete()
+    {
+        return obsolete.get();
+    }
+
+    public boolean equals(Object o)
+    {
+        return o instanceof SSTableIndex && 
index.getIndexPath().equals(((SSTableIndex) o).index.getIndexPath());
+    }
+
+    public int hashCode()
+    {
+        return new HashCodeBuilder().append(index.getIndexPath()).build();
+    }
+
+    public String toString()
+    {
+        return String.format("SSTableIndex(column: %s, SSTable: %s)", 
columnIndex.getColumnName(), sstable.descriptor);
+    }
+
+    private static class DecoratedKeyFetcher implements Function<Long, 
DecoratedKey>
+    {
+        private final SSTableReader sstable;
+
+        DecoratedKeyFetcher(SSTableReader reader)
+        {
+            sstable = reader;
+        }
+
+        public DecoratedKey apply(Long offset)
+        {
+            try
+            {
+                return sstable.keyAt(offset);
+            }
+            catch (IOException e)
+            {
+                throw new FSReadError(new IOException("Failed to read key from 
" + sstable.descriptor, e), sstable.getFilename());
+            }
+        }
+
+        public int hashCode()
+        {
+            return sstable.descriptor.hashCode();
+        }
+
+        public boolean equals(Object other)
+        {
+            return other instanceof DecoratedKeyFetcher
+                    && sstable.descriptor.equals(((DecoratedKeyFetcher) 
other).sstable.descriptor);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/72790dc8/src/java/org/apache/cassandra/index/sasi/Term.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/index/sasi/Term.java 
b/src/java/org/apache/cassandra/index/sasi/Term.java
new file mode 100644
index 0000000..8e8ceb2
--- /dev/null
+++ b/src/java/org/apache/cassandra/index/sasi/Term.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.index.sasi;
+
+import java.nio.ByteBuffer;
+
+import org.apache.cassandra.index.sasi.disk.OnDiskIndexBuilder.TermSize;
+import org.apache.cassandra.index.sasi.utils.MappedBuffer;
+import org.apache.cassandra.db.marshal.AbstractType;
+
+public class Term
+{
+    protected final MappedBuffer content;
+    protected final TermSize termSize;
+
+
+    public Term(MappedBuffer content, TermSize size)
+    {
+        this.content = content;
+        this.termSize = size;
+    }
+
+    public ByteBuffer getTerm()
+    {
+        long offset = termSize.isConstant() ? content.position() : 
content.position() + 2;
+        int  length = termSize.isConstant() ? termSize.size : 
content.getShort(content.position());
+
+        return content.getPageRegion(offset, length);
+    }
+
+    public long getDataOffset()
+    {
+        long position = content.position();
+        return position + (termSize.isConstant() ? termSize.size : 2 + 
content.getShort(position));
+    }
+
+    public int compareTo(AbstractType<?> comparator, ByteBuffer query)
+    {
+        return compareTo(comparator, query, true);
+    }
+
+    public int compareTo(AbstractType<?> comparator, ByteBuffer query, boolean 
checkFully)
+    {
+        long position = content.position();
+        int padding = termSize.isConstant() ? 0 : 2;
+        int len = termSize.isConstant() ? termSize.size : 
content.getShort(position);
+
+        return content.comparePageTo(position + padding, checkFully ? len : 
Math.min(len, query.remaining()), comparator, query);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/72790dc8/src/java/org/apache/cassandra/index/sasi/TermIterator.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/index/sasi/TermIterator.java 
b/src/java/org/apache/cassandra/index/sasi/TermIterator.java
new file mode 100644
index 0000000..cfa87c0
--- /dev/null
+++ b/src/java/org/apache/cassandra/index/sasi/TermIterator.java
@@ -0,0 +1,208 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.index.sasi;
+
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.index.sasi.disk.Token;
+import org.apache.cassandra.index.sasi.plan.Expression;
+import org.apache.cassandra.index.sasi.utils.RangeUnionIterator;
+import org.apache.cassandra.index.sasi.utils.RangeIterator;
+import org.apache.cassandra.io.util.FileUtils;
+
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.common.util.concurrent.Uninterruptibles;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TermIterator extends RangeIterator<Long, Token>
+{
+    private static final Logger logger = 
LoggerFactory.getLogger(TermIterator.class);
+
+    private static final ThreadLocal<ExecutorService> SEARCH_EXECUTOR = new 
ThreadLocal<ExecutorService>()
+    {
+        public ExecutorService initialValue()
+        {
+            final String currentThread = Thread.currentThread().getName();
+            final int concurrencyFactor = 
DatabaseDescriptor.searchConcurrencyFactor();
+
+            logger.info("Search Concurrency Factor is set to {} for {}", 
concurrencyFactor, currentThread);
+
+            return (concurrencyFactor <= 1)
+                    ? MoreExecutors.newDirectExecutorService()
+                    : Executors.newFixedThreadPool(concurrencyFactor, new 
ThreadFactory()
+            {
+                public final AtomicInteger count = new AtomicInteger();
+
+                public Thread newThread(Runnable task)
+                {
+                    return new Thread(task, currentThread + "-SEARCH-" + 
count.incrementAndGet()) {{ setDaemon(true); }};
+                }
+            });
+        }
+    };
+
+    private final Expression expression;
+
+    private final RangeIterator<Long, Token> union;
+    private final Set<SSTableIndex> referencedIndexes;
+
+    private TermIterator(Expression e,
+                         RangeIterator<Long, Token> union,
+                         Set<SSTableIndex> referencedIndexes)
+    {
+        super(union.getMinimum(), union.getMaximum(), union.getCount());
+
+        this.expression = e;
+        this.union = union;
+        this.referencedIndexes = referencedIndexes;
+    }
+
+    public static TermIterator build(final Expression e, Set<SSTableIndex> 
perSSTableIndexes)
+    {
+        final List<RangeIterator<Long, Token>> tokens = new 
CopyOnWriteArrayList<>();
+        final AtomicLong tokenCount = new AtomicLong(0);
+
+        RangeIterator<Long, Token> memtableIterator = 
e.index.searchMemtable(e);
+        if (memtableIterator != null)
+        {
+            tokens.add(memtableIterator);
+            tokenCount.addAndGet(memtableIterator.getCount());
+        }
+
+        final Set<SSTableIndex> referencedIndexes = new 
CopyOnWriteArraySet<>();
+
+        try
+        {
+            final CountDownLatch latch = new 
CountDownLatch(perSSTableIndexes.size());
+            final ExecutorService searchExecutor = SEARCH_EXECUTOR.get();
+
+            for (final SSTableIndex index : perSSTableIndexes)
+            {
+                if (!index.reference())
+                {
+                    latch.countDown();
+                    continue;
+                }
+
+                // add to referenced right after the reference was acquired,
+                // that helps to release index if something goes bad inside of 
the search
+                referencedIndexes.add(index);
+
+                searchExecutor.submit((Runnable) () -> {
+                    try
+                    {
+                        e.checkpoint();
+
+                        RangeIterator<Long, Token> keyIterator = 
index.search(e);
+                        if (keyIterator == null)
+                        {
+                            releaseIndex(referencedIndexes, index);
+                            return;
+                        }
+
+                        tokens.add(keyIterator);
+                        tokenCount.getAndAdd(keyIterator.getCount());
+                    }
+                    catch (Throwable e1)
+                    {
+                        releaseIndex(referencedIndexes, index);
+
+                        if (logger.isDebugEnabled())
+                            logger.debug(String.format("Failed search an index 
%s, skipping.", index.getPath()), e1);
+                    }
+                    finally
+                    {
+                        latch.countDown();
+                    }
+                });
+            }
+
+            Uninterruptibles.awaitUninterruptibly(latch);
+
+            // checkpoint right away after all indexes complete search because 
we might have crossed the quota
+            e.checkpoint();
+
+            RangeIterator<Long, Token> ranges = 
RangeUnionIterator.build(tokens);
+            return ranges == null ? null : new TermIterator(e, ranges, 
referencedIndexes);
+        }
+        catch (Throwable ex)
+        {
+            // if execution quota was exceeded while opening indexes or 
something else happened
+            // local (yet to be tracked) indexes should be released first 
before re-throwing exception
+            referencedIndexes.forEach(TermIterator::releaseQuietly);
+
+            throw ex;
+        }
+    }
+
+    protected Token computeNext()
+    {
+        try
+        {
+            return union.hasNext() ? union.next() : endOfData();
+        }
+        finally
+        {
+            expression.checkpoint();
+        }
+    }
+
+    protected void performSkipTo(Long nextToken)
+    {
+        try
+        {
+            union.skipTo(nextToken);
+        }
+        finally
+        {
+            expression.checkpoint();
+        }
+    }
+
+    public void close()
+    {
+        FileUtils.closeQuietly(union);
+        referencedIndexes.forEach(TermIterator::releaseQuietly);
+        referencedIndexes.clear();
+    }
+
+    private static void releaseIndex(Set<SSTableIndex> indexes, SSTableIndex 
index)
+    {
+        indexes.remove(index);
+        releaseQuietly(index);
+    }
+
+    private static void releaseQuietly(SSTableIndex index)
+    {
+        try
+        {
+            index.release();
+        }
+        catch (Throwable e)
+        {
+            logger.error(String.format("Failed to release index %s", 
index.getPath()), e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/72790dc8/src/java/org/apache/cassandra/index/sasi/analyzer/AbstractAnalyzer.java
----------------------------------------------------------------------
diff --git 
a/src/java/org/apache/cassandra/index/sasi/analyzer/AbstractAnalyzer.java 
b/src/java/org/apache/cassandra/index/sasi/analyzer/AbstractAnalyzer.java
new file mode 100644
index 0000000..b3fdd8c
--- /dev/null
+++ b/src/java/org/apache/cassandra/index/sasi/analyzer/AbstractAnalyzer.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.index.sasi.analyzer;
+
+import java.nio.ByteBuffer;
+import java.text.Normalizer;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.cassandra.db.marshal.AbstractType;
+
+public abstract class AbstractAnalyzer implements Iterator<ByteBuffer>
+{
+    protected ByteBuffer next = null;
+
+    public ByteBuffer next()
+    {
+        return next;
+    }
+
+    public void remove()
+    {
+        throw new UnsupportedOperationException();
+    }
+
+    public abstract void init(Map<String, String> options, AbstractType 
validator);
+
+    public abstract void reset(ByteBuffer input);
+
+    public static String normalize(String original)
+    {
+        return Normalizer.isNormalized(original, Normalizer.Form.NFC)
+                ? original
+                : Normalizer.normalize(original, Normalizer.Form.NFC);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/72790dc8/src/java/org/apache/cassandra/index/sasi/analyzer/NoOpAnalyzer.java
----------------------------------------------------------------------
diff --git 
a/src/java/org/apache/cassandra/index/sasi/analyzer/NoOpAnalyzer.java 
b/src/java/org/apache/cassandra/index/sasi/analyzer/NoOpAnalyzer.java
new file mode 100644
index 0000000..9939a13
--- /dev/null
+++ b/src/java/org/apache/cassandra/index/sasi/analyzer/NoOpAnalyzer.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.index.sasi.analyzer;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+
+import org.apache.cassandra.db.marshal.AbstractType;
+
+/**
+ * Default noOp tokenizer. The iterator will iterate only once
+ * returning the unmodified input
+ */
+public class NoOpAnalyzer extends AbstractAnalyzer
+{
+    private ByteBuffer input;
+    private boolean hasNext = false;
+
+    public void init(Map<String, String> options, AbstractType validator)
+    {}
+
+    public boolean hasNext()
+    {
+        if (hasNext)
+        {
+            this.next = input;
+            this.hasNext = false;
+            return true;
+        }
+        return false;
+    }
+
+    public void reset(ByteBuffer input)
+    {
+        this.next = null;
+        this.input = input;
+        this.hasNext = true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/72790dc8/src/java/org/apache/cassandra/index/sasi/analyzer/NonTokenizingAnalyzer.java
----------------------------------------------------------------------
diff --git 
a/src/java/org/apache/cassandra/index/sasi/analyzer/NonTokenizingAnalyzer.java 
b/src/java/org/apache/cassandra/index/sasi/analyzer/NonTokenizingAnalyzer.java
new file mode 100644
index 0000000..676b304
--- /dev/null
+++ 
b/src/java/org/apache/cassandra/index/sasi/analyzer/NonTokenizingAnalyzer.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.index.sasi.analyzer;
+
+import java.nio.ByteBuffer;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.cassandra.index.sasi.analyzer.filter.BasicResultFilters;
+import org.apache.cassandra.index.sasi.analyzer.filter.FilterPipelineBuilder;
+import org.apache.cassandra.index.sasi.analyzer.filter.FilterPipelineExecutor;
+import org.apache.cassandra.index.sasi.analyzer.filter.FilterPipelineTask;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.AsciiType;
+import org.apache.cassandra.db.marshal.UTF8Type;
+import org.apache.cassandra.serializers.MarshalException;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Analyzer that does *not* tokenize the input. Optionally will
+ * apply filters for the input output as defined in analyzers options
+ */
+public class NonTokenizingAnalyzer extends AbstractAnalyzer
+{
+    private static final Logger logger = 
LoggerFactory.getLogger(NonTokenizingAnalyzer.class);
+
+    private static final Set<AbstractType<?>> VALID_ANALYZABLE_TYPES = new 
HashSet<AbstractType<?>>()
+    {{
+            add(UTF8Type.instance);
+            add(AsciiType.instance);
+    }};
+
+    private AbstractType validator;
+    private NonTokenizingOptions options;
+    private FilterPipelineTask filterPipeline;
+
+    private ByteBuffer input;
+    private boolean hasNext = false;
+
+    public void init(Map<String, String> options, AbstractType validator)
+    {
+        init(NonTokenizingOptions.buildFromMap(options), validator);
+    }
+
+    public void init(NonTokenizingOptions tokenizerOptions, AbstractType 
validator)
+    {
+        this.validator = validator;
+        this.options = tokenizerOptions;
+        this.filterPipeline = getFilterPipeline();
+    }
+
+    public boolean hasNext()
+    {
+        // check that we know how to handle the input, otherwise bail
+        if (!VALID_ANALYZABLE_TYPES.contains(validator))
+            return false;
+
+        if (hasNext)
+        {
+            String inputStr;
+
+            try
+            {
+                inputStr = validator.getString(input);
+                if (inputStr == null)
+                    throw new MarshalException(String.format("'null' 
deserialized value for %s with %s", ByteBufferUtil.bytesToHex(input), 
validator));
+
+                Object pipelineRes = 
FilterPipelineExecutor.execute(filterPipeline, inputStr);
+                if (pipelineRes == null)
+                    return false;
+
+                next = validator.fromString(normalize((String) pipelineRes));
+                return true;
+            }
+            catch (MarshalException e)
+            {
+                logger.error("Failed to deserialize value with " + validator, 
e);
+                return false;
+            }
+            finally
+            {
+                hasNext = false;
+            }
+        }
+
+        return false;
+    }
+
+    public void reset(ByteBuffer input)
+    {
+        this.next = null;
+        this.input = input;
+        this.hasNext = true;
+    }
+
+    private FilterPipelineTask getFilterPipeline()
+    {
+        FilterPipelineBuilder builder = new FilterPipelineBuilder(new 
BasicResultFilters.NoOperation());
+        if (options.isCaseSensitive() && options.shouldLowerCaseOutput())
+            builder = builder.add("to_lower", new 
BasicResultFilters.LowerCase());
+        if (options.isCaseSensitive() && options.shouldUpperCaseOutput())
+            builder = builder.add("to_upper", new 
BasicResultFilters.UpperCase());
+        if (!options.isCaseSensitive())
+            builder = builder.add("to_lower", new 
BasicResultFilters.LowerCase());
+        return builder.build();
+    }
+}

Reply via email to